shithub: scc

Download patch

ref: adc39da8ab9cb40357ddfedeea5e7190f72bcdfd
parent: d2f2f98130f28e9e02a4210f1096c1bd3afffb93
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Thu Aug 29 14:51:11 EDT 2019

[ld] Rewrite ld to use the new interfaces

This patch reintroduces ld and do some other small changes.

--- a/include/scc/scc/mach.h
+++ b/include/scc/scc/mach.h
@@ -1,5 +1,6 @@
-typedef struct symbol Symbol;
+typedef struct segment Segment;
 typedef struct section Section;
+typedef struct symbol Symbol;
 typedef struct objops Objops;
 typedef struct obj Obj;
 
@@ -22,13 +23,24 @@
 	void *data;
 };
 
-struct section {
+struct segment {
 	char *name;
 	unsigned long long base;
 	unsigned long long size;
 	unsigned flags;
+	int index;
 	int type;
+	int align;
+	int nsec;
+};
+
+struct section {
+	char *name;
+	unsigned long long base;
+	unsigned long long size;
+	unsigned flags;
 	int index;
+	int type;
 	int align;
 };
 
@@ -37,7 +49,7 @@
 	unsigned long long size;
 	unsigned long long value;
 	int index;
-	char class;
+	int section;
 	char type;
 };
 
@@ -53,7 +65,10 @@
 
 extern int strip(Obj *obj);
 extern int pc2line(Obj *obj, unsigned long long pc, char *fname, int *ln);
+extern int rebase(Obj *obj, long index, unsigned long offset);
+extern int mapsec(Obj *obj, int idx, FILE *fp);
 
+/* TODO: Change index to int */
 extern Symbol *getsym(Obj *obj, long *index, Symbol *sym);
 extern Section *getsec(Obj *obj, long *index, Section *sec);
 
--- a/src/cmd/Makefile
+++ b/src/cmd/Makefile
@@ -3,16 +3,17 @@
 PROJECTDIR = ../..
 include $(PROJECTDIR)/scripts/rules.mk
 
-TARGET = $(BINDIR)/nm \
-         $(BINDIR)/ar \
-         $(BINDIR)/strip \
-         $(BINDIR)/size \
-         $(BINDIR)/ranlib \
-         $(BINDIR)/objdump \
-         $(BINDIR)/objcopy \
-         $(BINDIR)/addr2line \
+TARGET =\
+	$(BINDIR)/nm\
+	$(BINDIR)/ar\
+	$(BINDIR)/strip\
+	$(BINDIR)/size\
+	$(BINDIR)/ranlib\
+	$(BINDIR)/objdump\
+	$(BINDIR)/objcopy\
+	$(BINDIR)/addr2line\
 
-DIRS   = as scc
+DIRS   = ld as scc
 
 LIBMACH = $(LIBDIR)/libmach.a
 LIBSCC  = $(LIBDIR)/libscc.a
--- a/src/cmd/ld/Makefile
+++ b/src/cmd/ld/Makefile
@@ -4,13 +4,16 @@
 
 TARGET = $(BINDIR)/ld
 
-OBJS = main.o \
-       symbol.o \
-       pass1.o \
-       pass2.o \
-       pass3.o \
-       pass4.o \
-       pass5.o \
+OBJS =\
+	main.o\
+	symbol.o\
+	section.o\
+	pass1.o\
+
+#       pass2.o \
+#       pass3.o \
+#       pass4.o \
+#       pass5.o \
 
 all: $(TARGET)
 
