shithub: scc

Download patch

ref: 3e50e418c633600bac4a41e899147d9e8de78f29
parent: 439629f3f58c21dd056721107e4dadb3b6e0482f
author: Roberto E. Vargas Caballero <[email protected]>
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);