scc

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

commit ae8d51718664aa49b07acb535569362aa71c94b2
parent ad5ff8712dc62f69cdd0d84822fdd04aa4a0f69d
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Mon,  7 Jan 2019 16:10:28 +0000

[libmach] Rework the object interface

Diffstat:
Minclude/scc/scc/mach.h | 41++++++++++++++++++++++++++++++++++-------
Msrc/libmach/Makefile | 1+
Msrc/libmach/coff32.c | 200+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/libmach/libmach.h | 12+++++++-----
Msrc/libmach/object.c | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/nm/nm.c | 94++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
6 files changed, 315 insertions(+), 190 deletions(-)

diff --git a/include/scc/scc/mach.h b/include/scc/scc/mach.h @@ -1,18 +1,37 @@ +#define NR_SYMHASH 32 + +typedef struct section Section; typedef struct symbol Symbol; typedef struct object Obj; +enum sectype { + SREAD = 1 << 0, + SWRITE = 1 << 1, + SEXEC = 1 << 2, + SNOLOAD = 1 << 3, + SFILE = 1 << 4, + SABS = 1 << 5, + SBLOB = 1 << 6, +}; + +struct section { + char *name; + unsigned flags; +}; + struct symbol { char type; char *name; unsigned long long size; unsigned long long value; + Symbol *next; + Symbol *hash; }; struct object { int type; - Symbol *symtbl; - unsigned long nsym; - unsigned long cursym; + Symbol *htab[NR_SYMHASH]; + Symbol *head; fpos_t pos; void *data; }; @@ -24,7 +43,15 @@ extern int artraverse(FILE *fp, int (*fn)(FILE *, char *, void *), void *data); -extern int objtest(FILE *fp, char **name); -extern int objopen(FILE *fp, int type, Obj *obj); -extern int objread(FILE *fp, Obj *obj, int (*filter)(Symbol *)); -extern void objclose(Obj *obj); +extern int objtype(FILE *fp, char **name); +extern Obj *objnew(int type); +extern void objdel(Obj *obj); +extern void objreset(Obj *obj); +extern int objread(Obj *obj, FILE *fp); +extern Symbol *objlookup(Obj *obj, char *name); +extern int objtraverse(Obj *obj, int (*fn)(Symbol *sym, void *data), void *data); + +/* TODO */ +extern int objload(Obj *obj, Obj *to); +extern int objreloc(Obj *obj, char *sect, void *rel); +extern int objwrite(Obj *obj, FILE *fp); diff --git a/src/libmach/Makefile b/src/libmach/Makefile @@ -9,6 +9,7 @@ OBJS = object.o \ unpack.o \ artraverse.o \ armember.o \ + objfmt.o \ coff32.o \ all: $(TARGET) diff --git a/src/libmach/coff32.c b/src/libmach/coff32.c @@ -109,28 +109,109 @@ probe(unsigned char *buf, char **name) return -1; } +static char * +symname(Coff32 *coff, SYMENT *ent) +{ + long off; + + if (ent->n_zeroes != 0) + return ent->n_name; + + off = ent->n_offset; + if (off >= coff->strsiz) + return NULL; + return &coff->strtbl[off]; +} + static int -open(FILE *fp, int type, Obj *obj) +typeof(Coff32 *coff, SYMENT *ent) +{ + int c; + SCNHDR *scn; + long flags; + + switch (ent->n_scnum) { + case N_DEBUG: + c = 'N'; + break; + case N_ABS: + c = 'a'; + break; + case N_UNDEF: + c = (ent->n_value != 0) ? 'C' : 'U'; + break; + default: + if (ent->n_scnum > coff->hdr.f_nscns) + return -1; + scn = &coff->scns[ent->n_scnum-1]; + flags = scn->s_flags; + if (flags & STYP_TEXT) + c = 't'; + else if (flags & STYP_DATA) + c = 'd'; + else if (flags & STYP_BSS) + c = 'b'; + else + c = '?'; + break; + } + + if (ent->n_sclass == C_EXT) + c = toupper(c); + + return c; +} + +static int +mkindex(Obj *obj) +{ + int t; + long i; + char *s; + Symbol *sym; + SYMENT *ent; + Coff32 *coff = obj->data; + + for (i = 0; i < coff->hdr.f_nsyms; i += ent->n_numaux + 1) { + ent = &coff->ents[i]; + + if ((t = typeof(coff, ent)) < 0) + return -1; + + if ((s = symname(coff, ent)) == NULL) + return -1; + + if ((sym = objlookup(obj, s)) == NULL) + return -1; + + sym->type = t; + sym->value = ent->n_value; + sym->size = (sym->type == 'C') ? ent->n_value : 0; + } + + return 0; +} + +static int +read(Obj *obj, FILE *fp) { int order; long i, siz; FILHDR *hdr; - SCNHDR *scn = NULL; - SYMENT *ent = NULL; + SCNHDR *scn; + SYMENT *ent; char *str = NULL; - struct coff32 *coff = NULL; + struct coff32 *coff; unsigned char buf[100]; assert(FILHSZ < sizeof(buf)); assert(SCNHSZ < sizeof(buf)); assert(SYMESZ < sizeof(buf)); - coff = calloc(1, sizeof(*coff)); - if (!coff) - goto error; + coff = obj->data; hdr = &coff->hdr; - order = ORDER(type); + order = ORDER(obj->type); if (fgetpos(fp, &obj->pos)) goto error; if (fread(buf, FILHSZ, 1, fp) != 1) @@ -185,98 +266,25 @@ open(FILE *fp, int type, Obj *obj) } obj->data = coff; + if (mkindex(obj) < 0) + goto error; + return 0; error: - free(str); - free(scn); - free(ent); - free(coff); + objreset(obj); return -1; } -static char * -symname(Coff32 *coff, SYMENT *ent) -{ - long off; - - if (ent->n_zeroes != 0) - return ent->n_name; - - off = ent->n_offset; - if (off >= coff->strsiz) - return NULL; - return &coff->strtbl[off]; -} - -static int -typeof(Coff32 *coff, SYMENT *ent) -{ - int c; - SCNHDR *scn; - long flags; - - switch (ent->n_scnum) { - case N_DEBUG: - c = 'N'; - break; - case N_ABS: - c = 'a'; - break; - case N_UNDEF: - c = (ent->n_value != 0) ? 'C' : 'U'; - break; - default: - if (ent->n_scnum > coff->hdr.f_nscns) - return -1; - scn = &coff->scns[ent->n_scnum-1]; - flags = scn->s_flags; - if (flags & STYP_TEXT) - c = 't'; - else if (flags & STYP_DATA) - c = 'd'; - else if (flags & STYP_BSS) - c = 'b'; - else - c = '?'; - break; - } - - if (ent->n_sclass == C_EXT) - c = toupper(c); - - return c; -} - static int -read(Obj *obj, Symbol *sym) +write(Obj *obj, FILE *fp) { - int t; - char *s; - SYMENT *ent; - Coff32 *coff = obj->data; - - if (obj->cursym >= coff->hdr.f_nsyms) - return 0; - ent = &coff->ents[obj->cursym]; - - if ((t = typeof(coff, ent)) < 0) - return -1; - - if ((s = symname(coff, ent)) == NULL) - return -1; - - obj->cursym += ent->n_numaux + 1; - sym->type = t; - sym->name = s; - sym->value = ent->n_value; - sym->size = (sym->type == 'C') ? ent->n_value : 0; - return 1; + return -1; } static void -close(Obj *obj) +del(Obj *obj) { struct coff32 *coff = obj->data; @@ -286,9 +294,21 @@ close(Obj *obj) free(obj->data); } +static int +new(Obj *obj) +{ + struct coff32 *coff; + + if ((coff = calloc(1, sizeof(*coff))) == NULL) + return -1; + obj->data = coff; + return 0; +} + struct format objcoff32 = { .probe = probe, - .open = open, + .new = new, + .del = del, .read = read, - .close = close, + .write = write, }; diff --git a/src/libmach/libmach.h b/src/libmach/libmach.h @@ -28,13 +28,15 @@ enum order { struct format { int (*probe)(unsigned char *buf, char **name); - int (*open)(FILE *fp, int type, Obj *obj); - int (*read)(Obj *obj, Symbol *sym); - void (*close)(Obj *obj); + int (*new)(Obj *obj); + int (*read)(Obj *obj, FILE *fp); + int (*write)(Obj *obj, FILE *fp); + void (*del)(Obj *obj); }; extern int pack(int order, unsigned char *dst, char *fmt, ...); extern int unpack(int order, unsigned char *src, char *fmt, ...); -/* coff32.c */ -extern struct format objcoff32; + +/* globals */ +extern struct format *objfmt[]; diff --git a/src/libmach/object.c b/src/libmach/object.c @@ -9,13 +9,8 @@ static char sccsid[] = "@(#) ./libmach/object.c"; #include "libmach.h" -static struct format *fmts[] = { - [COFF32] = &objcoff32, - [NFORMATS] = NULL, -}; - int -objtest(FILE *fp, char **name) +objtype(FILE *fp, char **name) { int n, i; int (*fn)(unsigned char *, char **); @@ -30,7 +25,7 @@ objtest(FILE *fp, char **name) if (n != 1 || ferror(fp)) return -1; - for (bp = fmts; bp < &fmts[NFORMATS]; ++bp) { + for (bp = objfmt; bp < &objfmt[NFORMATS]; ++bp) { op = *bp; if (!op || !op->probe) continue; @@ -43,70 +38,138 @@ objtest(FILE *fp, char **name) return -1; } +Symbol * +objlookup(Obj *obj, char *name) +{ + unsigned h; + size_t len; + char *s; + Symbol *sym; + + h = 0; + for (s = name; *s; s++) + h += *s; + h %= NR_SYMHASH; + + for (sym = obj->htab[h]; sym; sym = sym->hash) { + if (!strcmp(name, sym->name)) + return sym; + } + + if ((sym = malloc(sizeof(*sym))) == NULL) + return NULL; + len = strlen(name) + 1; + if ((s = malloc(len)) == NULL) { + free(sym); + return NULL; + } + sym->name = memcpy(s, name, len); + sym->type = 'U'; + sym->size = 0; + sym->value = 0; + sym->hash = obj->htab[h]; + obj->htab[h] = sym; + sym->next = obj->head; + obj->head = sym; + + return sym; +} + int -objopen(FILE *fp, int type, Obj *obj) +objwrite(Obj *obj, FILE *fp) { + int fmt; struct format *op; - obj->type = type; - obj->symtbl = NULL; - obj->data = NULL; - obj->nsym = obj->cursym = 0; - op = fmts[FORMAT(type)]; - if ((*op->open)(fp, type, obj) < 0) + fmt = FORMAT(obj->type); + if (fmt >= NFORMATS) + return -1; + op = objfmt[fmt]; + if ((*op->write)(obj, fp) < 0) return -1; return 0; } -static int -addsym(Obj *obj, Symbol *sym) +int +objread(Obj *obj, FILE *fp) { - Symbol *p, *new; - char *s; - size_t len, siz = obj->nsym * sizeof(*sym); + int fmt; + struct format *op; - if (siz > SIZE_MAX - sizeof(*sym)) + fmt = FORMAT(obj->type); + if (fmt >= NFORMATS) return -1; - siz += sizeof(*sym); - if ((p = realloc(obj->symtbl, siz)) == NULL) + op = objfmt[fmt]; + if ((*op->read)(obj, fp) < 0) return -1; - obj->symtbl = p; - - new = &p[obj->nsym]; - new->type = sym->type; - len = strlen(sym->name) + 1; - if ((new->name = malloc(len)) == NULL) - return -1; - memcpy(new->name, sym->name, len); - new->size = sym->size; - new->value = sym->value; - obj->nsym++; - return 0; } -int -objread(FILE *fp, Obj *obj, int (*filter)(Symbol *)) +Obj * +objnew(int type) { - int r; - Symbol sym, *p; + Obj *obj; + int fmt; struct format *op; - op = fmts[FORMAT(obj->type)]; - while ((r = (*op->read)(obj, &sym)) > 0) { - if (filter && (*filter)(&sym)) - continue; - addsym(obj, &sym); + fmt = FORMAT(type); + if (fmt >= NFORMATS) + return NULL; + + if ((obj = malloc(sizeof(*obj))) == NULL) + return NULL; + + obj->type = type; + obj->head = NULL; + memset(obj->htab, 0, sizeof(obj->htab)); + + op = objfmt[fmt]; + if ((*op->new)(obj) < 0) { + free(obj); + return NULL; } - return r; + return obj; +} + +int +objtraverse(Obj *obj, int (*fn)(Symbol *, void *), void *data) +{ + Symbol *sym; + + for (sym = obj->head; sym; sym = sym->next) { + if (!(*fn)(sym, data)) + return 0; + } + return 1; } void -objclose(Obj *obj) +objreset(Obj *obj) { + int fmt; + Symbol *sym, *next; struct format *op; - op = fmts[FORMAT(obj->type)]; - (*op->close)(obj); + fmt = FORMAT(obj->type); + if (fmt < NFORMATS) { + op = objfmt[fmt]; + (*op->del)(obj); + } + + for (sym = obj->head; sym; sym = next) { + next = sym->next; + free(sym->name); + free(sym); + } + + obj->head = NULL; + memset(obj->htab, 0, sizeof(obj->htab)); +} + +void +objdel(Obj *obj) +{ + objreset(obj); + free(obj); } diff --git a/src/nm/nm.c b/src/nm/nm.c @@ -11,6 +11,12 @@ static char sccsid[] = "@(#) ./nm/main.c"; #include <scc/arg.h> #include <scc/mach.h> + +struct symtbl { + Symbol **buf; + size_t nsyms; +}; + char *argv0; static int status, multi; static int radix = 16; @@ -40,42 +46,38 @@ error(char *fmt, ...) static int cmp(const void *p1, const void *p2) { - const Symbol *s1 = p1, *s2 = p2; + Symbol **s1 = (Symbol **) p1, **s2 = (Symbol **) p2; + Symbol *sym1 = *s1, *sym2 = *s2; if (vflag) { - if (s1->value > s2->value) + if (sym1->value > sym2->value) return 1; - if (s1->value < s2->value) + if (sym1->value < sym2->value) return -1; - if (s1->type == 'U' && s2->type == 'U') + if (sym1->type == 'U' && sym2->type == 'U') return 0; - if (s1->type == 'U') + if (sym1->type == 'U') return -1; - if (s2->type == 'U') + if (sym2->type == 'U') return 1; return 0; } else { - return strcmp(s1->name, s2->name); + return strcmp(sym1->name, sym2->name); } } static void -printsyms(Obj *obj) +printsyms(Symbol **syms, size_t nsym) { - unsigned long nsym; - Symbol *sym; - - if (!obj->symtbl) - return; - sym = obj->symtbl; - nsym = obj->nsym; + size_t i; - qsort(sym, nsym, sizeof(*sym), cmp); + qsort(syms, nsym, sizeof(syms), cmp); if (multi) printf("%s:\n", (membname) ? membname : filename); - for (sym = obj->symtbl; nsym--; sym++) { + for (i = 0; i < nsym; i++) { + Symbol *sym = syms[i]; int type = sym->type; char *fmt; @@ -112,41 +114,51 @@ printsyms(Obj *obj) } static int -filter(Symbol *sym) +newsym(Symbol *sym, void *data) { - int type = sym->type; - - if (type == '?' || type == 'N') - return 1; + struct symtbl *tbl = data; + Symbol **p; + size_t n, size; - if (uflag && type != 'U') - return 1; + n = tbl->nsyms+1; + if (n == 0 || n > SIZE_MAX / sizeof(*p)) + return 0; + size = n *sizeof(*p); - if (gflag && !isupper(type)) - return 1; + if ((p = realloc(tbl->buf, size)) == NULL) + return 0; + tbl->buf = p; + p[tbl->nsyms++] = sym; - return 0; + return 1; } static void newobject(FILE *fp, int type) { - Obj obj; + int err = 1; + Obj *obj; + struct symtbl tbl = {NULL, 0}; + + if ((obj = objnew(type)) == NULL) { + error("out of memory"); + return; + } - if (objopen(fp, type, &obj) < 0) - goto err1; + if (objread(obj, fp) < 0) + goto error; - if (objread(fp, &obj, filter) < 0) - goto err2; + if (!objtraverse(obj, newsym, &tbl)) + goto error; - printsyms(&obj); - objclose(&obj); - return; + printsyms(tbl.buf, tbl.nsyms); + err = 0; -err2: - objclose(&obj); -err1: - error("object file corrupted"); +error: + free(tbl.buf); + objdel(obj); + if (err) + error("object file corrupted"); } static int @@ -156,7 +168,7 @@ newmember(FILE *fp, char *name, void *data) multi = 1; membname = name; - if ((t = objtest(fp, NULL)) != -1) + if ((t = objtype(fp, NULL)) != -1) newobject(fp, t); return 1; @@ -176,7 +188,7 @@ nm(char *fname) return; } - if ((t = objtest(fp, NULL)) != -1) + if ((t = objtype(fp, NULL)) != -1) newobject(fp, t); else if (archive(fp)) artraverse(fp, newmember, NULL);