--- a/src/cmd/ld/ld.h
+++ b/src/cmd/ld/ld.h
@@ -1,44 +1,3 @@
-struct obj;
-struct objsym;
-
-typedef struct objlst Objlst;
-typedef struct symbol Symbol;
-typedef struct section Section;
-typedef struct segment Segment;
-
-struct section {
-	char *name;
-	unsigned long long base;
-	unsigned long size;
-	unsigned flags;
-	int type;
-	FILE *fp;
-	Section *hash;
-	Section *next;
-};
-
-struct segment {
-	int type;
-	int nsec;
-	unsigned long long base;
-	unsigned long size;
-	Section **sections;
-};
-
-struct objlst {
-	struct obj *obj;
-	struct objlst *next;
-};
-
-struct symbol {
-	char *name;
-	struct obj *obj;
-	struct objsym *def;
-	unsigned long long size, value;
-	struct symbol *next, *prev;
-	struct symbol *hash;
-};
-
 /* passes */
 extern void pass1(int argc, char *argv[]);
 extern void pass2(int argc, char *argv[]);
@@ -47,14 +6,21 @@
 extern void pass5(int argc, char *argv[]);
 
 /* main.c */
-extern char *errstr(void);
 extern void error(char *fmt, ...);
 
 /* symbol.c */
-extern Symbol *lookup(char *name);
-extern Symbol *install(char *name);
-extern Section *section(char *name);
+extern int hasref(char *name);
+extern Symbol *lookupsym(char *name);
+extern int moreundef(void);
+extern void listundef(void);
+extern Symbol *define(Symbol *osym, Obj *obj);
 extern void debugsym(void);
+
+/* section.c */
+extern Section *lookupsec(char *name);
+extern void copy(Obj *obj, Section *osec, Section *sec);
+extern void grow(Section *sec, int nbytes);
+
 extern void debugsec(void);
 
 /* globals */
@@ -67,6 +33,4 @@
 extern int gflag;
 extern char *Dflag;
 extern char *output, *entry;
-extern Objlst *objhead;
-extern Section *sechead;
-extern Segment text, rodata, data, bss;
+extern Segment debug, text, rodata, data, bss;
--- a/src/cmd/ld/main.c
+++ b/src/cmd/ld/main.c
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <scc/mach.h>
 #include <scc/syslibs.h>
 
 #include "ld.h"
@@ -27,12 +28,6 @@
 char *output = "a.out", *entry = "start";
 static int status;
 
-char *
-errstr(void)
-{
-	return strerror(errno);
-}
-
 void
 error(char *fmt, ...)
 {
@@ -67,10 +62,10 @@
 ld(int argc, char*argv[])
 {
 	pass1(argc, argv);
-	pass2(argc, argv);
+/*	pass2(argc, argv);
 	pass3(argc, argv);
 	pass4(argc, argv);
-	pass5(argc, argv);
+	pass5(argc, argv); */
 	debugsym();
 	debugsec();
 }
@@ -131,6 +126,7 @@
 				break;
 			case 'u':
 			case 'l':
+				/* FIXME: This way of handling options is wrong */
 				arg = (cp[1]) ? cp+1 : *++ap;
 				if (!arg)
 					goto usage;
--- a/src/cmd/ld/pass1.c
+++ b/src/cmd/ld/pass1.c
@@ -1,3 +1,4 @@
+#include <errno.h>
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -16,94 +17,15 @@
 };
 
 int bintype = -1;
-static Objops *binops;
-static Symbol refhead = {
-	.next = &refhead,
-	.prev = &refhead,
-};
 
-Symbol defhead = {
-	.next = &defhead,
-	.prev = &defhead,
-};
-static Objlst *objlast;
-
-Objlst *objhead;
-
-static Symbol *
-linksym(Symbol *list, Symbol *sym)
-{
-	sym->next = list;
-	sym->prev = list->prev;
-	list->prev->next = sym;
-	list->prev = sym;
-	return sym;
-}
-
-static Symbol *
-unlinksym(Symbol *sym)
-{
-	sym->next->prev = sym->prev;
-	sym->prev->next = sym->next;
-	return sym;
-}
-
-static Symbol *
-undef(char *name)
-{
-	return linksym(&refhead, install(name));
-}
-
-static Symbol *
-define(Objsym *osym, Obj *obj)
-{
-	Symbol *sym = lookup(osym->name);
-
-	if (!sym) {
-		sym = undef(osym->name);
-	} else if (sym->def && sym->def->type != 'C') {
-		error("%s: symbol redefined", osym->name);
-		return NULL;
-	}
-
-	/* TODO: deal with C symbols */
-
-	sym->obj = obj;
-	sym->def = osym;
-	sym->size = osym->size;
-	sym->value = osym->value;
-
-	unlinksym(sym);
-	linksym(&defhead, sym);
-
-	return sym;
-}
-
 static int
