ref: 3e50e418c633600bac4a41e899147d9e8de78f29
parent: 439629f3f58c21dd056721107e4dadb3b6e0482f
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Jan 7 11:10:28 EST 2019
[libmach] Rework the object interface
--- 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 @@
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);
--- a/src/libmach/Makefile
+++ b/src/libmach/Makefile
@@ -9,6 +9,7 @@
unpack.o \
artraverse.o \
armember.o \
+ objfmt.o \
coff32.o \
all: $(TARGET)
--- a/src/libmach/coff32.c
+++ b/src/libmach/coff32.c
@@ -109,16 +109,99 @@
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));
@@ -125,12 +208,10 @@
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 @@
}
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)
+write(Obj *obj, FILE *fp)
{
- 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;
+ return -1;
}
-static int
-read(Obj *obj, Symbol *sym)
-{
- 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;
-}
-
static void
-close(Obj *obj)
+del(Obj *obj)
{
struct coff32 *coff = obj->data;
@@ -286,9 +294,21 @@
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,
};
--- a/src/libmach/libmach.h
+++ b/src/libmach/libmach.h
@@ -28,13 +28,15 @@
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[];
--- a/src/libmach/object.c
+++ b/src/libmach/object.c
@@ -9,13 +9,8 @@
#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 @@
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 @@
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);
}
--- a/src/nm/nm.c
+++ b/src/nm/nm.c
@@ -11,6 +11,12 @@
#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 @@
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;
+ size_t i;
- if (!obj->symtbl)
- return;
- sym = obj->symtbl;
- nsym = obj->nsym;
+ qsort(syms, nsym, sizeof(syms), cmp);
- qsort(sym, nsym, sizeof(*sym), 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 @@
}
static int
-filter(Symbol *sym)
+newsym(Symbol *sym, void *data)
{
- int type = sym->type;
+ struct symtbl *tbl = data;
+ Symbol **p;
+ size_t n, size;
- if (type == '?' || type == 'N')
- return 1;
+ n = tbl->nsyms+1;
+ if (n == 0 || n > SIZE_MAX / sizeof(*p))
+ return 0;
+ size = n *sizeof(*p);
- if (uflag && type != 'U')
- return 1;
+ if ((p = realloc(tbl->buf, size)) == NULL)
+ return 0;
+ tbl->buf = p;
+ p[tbl->nsyms++] = sym;
- if (gflag && !isupper(type))
- return 1;
-
- return 0;
+ return 1;
}
static void
newobject(FILE *fp, int type)
{
- Obj obj;
+ int err = 1;
+ Obj *obj;
+ struct symtbl tbl = {NULL, 0};
- if (objopen(fp, type, &obj) < 0)
- goto err1;
+ if ((obj = objnew(type)) == NULL) {
+ error("out of memory");
+ return;
+ }
- if (objread(fp, &obj, filter) < 0)
- goto err2;
+ if (objread(obj, fp) < 0)
+ goto error;
- printsyms(&obj);
- objclose(&obj);
- return;
+ if (!objtraverse(obj, newsym, &tbl))
+ goto error;
-err2:
- objclose(&obj);
-err1:
- error("object file corrupted");
+ printsyms(tbl.buf, tbl.nsyms);
+ err = 0;
+
+error:
+ free(tbl.buf);
+ objdel(obj);
+ if (err)
+ error("object file corrupted");
}
static int
@@ -156,7 +168,7 @@
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 @@
return;
}
- if ((t = objtest(fp, NULL)) != -1)
+ if ((t = objtype(fp, NULL)) != -1)
newobject(fp, t);
else if (archive(fp))
artraverse(fp, newmember, NULL);