scc

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

commit 682597159c584f8e509371ecbe32cf15d897da75
parent 53ffabd5c6ca88f3980d33a7ed1459b73ea2bd5b
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Tue, 27 Aug 2019 12:10:33 +0100

[libmach] Big rework of libmach (Symbol)

Libmach had a lot of different problems and one of them
was the definition of Objsym, that forced every tool to mess
with object symbol datatypes and specific types.

Diffstat:
Minclude/scc/scc/mach.h | 21+++++++--------------
Msrc/cmd/Makefile | 13+++++++------
Msrc/cmd/nm.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/libmach/Makefile | 10++--------
Msrc/libmach/coff32/Makefile | 1+
Msrc/libmach/coff32/coff32.c | 2++
Msrc/libmach/coff32/coff32.h | 5++++-
Msrc/libmach/coff32/coff32del.c | 1-
Asrc/libmach/coff32/coff32getsym.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/libmach/coff32/coff32read.c | 209+++++++++----------------------------------------------------------------------
Msrc/libmach/coff32/coff32strip.c | 1-
Msrc/libmach/coff32/coff32write.c | 2+-
Asrc/libmach/getsym.c | 9+++++++++
Msrc/libmach/libmach.h | 2+-
Dsrc/libmach/objaddseg.c | 9---------
Dsrc/libmach/objdel.c | 18------------------
Dsrc/libmach/objlookup.c | 35-----------------------------------
Msrc/libmach/objnew.c | 6------
Msrc/libmach/objtype.c | 2+-
Asrc/libmach/readobj.c | 15+++++++++++++++
Mtests/nm/execute/Makefile | 5++---
21 files changed, 197 insertions(+), 318 deletions(-)

