scc

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

commit d3e654ade40320f6b68b2834521124580cb0c74b
parent c51ac670f0c7765275beb7759785af52726a585e
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Mon, 19 Aug 2019 10:20:44 +0100

[ld] Add structures for sections and segments

Diffstat:
Msrc/cmd/ld/ld.h | 19++++++++++++++++---
Msrc/cmd/ld/main.c | 3+--
Msrc/cmd/ld/pass1.c | 42+++++++++++++++++++++---------------------
Msrc/cmd/ld/pass2.c | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/cmd/ld/pass3.c | 21++++++++++++---------
Msrc/cmd/ld/symbol.c | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
6 files changed, 182 insertions(+), 57 deletions(-)

diff --git a/src/cmd/ld/ld.h b/src/cmd/ld/ld.h @@ -4,6 +4,7 @@ struct objsym; typedef struct objlst Objlst; typedef struct symbol Symbol; typedef struct section Section; +typedef struct segment Segment; struct section { char *name; @@ -12,9 +13,19 @@ struct section { unsigned flags; int type; FILE *fp; + Section *hash; Section *next; }; +struct segment { + char *name; + int type; + unsigned nsec; + unsigned long long base; + unsigned long size; + Section **sections; +}; + struct objlst { struct obj *obj; struct objlst *next; @@ -42,12 +53,12 @@ extern void error(char *fmt, ...); /* symbol.c */ extern Symbol *lookup(char *name); extern Symbol *install(char *name); -extern int debugsym(void); +extern Section *section(char *name); +extern void debugsym(void); +extern void debugsec(void); /* 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; @@ -56,3 +67,5 @@ extern int dflag; extern int gflag; extern char *Dflag; extern Objlst *objhead; +extern Section *sechead; +extern Segment text, rodata, data, bss; diff --git a/src/cmd/ld/main.c b/src/cmd/ld/main.c @@ -11,8 +11,6 @@ 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 */ @@ -65,6 +63,7 @@ ld(int argc, char*argv[]) pass2(argc, argv); pass3(argc, argv); debugsym(); + debugsec(); } static void diff --git a/src/cmd/ld/pass1.c b/src/cmd/ld/pass1.c @@ -25,17 +25,32 @@ static Objlst *objlast; Objlst *objhead; static Symbol * +undef(char *name) +{ + Symbol *sym = install(name); + + sym->next = &refhead; + sym->prev = refhead.prev; + refhead.prev->next = sym; + refhead.prev = sym; + + return sym; +} + +static Symbol * define(Objsym *osym, Obj *obj) { Symbol *sym = lookup(osym->name); if (!sym) { - sym = install(osym->name); + 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; @@ -48,33 +63,18 @@ define(Objsym *osym, Obj *obj) return sym; } -static Symbol * -undef(char *name) -{ - Symbol *sym = install(name); - - refhead.next->prev = sym; - sym->next = refhead.next; - refhead.next = sym; - sym->prev = &refhead; - - return sym; -} - static int moreundef(void) { - return refhead.next != &refhead; } static void listundef(void) { - Symbol *sym, *p; + Symbol *sym; - p = &refhead; - for (sym = p->next; sym != p; sym = sym->next) { + for (sym = refhead.next; sym != &refhead; sym = sym->next) { fprintf(stderr, "ld: symbol '%s' not defined\n", sym->name); @@ -84,10 +84,9 @@ listundef(void) static int is_needed(Obj *obj) { - Symbol *sym, *p; + Symbol *sym; - p = &refhead; - for (sym = p->next; sym != p; sym = sym->next) { + for (sym = refhead.next; sym != &refhead; sym = sym->next) { if (objlookup(obj, sym->name, 0)) return 1; } @@ -228,6 +227,7 @@ addlib(FILE *fp) newobject(fp, t, OUTLIB); added = 1; } + if (!added) break; } diff --git a/src/cmd/ld/pass2.c b/src/cmd/ld/pass2.c @@ -6,40 +6,78 @@ #include "ld.h" -static unsigned long long -sectsize(int type) +Segment text = {.type = 'T'}; +Segment rodata = {.type = 'R'}; +Segment data = {.type = 'D'}; +Segment bss = {.type = 'B'}; +Segment debug = {.type = 'N'}; + +static void +mksecs(void) { - unsigned long long size; Objlst *lp; Objsect *sp; + Section *sec; - 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; + sec = section(sp->name); + + if (sec->type == '?') { + sec->type = sp->type; + sec->flags = sp->flags; + } + + if (sec->type != sp->type || sec->flags != sp->flags) { + error("incompatible definitions of section '%s'", + sec->name); + } + + sec->size += sp->size; } } +} - return size; +static void +merge(Segment *seg) +{ + Section *sec, **p; + int n; + + for (n = 0, sec = sechead; sec; sec = sec->next, ++n) { + if (sec->type != seg->type) + continue; + p = realloc(seg->sections, n * sizeof(*p)); + if (!p) { + error("ou of memory"); + exit(EXIT_FAILURE); + } + p[n] = sec; + seg->sections = p; + seg->size += sec->size; + } + + seg->nsec = n; +} + +static void +mksegs(void) +{ + merge(&text); + merge(&rodata); + merge(&data); + merge(&bss); + merge(&debug); } -/* - * 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'); + mksecs(); + mksegs(); if (Dflag) { n = strtoull(Dflag, &end, 0); @@ -47,7 +85,8 @@ pass2(int argc, char *argv[]) error("incorrect -D value"); exit(EXIT_FAILURE); } - if (n > datasiz) - datasiz = n; + + if (n > data.size) + data.size = n; } } diff --git a/src/cmd/ld/pass3.c b/src/cmd/ld/pass3.c @@ -46,33 +46,36 @@ pass3(int argc, char *argv[]) Obj *obj; Objlst *lst; Objsect *sp; - unsigned long long *base, text, data, bss; + Segment *seg; /* * TODO: deal with page aligment */ - textbase = text = 0x100; - database = data = textsiz; - bssbase = bss = data+datasiz; + text.base = 0x100; + rodata.base = text.base + text.size; + data.base = rodata.base + rodata.size; + bss.base = data.base + data.size; for (lst = objhead; lst; lst = lst->next) { obj = lst->obj; for (sp = obj->secs; sp; sp = sp->next) { switch (sp->type) { case 'T': - base = &text; + seg = &text; break; + /* TODO: what happens with rodata? */ case 'D': - base = &data; + seg = &data; break; case 'B': - base = &bss; + seg = &bss; break; default: abort(); } - sp->base = *base; - *base += sp->size; + sp->base = seg->base + seg->size; + /* TODO: deal with symbol aligment */ + seg->size += sp->size; } rebase(obj); } diff --git a/src/cmd/ld/symbol.c b/src/cmd/ld/symbol.c @@ -8,8 +8,13 @@ #include "ld.h" #define NR_SYMBOL 128 +#define NR_SECTIONS 32 static Symbol *symtab[NR_SYMBOL]; +static Section *sectab[NR_SECTIONS]; +static Section *seclast; + +Section *sechead; Symbol * lookup(char *name) @@ -35,9 +40,11 @@ install(char *name) char *s; h = genhash(name) % NR_SYMBOL; + len = strlen(name) + 1; + s = malloc(len); sym = malloc(sizeof(*sym)); - if ((s = malloc(len)) == NULL) { + if (!s || !sym) { error("out of memory"); exit(EXIT_FAILURE); } @@ -53,18 +60,82 @@ install(char *name) return sym; } +Section * +section(char *name) +{ + unsigned h; + size_t len; + char *s; + Section *sec; + + h = genhash(name) % NR_SECTIONS; + for (sec = sectab[h]; sec; sec = sec->hash) { + if (!strcmp(name, sec->name)) + return sec; + } + + len = strlen(name) + 1; + s = malloc(len); + sec = malloc(sizeof(*sec)); + if (!s || !sec) { + error("out of memory"); + exit(EXIT_FAILURE); + } + + sec->name = memcpy(s, name, len); + sec->type = '?'; + sec->base = 0; + sec->size = 0; + sec->flags = 0; + sec->hash = sectab[h]; + sectab[h] = sec; + + if (!sechead) + sechead = sec; + else + seclast->next = sec; + sec->next = NULL; + + return seclast = sec; +} + #ifndef NDEBUG -int +void debugsym(void) { Symbol **symp, *sym; + fputs("Symbols:\n", stderr); for (symp = symtab; symp < &symtab[NR_SYMBOL]; symp++) { for (sym = *symp; sym; sym = sym->hash) fprintf(stderr, - "sym: %s (%#x)\n", + "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