scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

commit 1ac8b4fa6fd5593521d8d5ee7fb00cd4139b6bda
parent 71bb98c5705ca7e5e8fee2b3f0fb9725065e9db2
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sun, 10 Feb 2019 10:09:53 +0000

[ld] Rewrite ld using libmach

Diffstat:
Msrc/cmd/ld/Makefile | 3+--
Dsrc/cmd/ld/ld.h | 84-------------------------------------------------------------------------------
Msrc/cmd/ld/main.c | 344++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Dsrc/cmd/ld/obj.c | 153-------------------------------------------------------------------------------
4 files changed, 220 insertions(+), 364 deletions(-)

diff --git a/src/cmd/ld/Makefile b/src/cmd/ld/Makefile @@ -4,7 +4,6 @@ PROJECTDIR = ../../.. include $(PROJECTDIR)/scripts/rules.mk OBJS = main.o \ - obj.o \ TARGET = $(BINDIR)/ld @@ -13,7 +12,7 @@ all: $(TARGET) $(TARGET): $(LIBDIR)/libscc.a $(TARGET): $(OBJS) - $(CC) $(SCC_LDFLAGS) $(OBJS) -lscc -o $@ + $(CC) $(SCC_LDFLAGS) $(OBJS) -lmach -o $@ dep: inc-dep diff --git a/src/cmd/ld/ld.h b/src/cmd/ld/ld.h @@ -1,84 +0,0 @@ -#define INSTALL 1 -#define NOINSTALL 0 - -typedef struct obj Obj; -typedef struct symbol Symbol; -typedef struct section Section; - -struct obj { - char *fname; - char *member; - FILE *fp; - long offset; - - void *filhdr; - void *scnhdr; - void *enthdr; - - char *strtbl; - size_t strsiz; - - int (*unpack)(unsigned char *, char *, ...); - int align; - - struct obj *next; -}; - -enum symflg { - SDEFINED = 1 << 1, -}; - -struct symbol { - char *name; - unsigned char flags; - long size; - TUINT base; - TUINT value; - Section *section; - Obj *where; - struct symbol *hash, *next; -}; - -struct section { - char *name; - TUINT base; - TUINT size; - struct section *next; -}; - -/* obj.c */ -extern Obj *newobj(char *fname, char *member, FILE *fp); -extern Obj *add(Obj *obj); -extern void delobj(Obj *obj); -extern Section *slookup(char *name); -extern Symbol *lookup(char *name, int install); - -/* main.c */ -extern void outmem(void); -extern void corrupted(char *fname, char *member); -extern void redefined(Obj *obj, Symbol *sym); - -/* object format */ -extern Obj *probe(char *fname, char *member, FILE *fp); -extern Obj *load(Obj *obj); -extern void writeout(FILE *fp); - - -/* - * Definition of globals variables - */ -extern int pass; -extern int sflag; -extern int xflag; -extern int Xflag; -extern int rflag; -extern int dflag; -extern int gflag; -extern Obj *objlst; -extern Section *sectlst; -extern long numsects; -extern long numsymbols; -extern TUINT tsize, dsize, bsize; -extern char *output; -extern char *entry; -extern char *datasiz; diff --git a/src/cmd/ld/main.c b/src/cmd/ld/main.c @@ -3,17 +3,44 @@ 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> -#include "ld.h" + +#define NR_SYMBOL 128 + +typedef struct objlst Objlst; +typedef struct symbol Symbol; + +struct objlst { + Obj *obj; + struct objlst *next; +}; + +struct symbol { + char *name; + Obj *obj; + Objsym *sym; + struct symbol *next, *prev; + struct symbol *hash; +}; char *output = "a.out", *entry = "start", *datasiz; -int pass; + +static char *filename, *membname; +static Objlst *objhead, *objlast; +static Symbol *symtab[NR_SYMBOL]; +static Symbol refhead = { + .next = &refhead, + .prev = &refhead, +}; + int sflag; /* discard all the symbols */ int xflag; /* discard local symbols */ int Xflag; /* discard locals starting with 'L' */ @@ -21,188 +48,239 @@ int rflag; /* preserve relocation bits */ int dflag; /* define common even with rflag */ int gflag; /* preserve debug symbols */ -static int done; +static int status; -Obj * -probe(char *fname, char *member, FILE *fp) +static char * +errstr(void) { + return strerror(errno); } -Obj * -load(Obj *obj) +static void +error(char *fmt, ...) { -} + va_list va; -void -writeout(FILE *fp) -{ + va_start(va, fmt); + fprintf(stderr, "nm: %s: ", filename); + if (membname) + fprintf(stderr, "%s: ", membname); + vfprintf(stderr, fmt, va); + putc('\n', stderr); + va_end(va); + + status = EXIT_FAILURE; } -void -redefined(Obj *obj, Symbol *sym) +static void +cleanup(void) { - /* TODO: add infotmation about where it is defined */ - fprintf(stderr, - "ld: %s: redifinition of symbol '%s'\n", - obj->fname, sym->name); + if (status != EXIT_FAILURE) + remove(output); } -void -corrupted(char *fname, char *member) +static Symbol * +lookup(Objsym *osym) { - char *fmt; + char *s; + unsigned h; + Symbol *sym; + char *name = osym->name; + + h = 0; + for (s = name; *s; s++) + h += *s; + h %= NR_SYMBOL; + + for (sym = symtab[h]; sym; sym = sym->hash) { + if (!strcmp(name, sym->name)) + return sym; + } - fmt = (member) ? - "ld: %s(%s): corrupted file\n" : "ld: %s: corrupted file\n"; - fprintf(stderr, fmt, fname, member); - exit(EXIT_FAILURE); -} + if ((sym = malloc(sizeof(*sym))) == NULL) { + error("out of memory"); + exit(EXIT_FAILURE); + } -void -outmem(void) -{ - fputs("ld: out of memory\n", stderr); - exit(EXIT_FAILURE); + sym->obj = NULL; + sym->name = osym->name; + sym->hash = symtab[h]; + symtab[h] = sym; + + refhead.next->prev = sym; + sym->next = refhead.next; + refhead.next = sym; + sym->prev = &refhead; + + return sym; } -static void -cleanup(void) +static Symbol * +define(Objsym *osym, Obj *obj) { - if (!done) - remove(output); + Symbol *sym = lookup(osym); + + if (sym->obj) { + error("%s: symbol redefined", osym->name); + return NULL; + } + + sym->obj = obj; + sym->sym = osym; + + sym->next->prev = sym->prev; + sym->prev->next = sym->next; + sym->next = sym->prev = NULL; + + return sym; } static int -object(char *fname, char *member, FILE *fp) +newsym(Objsym *osym, void *obj) { - Obj *obj; - - obj = probe(fname, member, fp); - if (!obj) - return 0; - load(obj); + switch (osym->type) { + case 'U': + lookup(osym); + case '?': + case 'N': + break; + default: + if (isupper(osym->type)) + define(osym, obj); + break; + } return 1; } -static char * -getfname(struct ar_hdr *hdr, char *dst) +static void +load(Obj *obj) { - char *p; - int i; - - memcpy(dst, hdr->ar_name, SARNAM); - dst[SARNAM] = '\0'; + Objlst *lst; - for (i = SARNAM-1; i >= 0; i--) { - if (dst[i] != ' ' && dst[i] != '/') - break; - dst[i] = '\0'; + if ((lst = malloc(sizeof(*lst))) == NULL) { + error("out of memory"); + return; } - return dst; + + lst->obj = obj; + lst->next = NULL; + + if (!objlast) + objlast = objhead = lst; + else + objlast = objlast->next = lst; + + forsym(obj, newsym, obj); } static void -ar(char *fname, FILE *fp) +newobject(FILE *fp, int type) { - struct ar_hdr hdr; - long pos, siz; - char member[SARNAM+1]; - - if (fseek(fp, SARMAG, SEEK_SET) == EOF) - goto file_error; - - while (fread(&hdr, sizeof(hdr), 1, fp) == 1) { - if (strncmp(hdr.ar_fmag, ARFMAG, sizeof(hdr.ar_fmag))) - corrupted(fname, NULL); - - siz = 0; - sscanf(hdr.ar_size, "%10ld", &siz); - if (siz & 1) - siz++; - if (siz == 0) - corrupted(fname, NULL); - - pos = ftell(fp); - if (pos == -1 || pos > LONG_MAX - siz) { - fprintf(stderr, - "ld: %s(%s): overflow in size of archive", - fname, member); - exit(EXIT_FAILURE); - } - pos += siz; + Obj *obj; - getfname(&hdr, member); - object(fname, member, fp); - if (fseek(fp, pos, SEEK_SET) == EOF) - break; + if ((obj = objnew(type)) == NULL) { + error("out of memory"); + return; } -file_error: - if (ferror(fp)) { - fprintf(stderr, "ld: %s: %s\n", fname, strerror(errno)); - exit(EXIT_FAILURE); + if (objread(obj, fp) < 0) { + error("object file corrupted"); + goto error; } + + load(obj); + + return; + +error: + objdel(obj); + return; +} + +static int +newmember(FILE *fp, char *name, void *data) +{ + return 1; } static int -archive(char *fname, FILE *fp) +newlibrary(FILE *fp) { - char magic[SARMAG]; - fpos_t pos; - fgetpos(fp, &pos); - fread(magic, SARMAG, 1, fp); - fsetpos(fp, &pos); + return artraverse(fp, newmember, NULL); +} + +static FILE * +openfile(char *name, char *buffer) +{ + size_t len; + FILE *fp; - if (ferror(fp)) - return 0; - if (strncmp(magic, ARMAG, SARMAG) != 0) - return 0; + filename = name; + membname = NULL; - ar(fname, fp); - return 1; + if (name[0] != '-' || name[1] != 'l') { + if ((fp = fopen(name, "rb")) == NULL) + error(errstr()); + return fp; + } + + len = strlen(name+2); + if (len > FILENAME_MAX-4) { + error("library name too long"); + return NULL; + } + + strcat(strcpy(buffer, "lib"), name+2); + filename = buffer; + + /* TODO: search the library now */ } static void pass1(int argc, char *argv[]) { + int t; FILE *fp; - char *s; + char buff[FILENAME_MAX]; + + for ( ; *argv; ++argv) { + if ((fp = openfile(*argv, buff)) == NULL) + continue; + + if ((t = objtype(fp, NULL)) != -1) + newobject(fp, t); + else if (archive(fp)) + newlibrary(fp); + else + error("bad format"); - while ((s = *argv++) != NULL) { - if ((fp = fopen(s, "rb")) == NULL) { - fprintf(stderr, "ld: %s: %s\n", s, strerror(errno)); - exit(EXIT_FAILURE); - } - if (!object(s, NULL, fp) && !archive(s, fp)) { - fprintf(stderr, "ld: %s: File format not recognized\n", s); - exit(EXIT_FAILURE); - } fclose(fp); } + + if (refhead.next != &refhead) { + Symbol *sym; + + for (sym = refhead.next; sym != &refhead; sym = sym->next) { + fprintf(stderr, + "ld: symbol '%s' not defined\n", + sym->name); + } + exit(EXIT_FAILURE); + } } static void pass2(int argc, char *argv[]) { - FILE *fp; - - if ((fp = fopen(output, "wb")) != NULL) { - writeout(fp); - if (fclose(fp) != EOF) - return; - } - - fprintf(stderr, "ld: %s: %s\n", output, strerror(errno)); - exit(EXIT_FAILURE); } static void usage(void) { fputs("usage: ld [options] file ...\n", stderr); - exit(1); + exit(EXIT_FAILURE); } static void @@ -219,6 +297,24 @@ Lpath(char *path) *bp = path; } +static void +refer(char *name) +{ + Objsym *osym; + + if ((osym = malloc(sizeof(*osym))) == NULL) { + fputs("ld: out of memory\n", stderr); + return; + } + + osym->name = name; + osym->type = 'U'; + osym->size = osym->value = 0; + osym->next = osym->hash = NULL; + + lookup(osym); +} + int main(int argc, char *argv[]) { @@ -262,7 +358,7 @@ main(int argc, char *argv[]) if (argc == 0) goto usage; ++argv, --argc; - lookup(*argv, INSTALL); + refer(*argv); break; case 'o': if (argc == 0) @@ -297,7 +393,5 @@ main(int argc, char *argv[]) pass1(argc, argv); pass2(argc, argv); - done = 1; - - return 0; + return status; } diff --git a/src/cmd/ld/obj.c b/src/cmd/ld/obj.c @@ -1,153 +0,0 @@ -static char sccsid[] = "@(#) ./ld/obj.c"; - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <scc/scc.h> -#include "ld.h" - -#define NR_SYM_HASH 64 - -TUINT tsize, dsize, bsize; - -Obj *objlst; -static Obj *objtail; - -long numsects, numsymbols; -static Symbol *secttail; -static Symbol *symtbl[NR_SYM_HASH]; - -Section *sectlst; - -Obj * -add(Obj *obj) -{ - obj->next = NULL; - - if (!objlst) { - objtail = objlst = obj; - } else { - objtail->next = obj; - objtail = obj; - } -} - -void -delobj(Obj *obj) -{ - free(obj->strtbl); - free(obj->scnhdr); - free(obj->filhdr); - free(obj->fname); - free(obj->member); - free(obj); -} - -Obj * -newobj(char *fname, char *member, FILE *fp) -{ - Obj *obj; - char *s, *t; - size_t len; - - len = strlen(fname); - obj = malloc(sizeof(*obj)); - s = malloc(len) + 1; - if (!obj || !s) - outmem(); - memset(obj, 0, sizeof(*obj)); - obj->fname = memcpy(s, fname, len); - - if (!member) { - obj->member = NULL; - } else { - len = strlen(member) + 1; - if ((s = malloc(len)) == NULL) - outmem(); - obj->member = memcpy(s, member, len); - } - - obj->fp = fp; - if ((obj->offset = ftell(fp)) == EOF) { - fprintf(stderr, "ld: %s: %s\n", fname, strerror(errno)); - exit(1); - } - - return obj; -} - -Section * -slookup(char *name) -{ - char *s; - Section *prev, *sp; - size_t len = strlen(name); - - for (prev = sp = sectlst; sp; prev = sp, sp = sp->next) { - if (!memcmp(sp->name, name, len)) - return sp; - } - - sp = malloc(sizeof(*sp)); - s = malloc(len); - if (!sp || !s) - outmem(); - sp->name = s; - sp->base = 0; - sp->size = 0; - sp->next = NULL; - - if (!prev) - sectlst = sp; - else - prev->next = sp; - numsects++; - - return sp; -} - -static unsigned -hash(char *s) -{ - unsigned h, c; - - for (h = 0; c = *s; ++s) - h = h*33 ^ c; - return h & NR_SYM_HASH-1; -} - -Symbol * -lookup(char *name, int install) -{ - unsigned h; - char *s; - size_t len; - Symbol *sym; - - h = hash(name); - for (sym = symtbl[h]; sym; sym = sym->hash) { - s = sym->name; - if (*name == *s && !strcmp(name, s)) - return sym; - } - - if (!install) - return NULL; - - len = strlen(name) + 1; - sym = malloc(sizeof(*sym)); - s = malloc(len); - if (!sym || !s) - outmem(); - memset(sym, 0, sizeof(*sym)); - memcpy(s, name, len); - - sym->hash = symtbl[h]; - symtbl[h] = sym; - sym->name = s; - numsymbols++; - - return sym; -}