-moreundef(void)
-{
-	return refhead.next != &refhead;
-}
-
-static void
-listundef(void)
-{
-	Symbol *sym;
-
-	for (sym = refhead.next; sym != &refhead; sym = sym->next) {
-		fprintf(stderr,
-		        "ld: symbol '%s' not defined\n",
-		        sym->name);
-	}
-}
-
-static int
 is_needed(Obj *obj)
 {
-	Symbol *sym;
+	long i;
+	Symbol sym;
 
-	for (sym = refhead.next; sym != &refhead; sym = sym->next) {
-		if (objlookup(obj, sym->name, 0))
+	for (i = 0; getsym(obj, &i, &sym); i++) {
+		if (hasref(sym.name))
 			return 1;
 	}
 
@@ -110,84 +32,78 @@
 	return 0;
 }
 
-
-static int
-newsym(Objsym *osym, Obj *obj)
+static void
+newsec(Section *osec, Obj *obj)
 {
-	Symbol *sym;
+	int align;
+	Section *sec;
+	unsigned long long base;
 
-	switch (osym->type) {
-	case 'U':
-		if ((sym = lookup(osym->name)) == NULL)
-			sym = undef(osym->name);
-		break;
-	case '?':
-	case 'N':
-		break;
-	case 'C':
-		sym = lookup(osym->name);
-		if (!sym || !sym->def) {
-			sym = define(osym, obj);
-			break;
+	sec = lookupsec(osec->name);
+	if (sec->type != 'U') {
+		if (sec->type != osec->type
+		|| sec->flags != osec->flags
+		|| sec->base != osec->base
+		|| sec->align != osec->align) {
+			error("incompatible definition of section %s", sec->name);
+			return;
 		}
-		if (sym->def->type != 'C')
-			break;
-		if (sym->size < osym->size)
-			sym->size = osym->size;
-		break;
-	default:
-		if (isupper(osym->type))
-			define(osym, obj);
-		break;
+		align = osec->align;
+		align -= sec->size & align-1;
+		grow(sec, align);
+		rebase(obj, osec->index,  sec->size);
+	} else {
+		sec->type = osec->type;
+		sec->base = osec->base;
+		sec->size = osec->size;
+		sec->flags = osec->flags;
 	}
 
-	return 1;
+	copy(obj, osec, sec);
 }
 
 static void
-addobj(Obj *obj, FILE *fp)
+newsym(Symbol *sym, Obj *obj)
 {
-	int n;
-	Objlst *lst;
-	Objsym *sym;
-	Objsec *secp;
+	long id;
+	Section sec;
 
-	if ((lst = malloc(sizeof(*lst))) == NULL) {
-		error("out of memory");
+	if (sym->type == 'U' || islower(sym->type))
 		return;
-	}
 
-	lst->obj = obj;
-	lst->next = NULL;
-
-	if (!objlast)
-		objlast = objhead = lst;
-	else
-		objlast = objlast->next = lst;
-
-	for (sym = obj->syms; sym; sym = sym->next)
-		newsym(sym, obj);
+	sym = define(sym, obj);
+	id = sym->section;
+	getsec(obj, &id, &sec);
+  	sym->value += sec.base;
 }
 
 static void
-newobject(FILE *fp, int type, int inlib)
+load(FILE *fp, int inlib)
 {
+	int t;
+	long i;
 	Obj *obj;
- 
-	if (bintype != -1 && bintype != type) {
+	Section sec;
+	Symbol sym;
+
+	if ((t = objtype(fp, NULL)) < 0) {
+		error("bad format");
+		return;
+	}
+
+	if (bintype != -1 && bintype != t) {
 		error("not compatible object file");
 		return;
 	}
-	bintype = type;
-	binops = obj->ops;
+	bintype = t;
 
-	if ((obj = objnew(type)) == NULL) {
-		error("out of memory");
+	if ((obj = newobj(t)) == NULL) {
+		error(strerror(errno));
 		return;
 	}
 
-	if ((*binops->read)(obj, fp) < 0) {
-		error("object file corrupted");
+	if (readobj(obj, fp) < 0) {
+		error(strerror(errno));
 		goto delete;
 	}
 
@@ -194,16 +110,23 @@
 	if (inlib && !is_needed(obj))
 		goto delete;
 
-	addobj(obj, fp);
+	for (i = 0; getsec(obj, &i, &sec); i++)
+		newsec(&sec, obj);
+
+	for ( i = 0; getsym(obj, &i, &sym); i++)
+		newsym(&sym, obj);
+
+	/* TODO: link the object */
+
 	return;
 
  delete:
-	(*binops->del)(obj);
+	delobj(obj);
 	return;
 }
 
 static void
-addlib(FILE *fp)
+scanindex(FILE *fp)
 {
 	int t, added;
 	long n, i, *offs;
@@ -210,7 +133,7 @@
 	char **names;
 	Symbol *sym;
 
-	if ((*binops->getidx)(&n, &names, &offs, fp) < 0) {
+	if (getindex(bintype, &n, &names, &offs, fp) < 0) {
 		error("corrupted index");
 		return;
 	}
@@ -217,26 +140,15 @@
 
 	for (added = 0; moreundef(); added = 0) {
 		for (i = 0; i < n; i++) {
-			sym = lookup(names[i]);
-			if (!sym || sym->def)
+			if (!hasref(names[i]))
 				continue;
 
 			if (fseek(fp, offs[i], SEEK_SET) == EOF) {
-				error(errstr());
+				error(strerror(errno));
 				goto clean;
 			}
 
-			if ((t = objtype(fp, NULL)) == -1) {
-				error("library file corrupted");
-				goto clean;
-			}
-
-			if (t != bintype) {
-				error("incompatible library");
-				goto clean;
-			}
-
-			newobject(fp, t, OUTLIB);
+			load(fp, OUTLIB);
 			added = 1;
 		}
 
@@ -250,55 +162,59 @@
 	free(offs);
 }
 
-static int
-newmember(FILE *fp, char *name, void *data)
+void
+scanlib(FILE *fp)
 {
-	int t;
-	int *nmemb = data;
+	long cur, off;
+	char memb[SARNAM+1];
 
 	if (bintype == -1) {
 		error("an object file is needed before any library");
-		return 0;
+		return;
 	}
 
-	if (*nmemb++ == 0) {
-		if (!strncmp(name, "/", SARNAM) ||
-		    !strncmp(name, "__.SYMDEF", SARNAM)) {
-			addlib(fp);
-			return 0;
-		}
+	cur = ftell(fp);
+	if ((off = armember(fp, memb)) < 0)
+		goto corrupted;
+
+	if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0) {
+		scanindex(fp);
+		return;
 	}
 
-	membname = name;
-	if ((t = objtype(fp, NULL)) == -1)
-		return 1;
-
-	if (bintype != t) {
-		error("wrong object file format");
-		return 1;
+	fseek(fp, cur, SEEK_SET);
+	for (;;) {
+		cur = ftell(fp);
+		off = armember(fp, memb);
+		switch (off) {
+		case -1:
+			goto corrupted;
+		case 0:
+			return;
+		default:
+			membname = memb;
+			if (objtype(fp, NULL) != -1)
+				load(fp, INLIB);
+			membname = NULL;
+			fseek(fp, cur, SEEK_SET);
+			fseek(fp, off, SEEK_CUR);
+			break;
+		}
 	}
 
-	newobject(fp, t, INLIB);
-	membname = NULL;
-
-	return 1;
+corrupted:
+	error(strerror(errno));
+	error("library corrupted");
 }
 
-static int
-newlibrary(FILE *fp)
-{
-	int nmemb = 0;
-
-	return formember(fp, newmember, &nmemb);
-}
-
 static FILE *
-openfile(char *name, char *buffer)
+openfile(char *name)
 {
 	size_t pathlen, len;
 	FILE *fp;
 	char **bp;
 	char libname[FILENAME_MAX];
+	static char buffer[FILENAME_MAX];
 	extern char *syslibs[];
 
 	filename = name;
@@ -305,7 +221,7 @@
 	membname = NULL;
 	if (name[0] != '-' || name[1] != 'l') {
 		if ((fp = fopen(name, "rb")) == NULL)
-			error(errstr());
+			error(strerror(errno));
 		return fp;
 	}
 
@@ -317,7 +233,7 @@
 	strcat(strcpy(buffer, "lib"), name+2);
 
 	filename = buffer;
-	if ((fp = fopen(libname, "rb")) != NULL)
+	if ((fp = fopen(buffer, "rb")) != NULL)
 		return fp;
 
 	for (bp = syslibs; *bp; ++bp) {
@@ -328,7 +244,7 @@
 		memcpy(libname+pathlen+1, buffer, len);
 		buffer[pathlen] = '/';
 
-		if ((fp = fopen(buffer, "rb")) != NULL)
+		if ((fp = fopen(libname, "rb")) != NULL)
 			return fp;
 	}
 
@@ -337,21 +253,20 @@
 }
 
 static void
-load(char *name)
+process(char *name)
 {
 	int t;
 	FILE *fp;
-	char buff[FILENAME_MAX];
 
-	if ((fp = openfile(name, buff)) == NULL)
+	if ((fp = openfile(name)) == NULL)
 		return;
 
-	if ((t = objtype(fp, NULL)) != -1)
-		newobject(fp, t, OUTLIB);
-	else if (archive(fp))
-		newlibrary(fp);
+	if (archive(fp))
+		scanlib(fp);
 	else
-		error("bad format");
+		load(fp, OUTLIB);
+
+	fclose(fp);
 }
 
 /*
@@ -364,18 +279,20 @@
 
 	for (ap = argv+1; *ap; ++ap) {
 		if (ap[0][0] != '-') {
-			load(*ap);
+			process(*ap);
 			continue;
 		}
 		for (cp = &ap[0][1]; *cp; ++cp) {
 			switch (*cp) {
 			case 'l':
+				/* FIXME: we proccess arg again after this */
 				arg = (cp[1]) ? cp+1 : *++ap;
-				load(arg);
+				process(arg);
 				continue;
 			case 'u':
+				/* FIXME: we proccess arg again after this */
 				arg = (cp[1]) ? cp+1 : *++ap;
-				undef(arg);
+				lookupsym(arg);
 				continue;
 			}
 		}
--- a/src/cmd/ld/pass3.c
+++ b/src/cmd/ld/pass3.c
@@ -6,6 +6,7 @@
 
 #include "ld.h"
 
+/* TODO: This function must go in pass2 */
 static void
 rebase(Obj *obj)
 {
--- /dev/null
+++ b/src/cmd/ld/section.c
@@ -1,0 +1,140 @@
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/mach.h>
+#include <scc/scc.h>
+
+#include "ld.h"
+
+#define NR_SECTION 32
+
+struct sectab {
+	Section sec;
+	FILE *tmpfp;
+	struct sectab *hash;
+	struct sectab *next, *prev;
+};
+
+static struct sectab *sectab[NR_SECTION];
+static struct sectab secs = {.next = &secs, .prev = &secs};
+
+static Section *
+linksec(struct sectab *lst, Section *sec)
+{
+	struct sectab *sp = (struct sectab *) sec;
+
+	sp->next = lst;
+	sp->prev = lst->prev;
+	lst->prev->next = sp;
+	lst->prev = sp;
+
+	return sec;
+}
+
+Section *
+lookupsec(char *name)
+{
+	unsigned h;
+	size_t len;
+	char *s;
+	Section *sec;
+	struct sectab *sp;
+
+	h = genhash(name) % NR_SECTION;
+	for (sp = sectab[h]; sp; sp = sp->hash) {
+		if (!strcmp(name, sp->sec.name))
+			return &sp->sec;
+	}
+
+	len = strlen(name) + 1;
+	s = malloc(len);
+	sp = malloc(sizeof(*sp));
+	if (!s || !sp) {
+		error(strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	sec = &sp->sec;
+	sec->name = memcpy(s, name, len);
+	sec->type = 'U';
+	sec->base = 0;
+	sec->size = 0;
+	sec->align = 0;
+	sec->index = 0;
+	sec->flags = 0;
+	sp->tmpfp;
+	sp->hash = sectab[h];
+	sectab[h] = sp;
+
+	return linksec(&secs, sec);
+}
+
+void
+copy(Obj *obj, Section *osec, Section *sec)
+{
+	struct sectab *sp = (struct sectab *) sec;
+
+	if (sec->size > ULLONG_MAX - osec->size) {
+		error("%s: section too long", sec->name);
+		return;
+	}
+
+	if (!sp->tmpfp && (sp->tmpfp = tmpfile()) == NULL) {
+		error(strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (mapsec(obj, osec->index, sp->tmpfp) < 0) {
+		error(strerror(errno));
+		return;
+	}
+
+	sec->size += osec->size;
+}
+
+void
+grow(Section *sec, int nbytes)
+{
+	struct sectab *sp = (struct sectab *) sec;
+
+	if (sec->size > ULLONG_MAX - nbytes) {
+		error("%s: section too long", sec->name);
+		return;
+	}
+
+	if (!sp->tmpfp && (sp->tmpfp = tmpfile()) == NULL) {
+		error(strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	while (nbytes-- > 0)
+		putc(0, sp->tmpfp);
+
+	sec->size += nbytes;
+}
+
+#ifndef NDEBUG
+void
+debugsec(void)
+{
+	struct sectab **spp, *sp;
+	Section *sec;
+
+	fputs("Sections:\n", stderr);
+	for (spp = sectab; spp < &sectab[NR_SECTION]; spp++) {
+		for (sp = *spp; sp; sp = sp->hash) {
+			sec = &sp->sec;
+			fprintf(stderr,
+			        "sec: %s - %c (%#llx,%#lx)\n",
+			        sec->name,
+			        sec->type,
+			        sec->base,
+			        sec->size);
+		}
+	}
+}
+#endif
\ No newline at end of file
--- a/src/cmd/ld/symbol.c
+++ b/src/cmd/ld/symbol.c
@@ -1,3 +1,5 @@
+#include <assert.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -8,95 +10,147 @@
 #include "ld.h"
 
 #define NR_SYMBOL 128
-#define NR_SECTIONS 32
 
-static Symbol *symtab[NR_SYMBOL];
-static Section *sectab[NR_SECTIONS];
-static Section *seclast;
+/*
+ * struct symtab and struct sectab have a Symbol and a
+ * Section as first field because the code is going to
+ * cast from the symbols and the sections to the tab.
+ */
+struct symtab {
+	Symbol sym;
+	Obj *where;
+	struct symtab *hash;
+	struct symtab *next, *prev;
+};
 
-Section *sechead;
+static struct symtab *symtab[NR_SYMBOL];
+static struct symtab undef = {.next = &undef, .prev = &undef};
+static struct symtab def = {.next = &def, .prev = &def};
+static struct symtab common = {.next = &common, .prev = &common};
 
-Symbol *
-lookup(char *name)
+static Symbol *
+unlinksym(Symbol *sym)
 {
+	struct symtab *sp = (struct symtab *) sym;
+
+	sp->next->prev = sp->prev;
+	sp->prev->next = sp->next;
+
+	return sym;
+}
+
+static Symbol *
+linksym(struct symtab *lst, Symbol *sym)
+{
+	struct symtab *sp = (struct symtab *) sym;
+
+	sp->next = lst;
+	sp->prev = lst->prev;
+	lst->prev->next = sp;
+	lst->prev = sp;
+
+	return sym;
+}
+
+int
+hasref(char *name)
+{
 	unsigned h;
-	Symbol *sym;
+	struct symtab *sp;
 
 	h = genhash(name) % NR_SYMBOL;
-	for (sym = symtab[h]; sym; sym = sym->hash) {
-		if (!strcmp(name, sym->name))
-			return sym;
+	for (sp = symtab[h]; sp; sp = sp->hash) {
+		if (!strcmp(name, sp->sym.name))
+			return sp->sym.type == 'U';
 	}
-
-	return NULL;
+	return 0;
 }
 
 Symbol *
-install(char *name)
+lookupsym(char *name)
 {
 	unsigned h;
 	size_t len;
-	Symbol *sym;
 	char *s;
+	Symbol *sym;
+	struct symtab *sp;
 
 	h = genhash(name) % NR_SYMBOL;
+	for (sp = symtab[h]; sp; sp = sp->hash) {
+		if (!strcmp(name, sp->sym.name))
+			return &sp->sym;
+	}
 
 	len = strlen(name) + 1;
 	s = malloc(len);
-	sym = malloc(sizeof(*sym));
-	if (!s || !sym) {
-		error("out of memory");
+	sp = malloc(sizeof(*sp));
+	if (!s  || !sp) {
+		error(strerror(errno));
 		exit(EXIT_FAILURE);
 	}
 
-	sym->obj = NULL;
+	sym = &sp->sym;
 	sym->name = memcpy(s, name, len);
-	sym->hash = symtab[h];
-	symtab[h] = sym;
 	sym->value = 0;
 	sym->size = 0;
-	sym->next = sym->prev = NULL;
+	sym->index = 0;
+	sym->type = 'U';
+	sp->where = NULL;
+	sp->hash = symtab[h];
+	symtab[h] = sp;
 
-	return sym;
+	return linksym(&undef, sym);;
 }
 
-Section *
-section(char *name)
+
+int
+moreundef(void)
 {
-	unsigned h;
-	size_t len;
-	char *s;
-	Section *sec;
+	return undef.next != &undef;
+}
 
-	h = genhash(name) % NR_SECTIONS;
-	for (sec = sectab[h]; sec; sec = sec->hash) {
-		if (!strcmp(name, sec->name))
-			return sec;
-	}
+void
+listundef(void)
+{
+	struct symtab *sp;
 
-	len = strlen(name) + 1;
-	s = malloc(len);
-	sec = malloc(sizeof(*sec));
-	if (!s || !sec) {
-		error("out of memory");
-		exit(EXIT_FAILURE);
-	}
+	for (sp = undef.next; sp != &undef; sp = sp->next)
+		error("ld: symbol '%s' not defined", sp->sym.name);
+}
 
-	sec->name = memcpy(s, name, len);
-	sec->type = '?';
-	sec->base = 0;
-	sec->size = 0;
-	sec->flags = 0;
-	sec->hash = sectab[h];
-	sectab[h] = sec;
+Symbol *
+define(Symbol *osym, Obj *obj)
+{
+	struct symtab *lst;
+	Symbol *sym = lookupsym(osym->name);
+	struct symtab *sp = (struct symtab *) sym;
 
-	if (!sechead)
-		sechead = sec;
-	else
-		seclast->next = sec;
-	sec->next = NULL;
+	assert(osym->type != 'U');
+	sp->where = obj;
 
-	return seclast = sec;
+	switch (sym->type) {
+	case 'U':
+		sym->value = osym->value;
+		sym->size = osym->size;
+		lst = (osym->type == 'C') ? &common : &def;
+		linksym(lst, unlinksym(sym));
+		break;
+	case 'C':
+		if (osym->type != 'C') {
+			sym->size = osym->size;
+			sym->value = osym->size;
+			linksym(&def, unlinksym(sym));
+		} else  if (sym->size < osym->size) {
+			sym->value = osym->value;
+			sym->size = osym->size;
+		}
+		break;
+	defaul:
+		error("%s: symbol redefined", sym->name);
+		break;
+	}
+
+	return sym;
 }
 
 #ifndef NDEBUG
@@ -103,39 +157,18 @@
 void
 debugsym(void)
 {
-	Symbol **symp, *sym;
+	struct symtab **spp, *sp;
+	Symbol*sym;
 
 	fputs("Symbols:\n", stderr);
-	for (symp = symtab; symp < &symtab[NR_SYMBOL]; symp++) {
-		for (sym = *symp; sym; sym = sym->hash)
+	for (spp = symtab; spp < &symtab[NR_SYMBOL]; spp++) {
+		for (sp = *spp; sp; sp = sp->hash) {
+			sym = &sp->sym;
 			fprintf(stderr,
 			        "sym: %s (%#llx)\n",
 			        sym->name,
 			        sym->value);
-	}
-}
-
-void
-debugsec(void)
-{
-	Section **secp, *sec;
-
-	fputs("Sections:\n", stderr);
-	for (secp = sectab; secp < &sectab[NR_SECTIONS]; secp++) {
-		for (sec = *secp; sec; sec = sec->hash)
-			fprintf(stderr,
-			        "sec: %s - %c (%#llx,%#lx)\n",
-			        sec->name,
-			        sec->type,
-			        sec->base,
-			        sec->size);
-	}
-
-	for (sec = sechead; sec; sec = sec->next) {
-		fprintf(stderr,
-		        "%s %s",
-		        sec->name,
-			sec->next ? "->" : "\n");
+		}
 	}
 }
 #endif
--- a/src/cmd/ranlib.c
+++ b/src/cmd/ranlib.c
@@ -201,7 +201,7 @@
 	if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0)
 		cur = ftell(fp) + off;
 
-	fseek(fp, SEEK_SET, cur);
+	fseek(fp, cur, SEEK_SET);
 	for (;;) {
 		cur = ftell(fp);
 		off = armember(fp, memb);
--- a/src/libmach/Makefile
+++ b/src/libmach/Makefile
@@ -4,23 +4,26 @@
 
 TARGET = $(LIBDIR)/libmach.a
 
-OBJS = mach.o \
-       newobj.o \
-       delobj.o \
-       objpos.o \
-       archive.o \
-       armember.o \
-       objtype.o \
-       readobj.o \
-       writeobj.o \
-       getsym.o \
-       getsec.o \
-       strip.o \
-       pc2line.o \
-       pack.o \
-       unpack.o \
-       setindex.o \
-       getindex.o \
+OBJS =\
+	mach.o\
+	newobj.o \
+	delobj.o\
+	objpos.o\
+	archive.o\
+	armember.o\
+	objtype.o\
+	readobj.o\
+	writeobj.o\
+	getsym.o\
+	getsec.o\
+	rebase.o\
+	mapsec.o\
+	strip.o\
+	pc2line.o\
+	pack.o\
+	unpack.o\
+	setindex.o\
+	getindex.o\
 
 DIRS = coff32
 
--- /dev/null
+++ b/src/libmach/mapsec.c
@@ -1,0 +1,11 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+int
+mapsec(Obj *obj, int idx, FILE *fp)
+{
+	return 0;
+}
--- /dev/null
+++ b/src/libmach/rebase.c
@@ -1,0 +1,11 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+int
+rebase(Obj *obj, long idx, unsigned long base)
+{
+	return 0;
+}