scc

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

commit ef32f8d8da1196b6d6dbde048c4f1188408d7f4d
parent 25f3696093b4a1507117fad68010bb80dad89d79
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Mon,  4 Jun 2018 08:33:48 +0100

[ld/coff32] Implement load()

This function loads all the headers of the coff file and it installs
all the global symbols in the hash table. After this patch we are
ready to begin with the second pass.

Diffstat:
Mld/coff32.c | 94++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mld/ld.h | 27+++++++++++++++++----------
Mld/main.c | 20++++++++++++++++++++
Mld/obj.c | 42++++++++++++++++++++++++++----------------
4 files changed, 137 insertions(+), 46 deletions(-)

diff --git a/ld/coff32.c b/ld/coff32.c @@ -100,17 +100,16 @@ readsects(Obj *obj, long off) hdr = obj->filhdr; nsec = hdr->f_nscns; - if (nsec > SIZE_MAX / sizeof(*scn)) - return -1; + scn = NULL; + sec = NULL; + if (nsec <= SIZE_MAX / sizeof(*scn)) + scn = malloc(nsec * sizeof(*scn)); - if (nsec > SIZE_MAX / sizeof(Symbol *)) - return -1; + if (nsec <= SIZE_MAX / sizeof(Symbol *)) + sec = malloc(nsec * sizeof(Symbol *)); - scn = malloc(nsec * sizeof(*scn)); - sec = malloc(nsec * sizeof(Symbol *)); if (!scn || !sec) outmem(); - obj->sections = sec; obj->scnhdr = scn; if (fseek(obj->fp, off, SEEK_SET) == EOF) @@ -154,28 +153,24 @@ readents(Obj *obj, long off) { SYMENT *ent, *ents; FILHDR *hdr = obj->filhdr;; - long i, nsyms = hdr->f_nsyms; + long nsyms = hdr->f_nsyms; unsigned char buff[SYMESZ]; if (fseek(obj->fp, off, SEEK_SET) == EOF) return -1; - if (nsyms > SIZE_MAX/sizeof(SYMENT)) { - fprintf(stderr, - "ld: %s: overflow in size of symbol redirection\n", - obj->fname); - exit(EXIT_FAILURE); - } - - if ((ents = malloc((nsyms * sizeof(SYMENT)))) == NULL) + ents = NULL; + if (nsyms <= SIZE_MAX/sizeof(SYMENT)) + ents = malloc((nsyms * sizeof(SYMENT))); + if (!ents) outmem(); obj->enthdr = ents; for (ent = ents; ent < &ents[nsyms]; ++ent) { if (fread(buff, SYMESZ, 1, obj->fp) != 1) return -1; - getent(obj, buff, &ents[i]); + getent(obj, buff, ent); } return 0; @@ -297,6 +292,63 @@ needed(Obj *obj) return 0; } +static Obj * +load(Obj *obj) +{ + FILHDR *hdr = obj->filhdr; + SCNHDR *scn, *scns = obj->scnhdr;; + SYMENT *ent, *ents = obj->enthdr; + int nsect, aux; + + for (scn = scns; scn < &scns[hdr->f_nscns]; ++scn) { + /* TODO: padding */ + Section *sect = slookup(scn->s_name); + scn->s_vaddr = sect->base + sect->size; + sect->size += scn->s_size; + } + + aux = 0; + for (ent = ents; ent < &ents[hdr->f_nsyms]; ++ent) { + if (aux > 0) { + --aux; + continue; + } + aux = ent->n_numaux; + + scn = NULL; + switch (ent->n_scnum) { + case N_DEBUG: + continue; + case N_ABS: + break; + case N_UNDEF: + /* TODO: deal wth common blocks */ + break; + default: + nsect = ent->n_scnum-1; + if (nsect >= hdr->f_nscns) + corrupted(obj->fname, obj->member); + scn = &scns[nsect]; + ent->n_value += scn->s_vaddr; + } + + if (ent->n_sclass == C_EXT && ent->n_scnum != N_UNDEF) { + Symbol *sym = lookup(symname(obj, ent), INSTALL); + + if (sym->flags & SDEFINED) { + redefined(obj, sym); + } else { + sym->flags |= SDEFINED; + sym->where = obj; + if (scn) + sym->section = slookup(scn->s_name); + } + } + } + + return obj; +} + static void pass1(Obj *obj) { @@ -310,6 +362,7 @@ pass1(Obj *obj) } add(obj); + load(obj); } static void @@ -324,16 +377,16 @@ probe(char *fname, char *member, FILE *fp) { int c; int c1, c2; - fpos_t pos; + long pos; unsigned short magic; unsigned align; int (*unpack)(unsigned char *, char *, ...); Obj *obj; - fgetpos(fp, &pos); + pos = ftell(fp); c1 = getc(fp); c2 = getc(fp); - fsetpos(fp, &pos); + fseek(fp, pos, SEEK_SET); if (ferror(fp)) die("ld: %s: %s", fname, strerror(errno)); @@ -356,6 +409,7 @@ probe(char *fname, char *member, FILE *fp) obj->unpack = unpack; obj->align = align; obj->fmt = &coff32; + obj->offset = pos; return obj; } diff --git a/ld/ld.h b/ld/ld.h @@ -5,6 +5,7 @@ typedef struct obj Obj; typedef struct symbol Symbol; typedef struct objfmt Fmt; +typedef struct section Section; struct obj { char *fname; @@ -17,33 +18,37 @@ struct obj { void *scnhdr; void *enthdr; - Symbol **symbols; - Symbol **sections; - char *strtbl; size_t strsiz; int (*unpack)(unsigned char *, char *, ...); int align; - struct obj *next, *prev; + struct obj *next; }; -enum symflgs { - SSECT = 1 << 0, +enum symflg { + SDEFINED = 1 << 1, }; struct symbol { char *name; - char type; - short flags; + 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; +}; + struct objfmt { Obj *(*probe)(char *fname, char *member, FILE *fp); void (*pass1)(Obj *obj); @@ -52,13 +57,15 @@ struct objfmt { /* obj.c */ extern Obj *newobj(char *fname, char *member, FILE *fp); -extern void add(Obj *obj); +extern Obj *add(Obj *obj); extern void delobj(Obj *obj); -extern void newsect(Symbol *sym); +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); /* * Definition of globals variables diff --git a/ld/main.c b/ld/main.c @@ -22,6 +22,26 @@ int dflag; /* define common even with rflag */ int gflag; /* preserve debug symbols */ void +redefined(Obj *obj, Symbol *sym) +{ + /* TODO: add infotmation about where it is defined */ + fprintf(stderr, + "ld: %s: redifinition of symbol '%s'\n", + obj->fname, sym->name); +} + +void +corrupted(char *fname, char *member) +{ + char *fmt; + + fmt = (member) ? + "ld: %s(%s): corrupted file\n" : "ld: %s: corrupted file\n"; + fprintf(stderr, fmt, fname, member); + exit(EXIT_FAILURE); +} + +void outmem(void) { fputs("ld: out of memory\n", stderr); diff --git a/ld/obj.c b/ld/obj.c @@ -13,14 +13,14 @@ static char sccsid[] = "@(#) ./ld/obj.c"; Obj *objlst; static Obj *objtail; -Symbol *sectlst; static Symbol *secttail; static Symbol *symtbl[NR_SYM_HASH]; -void +Section *sectlst; + +Obj * add(Obj *obj) { - obj->prev = objlst; obj->next = NULL; if (!objlst) { @@ -35,8 +35,6 @@ void delobj(Obj *obj) { free(obj->strtbl); - free(obj->sections); - free(obj->symbols); free(obj->scnhdr); free(obj->filhdr); free(obj->fname); @@ -77,20 +75,33 @@ newobj(char *fname, char *member, FILE *fp) return obj; } -void -newsect(Symbol *sym) +Section * +slookup(char *name) { - if (sym->flags & SSECT) - return; + char *s; + Section *prev, *sp; + size_t len = strlen(name); - if (!sectlst) { - secttail = sectlst = sym; - } else { - secttail->next = sym; - secttail = sym; + for (prev = sp = sectlst; sp; prev = sp, sp = sp->next) { + if (!memcmp(sp->name, name, len)) + return sp; } - sym->flags |= SSECT; + 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; + + return sp; } static unsigned @@ -132,7 +143,6 @@ lookup(char *name, int install) sym->hash = symtbl[h]; symtbl[h] = sym; sym->name = s; - sym->type = 'U'; return sym; }