ref: a33062b124d31a503e3800e9d050d32982520a95
parent: dc1712922b142c0f4199ccf8bd60d45bf43bf304
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Tue Feb 26 06:22:25 EST 2019
[ld] Create a custom directory for ld Ld is too complex to be only a file. It is better to split it in a file per pass. We can always merge them later.
--- a/include/scc/scc/mach.h
+++ b/include/scc/scc/mach.h
@@ -3,7 +3,7 @@
typedef struct objsect Objsect;
typedef struct objsym Objsym;
typedef struct objsymdef Objsymdef;
-typedef struct object Obj;
+typedef struct obj Obj;
enum sectype {
SREAD = 1 << 0,
@@ -41,12 +41,13 @@
Objsymdef *hash, *next;
};
-struct object {
+struct obj {
int type;
char *index;
Objsym *htab[NR_SYMHASH];
Objsym *syms;;
Objsect *secs;
+ FILE *fp;
fpos_t pos;
int nsecs;
int nsyms;
--- a/src/cmd/Makefile
+++ b/src/cmd/Makefile
@@ -13,7 +13,7 @@
$(BINDIR)/objcopy \
$(BINDIR)/addr2line \
-DIRS = as scc
+DIRS = ld as scc
LIBMACH = $(LIBDIR)/libmach.a
LIBSCC = $(LIBDIR)/libscc.a
@@ -21,7 +21,7 @@
all: $(TARGET) $(DIRS)
$(DIRS): FORCE
- @+cd $@ && $(MAKE)
+ +@cd $@ && $(MAKE)
$(BINDIR)/nm: nm.o $(LIBMACH) $(LIBSCC)
$(CC) $(SCC_LDFLAGS) nm.o -lmach -lscc -o $@
@@ -34,9 +34,6 @@
$(BINDIR)/ranlib: ranlib.o $(DRIVER).o $(LIBMACH) $(LIBSCC)
$(CC) $(SCC_LDFLAGS) ranlib.o $(DRIVER).o -lmach -lscc -o $@
-
-$(BINDIR)/ld: ld.o $(LIBMACH) $(LIBSCC)
- $(CC) $(SCC_LDFLAGS) ld.o -lmach -lscc -o $@
$(BINDIR)/objdump: objdump.o $(LIBMACH)
$(CC) $(SCC_LDFLAGS) objdump.o -lmach -o $@
--- a/src/cmd/ld.c
+++ /dev/null
@@ -1,708 +1,0 @@
-static char sccsid[] = "@(#) ./ld/main.c";
-
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <scc/mach.h>
-#include <scc/scc.h>
-#include <scc/ar.h>
-#include <scc/syslibs.h>
-
-#define NR_SYMBOL 128
-
-typedef struct objlst Objlst;
-typedef struct symbol Symbol;
-typedef struct section Section;
-
-enum {
- NOINSTALL,
- INSTALL,
-};
-
-enum {
- OUTLIB,
- INLIB,
-};
-
-struct section {
- char *name;
- unsigned long long size, offset;
- unsigned flags;
- int type;
- FILE *fp;
- Section *next;
-};
-
-struct objlst {
- Obj *obj;
- struct objlst *next;
-};
-
-struct symbol {
- char *name;
- Obj *obj;
- Objsym *def;
- unsigned long long size, value;
- struct symbol *next, *prev;
- struct symbol *hash;
-};
-
-char *output = "a.out", *entry = "start", *datasiz;
-
-static Section *sections;
-static int bintype = -1;
-static char *filename, *membname;
-static Objlst *objhead, *objlast;
-static Symbol *symtab[NR_SYMBOL];
-static Symbol refhead = {
- .next = &refhead,
- .prev = &refhead,
-};
-
-static int sflag; /* discard all the symbols */
-static int xflag; /* discard local symbols */
-static int Xflag; /* discard locals starting with 'L' */
-static int rflag; /* preserve relocation bits */
-static int dflag; /* define common even with rflag */
-static int gflag; /* preserve debug symbols */
-
-static int status;
-
-static char *
-errstr(void)
-{
- return strerror(errno);
-}
-
-static void
-error(char *fmt, ...)
-{
- va_list va;
-
- va_start(va, fmt);
- fprintf(stderr, "ld: %s: ", filename);
- if (membname)
- fprintf(stderr, "%s: ", membname);
- vfprintf(stderr, fmt, va);
- putc('\n', stderr);
- va_end(va);
-
- status = EXIT_FAILURE;
-}
-
-static void
-cleanup(void)
-{
- if (status != EXIT_FAILURE)
- remove(output);
-}
-
-static int
-moreundef(void)
-{
-
- return refhead.next != &refhead;
-}
-
-static Symbol *
-lookup(char *name, int install)
-{
- size_t len;
- char *s;
- unsigned h;
- Symbol *sym;
-
- h = genhash(name) % NR_SYMBOL;
-
- for (sym = symtab[h]; sym; sym = sym->hash) {
- if (!strcmp(name, sym->name))
- return sym;
- }
-
- if (!install)
- return NULL;
-
- len = strlen(name) + 1;
- sym = malloc(sizeof(*sym));
- s = malloc(len);
- if (!len || !s) {
- error("out of memory");
- exit(EXIT_FAILURE);
- }
-
- sym->obj = NULL;
- sym->name = memcpy(s, name, len);
- sym->hash = symtab[h];
- symtab[h] = sym;
- sym->value = 0;
- sym->size = 0;
-
- refhead.next->prev = sym;
- sym->next = refhead.next;
- refhead.next = sym;
- sym->prev = &refhead;
-
- return sym;
-}
-
-static Symbol *
-define(Objsym *osym, Obj *obj)
-{
- Symbol *sym = lookup(osym->name, INSTALL);
-
- if (sym->def && sym->def->type != 'C') {
- error("%s: symbol redefined", osym->name);
- return NULL;
- }
-
- sym->obj = obj;
- sym->def = osym;
- sym->size = osym->size;
- sym->value = osym->value;
-
- sym->next->prev = sym->prev;
- sym->prev->next = sym->next;
- sym->next = sym->prev = NULL;
-
- return sym;
-}
-
-static int
-newsym(Objsym *osym, Obj *obj)
-{
- Symbol *sym;
-
- switch (osym->type) {
- case 'U':
- lookup(osym->name, INSTALL);
- case '?':
- case 'N':
- break;
- case 'C':
- sym = lookup(osym->name, NOINSTALL);
- if (!sym || !sym->def) {
- define(osym, obj);
- break;
- }
- 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;
- }
-
- return 1;
-}
-
-static void
-copy(FILE *to, FILE *from, long pad, long nbytes)
-{
- int c;
-
- while (pad--)
- putc(0, to);
-
- while (nbytes-- && (c = getc(from)) != EOF)
- putc(c, to);
-
- if (c == EOF) {
- error("section truncated");
- exit(EXIT_FAILURE);
- }
-
- if (ferror(to) || ferror(from)) {
- error(errstr());
- exit(EXIT_FAILURE);
- }
-}
-
-static Section *
-findsect(Objsect *secp)
-{
- size_t len;
- char *s;
- FILE *fp;
- Section *sp, *lastp;
-
- for (lastp = sp = sections; sp; lastp = sp, sp = sp->next) {
- if (!strcmp(sp->name, secp->name))
- return sp;
- }
-
- len = strlen(secp->name) + 1;
- s = malloc(len);
- fp = tmpfile();
-
- sp = malloc(sizeof(*sp));
- if (!s || !sp || !fp) {
- error(errstr());
- exit(EXIT_FAILURE);
- }
-
- if (lastp) {
- lastp->next = sp;
- } else {
- sections = sp;
- sp->next = NULL;
- }
-
- sp->name = memcpy(s, secp->name, len);
- sp->offset = sp->size = 0;
- sp->fp = fp;
- sp->flags = secp->flags;
- sp->type = secp->type;
-
- return sp;
-}
-
-extern int objpos(Obj *obj, FILE *fp, long pos);
-
-static void
-newsect(Objsect *secp, Obj *obj, FILE *fp)
-{
- unsigned long long align, size, pad, off;
- Section *sp;
-
- sp = findsect(secp);
-
- align = secp->align - 1;
- pad = (sp->size+align) & ~align;
-
- if (sp->size > ULLONG_MAX - pad)
- goto overflow;
- off = sp->size += pad;
-
- if (sp->size > ULLONG_MAX - secp->size)
- goto overflow;
- sp->size += secp->size;
-
- objpos(obj, fp, secp->offset);
- copy(sp->fp, fp, pad, secp->size);
-
- /*
- * and now update the offset to relect the offset
- * in the output file
- */
- secp->offset = off;
-
- return;
-
-overflow:
- error("section overflow");
- exit(EXIT_FAILURE);
-}
-
-static void
-loadobj(Obj *obj, FILE *fp)
-{
- int n;
- Objlst *lst;
- Objsym *sym;
- Objsect *secp;
-
- if ((lst = malloc(sizeof(*lst))) == NULL) {
- error("out of memory");
- 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);
-
- for (secp = obj->secs; secp; secp = secp->next)
- newsect(secp, obj, fp);
-}
-
-static void
-newobject(FILE *fp, int type, int inlib)
-{
- Obj *obj;
- Symbol *sym, *p;
-
- if ((obj = objnew(type)) == NULL) {
- error("out of memory");
- return;
- }
-
- if (bintype == -1) {
- bintype = type;
- } else if (bintype != type) {
- error("not compatible object file");
- goto delete;
- }
- bintype = type;
-
- if (objread(obj, fp) < 0) {
- error("object file corrupted");
- goto delete;
- }
-
- if (objsyms(obj) < 0 || objsect(obj) < 0) {
- error("object file corrupted");
- goto delete;
- }
-
- if (!inlib) {
- loadobj(obj, fp);
- return;
- }
-
- /*
- * we are in a library without index, so we have to check
- * if it defines some symbol that is undefined and only
- * in that case we have to load the object
- */
- p = &refhead;
- for (sym = p->next; sym != p; sym = sym->next) {
- if (objlookup(obj, sym->name, 0)) {
- loadobj(obj, fp);
- return;
- }
- }
-
-delete:
- objdel(obj);
- return;
-}
-
-static void
-loadlib(FILE *fp)
-{
- int t, loaded;
- long n;
- Objsymdef *def, *dp;
- Symbol *sym;
-
- if (getindex(bintype, &n, &def, fp) < 0) {
- error("corrupted index");
- return;
- }
-
- loaded = 1;
- while (moreundef() && loaded) {
- loaded = 0;
- for (dp = def; dp; dp = dp->next) {
- sym = lookup(dp->name, NOINSTALL);
- if (!sym || sym->def)
- continue;
-
- if (fseek(fp, dp->offset, SEEK_SET) == EOF) {
- error(errstr());
- 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);
- loaded = 1;
- }
- }
-clean:
- free(def);
-}
-
-static int
-newmember(FILE *fp, char *name, void *data)
-{
- int t;
- int *nmemb = data;
-
- if (bintype == -1) {
- error("an object file is needed before any library");
- return 0;
- }
-
- if (*nmemb++ == 0) {
- if (!strncmp(name, "/", SARNAM) ||
- !strncmp(name, "__.SYMDEF", SARNAM)) {
- loadlib(fp);
- return 0;
- }
- }
-
- membname = name;
- if ((t = objtype(fp, NULL)) == -1)
- return 1;
-
- if (bintype != t) {
- error("wrong object file format");
- return 1;
- }
-
- newobject(fp, t, INLIB);
- membname = NULL;
-
- return 1;
-}
-
-static int
-newlibrary(FILE *fp)
-{
- int nmemb = 0;
-
- return formember(fp, newmember, &nmemb);
-}
-
-static FILE *
-openfile(char *name, char *buffer)
-{
- size_t pathlen, len;
- FILE *fp;
- char **bp, **base, **end;
- char libname[FILENAME_MAX];
-
- filename = name;
- membname = NULL;
- if (name[0] != '-' || name[1] != 'l') {
- if ((fp = fopen(name, "rb")) == NULL)
- error(errstr());
- return fp;
- }
-
- len = strlen(name+2) + 3;
- if (len > FILENAME_MAX-1) {
- error("library name too long");
- return NULL;
- }
- strcat(strcpy(buffer, "lib"), name+2);
-
- filename = buffer;
- if ((fp = fopen(libname, "rb")) != NULL)
- return fp;
-
- base = syslibs;
- end = &syslibs[MAX_LIB_PATHS];
- for (bp = base; bp < end && *bp; ++bp) {
- pathlen = strlen(*bp);
- if (pathlen + len > FILENAME_MAX-1)
- continue;
- memcpy(libname, *bp, pathlen);
- memcpy(libname+pathlen+1, buffer, len);
- buffer[pathlen] = '/';
-
- if ((fp = fopen(buffer, "rb")) != NULL)
- return fp;
- }
-
- error("not found");
- return NULL;
-}
-
-static void
-listundef(void)
-{
- Symbol *sym, *p;
-
- p = &refhead;
- for (sym = p->next; sym != p; sym = sym->next) {
- fprintf(stderr,
- "ld: symbol '%s' not defined\n",
- sym->name);
- }
-}
-
-static void
-pass1(int argc, char *argv[])
-{
- int t;
- FILE *fp;
- char buff[FILENAME_MAX];
-
- for ( ; *argv; ++argv) {
- if ((fp = openfile(*argv, buff)) == NULL)
- continue;
-
- if ((t = objtype(fp, NULL)) != -1)
- newobject(fp, t, OUTLIB);
- else if (archive(fp))
- newlibrary(fp);
- else
- error("bad format");
-
- fclose(fp);
- }
-
- if (moreundef()) {
- listundef();
- exit(EXIT_FAILURE);
- }
-}
-
-/*
- * default memory layout:
- * -text
- * -data
- * -bss
- */
-static void
-pass2(int argc, char *argv[])
-{
- FILE *fp;
- Section *sp;
- long off;
- unsigned long long addr;
-
- if ((fp = fopen("binary", "wb")) == NULL) {
- perror("opening output");
- exit(EXIT_FAILURE);
- }
-
- addr = 0x100;
- for (sp = sections; sp; sp = sp->next) {
- fprintf(stderr, "1st - %c\n", sp->type);
- if (sp->type != 'T')
- continue;
- rewind(sp->fp);
- copy(fp, sp->fp, 0, sp->size);
- addr += sp->size;
- fclose(sp->fp);
- }
-
- addr = addr+3 & ~3;
- for (sp = sections; sp; sp = sp->next) {
- fprintf(stderr, "2nd - %c\n", sp->type);
- if (sp->type != 'D')
- continue;
- rewind(sp->fp);
- copy(fp, sp->fp, 0, sp->size);
- addr += sp->size;
- fclose(sp->fp);
- }
-
- addr = addr+3 & ~3;
- for (sp = sections; sp; sp = sp->next) {
- fprintf(stderr, "3rd - %c\n", sp->type);
- if (sp->type != 'B')
- continue;
- addr += sp->size;
- fclose(sp->fp);
- }
-}
-
-static void
-usage(void)
-{
- fputs("usage: ld [options] file ...\n", stderr);
- exit(EXIT_FAILURE);
-}
-
-static void
-Lpath(char *path)
-{
- char **bp, **base, **end;
-
- base = syslibs;
- end = &syslibs[MAX_LIB_PATHS];
- for (bp = base; bp < end && *bp; ++bp)
- ;
- if (bp == end) {
- fputs("ld: too many -L options\n", stderr);
- exit(1);
- }
- *bp = path;
-}
-
-int
-main(int argc, char *argv[])
-{
- char *cp, **p;
-
- for (--argc; *++argv; --argc) {
- if (argv[0][0] != '-' || argv[0][1] == 'l')
- break;
- if (argv[0][1] == '-') {
- --argc, ++argv;
- break;
- }
- for (cp = &argv[0][1]; *cp; ++cp) {
- switch (*cp) {
- case 's':
- sflag = 1;
- break;
- case 'x':
- xflag = 1;
- break;
- case 'X':
- Xflag = 1;
- break;
- case 'r':
- rflag = 1;
- break;
- case 'd':
- dflag = 1;
- break;
- case 'i':
- case 'n':
- /* TODO */
- break;
- case 'L':
- if (argc == 0)
- goto usage;
- ++argv, --argc;
- Lpath(*argv);
- break;
- case 'u':
- if (argc == 0)
- goto usage;
- ++argv, --argc;
- lookup(*argv, INSTALL);
- break;
- case 'o':
- if (argc == 0)
- goto usage;
- ++argv, --argc;
- output = *argv;
- break;
- case 'e':
- if (argc == 0)
- goto usage;
- ++argv, --argc;
- entry = *argv;
- break;
- case 'D':
- if (argc == 0)
- goto usage;
- ++argv, --argc;
- datasiz = *argv;
- break;
- default:
- usage:
- usage();
- }
- }
- }
-
- if (argc == 0)
- usage();
-
- atexit(cleanup);
-
- pass1(argc, argv);
- pass2(argc, argv);
-
- return status;
-}
--- /dev/null
+++ b/src/cmd/ld/Makefile
@@ -1,0 +1,23 @@
+.POSIX:
+PROJECTDIR = ../../..
+include $(PROJECTDIR)/scripts/rules.mk
+
+TARGET = $(BINDIR)/ld
+
+OBJS = main.o \
+ symbol.o \
+ pass1.o \
+ pass2.o \
+ pass3.o \
+
+
+all: $(TARGET)
+
+#TODO Add library dependencies
+$(TARGET): $(OBJS)
+ $(CC) $(SCC_LDFLAGS) $(OBJS) -lmach -lscc -o $@
+
+dep: inc-dep
+
+clean:
+ rm -f $(OBJS)
--- /dev/null
+++ b/src/cmd/ld/deps.mk
@@ -1,0 +1,14 @@
+#deps
+./main.o: $(INCDIR)/scc/scc/syslibs.h
+./main.o: ./ld.h
+./pass1.o: $(INCDIR)/scc/scc/ar.h
+./pass1.o: $(INCDIR)/scc/scc/mach.h
+./pass1.o: $(INCDIR)/scc/scc/scc.h
+./pass1.o: ./ld.h
+./pass2.o: $(INCDIR)/scc/scc/mach.h
+./pass2.o: ./ld.h
+./pass3.o: $(INCDIR)/scc/scc/mach.h
+./pass3.o: ./ld.h
+./symbol.o: $(INCDIR)/scc/scc/mach.h
+./symbol.o: $(INCDIR)/scc/scc/scc.h
+./symbol.o: ./ld.h
--- /dev/null
+++ b/src/cmd/ld/ld.h
@@ -1,0 +1,70 @@
+struct obj;
+struct objsym;
+
+typedef struct objlst Objlst;
+typedef struct symbol Symbol;
+typedef struct section Section;
+
+enum {
+ NOINSTALL,
+ INSTALL,
+};
+
+enum {
+ OUTLIB,
+ INLIB,
+};
+
+struct section {
+ char *name;
+ unsigned long base;
+ unsigned long long size;
+ unsigned flags;
+ int type;
+ FILE *fp;
+ Section *next;
+};
+
+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[]);
+extern void pass3(int argc, char *argv[]);
+
+/* main.c */
+extern char *errstr(void);
+extern void error(char *fmt, ...);
+
+/* symbol.c */
+extern Symbol *lookup(char *name, int install);
+extern Symbol *define(struct objsym *osym, struct obj *obj);
+extern int newsym(struct objsym *osym, struct obj *obj);
+extern int moreundef(void);
+extern void listundef(void);
+extern int defasym(struct obj *obj);
+
+/* globals */
+extern char *filename, *membname;
+extern unsigned long textsiz, datasiz, bsssiz;
+extern unsigned long textbase, database, bssbase;
+extern int sflag;
+extern int xflag;
+extern int Xflag;
+extern int rflag;
+extern int dflag;
+extern int gflag;
+extern char *Dflag;
+extern Objlst *objhead, *objlast;
--- /dev/null
+++ b/src/cmd/ld/main.c
@@ -1,0 +1,160 @@
+static char sccsid[] = "@(#) ./ld/main.c";
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/syslibs.h>
+
+#include "ld.h"
+
+char *output = "a.out", *entry = "start";
+
+char *filename, *membname;
+unsigned long textsiz, datasiz, bsssiz;
+unsigned long textbase, database, bssbase;
+
+int sflag; /* discard all the symbols */
+int xflag; /* discard local symbols */
+int Xflag; /* discard locals starting with 'L' */
+int rflag; /* preserve relocation bits */
+int dflag; /* define common even with rflag */
+int gflag; /* preserve debug symbols */
+char *Dflag; /* size of data */
+
+static int status;
+
+char *
+errstr(void)
+{
+ return strerror(errno);
+}
+
+void
+error(char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ fprintf(stderr, "ld: %s: ", filename);
+ if (membname)
+ fprintf(stderr, "%s: ", membname);
+ vfprintf(stderr, fmt, va);
+ putc('\n', stderr);
+ va_end(va);
+
+ status = EXIT_FAILURE;
+}
+
+static void
+cleanup(void)
+{
+ if (status != EXIT_FAILURE)
+ remove(output);
+}
+
+static void
+usage(void)
+{
+ fputs("usage: ld [options] file ...\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+static void
+Lpath(char *path)
+{
+ char **bp, **end;
+
+ end = &syslibs[MAX_LIB_PATHS];
+ for (bp = syslibs; bp < end && *bp; ++bp)
+ ;
+ if (bp == end) {
+ fputs("ld: too many -L options\n", stderr);
+ exit(1);
+ }
+ *bp = path;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *cp, **p;
+
+ for (--argc; *++argv; --argc) {
+ if (argv[0][0] != '-' || argv[0][1] == 'l')
+ break;
+ if (argv[0][1] == '-') {
+ --argc, ++argv;
+ break;
+ }
+ for (cp = &argv[0][1]; *cp; ++cp) {
+ switch (*cp) {
+ case 's':
+ sflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ case 'X':
+ Xflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'i':
+ case 'n':
+ /* TODO */
+ break;
+ case 'L':
+ if (argc == 0)
+ goto usage;
+ ++argv, --argc;
+ Lpath(*argv);
+ break;
+ case 'u':
+ if (argc == 0)
+ goto usage;
+ ++argv, --argc;
+ lookup(*argv, INSTALL);
+ break;
+ case 'o':
+ if (argc == 0)
+ goto usage;
+ ++argv, --argc;
+ output = *argv;
+ break;
+ case 'e':
+ if (argc == 0)
+ goto usage;
+ ++argv, --argc;
+ entry = *argv;
+ break;
+ case 'D':
+ if (argc == 0)
+ goto usage;
+ ++argv, --argc;
+ Dflag = *argv;
+ break;
+ default:
+ usage:
+ usage();
+ }
+ }
+ }
+
+ if (argc == 0)
+ usage();
+
+ atexit(cleanup);
+
+ pass1(argc, argv);
+ pass2(argc, argv);
+ pass3(argc, argv);
+
+ return status;
+}
--- /dev/null
+++ b/src/cmd/ld/pass1.c
@@ -1,0 +1,238 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/mach.h>
+#include <scc/scc.h>
+#include <scc/ar.h>
+
+#include "ld.h"
+
+static int bintype = -1;
+Objlst *objhead, *objlast;
+
+static void
+loadobj(Obj *obj, FILE *fp)
+{
+ int n;
+ Objlst *lst;
+ Objsym *sym;
+ Objsect *secp;
+
+ if ((lst = malloc(sizeof(*lst))) == NULL) {
+ error("out of memory");
+ 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);
+}
+
+static void
+newobject(FILE *fp, int type, int inlib)
+{
+ Obj *obj;
+
+ if ((obj = objnew(type)) == NULL) {
+ error("out of memory");
+ return;
+ }
+
+ if (bintype != -1 && bintype != type) {
+ error("not compatible object file");
+ goto delete;
+ }
+ bintype = type;
+
+ if (objread(obj, fp) < 0) {
+ error("object file corrupted");
+ goto delete;
+ }
+
+ if (objsyms(obj) < 0 || objsect(obj) < 0) {
+ error("object file corrupted");
+ goto delete;
+ }
+
+ /*
+ * we add the object to the list of objects
+ * if we are not in a library without index,
+ * or in that case if the library defines
+ * some symbol needed.
+ */
+ if (!inlib || defasym(obj)) {
+ loadobj(obj, fp);
+ return;
+ }
+
+ delete:
+ objdel(obj);
+ return;
+}
+
+static void
+loadlib(FILE *fp)
+{
+ int t, loaded;
+ long n;
+ Objsymdef *def, *dp;
+ Symbol *sym;
+
+ if (getindex(bintype, &n, &def, fp) < 0) {
+ error("corrupted index");
+ return;
+ }
+
+ loaded = 1;
+ while (moreundef() && loaded) {
+ loaded = 0;
+ for (dp = def; dp; dp = dp->next) {
+ sym = lookup(dp->name, NOINSTALL);
+ if (!sym || sym->def)
+ continue;
+
+ if (fseek(fp, dp->offset, SEEK_SET) == EOF) {
+ error(errstr());
+ 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);
+ loaded = 1;
+ }
+ }
+clean:
+ free(def);
+}
+
+static int
+newmember(FILE *fp, char *name, void *data)
+{
+ int t;
+ int *nmemb = data;
+
+ if (bintype == -1) {
+ error("an object file is needed before any library");
+ return 0;
+ }
+
+ if (*nmemb++ == 0) {
+ if (!strncmp(name, "/", SARNAM) ||
+ !strncmp(name, "__.SYMDEF", SARNAM)) {
+ loadlib(fp);
+ return 0;
+ }
+ }
+
+ membname = name;
+ if ((t = objtype(fp, NULL)) == -1)
+ return 1;
+
+ if (bintype != t) {
+ error("wrong object file format");
+ return 1;
+ }
+
+ newobject(fp, t, INLIB);
+ membname = NULL;
+
+ return 1;
+}
+
+static int
+newlibrary(FILE *fp)
+{
+ int nmemb = 0;
+
+ return formember(fp, newmember, &nmemb);
+}
+
+static FILE *
+openfile(char *name, char *buffer)
+{
+ size_t pathlen, len;
+ FILE *fp;
+ char **bp;
+ char libname[FILENAME_MAX];
+ extern char *syslibs[];
+
+ filename = name;
+ membname = NULL;
+ if (name[0] != '-' || name[1] != 'l') {
+ if ((fp = fopen(name, "rb")) == NULL)
+ error(errstr());
+ return fp;
+ }
+
+ len = strlen(name+2) + 3;
+ if (len > FILENAME_MAX-1) {
+ error("library name too long");
+ return NULL;
+ }
+ strcat(strcpy(buffer, "lib"), name+2);
+
+ filename = buffer;
+ if ((fp = fopen(libname, "rb")) != NULL)
+ return fp;
+
+ for (bp = syslibs; *bp; ++bp) {
+ pathlen = strlen(*bp);
+ if (pathlen + len > FILENAME_MAX-1)
+ continue;
+ memcpy(libname, *bp, pathlen);
+ memcpy(libname+pathlen+1, buffer, len);
+ buffer[pathlen] = '/';
+
+ if ((fp = fopen(buffer, "rb")) != NULL)
+ return fp;
+ }
+
+ error("not found");
+ return NULL;
+}
+
+/*
+ * Get the list of object files that are going to be linked
+ */
+void
+pass1(int argc, char *argv[])
+{
+ int t;
+ FILE *fp;
+ char buff[FILENAME_MAX];
+
+ for ( ; *argv; ++argv) {
+ if ((fp = openfile(*argv, buff)) == NULL)
+ continue;
+
+ if ((t = objtype(fp, NULL)) != -1)
+ newobject(fp, t, OUTLIB);
+ else if (archive(fp))
+ newlibrary(fp);
+ else
+ error("bad format");
+ }
+
+ if (moreundef()) {
+ listundef();
+ exit(EXIT_FAILURE);
+ }
+}
--- /dev/null
+++ b/src/cmd/ld/pass2.c
@@ -1,0 +1,53 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include <scc/mach.h>
+
+#include "ld.h"
+
+static unsigned long long
+sectsize(int type)
+{
+ unsigned long long size;
+ Objlst *lp;
+ Objsect *sp;
+
+ size = 0;
+ for (lp = objhead; lp; lp = lp->next) {
+ for (sp = lp->obj->secs; sp; sp = sp->next) {
+ if (sp->type != type)
+ continue;
+ size += sp->size;
+ }
+ }
+
+ return size;
+}
+
+/*
+ * calculate the size of every segment
+ */
+void
+pass2(int argc, char *argv[])
+{
+ unsigned long long n;
+ char *end;
+ Objsect *sp;
+
+ datasiz = bsssiz = textsiz = 0;
+
+ textsiz = sectsize('T');
+ datasiz = sectsize('D');
+ bsssiz = sectsize('B');
+
+ if (Dflag) {
+ n = strtoull(Dflag, &end, 0);
+ if (n == ULLONG_MAX || *end != '\0') {
+ error("incorrect -D value");
+ exit(EXIT_FAILURE);
+ }
+ if (n > datasiz)
+ datasiz = n;
+ }
+}
--- /dev/null
+++ b/src/cmd/ld/pass3.c
@@ -1,0 +1,34 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/mach.h>
+
+#include "ld.h"
+
+/*
+ * relocate the sections
+ */
+void
+pass3(int argc, char *argv[])
+{
+ Obj *obj;
+ Objlst *lst;
+ Objsect *sp;
+ unsigned long long text, data, bss;
+
+ textbase = text = 0;
+ database = data = textsiz+3 & ~3;
+ bssbase = bss = data+datasiz+3 & ~3;
+
+ for (lst = objhead; lst; lst = lst->next) {
+ for (sp = lst->obj->secs; sp; sp = sp->next) {
+ switch (sp->type) {
+ case 'T':
+ case 'D':
+ case 'B':
+ default:
+ abort();
+ }
+ }
+ }
+}
--- /dev/null
+++ b/src/cmd/ld/symbol.c
@@ -1,0 +1,146 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/mach.h>
+#include <scc/scc.h>
+
+#include "ld.h"
+
+#define NR_SYMBOL 128
+
+static Symbol *symtab[NR_SYMBOL];
+
+static Symbol refhead = {
+ .next = &refhead,
+ .prev = &refhead,
+};
+
+Symbol *
+lookup(char *name, int install)
+{
+ size_t len;
+ char *s;
+ unsigned h;
+ Symbol *sym;
+
+ h = genhash(name) % NR_SYMBOL;
+
+ for (sym = symtab[h]; sym; sym = sym->hash) {
+ if (!strcmp(name, sym->name))
+ return sym;
+ }
+
+ if (!install)
+ return NULL;
+
+ len = strlen(name) + 1;
+ sym = malloc(sizeof(*sym));
+ s = malloc(len);
+ if (!len || !s) {
+ error("out of memory");
+ exit(EXIT_FAILURE);
+ }
+
+ sym->obj = NULL;
+ sym->name = memcpy(s, name, len);
+ sym->hash = symtab[h];
+ symtab[h] = sym;
+ sym->value = 0;
+ sym->size = 0;
+
+ refhead.next->prev = sym;
+ sym->next = refhead.next;
+ refhead.next = sym;
+ sym->prev = &refhead;
+
+ return sym;
+}
+
+Symbol *
+define(Objsym *osym, Obj *obj)
+{
+ Symbol *sym = lookup(osym->name, INSTALL);
+
+ if (sym->def && sym->def->type != 'C') {
+ error("%s: symbol redefined", osym->name);
+ return NULL;
+ }
+
+ sym->obj = obj;
+ sym->def = osym;
+ sym->size = osym->size;
+ sym->value = osym->value;
+
+ sym->next->prev = sym->prev;
+ sym->prev->next = sym->next;
+ sym->next = sym->prev = NULL;
+
+ return sym;
+}
+
+int
+newsym(Objsym *osym, Obj *obj)
+{
+ Symbol *sym;
+
+ switch (osym->type) {
+ case 'U':
+ lookup(osym->name, INSTALL);
+ case '?':
+ case 'N':
+ break;
+ case 'C':
+ sym = lookup(osym->name, NOINSTALL);
+ if (!sym || !sym->def) {
+ define(osym, obj);
+ break;
+ }
+ 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;
+ }
+
+ return 1;
+}
+
+int
+moreundef(void)
+{
+
+ return refhead.next != &refhead;
+}
+
+void
+listundef(void)
+{
+ Symbol *sym, *p;
+
+ p = &refhead;
+ for (sym = p->next; sym != p; sym = sym->next) {
+ fprintf(stderr,
+ "ld: symbol '%s' not defined\n",
+ sym->name);
+ }
+}
+
+int
+defasym(Obj *obj)
+{
+ Symbol *sym, *p;
+
+ p = &refhead;
+ for (sym = p->next; sym != p; sym = sym->next) {
+ if (objlookup(obj, sym->name, 0))
+ return 1;
+ }
+
+ return 0;
+}
--- a/src/libmach/objread.c
+++ b/src/libmach/objread.c
@@ -19,5 +19,7 @@
if ((*funv[fmt])(obj, fp) < 0)
return -1;
+ obj->fp = fp;
+
return 0;
}