diff --git a/include/scc/scc/mach.h b/include/scc/scc/mach.h @@ -1,7 +1,7 @@ #define NR_SYMHASH 32 typedef struct objsec Objsec; -typedef struct objsym Objsym; +typedef struct symbol Symbol; typedef struct objseg Objseg; typedef struct objops Objops; typedef struct obj Obj; @@ -28,7 +28,7 @@ struct objsec { Objsec *next; }; -struct objsym { +struct symbol { char *name; unsigned long long size; unsigned long long value; @@ -36,8 +36,6 @@ struct objsym { int index; char class; char type; - - Objsym *next, *hash; }; struct objseg { @@ -51,23 +49,18 @@ struct objops { void (*del)(Obj *obj); int (*read)(Obj *obj, FILE *fp); int (*write)(Obj *obj, FILE *fp); - int (*addseg)(Obj *obj, void *seg); int (*strip)(Obj *obj); int (*addr2line)(Obj *, unsigned long long , char *, int *); + int (*getsym)(Obj *obj, long *index, Symbol *sym); int (*setidx)(long nsyms, char *names[], long offset[], FILE *fp); int (*getidx)(long *nsyms, char ***names, long **offset, FILE *fp); }; struct obj { - int type; - Objops *ops; char *index; - Objsym *htab[NR_SYMHASH]; - Objsym *syms; - Objsec *secs; + Objops *ops; + int type; long pos; - int nsecs; - int nsyms; void *data; }; @@ -76,5 +69,5 @@ extern long armember(FILE *fp, char *member); extern int objtype(FILE *fp, char **name); extern Obj *objnew(int type); -extern Objsym *objlookup(Obj *obj, char *name, int install); -extern int objpos(Obj *obj, FILE *fp, long pos); +extern int readobj(Obj *obj, FILE *fp); +extern int getsym(Obj *obj, long *index, Symbol *sym); diff --git a/src/cmd/Makefile b/src/cmd/Makefile @@ -4,13 +4,14 @@ PROJECTDIR = ../.. include $(PROJECTDIR)/scripts/rules.mk TARGET = $(BINDIR)/nm \ - $(BINDIR)/strip \ - $(BINDIR)/size \ $(BINDIR)/ar \ - $(BINDIR)/ranlib \ - $(BINDIR)/objdump \ - $(BINDIR)/objcopy \ - $(BINDIR)/addr2line \ + +# $(BINDIR)/strip \ +# $(BINDIR)/size \ +# $(BINDIR)/ranlib \ +# $(BINDIR)/objdump \ +# $(BINDIR)/objcopy \ +# $(BINDIR)/addr2line \ DIRS = as scc diff --git a/src/cmd/nm.c b/src/cmd/nm.c @@ -12,7 +12,7 @@ struct symtbl { - Objsym **buf; + Symbol **buf; size_t nsyms; }; @@ -45,8 +45,8 @@ error(char *fmt, ...) static int cmp(const void *p1, const void *p2) { - Objsym **s1 = (Objsym **) p1, **s2 = (Objsym **) p2; - Objsym *sym1 = *s1, *sym2 = *s2; + Symbol **s1 = (Symbol **) p1, **s2 = (Symbol **) p2; + Symbol *sym1 = *s1, *sym2 = *s2; if (vflag) { if (sym1->value > sym2->value) @@ -66,17 +66,19 @@ cmp(const void *p1, const void *p2) } static void -printsyms(Objsym **syms, size_t nsym) +printsyms(Symbol **syms, size_t nsym) { size_t i; qsort(syms, nsym, sizeof(syms), cmp); - if (multi) - printf("%s:\n", (membname) ? membname : filename); + if (!Aflag) { + if (multi || membname) + printf("%s:\n", (membname) ? membname : filename); + } for (i = 0; i < nsym; i++) { - Objsym *sym = syms[i]; + Symbol *sym = syms[i]; int type = sym->type; char *fmt; @@ -113,9 +115,9 @@ printsyms(Objsym **syms, size_t nsym) } static int -newsym(Objsym *sym, struct symtbl *tbl) +newsym(Symbol *sym, struct symtbl *tbl) { - Objsym **p; + Symbol **p, *s; size_t n, size; int type = sym->type; @@ -133,10 +135,16 @@ newsym(Objsym *sym, struct symtbl *tbl) return 0; size = n *sizeof(*p); - if ((p = realloc(tbl->buf, size)) == NULL) - return 0; + p = realloc(tbl->buf, size); + s = malloc(sizeof(*s)); + if (!p || !s) { + error("out of memory"); + exit(EXIT_FAILURE); + } + + *s = *sym; tbl->buf = p; - p[tbl->nsyms++] = sym; + p[tbl->nsyms++] = s; return 1; } @@ -145,20 +153,21 @@ static void newobject(FILE *fp, int type) { int err = 1; + long i; Obj *obj; - Objsym *sym; + Symbol sym; struct symtbl tbl = {NULL, 0}; if ((obj = objnew(type)) == NULL) { error("out of memory"); - return; + exit(EXIT_FAILURE); } - if ((*obj->ops->read)(obj, fp) < 0) + if (readobj(obj, fp) < 0) goto error; - for (sym = obj->syms; sym; sym = sym->next) - newsym(sym, &tbl); + for (i = 0; getsym(obj, &i, &sym); i++) + newsym(&sym, &tbl); printsyms(tbl.buf, tbl.nsyms); err = 0; @@ -174,17 +183,29 @@ static void newlib(FILE *fp) { int t; - long r; + long off, cur; char memb[SARNAM+1]; - while ((r = armember(fp, memb)) > 0) { - membname = memb; - if ((t = objtype(fp, NULL)) != -1) - newobject(fp, t); - membname = NULL; + while (!feof(fp)) { + cur = ftell(fp); + off = armember(fp, memb); + switch (off) { + case -1: + error("library corrupted"); + case 0: + return; + default: + membname = memb; + if ((t = objtype(fp, NULL)) != -1) + newobject(fp, t); + membname = NULL; + fseek(fp, cur, SEEK_SET); + fseek(fp, off, SEEK_CUR); + break; + } } - if (r < 0) - error("library corrupted"); + + error("library corrupted:%s", strerror(errno)); } static void @@ -267,7 +288,9 @@ main(int argc, char *argv[]) } if (fflush(stdout)) { - fprintf(stderr, "nm: error writing in output"); + fprintf(stderr, + "nm: error writing in output:%s\n", + strerror(errno)); status = 1; } diff --git a/src/libmach/Makefile b/src/libmach/Makefile @@ -7,17 +7,11 @@ TARGET = $(LIBDIR)/libmach.a OBJS = mach.o \ objnew.o \ objpos.o \ - objfree.o \ - objstrip.o \ - objdel.o \ - objaddseg.o \ - objsync.o \ - addr2line.o \ archive.o \ armember.o \ - objlookup.o \ objtype.o \ - objwrite.o \ + readobj.o \ + getsym.o \ pack.o \ unpack.o \ diff --git a/src/libmach/coff32/Makefile b/src/libmach/coff32/Makefile @@ -16,6 +16,7 @@ OBJS = coff32.o \ coff32setidx.o \ coff32getidx.o \ coff32addr2line.o \ + coff32getsym.o \ all: $(OBJS) diff --git a/src/libmach/coff32/coff32.c b/src/libmach/coff32/coff32.c @@ -6,6 +6,7 @@ #include "coff32.h" Objops coff32 = { + .probe = coff32probe, .new = coff32new, .read = coff32read, .getidx = coff32getidx, @@ -14,4 +15,5 @@ Objops coff32 = { .strip = coff32strip, .del = coff32del, .write = coff32write, + .getsym = coff32getsym, }; diff --git a/src/libmach/coff32/coff32.h b/src/libmach/coff32/coff32.h @@ -15,7 +15,7 @@ struct arch { struct coff32 { FILHDR hdr; - AOUTHDR *aout; + AOUTHDR aout; SCNHDR *scns; SYMENT *ents; RELOC **rels; @@ -38,3 +38,5 @@ extern int coff32xsetidx(int order, long nsymbols, char *names[], long offs[], FILE *fp); extern int coff32xgetidx(int order, long *nsyms, char ***namep, long **offsp, FILE *fp); + +extern int coff32getsym(Obj *obj, long *idx, Symbol *sym); +\ No newline at end of file diff --git a/src/libmach/coff32/coff32del.c b/src/libmach/coff32/coff32del.c @@ -19,6 +19,5 @@ coff32del(Obj *obj) free(obj->data); obj->data = NULL; - objdel(obj); free(obj); } diff --git a/src/libmach/coff32/coff32getsym.c b/src/libmach/coff32/coff32getsym.c @@ -0,0 +1,74 @@ +#include <ctype.h> +#include <stdio.h> + +#include <scc/mach.h> + +#include "../libmach.h" +#include "coff32.h" + +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: + 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 char * +symname(Coff32 *coff, SYMENT *ent) +{ + if (ent->n_zeroes != 0) + return ent->n_name; + + return &coff->strtbl[ent->n_offset]; +} + +int +coff32getsym(Obj *obj, long *idx, Symbol *sym) +{ + long n = *idx; + SYMENT *ent; + Coff32 *coff = obj->data; + + if (*idx >= coff->hdr.f_nsyms) + return 0; + + ent = &coff->ents[n]; + sym->name = symname(coff, ent); + sym->type = typeof(coff, ent); + sym->value = ent->n_value; + sym->size = (sym->type == 'C') ? ent->n_value : 0; + sym->index = n; + *idx += ent->n_numaux; + + return 1; +} diff --git a/src/libmach/coff32/coff32read.c b/src/libmach/coff32/coff32read.c @@ -82,7 +82,7 @@ unpack_ent(int order, unsigned char *buf, SYMENT *ent) s = ent->n_name; if (!s[0] && !s[1] && !s[2] && !s[3]) - unpack(order, "ll", buf, &ent->n_zeroes, &ent->n_offset); + unpack(order, buf, "ll", &ent->n_zeroes, &ent->n_offset); } static void @@ -153,10 +153,9 @@ readstr(Obj *obj, FILE *fp) if (fread(buf, 4, 1, fp) != 1) return 0; unpack(ORDER(obj->type), buf, "l", &siz); - siz -= 4; - if (siz < 0) + if (siz == 4) return 0; - if (siz > 0) { + if (siz > 4) { if (siz > SIZE_MAX) return 0; str = malloc(siz); @@ -165,7 +164,7 @@ readstr(Obj *obj, FILE *fp) coff->strtbl = str; coff->strsiz = siz; - if (fread(str, siz, 1, fp) != 1) + if (fread(str+4, siz-4, 1, fp) != 1) return 0; } return 1; @@ -185,7 +184,7 @@ readreloc(Obj *obj, FILE *fp) coff = obj->data; hdr = &coff->hdr; - rels = calloc(obj->nsecs, sizeof(*rels)); + rels = calloc(hdr->f_nscns, sizeof(*rels)); if (!rels) return 0; coff->rels = rels; @@ -207,6 +206,8 @@ readreloc(Obj *obj, FILE *fp) if (fread(buf, RELSZ, 1, fp) != 1) return 0; unpack_reloc(ORDER(obj->type), buf, &rp[i]); + if (rp[i].r_symndx >= hdr->f_nsyms) + return 0; } } @@ -239,6 +240,8 @@ readents(Obj *obj, FILE *fp) if (fread(buf, SYMESZ, 1, fp) != 1) return 0; unpack_ent(ORDER(obj->type), buf, &ent[i]); + if (ent->n_scnum > hdr->f_nscns) + return 0; } return 1; @@ -306,6 +309,8 @@ readlines(Obj *obj, FILE *fp) if (fread(buf, LINESZ, 1, fp) == 1) return 0; unpack_line(ORDER(obj->type), buf, &lp[j]); + if (lp[i].l_symndx >= hdr->f_nsyms) + return 0; } } @@ -315,37 +320,27 @@ readlines(Obj *obj, FILE *fp) static int readaout(Obj *obj, FILE *fp) { - FILHDR *hdr; - struct coff32 *coff; + struct coff32 *coff = obj->data; + FILHDR *hdr = &coff->hdr; unsigned char buf[AOUTSZ]; - coff = obj->data; - hdr = &coff->hdr; - if (hdr->f_opthdr == 0) return 1; if (fread(buf, AOUTSZ, 1, fp) != 1) return 0; - coff->aout = malloc(sizeof(AOUTHDR)); - if (!coff->aout) - return 0; - - unpack_aout(ORDER(obj->type), buf, coff->aout); + unpack_aout(ORDER(obj->type), buf, &coff->aout); return 1; } -static int -readfile(Obj *obj, FILE *fp) +int +coff32read(Obj *obj, FILE *fp) { - long off; - - /* TODO: Add validation of the different fields */ - if ((off = ftell(fp)) == EOF) - return -1; - obj->pos = off; + long i; + struct coff32 *coff = obj->data; + FILHDR *hdr = &coff->hdr; if (!readhdr(obj, fp)) return -1; @@ -361,172 +356,12 @@ readfile(Obj *obj, FILE *fp) return -1; if (!readlines(obj, fp)) return -1; - return 0; -} - -static int -convsecs(Obj *obj) -{ - int i; - unsigned sflags, type; - unsigned long flags; - FILHDR *hdr; - struct coff32 *coff; - SCNHDR *scn; - Objsec *secs, *sp; - - coff = obj->data; - hdr = &coff->hdr; - - secs = malloc(sizeof(Objsec) * hdr->f_nscns); - if (!secs) - return -1; - - for (i = 0; i < hdr->f_nscns; i++) { - sp = &secs[i]; - sp->next = (i < hdr->f_nscns-1) ? &secs[i+1] : NULL; - scn = &coff->scns[i]; - flags = scn->s_flags; - - if (flags & STYP_TEXT) { - type = 'T'; - sflags = SALLOC | SRELOC | SLOAD | SEXEC | SREAD; - if (flags & STYP_NOLOAD) - sflags |= SSHARED; - } else if (flags & STYP_DATA) { - type = 'D'; - sflags = SALLOC | SRELOC | SLOAD | SWRITE | SREAD; - if (flags & STYP_NOLOAD) - sflags |= SSHARED; - } else if (flags & STYP_BSS) { - type = 'B'; - sflags = SALLOC | SREAD | SWRITE; - } else if (flags & STYP_INFO) { - type = 'N'; - sflags = 0; - } else if (flags & STYP_LIB) { - type = 'T'; - sflags = SRELOC; - } else if (flags & STYP_DSECT) { - type = 'D'; - sflags = SRELOC; - } else if (flags & STYP_PAD) { - type = 'D'; - sflags = SLOAD; - } else { - type = 'D'; /* We assume that STYP_REG is data */ - sflags = SALLOC | SRELOC | SLOAD | SWRITE | SREAD; - } - - if (flags & STYP_NOLOAD) - sflags &= ~SLOAD; - - sp->name = scn->s_name; - sp->id = i; - sp->seek = scn->s_scnptr; - sp->size = scn->s_size; - sp->type = type; - sp->flags = sflags; - sp->align = 4; /* TODO: Check how align is defined in coff */ - } - obj->secs = secs; - obj->nsecs = i; - - return 1; -} - -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 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 -convsyms(Obj *obj) -{ - int t; - long i; - char *s; - Objsym *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, 1)) == NULL) + for (i = 0; i < hdr->f_nsyms; i++) { + SYMENT *ent = &coff->ents[i]; + if (ent->n_zeroes != 0 && ent->n_offset > coff->strsiz) return -1; - - sym->type = t; - sym->value = ent->n_value; - sym->size = (sym->type == 'C') ? ent->n_value : 0; - sym->index = ent->n_scnum-1; } - return i; -} - -int -coff32read(Obj *obj, FILE *fp) -{ - if (readfile(obj, fp) < 0) - return -1; - if (convsecs(obj) < 0) - return -1; - if (convsyms(obj) < 0) - return -1; return 0; } diff --git a/src/libmach/coff32/coff32strip.c b/src/libmach/coff32/coff32strip.c @@ -34,7 +34,6 @@ coff32strip(Obj *obj) coff->ents = NULL; coff->rels = NULL; coff->lines = NULL; - objdel(obj); return 0; } diff --git a/src/libmach/coff32/coff32write.c b/src/libmach/coff32/coff32write.c @@ -231,7 +231,7 @@ writeaout(Obj *obj, FILE *fp) if (hdr->f_opthdr == 0) return 1; - pack_aout(ORDER(obj->type), buf, coff->aout); + pack_aout(ORDER(obj->type), buf, &coff->aout); return fread(buf, AOUTSZ, 1, fp) != 1; } diff --git a/src/libmach/getsym.c b/src/libmach/getsym.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +#include <scc/mach.h> + +int +getsym(Obj *obj, long *index, Symbol *sym) +{ + return (*obj->ops->getsym)(obj, index, sym); +} diff --git a/src/libmach/libmach.h b/src/libmach/libmach.h @@ -26,7 +26,7 @@ enum order { /* common functions */ extern int pack(int order, unsigned char *dst, char *fmt, ...); extern int unpack(int order, unsigned char *src, char *fmt, ...); -extern void objdel(Obj *obj); +extern int objpos(Obj *obj, FILE *fp, long pos); /* globals */ extern Objops *objops[]; diff --git a/src/libmach/objaddseg.c b/src/libmach/objaddseg.c @@ -1,9 +0,0 @@ -#include <stdio.h> - -#include <scc/mach.h> - -int -objaddseg(Obj *obj, void *seg) -{ - return 0; -} diff --git a/src/libmach/objdel.c b/src/libmach/objdel.c @@ -1,18 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <scc/mach.h> - -#include "libmach.h" - -void -objdel(Obj *obj) -{ - free(obj->secs); - free(obj->syms); - - obj->syms = NULL; - obj->secs = NULL; - memset(obj->htab, 0, sizeof(obj->htab)); -} diff --git a/src/libmach/objlookup.c b/src/libmach/objlookup.c @@ -1,35 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <scc/mach.h> -#include <scc/scc.h> - -Objsym * -objlookup(Obj *obj, char *name, int install) -{ - unsigned h; - Objsym *sym; - - h = genhash(name) % NR_SYMHASH; - for (sym = obj->htab[h]; sym; sym = sym->hash) { - if (!strcmp(name, sym->name)) - return sym; - } - if (!install) - return NULL; - - if ((sym = malloc(sizeof(*sym))) == NULL) - return NULL; - - sym->name = name; - sym->type = 'U'; - sym->size = 0; - sym->value = 0; - sym->hash = obj->htab[h]; - obj->htab[h] = sym; - sym->next = obj->syms; - obj->syms = sym; - - return sym; -} diff --git a/src/libmach/objnew.c b/src/libmach/objnew.c @@ -21,12 +21,6 @@ objnew(int type) return NULL; obj->type = type; - obj->syms = NULL; - obj->secs = NULL; - obj->nsyms = 0; - obj->nsecs = 0; - memset(obj->htab, 0, sizeof(obj->htab)); - ops = objops[fmt]; obj->ops = ops; diff --git a/src/libmach/objtype.c b/src/libmach/objtype.c @@ -22,7 +22,7 @@ objtype(FILE *fp, char **name) for (opsp = objops; ops = *opsp; ++opsp) { if ((*ops->probe)(buf, name) < 0) continue; - return n; + return opsp - objops; } return -1; diff --git a/src/libmach/readobj.c b/src/libmach/readobj.c @@ -0,0 +1,15 @@ +#include <stdio.h> + +#include <scc/mach.h> + +int +readobj(Obj *obj, FILE *fp) +{ + long off; + + if ((off = ftell(fp)) == EOF) + return -1; + obj->pos = off; + + return (*obj->ops->read)(obj, fp); +} diff --git a/tests/nm/execute/Makefile b/tests/nm/execute/Makefile @@ -1,13 +1,12 @@ .POSIX: - -ROOT=$(PROJECTDIR)/root +ROOT=../../.. OUT = z80.out all: tests tests: $(OUT) - @PATH=$(ROOT)/bin:$$PATH chktest.sh + @PATH=$(ROOT)/bin:$$PATH:. chktest.sh z80.out: master.s z80-unknown-coff-as -o $@ master.s