shithub: scc

Download patch

ref: 1d08a435776de0dd4f776cca9f2643570972809e
parent: 90f952cb3dee893681a64e5f08844785e6b30ea8
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Wed Feb 6 03:04:15 EST 2019

[libmach] Split object.c and coff32.c

--- a/src/libc/Makefile
+++ b/src/libc/Makefile
@@ -18,7 +18,7 @@
 $(DIRS): FORCE
 	+@cd $@ && $(MAKE)
 
-objlst.mk: FORCE
+objlst.mk: $(DIRS) FORCE
 	mklst $@
 
 clean:
--- /dev/null
+++ b/src/libmach/.gitignore
@@ -1,0 +1,8 @@
+objlst.mk
+del.c
+index.c
+new.c
+probe.c
+read.c
+strip.c
+write.c
--- a/src/libmach/Makefile
+++ b/src/libmach/Makefile
@@ -3,17 +3,59 @@
 include $(PROJECTDIR)/scripts/rules.mk
 
 TARGET = $(LIBDIR)/libmach.a
-OBJS = object.o \
+
+OBJS = addr2line.o \
        archive.o \
-       pack.o \
-       unpack.o \
-       artraverse.o \
+       arindex.o \
        armember.o \
-       objfmt.o \
-       coff32.o \
+       artraverse.o \
        coffelf32.o \
+       objdel.o \
+       objlookup.o \
+       objnew.o \
+       objpos.o \
+       objread.o \
+       objreset.o \
+       objsize.o \
+       objstrip.o \
+       objtraverse.o \
+       objtype.o \
+       objwrite.o \
+       objfree.o \
+       pack.o \
+       unpack.o \
+       index.o \
+       new.o \
+       read.o \
+       del.o \
+       strip.o \
+       probe.o \
+       write.o \
 
-all: $(TARGET)
 
-$(TARGET): $(OBJS)
-	mklib -o $@ $?
+DIRS = coff32
+
+TBLS = index.c \
+       new.c \
+       read.c \
+       del.c \
+       strip.c \
+       probe.c \
+       write.c \
+
+
+all: $(OBJS) $(DIRS) objlst.mk
+	+@$(MAKE) -f Makefile.mach
+
+$(DIRS): FORCE
+	+@cd $@ && $(MAKE)
+
+$(TBLS): formats.lst
+	mktbl -t `echo $@ | sed 's/\.c//'` -o $@
+
+objlst.mk: $(OBJS) $(DIRS)
+	mklst $@
+
+clean:
+	$(FORALL)
+	rm -f $(TBLS) objlst.mk
--- /dev/null
+++ b/src/libmach/Makefile.mach
@@ -1,0 +1,11 @@
+.POSIX:
+PROJECTDIR =../..
+include $(PROJECTDIR)/scripts/rules.mk
+include objlst.mk
+
+TARGET = $(LIBDIR)/libmach.a
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+	mklib -o $@ $?
--- /dev/null
+++ b/src/libmach/addr2line.c
@@ -1,0 +1,10 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+int
+addr2line(Obj *obj, unsigned long long addr, char *fname, int *line)
+{
+	/* TODO */
+	return -1;
+}
--- /dev/null
+++ b/src/libmach/arindex.c
@@ -1,0 +1,20 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+extern indexfun_t indexv[];
+
+long
+arindex(int type, long nsyms, Symdef *head, FILE *fp)
+{
+	int fmt;
+	indexfun_t fn;
+
+	fmt = FORMAT(type);
+	if (fmt >= NFORMATS)
+		return -1;
+	fn = indexv[fmt];
+	return (*fn)(type, nsyms, head, fp);
+}
--- a/src/libmach/coff32.c
+++ /dev/null
@@ -1,784 +1,0 @@
-#include <assert.h>
-#include <ctype.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <scc/coff32/filehdr.h>
-#include <scc/coff32/aouthdr.h>
-#include <scc/coff32/scnhdr.h>
-#include <scc/coff32/syms.h>
-#include <scc/coff32/reloc.h>
-#include <scc/coff32/linenum.h>
-#include <scc/mach.h>
-
-#include "libmach.h"
-
-typedef struct coff32 Coff32;
-
-struct arch {
-	char *name;
-	unsigned char magic[2];
-	int type;
-};
-
-struct coff32 {
-	FILHDR hdr;
-	AOUTHDR *aout;
-	SCNHDR *scns;
-	SYMENT *ents;
-	RELOC **rels;
-	LINENO **lines;
-	char *strtbl;
-	unsigned long strsiz;
-};
-
-static struct arch archs[] = {
-	"coff32-i386", "\x4c\x01", OBJ(COFF32, ARCH386, LITTLE_ENDIAN),
-	"coff32-z80", "\x5a\x80", OBJ(COFF32, ARCHZ80, LITTLE_ENDIAN),
-	NULL,
-};
-
-static void
-pack_hdr(int order, unsigned char *buf, FILHDR *hdr)
-{
-	int n;
-
-	n = pack(order,
-	         buf,
-	         "sslllss",
-	         hdr->f_magic,
-	         hdr->f_nscns,
-	         hdr->f_timdat,
-	         hdr->f_symptr,
-	         hdr->f_nsyms,
-	         hdr->f_opthdr,
-	         hdr->f_flags);
-	assert(n == FILHSZ);
-}
-
-static void
-unpack_hdr(int order, unsigned char *buf, FILHDR *hdr)
-{
-	int n;
-
-	n = unpack(order,
-	           buf,
-	           "sslllss",
-	           &hdr->f_magic,
-	           &hdr->f_nscns,
-	           &hdr->f_timdat,
-	           &hdr->f_symptr,
-	           &hdr->f_nsyms,
-	           &hdr->f_opthdr,
-	           &hdr->f_flags);
-	assert(n == FILHSZ);
-}
-
-static void
-pack_scn(int order, unsigned char *buf, SCNHDR *scn)
-{
-	int n;
-
-	n = pack(order,
-	         buf,
-	         "'8llllllssl",
-	         scn->s_name,
-	         scn->s_paddr,
-	         scn->s_vaddr,
-	         scn->s_size,
-	         scn->s_scnptr,
-	         scn->s_relptr,
-	         scn->s_lnnoptr,
-	         scn->s_nrelloc,
-	         scn->s_nlnno,
-	         scn->s_flags);
-	assert(n == SCNHSZ);
-}
-
-static void
-unpack_scn(int order, unsigned char *buf, SCNHDR *scn)
-{
-	int n;
-
-	n = unpack(order,
-	          buf,
-	          "'8llllllssl",
-	          scn->s_name,
-	          &scn->s_paddr,
-	          &scn->s_vaddr,
-	          &scn->s_size,
-	          &scn->s_scnptr,
-	          &scn->s_relptr,
-	          &scn->s_lnnoptr,
-	          &scn->s_nrelloc,
-	          &scn->s_nlnno,
-	          &scn->s_flags);
-	assert(n == SCNHSZ);
-}
-
-static void
-pack_ent(int order, unsigned char *buf, SYMENT *ent)
-{
-	int n;
-	char *s;
-
-	/* TODO: What happens with the union? */
-
-	n = pack(order,
-	         buf,
-	         "'8lsscc",
-	         ent->n_name,
-	         &ent->n_value,
-	         &ent->n_scnum,
-	         &ent->n_type,
-	         &ent->n_sclass,
-	         &ent->n_numaux);
-	assert(n == SYMESZ);
-}
-
-static void
-unpack_ent(int order, unsigned char *buf, SYMENT *ent)
-{
-	int n;
-	char *s;
-
-	n = unpack(order,
-	           buf,
-	           "'8lsscc",
-	           ent->n_name,
-	           &ent->n_value,
-	           &ent->n_scnum,
-	           &ent->n_type,
-	           &ent->n_sclass,
-	           &ent->n_numaux);
-	assert(n == SYMESZ);
-
-	s = ent->n_name;
-	if (!s[0] && !s[1] && !s[2] && !s[3])
-		unpack(order, "ll", buf, &ent->n_zeroes, &ent->n_offset);
-}
-
-static void
-pack_aout(int order, unsigned char *buf, AOUTHDR *aout)
-{
-	int n;
-
-	n = unpack(order,
-	           buf,
-	           "ssllllll",
-	           aout->magic,
-	           aout->vstamp,
-	           aout->tsize,
-	           aout->dsize,
-	           aout->bsize,
-	           aout->entry,
-	           aout->text_start,
-	           aout->data_start);
-	assert(n == AOUTSZ);
-}
-
-static void
-unpack_aout(int order, unsigned char *buf, AOUTHDR *aout)
-{
-	int n;
-
-	n = unpack(order,
-	           buf,
-	           "ssllllll",
-	           &aout->magic,
-	           &aout->vstamp,
-	           &aout->tsize,
-	           &aout->dsize,
-	           &aout->bsize,
-	           &aout->entry,
-	           &aout->text_start,
-	           &aout->data_start);
-	assert(n == AOUTSZ);
-}
-
-static void
-unpack_reloc(int order, unsigned char *buf, RELOC *rel)
-{
-	int n;
-
-	n = unpack(order,
-	           buf,
-	           "lls",
-	           &rel->r_vaddr,
-	           &rel->r_symndx,
-	           &rel->r_type);
-	assert(n == RELSZ);
-}
-
-static void
-pack_reloc(int order, unsigned char *buf, RELOC *rel)
-{
-	int n;
-
-	n = pack(order,
-	         buf,
-	         "lls",
-	         rel->r_vaddr,
-	         rel->r_symndx,
-	         rel->r_type);
-	assert(n == RELSZ);
-}
-
-static void
-unpack_line(int order, unsigned char *buf, LINENO *lp)
-{
-	int n;
-
-	n = unpack(order,
-	           buf,
-	           "lls",
-	           &lp->l_symndx,
-	           &lp->l_paddr,
-	           &lp->l_lnno);
-	assert(n == LINESZ);
-}
-
-static void
-pack_line(int order, unsigned char *buf, LINENO *lp)
-{
-	int n;
-
-	n = pack(order,
-	         buf,
-	         "lls",
-	         lp->l_symndx,
-	         lp->l_paddr,
-	         lp->l_lnno);
-	assert(n == LINESZ);
-}
-
-static int
-probe(unsigned char *buf, char **name)
-{
-	struct arch *ap;
-
-	for (ap = archs; ap->name; ap++) {
-		if (ap->magic[0] == buf[0] && ap->magic[1] == buf[1]) {
-			if (name)
-				*name = ap->name;
-			return ap->type;
-		}
-	}
-	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
-loadsyms(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 0;
-
-		if ((s = symname(coff, ent)) == NULL)
-			return 0;
-
-		if ((sym = objlookup(obj, s)) == NULL)
-			return 0;
-
-		sym->type = t;
-		sym->value = ent->n_value;
-		sym->size = (sym->type == 'C') ? ent->n_value : 0;
-	}
-
-	return 1;
-}
-
-static int
-readscns(Obj *obj, FILE *fp)
-{
-	FILHDR *hdr;
-	struct coff32 *coff;
-	SCNHDR *scn;
-	long i;
-	unsigned char buf[SCNHSZ];
-
-	coff  = obj->data;
-	hdr = &coff->hdr;
-
-	if (hdr->f_nscns > 0) {
-		scn = calloc(hdr->f_nscns, sizeof(*scn));
-		if (!scn)
-			return 0;
-		coff->scns = scn;
-	}
-	if (fseek(fp, hdr->f_opthdr, SEEK_CUR) < 0)
-		return 0;
-	for (i = 0; i < hdr->f_nscns; i++) {
-		if (fread(buf, SCNHSZ, 1, fp) < 0)
-			return 0;
-		unpack_scn(ORDER(obj->type), buf, &scn[i]);
-	}
-
-	return 1;
-}
-
-static int
-readents(Obj *obj, FILE *fp)
-{
-	FILHDR *hdr;
-	struct coff32 *coff;
-	SYMENT *ent;
-	long i;
-	unsigned char buf[SYMESZ];
-
-	coff  = obj->data;
-	hdr = &coff->hdr;
-
-	if (hdr->f_nsyms == 0)
-		return 1;
-
-	ent = calloc(hdr->f_nsyms, sizeof(*ent));
-	if (!ent)
-		return 0;
-	coff->ents = ent;
-
-	if (!objpos(obj, fp, hdr->f_symptr))
-		return 0;
-	for (i = 0; i < hdr->f_nsyms; i++) {
-		if (fread(buf, SYMESZ, 1, fp) != 1)
-			return 0;
-		unpack_ent(ORDER(obj->type), buf, &ent[i]);
-	}
-
-	return 1;
-}
-
-static int
-readreloc(Obj *obj, FILE *fp)
-{
-	int i, j;
-	RELOC **rels, *rp;
-	SCNHDR *scn;
-	FILHDR *hdr;
-	struct coff32 *coff;
-	unsigned char buf[RELSZ];
-
-	coff  = obj->data;
-	hdr = &coff->hdr;
-
-	rels = calloc(obj->nsecs, sizeof(*rels));
-	if (!rels)
-		return 0;
-	coff->rels = rels;
-
-	for (i = 0; i < hdr->f_nscns; i++) {
-		scn = &coff->scns[i];
-		if (scn->s_nlnno == 0)
-			continue;
-
-		if (!objpos(obj, fp, scn->s_relptr))
-			return 0;
-
-		rp = calloc(scn->s_nrelloc, sizeof(RELOC));
-		if (!rp)
-			return 0;
-		rels[i] = rp;
-
-		for (j = 0; j < scn->s_nrelloc; j++) {
-			if (fread(buf, RELSZ, 1, fp) != 1)
-				return 0;
-			unpack_reloc(ORDER(obj->type), buf, &rp[i]);
-		}
-	}
-
-	return 1;
-}
-
-static int
-readlines(Obj *obj, FILE *fp)
-{
-	int i,j;
-	LINENO **lines, *lp;
-	FILHDR *hdr;
-	SCNHDR *scn;
-	struct coff32 *coff;
-	unsigned char buf[LINESZ];
-
-	coff  = obj->data;
-	hdr = &coff->hdr;
-
-	lines = calloc(sizeof(lp), hdr->f_nscns);
-	if (!lines)
-		return 0;
-	coff->lines = lines;
-
-	for (i = 0; i < hdr->f_nscns; i++) {
-		scn = &coff->scns[i];
-		if (scn->s_nlnno == 0)
-			continue;
-
-		lp = calloc(sizeof(*lp), scn->s_nlnno);
-		if (!lp)
-			return 0;
-		lines[i] = lp;
-
-		for (j = 0; j < scn->s_nlnno; j++) {
-			if (!objpos(obj, fp, scn->s_lnnoptr))
-				return 0;
-			if (fread(buf, LINESZ, 1, fp) == 1)
-				return 0;
-			unpack_line(ORDER(obj->type), buf, &lp[j]);
-		}
-	}
-
-	return 1;
-}
-
-static int
-readstr(Obj *obj, FILE *fp)
-{
-	FILHDR *hdr;
-	struct coff32 *coff;
-	long siz;
-	char *str;
-	unsigned char buf[10];
-
-	coff  = obj->data;
-	hdr = &coff->hdr;
-
-	if (hdr->f_nsyms == 0)
-		return 1;
-
-	if (fread(buf, 4, 1, fp) != 1)
-		return 0;
-	unpack(ORDER(obj->type), buf, "l", &siz);
-	siz -= 4;
-	if (siz < 0)
-		return 0;
-	if (siz > 0) {
-		if (siz > SIZE_MAX)
-			return 0;
-		str = malloc(siz);
-		if (!str)
-			return 0;
-		coff->strtbl = str;
-		coff->strsiz = siz;
-
-		if (fread(str, siz, 1, fp) != 1)
-			return 0;
-	}
-	return 1;
-}
-
-static int
-readhdr(Obj *obj, FILE *fp)
-{
-	FILHDR *hdr;
-	struct coff32 *coff;
-	unsigned char buf[FILHSZ];
-
-	coff  = obj->data;
-	hdr = &coff->hdr;
-
-	if (fread(buf, FILHSZ, 1, fp) != 1)
-		return 0;
-	unpack_hdr(ORDER(obj->type), buf, hdr);
-
-	return 1;
-}
-
-static int
-loadsections(Obj *obj, FILE *fp)
-{
-	size_t len;
-	unsigned sflags, type;
-	unsigned long flags;
-	FILHDR *hdr;
-	struct coff32 *coff;
-	SCNHDR *scn;
-	Section *secs, *sp;
-
-	coff  = obj->data;
-	hdr = &coff->hdr;
-	scn = coff->scns;
-
-	secs = malloc(sizeof(Section) * hdr->f_nscns);
-	if (!secs)
-		return 0;
-	obj->sections = secs;
-
-	for (sp = secs; sp < &secs[hdr->f_nscns]; sp++) {
-		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;
-
-		len = strlen(scn->s_name) + 1;
-		if ((sp->name = malloc(len)) == NULL)
-			return 0;
-
-		memcpy(sp->name, scn->s_name, len);
-		sp->fp = fp;
-		sp->offset = scn->s_scnptr;
-		sp->size = scn->s_size;
-		sp->type = type;
-		obj->nsecs++;
-	}
-	return 1;
-}
-
-static int
-readaout(Obj *obj, FILE *fp)
-{
-	FILHDR *hdr;
-	struct coff32 *coff;
-	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);
-
-	return 1;
-}
-
-static int
-read(Obj *obj, FILE *fp)
-{
-	/* TODO: Add validation of the different fields */
-	if (fgetpos(fp, &obj->pos))
-		goto error;
-	if (!readhdr(obj, fp))
-		goto error;
-	if (!readaout(obj, fp))
-		goto error;
-	if (!readscns(obj, fp))
-		goto error;
-	if (!readents(obj, fp))
-		goto error;
-	if (!readstr(obj, fp))
-		goto error;
-	if (!readreloc(obj, fp))
-		goto error;
-	if (!readlines(obj, fp))
-		goto error;
-	if (!loadsyms(obj))
-		goto error;
-	if (!loadsections(obj, fp))
-		goto error;
-	return 0;
-
-error:
-	objreset(obj);
-	return -1;
-}
-
-static int
-writehdr(Obj *obj, FILE *fp)
-{
-	FILHDR *hdr;
-	struct coff32 *coff;
-	unsigned char buf[FILHSZ];
-
-	coff  = obj->data;
-	hdr = &coff->hdr;
-
-	pack_hdr(ORDER(obj->type), buf, hdr);
-	if (fwrite(buf, FILHSZ, 1, fp) != 1)
-		return 0;
-
-	return 1;
-}
-
-static int
-writescns(Obj *obj, FILE *fp)
-{
-	/* TODO */
-}
-
-static int
-writeents(Obj *obj, FILE *fp)
-{
-	/* TODO */
-}
-
-static int
-writestr(Obj *obj, FILE *fp)
-{
-	/* TODO */
-}
-
-static int
-write(Obj *obj, FILE *fp)
-{
-	struct coff32 *coff;
-
-	coff  = obj->data;
-	coff->strsiz = 0;
-	free(coff->strtbl);
-
-	if (!writehdr(obj, fp))
-		return -1;
-	if (!writescns(obj, fp))
-		return -1;
-	if (!writeents(obj, fp))
-		return -1;
-	if (!writestr(obj, fp))
-		return -1;
-
-	return 0;
-}
-
-static void
-del(Obj *obj)
-{
-	struct coff32 *coff = obj->data;
-
-	if (coff) {
-		free(coff->scns);
-		free(coff->ents);
-		free(coff->strtbl);
-	}
-	free(obj->data);
-	obj->data = NULL;
-}
-
-static int
-new(Obj *obj)
-{
-	struct coff32 *coff;
-
-	if ((coff = calloc(1, sizeof(*coff))) == NULL)
-		return -1;
-	obj->data = coff;
-	return 0;
-}
-
-static void
-strip(Obj *obj)
-{
-	struct coff32 *coff = obj->data;
-	FILHDR *hdr;
-
-	hdr = &coff->hdr;
-	free(coff->ents);
-	coff->ents = NULL;
-	hdr->f_nsyms = 0;
-	hdr->f_symptr = 0;
-}
-
-static long
-mkindex(int type, long nsymbols, Symdef *head, FILE *fp)
-{
-	return coff32idx(BIG_ENDIAN, nsymbols, head, fp);
-}
-
-struct format objcoff32 = {
-	.probe = probe,
-	.new = new,
-	.del = del,
-	.read = read,
-	.write = write,
-	.strip = strip,
-	.index = mkindex,
-};
--- /dev/null
+++ b/src/libmach/coff32/Makefile
@@ -1,0 +1,13 @@
+.POSIX:
+PROJECTDIR =../../..
+include $(PROJECTDIR)/scripts/rules.mk
+
+OBJS = coff32del.o \
+       coff32index.o \
+       coff32new.o \
+       coff32probe.o \
+       coff32read.o \
+       coff32strip.o \
+       coff32write.o \
+
+all: $(OBJS)
--- /dev/null
+++ b/src/libmach/coff32/coff-help.h
@@ -1,0 +1,576 @@
+/*
+******************************************************************
+**			29K COFF Declarations			**
+**								**
+**								**
+** This file contains the declarations required to define	**
+** the COFF format as proposed for use by AMD for the 29K	**
+** family of RISC microprocessors.				**
+** 								**
+** No attempt is made here to describe in detail those portions	**
+** of COFF which have not been modified or extended.  Pertinent	**
+** #define's and struct's are included for completeness.  Those **
+** declarations are distributed in several System V headers.	**
+**								**
+** For a better and more complete description of COFF with	**
+** general and 29K Family specific clarifications, see the	**
+** AMD's "Programmer's Guide to the Common Object File Format	**
+** (COFF) for the Am29000" Application Note, order number 11963.**
+**								**
+** For non-29K-Family specific COFF information, consult AT&amp;T	**
+** UNIX System V Release 3, Programmer's Guide, Chapter 11	**
+** (Manual 307-225, Issue 1).					**
+**								**
+**								**
+** Revision history:						**
+**								**
+** 0.01	JG - first published					**
+** 0.02 JG - added relocation type R_IFAR and renumbered	**
+** 0.03 RC - COFF spec now compiles without error		**
+** 0.04 RC - removed R_IPAIR and R_IFAR and renumbered		**
+** 0.05 RC - added R_HWORD relocation type			**
+** 0.06 RC - section types					**
+**		changed value of STYP_BSSREG			**
+**		replaced STYP_RDATA and STYP_IDATA		**
+**		 with STYP_LIT, STYP_ABS, and STYP_ENVIR	**
+**	   - relocation types					**
+**		added R_IABS					**
+**		replaced R_IBYTE with R_BYTE and renumbered	**
+**	   - changed comments and removed comments  		**
+** 0.07 RC - relocation types					**
+**		Added R_IHCONST to support relocation offsets	**
+**		 for CONSTH instruction.  Added commentary,	**
+**		 and renumbered to make room for R_IHCONST,	**
+**		 putting the (as yet unused) global reloc 	**
+**		 types at the end.				**
+**	   - bug fix (typo)					**
+**		Added slash to terminate comment field on	**
+**		 C_EXT so now C_STAT is defined.		**
+** 0.08 RC - official magic numbers assigned by AT&amp;T.		**
+** 0.09 RC - support multiple address spaces by adding magic	**
+**		a.out header numbers SASMAGIC and MASMAGIC.	**
+** 0.10 RC - No changes.   Just added the comments below and	**
+**		corrected comments on tsize, dsize, and bsize. 	**
+** 	   - All portions of the COFF file described as C 	**
+**		structs must use Host Endian byte ordering.	**
+**	  	Files created on a machine with a byte		**
+**		ordering different from	the host may be 	**
+**		converted using the UNIX conv(1) command.	**
+**	   - Assemblers and compilers must create section	**
+**		headers for .text, .data, and .bss (in that	**
+**		order) even if they are 0 length.		**
+**	   - tsize, dsize, and bsize are the size of .text,	**
+**		.data, and .bss respectively.   Other sections	**
+**		of type STYP_TEXT, STYP_DATA, and STYP_BSS	**
+**		are not included in the byte count.		**
+**	   - Assemblers and compilers must create output	**
+**		sections to the exact byte length (and not	**
+**		round them up).   The linker will take care	**
+**		of rounding.		                 	**
+** 2.1.01  - Added C_STARTOF storage class for support of	**
+**		assembler $startof(sect_name) and		**
+**		$sizeof(sect_name) operators.			**
+** 2.1.02  - Added a few more defines for completeness.		**
+** 2.1.03  - Added more magic numbers for completeness.		**
+******************************************************************
+*/
+
+/*
+** Overall structure of a COFF file
+*/
+
+/*
+		*--------------------------------*
+		|	File Header		 |
+		----------------------------------
+		|	Optional Information	 |
+		----------------------------------
+		|	Section 1 Header	 |
+		----------------------------------
+		|		...		 |
+		----------------------------------
+		|	Section n Header	 |
+		----------------------------------
+		| 	Raw Data for Section 1	 |
+		----------------------------------
+		|		...		 |
+		----------------------------------
+		|	Raw Data for Section n	 |
+		----------------------------------
+		| Relocation Info for Section 1	 |
+		----------------------------------
+		|		...		 |
+		----------------------------------
+		| Relocation Info for Section n	 |
+		----------------------------------
+		|  Line Numbers for Section 1	 |
+		----------------------------------
+		|		...		 |
+		----------------------------------
+		|  Line Numbers for Section n	 |
+		----------------------------------
+		|	  Symbol Table		 |
+		----------------------------------
+		|	  String Table		 |
+		*--------------------------------*
+*/
+ 
+/****************************************************************/
+
+
+/*
+** File Header and related definitions
+*/
+
+struct filehdr 
+{
+	unsigned short	f_magic;	/* magic number */
+	unsigned short	f_nscns;	/* number of sections */
+	long		f_timdat;	/* time &amp; date stamp */
+ 	long		f_symptr;	/* file pointer to symtab */
+	long		f_nsyms;	/* number of symtab entries */
+	unsigned short	f_opthdr;	/* sizeof(optional hdr) */
+	unsigned short	f_flags; 	/* flags */
+};
+
+#define FILHDR	struct filehdr
+#define FILHSZ	sizeof (FILHDR)
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/*
+** Magic numbers currently known to us,
+** Plus 29K magic numbers assigned by AT&amp;T.
+*/
+
+#define M68MAGIC	0210
+#define M68TVMAGIC	0211
+#define B16MAGIC	0502
+#define BTVMAGIC	0503
+#define IAPX16		0504
+#define IAPX16TV	0505
+#define IAPX20		0506
+#define IAPX20TV	0507
+#define X86MAGIC	0510
+#define XTVMAGIC	0511
+#define I286SMAGIC	0512
+#define I386MAGIC	0514
+#define MC68MAGIC	0520
+#define MC68KWRMAGIC	0520	/* 68K writeable text sections */
+#define MC68TVMAGIC	0521
+#define MC68KPGMAGIC	0522	/* 68K demand paged text (shared with i286) */
+#define I286LMAGIC	0522	/* i286 (shared with 68K) */
+/*			0524	 * reserved for NSC */
+/*			0525	 * reserved for NSC */
+/*			0544	 * reserved for Zilog */
+/*			0545	 * reserved for Zilog */
+#define N3BMAGIC	0550	/* 3B20S executable, no TV */    
+#define NTVMAGIC	0551	/* 3B20 executable with TV */
+#define FBOMAGIC	0560   	/* WE*-32 (Forward Byte Ordering) */
+#define WE32MAGIC	0560	/* WE 32000, no TV */
+#define MTVMAGIC	0561	/* WE 32000 with TV */
+#define RBOMAGIC	0562	/* WE-32 (Reverse Byte Ordering) */
+#define VAXWRMAGIC	0570	/* VAX-11/750 and VAX-11/780 */
+				/* (writable text sections) */
+#define VAXROMAGIC	0575	/* VAX-11/750 and VAX-11780 */
+				/* (read-only text sections) */
+#define U370WRMAGIC	0530	/* IBM 370 (writable text sections) */
+#define AMDWRMAGIC	0531	/* Amdahl 470/580 writable text sections */
+#define AMDROMAGIC	0534	/* Amdahl 470/580 read only sharable text */
+#define U370ROMAGIC	0535	/* IBM 370 (read-only sharable text sections) */
+
+#define	SIPFBOMAGIC	0572	/* 29K Family (Byte 0 is MSB - Big Endian) */
+#define	SIPRBOMAGIC	0573	/* 29K Family (Byte 0 is LSB - Little Endian) */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/*
+** File header flags currently known to us.
+**
+** Am29000 will use the F_AR32WR and F_AR32W flags to indicate
+** the byte ordering in the file.
+*/
+
+#define F_RELFLG	00001	/* Relocation information stripped */
+				/* from the file. */
+#define F_EXEC		00002	/* File is executable (i.e. no */
+				/* unresolved external references). */
+#define F_LNNO		00004	/* Line numbers stripped from */
+				/* the file. */
+#define F_LSYMS		00010	/* Local symbols stripped from */
+				/* the file. */
+#define F_MINMAL	00020	/* Not used by UNIX. */
+#define F_UPDATE	00040	/* Not used by UNIX. */
+#define F_SWABD		00100	/* Not used by UNIX. */
+#define F_AR16WR	00200	/* File has the byte ordering used */
+				/* by the PDP*-11/70 processor. */
+#define F_AR32WR	00400	/* File has 32 bits per word, */
+				/* least significant byte first. */
+#define F_AR32W		01000	/* File has 32 bits per word, */
+				/* most significant byte first. */
+#define F_PATCH		02000	/* Not used by UNIX. */
+#define F_BM32BRST    0010000	/* 32100 required; has RESTORE work-around. */
+#define F_BM32B       0020000	/* 32100 required. */
+#define F_BM32MAU     0040000	/* MAU required. */
+#define F_BM32ID      0160000	/* WE 32000 processor ID field. */
+
+/*--------------------------------------------------------------*/
+
+/*
+** Optional (a.out) header 
+*/
+
+typedef	struct aouthdr 
+{
+	short	magic;		/* magic number */
+	short	vstamp;		/* version stamp */
+	long	tsize;		/* size of .text in bytes */
+	long	dsize;		/* size of .data (initialized data) */
+	long	bsize;		/* size of .bss (uninitialized data) */
+	long	entry;		/* entry point */
+	long	text_start;	/* base of text used for this file */
+	long	data_start;	/* base of data used for this file */
+} AOUTHDR;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/*
+** Magic a.out header numbers for cross development (non-UNIX),
+** support of separate I and D address spaces.
+*/
+
+#define SASMAGIC	010000	/* Single Address Space */    
+#define MASMAGIC	020000	/* Multiple (separate I &amp; D) Address Spaces */
+
+/*--------------------------------------------------------------*/
+
+/*
+** Section header and related definitions
+*/
+
+struct scnhdr 
+{
+	char		s_name[8];	/* section name */
+	long		s_paddr;	/* physical address */
+	long		s_vaddr;	/* virtual address */
+	long		s_size;		/* section size */
+	long		s_scnptr;	/* file ptr to raw data for section */
+	long		s_relptr;	/* file ptr to relocation */
+	long		s_lnnoptr;	/* file ptr to line numbers */
+	unsigned short	s_nreloc;	/* number of relocation entries */
+	unsigned short	s_nlnno;	/* number of line number entries */
+	long		s_flags;	/* flags */
+};
+
+#define	SCNHDR	struct	scnhdr
+#define	SCNHSZ	sizeof	(SCNHDR)
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/*
+** Section types - with additional section type for global 
+** registers which will be relocatable for the Am29000.
+**
+** In instances where it is necessary for a linker to produce an
+** output file which contains text or data not based at virtual
+** address 0, e.g. for a ROM, then the linker should accept
+** address base information as command input and use PAD sections
+** to skip over unused addresses.
+*/
+
+#define STYP_REG	0x00	/* Regular section (allocated, */
+				/* relocated, loaded) */
+#define STYP_DSECT	0x01	/* Dummy section (not allocated, */
+				/* relocated, not loaded) */
+#define STYP_NOLOAD	0x02	/* Noload section (allocated, */
+				/* relocated, not loaded) */
+#define STYP_GROUP	0x04	/* Grouped section (formed from */
+				/* input sections) */
+#define STYP_PAD	0x08	/* Padded section (not allocated, */
+				/* not relocated, loaded) */
+#define	STYP_COPY	0x10	/* Copy section (for a decision */
+				/* function used in updating fields; */
+				/* not allocated, not relocated, */
+				/* loaded, relocation and line */
+				/* number entries processed */
+				/* normally) */
+#define	STYP_TEXT	0x20	/* Section contains executable text */
+#define	STYP_DATA	0x40	/* Section contains initialized data */
+#define	STYP_BSS	0x80	/* Section contains only uninitialized data */
+#define STYP_INFO	0x200	/* Comment section (not allocated, */
+				/* not relocated, not loaded) */
+#define STYP_OVER	0x400	/* Overlay section (relocated, */
+				/* not allocated, not loaded) */
+#define STYP_LIB	0x800	/* For .lib section (like STYP_INFO) */
+
+#define	STYP_BSSREG	0x1200	/* Global register area (like STYP_INFO) */
+#define STYP_ENVIR	0x2200	/* Environment (like STYP_INFO) */
+#define STYP_ABS	0x4000	/* Absolute (allocated, not reloc, loaded) */
+#define STYP_LIT	0x8020	/* Literal data (like STYP_TEXT) */
+
+/*
+NOTE:  The use of STYP_BSSREG for relocation is not yet defined.
+*/
+
+/*--------------------------------------------------------------*/
+
+/*
+** Relocation information declaration and related definitions
+*/
+
+struct reloc 
+{
+	long		r_vaddr;	/* (virtual) address of reference */
+	long		r_symndx;	/* index into symbol table */
+	unsigned short	r_type;		/* relocation type */
+};
+
+#define	RELOC		struct reloc
+#define	RELSZ		10		/* sizeof (RELOC) */ 
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/*
+** Relocation types for the Am29000 
+*/
+
+#define	R_ABS		0	/* reference is absolute */
+ 
+#define	R_IREL		030	/* instruction relative (jmp/call) */
+#define	R_IABS		031	/* instruction absolute (jmp/call) */
+#define	R_ILOHALF	032	/* instruction low half  (const)  */
+#define	R_IHIHALF	033	/* instruction high half (consth) part 1 */
+#define	R_IHCONST	034	/* instruction high half (consth) part 2 */
+				/* constant offset of R_IHIHALF relocation */
+#define	R_BYTE		035	/* relocatable byte value */
+#define R_HWORD		036	/* relocatable halfword value */
+#define R_WORD		037	/* relocatable word value */
+
+#define	R_IGLBLRC	040	/* instruction global register RC */
+#define	R_IGLBLRA	041	/* instruction global register RA */
+#define	R_IGLBLRB	042	/* instruction global register RB */
+ 
+/*
+NOTE:
+All the "I" forms refer to Am29000 instruction formats.  The linker is 
+expected to know how the numeric information is split and/or aligned
+within the instruction word(s).  R_BYTE works for instructions, too.
+
+If the parameter to a CONSTH instruction is a relocatable type, two 
+relocation records are written.  The first has an r_type of R_IHIHALF 
+(33 octal) and a normal r_vaddr and r_symndx.  The second relocation 
+record has an r_type of R_IHCONST (34 octal), a normal r_vaddr (which 
+is redundant), and an r_symndx containing the 32-bit constant offset 
+to the relocation instead of the actual symbol table index.  This 
+second record is always written, even if the constant offset is zero.
+The constant fields of the instruction are set to zero.
+*/
+
+/*--------------------------------------------------------------*/
+
+/*
+** Line number entry declaration and related definitions
+*/
+
+struct lineno 
+{
+   union 
+   {
+      long	l_symndx;	/* sym table index of function name */
+      long	l_paddr;	/* (physical) address of line number */
+   } l_addr;
+   unsigned short	l_lnno;		/* line number */
+};
+
+#define	LINENO		struct lineno
+#define	LINESZ		6		/* sizeof (LINENO) */
+
+/*--------------------------------------------------------------*/
+
+/*
+** Symbol entry declaration and related definitions
+*/
+
+#define	SYMNMLEN	8	/* Number of characters in a symbol name */
+
+struct	syment 
+{
+   union  
+   {
+      char	_n_name [SYMNMLEN];	/* symbol name */
+      struct 
+      {
+         long	_n_zeroes;		/* symbol name */
+         long	_n_offset;		/* offset into string table */
+      } _n_n;
+      char	*_n_nptr[2];		/* allows for overlaying */
+   } _n;
+#ifndef pdp11
+   unsigned
+#endif
+   long			n_value;		/* value of symbol */
+   short		n_scnum;		/* section number */
+   unsigned short	n_type;			/* type and derived type */
+   char			n_sclass;		/* storage class */
+   char			n_numaux;		/* number of aux entries */
+};
+
+#define	n_name		_n._n_name
+#define	n_nptr		_n._n_nptr[1]
+#define	n_zeroes	_n._n_n._n_zeroes 
+#define	n_offset	_n._n_n._n_offset
+
+#define	SYMENT	struct syment
+#define	SYMESZ	18
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/*
+** Storage class definitions - new classes for global registers.
+*/
+
+#define	C_EFCN		-1		/* physical end of a function */
+#define	C_NULL		0		/* - */
+#define	C_AUTO		1		/* automatic variable */
+#define	C_EXT		2		/* external symbol */
+#define C_STAT		3		/* static */
+#define C_REG		4		/* (local) register variable */
+#define C_EXTDEF	5		/* external definition */
+#define C_LABEL		6		/* label */
+#define C_ULABEL	7		/* undefined label */
+#define C_MOS		8		/* member of structure */
+#define C_ARG		9		/* function argument */
+#define C_STRTAG	10		/* structure tag */
+#define C_MOU		11		/* member of union */
+#define C_UNTAG		12		/* union tag */
+#define C_TPDEF		13		/* type definition */
+#define C_UNSTATIC	14		/* uninitialized static  */
+#define C_USTATIC	14		/* uninitialized static  */
+#define C_ENTAG		15		/* enumeration tag */
+#define C_MOE		16		/* member of enumeration */
+#define C_REGPARM	17		/* register parameter */
+#define C_FIELD		18		/* bit field */
+
+#define C_GLBLREG	19		/* global register */
+#define C_EXTREG	20		/* external global register */
+#define	C_DEFREG	21		/* ext. def. of global register */
+#define C_STARTOF	22		/* as29 $SIZEOF and $STARTOF symbols */
+
+
+#define C_BLOCK		100		/* beginning and end of block */
+#define C_FCN		101		/* beginning and end of function */
+#define C_EOS		102		/* end of structure */
+#define C_FILE		103		/* file name */
+#define C_LINE		104		/* used only by utility programs */
+#define C_ALIAS		105		/* duplicated tag */
+#define C_HIDDEN	106		/* like static, used to avoid name */
+					/* conflicts */
+#define C_SHADOW	107		/* shadow symbol */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/*
+** Special section number definitions used in symbol entries.
+** (Section numbers 1-65535 are used to indicate the section
+** where the symbol was defined.)
+*/
+
+#define	N_DEBUG		-2		/* special symbolic debugging symbol */
+#define	N_ABS		-1		/* absolute symbol */
+#define	N_UNDEF		 0		/* undefined external symbol */
+#define N_SCNUM	   1-65535		/* section num where symbol defined */
+	 			 
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/*
+** Fundamental symbol types.
+*/
+
+#define	T_NULL		0		/* type not assigned */
+#define T_VOID		1		/* void */
+#define	T_CHAR		2		/* character */
+#define	T_SHORT		3		/* short integer */
+#define	T_INT		4		/* integer */
+#define	T_LONG		5		/* long integer */
+#define	T_FLOAT		6		/* floating point */
+#define	T_DOUBLE	7		/* double word */
+#define	T_STRUCT	8		/* structure */
+#define	T_UNION		9		/* union */
+#define	T_ENUM		10		/* enumeration */
+#define	T_MOE		11		/* member of enumeration */
+#define	T_UCHAR		12		/* unsigned character */
+#define	T_USHORT	13		/* unsigned short */
+#define T_UINT		14		/* unsigned integer */
+#define	T_ULONG		15 		/* unsigned long */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/*
+** Derived symbol types.
+*/
+
+#define	DT_NON		0		/* no derived type  */
+#define	DT_PTR		1		/* pointer */
+#define	DT_FCN		2		/* function */
+#define	DT_ARY		3		/* array */
+
+/*--------------------------------------------------------------*/
+
+/*
+** Auxiliary symbol table entry declaration and related 
+** definitions.
+*/
+
+#define	FILNMLEN	14   /* Number of characters in a file name */
+#define	DIMNUM		4    /* Number of array dimensions in auxiliary entry */
+
+union auxent 
+{
+   struct 
+   {
+      long	x_tagndx;		/* str, un, or enum tag indx */
+      union 
+      {
+         struct 
+         {
+            unsigned short	x_lnno;		/* declaration line number */
+            unsigned short	x_size;		/* str, union, array size */
+         } x_lnsz;
+         long	x_size;				/* size of functions */
+      } x_misc;
+      union 
+      {
+         struct 				/* if ISFCN, tag, or .bb */
+         {
+            long	x_lnnoptr;		/* ptr to fcn line # */
+            long	x_endndx;		/* entry ndx past block end */
+         } x_fcn;
+         struct 				/* if ISARY, up to 4 dimen */
+         {
+            unsigned short	x_dimen[DIMNUM];
+         } x_ary;
+      } x_fcnary;
+      unsigned short	x_tvndx;		/* tv index */
+   } x_sym;
+   struct 
+   {
+      char		x_fname[FILNMLEN];
+   } x_file;
+   struct 
+   {
+      long		x_scnlen;	/* section length */
+      unsigned short	x_nreloc;	/* number of relocation entries */
+      unsigned short	x_nlinno;	/* number of line numbers */
+   } x_scn;
+   struct 
+   {
+      long		x_tvfill;			/* tv fill value */
+      unsigned short	x_tvlen;			/* length of tv */
+      unsigned short	x_tvrna[2];			/* tv range */
+   } x_tv;	 /* info about  tv section (in auxent of symbol  tv)) */
+};
+
+#define	AUXENT		union auxent
+#define	AUXESZ		18		/* sizeof(AUXENT) */
+
+</pre></div></body></html>
--- /dev/null
+++ b/src/libmach/coff32/coff32.h
@@ -1,0 +1,25 @@
+#include <scc/coff32/filehdr.h>
+#include <scc/coff32/aouthdr.h>
+#include <scc/coff32/scnhdr.h>
+#include <scc/coff32/syms.h>
+#include <scc/coff32/reloc.h>
+#include <scc/coff32/linenum.h>
+
+typedef struct coff32 Coff32;
+
+struct arch {
+	char *name;
+	unsigned char magic[2];
+	int type;
+};
+
+struct coff32 {
+	FILHDR hdr;
+	AOUTHDR *aout;
+	SCNHDR *scns;
+	SYMENT *ents;
+	RELOC **rels;
+	LINENO **lines;
+	char *strtbl;
+	unsigned long strsiz;
+};
--- /dev/null
+++ b/src/libmach/coff32/coff32del.c
@@ -1,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/mach.h>
+
+#include "../libmach.h"
+#include "coff32.h"
+
+void
+coff32del(Obj *obj)
+{
+	struct coff32 *coff = obj->data;
+
+	if (coff) {
+		free(coff->scns);
+		free(coff->ents);
+		free(coff->strtbl);
+	}
+	free(obj->data);
+	obj->data = NULL;
+}
--- /dev/null
+++ b/src/libmach/coff32/coff32index.c
@@ -1,0 +1,12 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "../libmach.h"
+#include "coff32.h"
+
+long
+coff32index(int type, long nsymbols, Symdef *head, FILE *fp)
+{
+	return coff32idx(BIG_ENDIAN, nsymbols, head, fp);
+}
--- /dev/null
+++ b/src/libmach/coff32/coff32new.c
@@ -1,0 +1,18 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/mach.h>
+
+#include "../libmach.h"
+#include "coff32.h"
+
+int
+coff32new(Obj *obj)
+{
+	struct coff32 *coff;
+
+	if ((coff = calloc(1, sizeof(*coff))) == NULL)
+		return -1;
+	obj->data = coff;
+	return 0;
+}
--- /dev/null
+++ b/src/libmach/coff32/coff32probe.c
@@ -1,0 +1,27 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "../libmach.h"
+#include "coff32.h"
+
+static struct arch archs[] = {
+	"coff32-i386", "\x4c\x01", OBJ(COFF32, ARCH386, LITTLE_ENDIAN),
+	"coff32-z80", "\x5a\x80", OBJ(COFF32, ARCHZ80, LITTLE_ENDIAN),
+	NULL,
+};
+
+int
+coff32probe(unsigned char *buf, char **name)
+{
+	struct arch *ap;
+
+	for (ap = archs; ap->name; ap++) {
+		if (ap->magic[0] == buf[0] && ap->magic[1] == buf[1]) {
+			if (name)
+				*name = ap->name;
+			return ap->type;
+		}
+	}
+	return -1;
+}
--- /dev/null
+++ b/src/libmach/coff32/coff32read.c
@@ -1,0 +1,522 @@
+#include <assert.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/mach.h>
+
+#include "../libmach.h"
+#include "coff32.h"
+
+static void
+unpack_hdr(int order, unsigned char *buf, FILHDR *hdr)
+{
+	int n;
+
+	n = unpack(order,
+	           buf,
+	           "sslllss",
+	           &hdr->f_magic,
+	           &hdr->f_nscns,
+	           &hdr->f_timdat,
+	           &hdr->f_symptr,
+	           &hdr->f_nsyms,
+	           &hdr->f_opthdr,
+	           &hdr->f_flags);
+	assert(n == FILHSZ);
+}
+
+static void
+unpack_line(int order, unsigned char *buf, LINENO *lp)
+{
+	int n;
+
+	n = unpack(order,
+	           buf,
+	           "lls",
+	           &lp->l_symndx,
+	           &lp->l_paddr,
+	           &lp->l_lnno);
+	assert(n == LINESZ);
+}
+
+static void
+unpack_scn(int order, unsigned char *buf, SCNHDR *scn)
+{
+	int n;
+
+	n = unpack(order,
+	          buf,
+	          "'8llllllssl",
+	          scn->s_name,
+	          &scn->s_paddr,
+	          &scn->s_vaddr,
+	          &scn->s_size,
+	          &scn->s_scnptr,
+	          &scn->s_relptr,
+	          &scn->s_lnnoptr,
+	          &scn->s_nrelloc,
+	          &scn->s_nlnno,
+	          &scn->s_flags);
+	assert(n == SCNHSZ);
+}
+
+static void
+unpack_ent(int order, unsigned char *buf, SYMENT *ent)
+{
+	int n;
+	char *s;
+
+	n = unpack(order,
+	           buf,
+	           "'8lsscc",
+	           ent->n_name,
+	           &ent->n_value,
+	           &ent->n_scnum,
+	           &ent->n_type,
+	           &ent->n_sclass,
+	           &ent->n_numaux);
+	assert(n == SYMESZ);
+
+	s = ent->n_name;
+	if (!s[0] && !s[1] && !s[2] && !s[3])
+		unpack(order, "ll", buf, &ent->n_zeroes, &ent->n_offset);
+}
+
+static void
+unpack_reloc(int order, unsigned char *buf, RELOC *rel)
+{
+	int n;
+
+	n = unpack(order,
+	           buf,
+	           "lls",
+	           &rel->r_vaddr,
+	           &rel->r_symndx,
+	           &rel->r_type);
+	assert(n == RELSZ);
+}
+
+static void
+unpack_aout(int order, unsigned char *buf, AOUTHDR *aout)
+{
+	int n;
+
+	n = unpack(order,
+	           buf,
+	           "ssllllll",
+	           &aout->magic,
+	           &aout->vstamp,
+	           &aout->tsize,
+	           &aout->dsize,
+	           &aout->bsize,
+	           &aout->entry,
+	           &aout->text_start,
+	           &aout->data_start);
+	assert(n == AOUTSZ);
+}
+
+static int
+readhdr(Obj *obj, FILE *fp)
+{
+	FILHDR *hdr;
+	struct coff32 *coff;
+	unsigned char buf[FILHSZ];
+
+	coff  = obj->data;
+	hdr = &coff->hdr;
+
+	if (fread(buf, FILHSZ, 1, fp) != 1)
+		return 0;
+	unpack_hdr(ORDER(obj->type), buf, hdr);
+
+	return 1;
+}
+
+static int
+loadsections(Obj *obj, FILE *fp)
+{
+	size_t len;
+	unsigned sflags, type;
+	unsigned long flags;
+	FILHDR *hdr;
+	struct coff32 *coff;
+	SCNHDR *scn;
+	Section *secs, *sp;
+
+	coff  = obj->data;
+	hdr = &coff->hdr;
+	scn = coff->scns;
+
+	secs = malloc(sizeof(Section) * hdr->f_nscns);
+	if (!secs)
+		return 0;
+	obj->sections = secs;
+
+	for (sp = secs; sp < &secs[hdr->f_nscns]; sp++) {
+		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;
+
+		len = strlen(scn->s_name) + 1;
+		if ((sp->name = malloc(len)) == NULL)
+			return 0;
+
+		memcpy(sp->name, scn->s_name, len);
+		sp->fp = fp;
+		sp->offset = scn->s_scnptr;
+		sp->size = scn->s_size;
+		sp->type = type;
+		obj->nsecs++;
+	}
+	return 1;
+}
+
+static int
+readstr(Obj *obj, FILE *fp)
+{
+	FILHDR *hdr;
+	struct coff32 *coff;
+	long siz;
+	char *str;
+	unsigned char buf[10];
+
+	coff  = obj->data;
+	hdr = &coff->hdr;
+
+	if (hdr->f_nsyms == 0)
+		return 1;
+
+	if (fread(buf, 4, 1, fp) != 1)
+		return 0;
+	unpack(ORDER(obj->type), buf, "l", &siz);
+	siz -= 4;
+	if (siz < 0)
+		return 0;
+	if (siz > 0) {
+		if (siz > SIZE_MAX)
+			return 0;
+		str = malloc(siz);
+		if (!str)
+			return 0;
+		coff->strtbl = str;
+		coff->strsiz = siz;
+
+		if (fread(str, siz, 1, fp) != 1)
+			return 0;
+	}
+	return 1;
+}
+
+static int
+readreloc(Obj *obj, FILE *fp)
+{
+	int i, j;
+	RELOC **rels, *rp;
+	SCNHDR *scn;
+	FILHDR *hdr;
+	struct coff32 *coff;
+	unsigned char buf[RELSZ];
+
+	coff  = obj->data;
+	hdr = &coff->hdr;
+
+	rels = calloc(obj->nsecs, sizeof(*rels));
+	if (!rels)
+		return 0;
+	coff->rels = rels;
+
+	for (i = 0; i < hdr->f_nscns; i++) {
+		scn = &coff->scns[i];
+		if (scn->s_nlnno == 0)
+			continue;
+
+		if (!objpos(obj, fp, scn->s_relptr))
+			return 0;
+
+		rp = calloc(scn->s_nrelloc, sizeof(RELOC));
+		if (!rp)
+			return 0;
+		rels[i] = rp;
+
+		for (j = 0; j < scn->s_nrelloc; j++) {
+			if (fread(buf, RELSZ, 1, fp) != 1)
+				return 0;
+			unpack_reloc(ORDER(obj->type), buf, &rp[i]);
+		}
+	}
+
+	return 1;
+}
+
+static int
+readents(Obj *obj, FILE *fp)
+{
+	FILHDR *hdr;
+	struct coff32 *coff;
+	SYMENT *ent;
+	long i;
+	unsigned char buf[SYMESZ];
+
+	coff  = obj->data;
+	hdr = &coff->hdr;
+
+	if (hdr->f_nsyms == 0)
+		return 1;
+
+	ent = calloc(hdr->f_nsyms, sizeof(*ent));
+	if (!ent)
+		return 0;
+	coff->ents = ent;
+
+	if (!objpos(obj, fp, hdr->f_symptr))
+		return 0;
+	for (i = 0; i < hdr->f_nsyms; i++) {
+		if (fread(buf, SYMESZ, 1, fp) != 1)
+			return 0;
+		unpack_ent(ORDER(obj->type), buf, &ent[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
+loadsyms(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 0;
+
+		if ((s = symname(coff, ent)) == NULL)
+			return 0;
+
+		if ((sym = objlookup(obj, s)) == NULL)
+			return 0;
+
+		sym->type = t;
+		sym->value = ent->n_value;
+		sym->size = (sym->type == 'C') ? ent->n_value : 0;
+	}
+
+	return 1;
+}
+
+static int
+readscns(Obj *obj, FILE *fp)
+{
+	FILHDR *hdr;
+	struct coff32 *coff;
+	SCNHDR *scn;
+	long i;
+	unsigned char buf[SCNHSZ];
+
+	coff  = obj->data;
+	hdr = &coff->hdr;
+
+	if (hdr->f_nscns > 0) {
+		scn = calloc(hdr->f_nscns, sizeof(*scn));
+		if (!scn)
+			return 0;
+		coff->scns = scn;
+	}
+	if (fseek(fp, hdr->f_opthdr, SEEK_CUR) < 0)
+		return 0;
+	for (i = 0; i < hdr->f_nscns; i++) {
+		if (fread(buf, SCNHSZ, 1, fp) < 0)
+			return 0;
+		unpack_scn(ORDER(obj->type), buf, &scn[i]);
+	}
+
+	return 1;
+}
+
+static int
+readlines(Obj *obj, FILE *fp)
+{
+	int i,j;
+	LINENO **lines, *lp;
+	FILHDR *hdr;
+	SCNHDR *scn;
+	struct coff32 *coff;
+	unsigned char buf[LINESZ];
+
+	coff  = obj->data;
+	hdr = &coff->hdr;
+
+	lines = calloc(sizeof(lp), hdr->f_nscns);
+	if (!lines)
+		return 0;
+	coff->lines = lines;
+
+	for (i = 0; i < hdr->f_nscns; i++) {
+		scn = &coff->scns[i];
+		if (scn->s_nlnno == 0)
+			continue;
+
+		lp = calloc(sizeof(*lp), scn->s_nlnno);
+		if (!lp)
+			return 0;
+		lines[i] = lp;
+
+		for (j = 0; j < scn->s_nlnno; j++) {
+			if (!objpos(obj, fp, scn->s_lnnoptr))
+				return 0;
+			if (fread(buf, LINESZ, 1, fp) == 1)
+				return 0;
+			unpack_line(ORDER(obj->type), buf, &lp[j]);
+		}
+	}
+
+	return 1;
+}
+
+static int
+readaout(Obj *obj, FILE *fp)
+{
+	FILHDR *hdr;
+	struct coff32 *coff;
+	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);
+
+	return 1;
+}
+
+int
+coff32read(Obj *obj, FILE *fp)
+{
+	/* TODO: Add validation of the different fields */
+	if (fgetpos(fp, &obj->pos))
+		goto error;
+	if (!readhdr(obj, fp))
+		goto error;
+	if (!readaout(obj, fp))
+		goto error;
+	if (!readscns(obj, fp))
+		goto error;
+	if (!readents(obj, fp))
+		goto error;
+	if (!readstr(obj, fp))
+		goto error;
+	if (!readreloc(obj, fp))
+		goto error;
+	if (!readlines(obj, fp))
+		goto error;
+	if (!loadsyms(obj))
+		goto error;
+	if (!loadsections(obj, fp))
+		goto error;
+	return 0;
+
+error:
+	objreset(obj);
+	return -1;
+}
--- /dev/null
+++ b/src/libmach/coff32/coff32strip.c
@@ -1,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/mach.h>
+
+#include "../libmach.h"
+#include "coff32.h"
+
+void
+coff32strip(Obj *obj)
+{
+	struct coff32 *coff = obj->data;
+	FILHDR *hdr;
+
+	hdr = &coff->hdr;
+	free(coff->ents);
+	coff->ents = NULL;
+	hdr->f_nsyms = 0;
+	hdr->f_symptr = 0;
+}
--- /dev/null
+++ b/src/libmach/coff32/coff32write.c
@@ -1,0 +1,172 @@
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/mach.h>
+
+#include "../libmach.h"
+#include "coff32.h"
+
+static void
+pack_hdr(int order, unsigned char *buf, FILHDR *hdr)
+{
+	int n;
+
+	n = pack(order,
+	         buf,
+	         "sslllss",
+	         hdr->f_magic,
+	         hdr->f_nscns,
+	         hdr->f_timdat,
+	         hdr->f_symptr,
+	         hdr->f_nsyms,
+	         hdr->f_opthdr,
+	         hdr->f_flags);
+	assert(n == FILHSZ);
+}
+
+static void
+pack_scn(int order, unsigned char *buf, SCNHDR *scn)
+{
+	int n;
+
+	n = pack(order,
+	         buf,
+	         "'8llllllssl",
+	         scn->s_name,
+	         scn->s_paddr,
+	         scn->s_vaddr,
+	         scn->s_size,
+	         scn->s_scnptr,
+	         scn->s_relptr,
+	         scn->s_lnnoptr,
+	         scn->s_nrelloc,
+	         scn->s_nlnno,
+	         scn->s_flags);
+	assert(n == SCNHSZ);
+}
+
+static void
+pack_ent(int order, unsigned char *buf, SYMENT *ent)
+{
+	int n;
+	char *s;
+
+	/* TODO: What happens with the union? */
+
+	n = pack(order,
+	         buf,
+	         "'8lsscc",
+	         ent->n_name,
+	         &ent->n_value,
+	         &ent->n_scnum,
+	         &ent->n_type,
+	         &ent->n_sclass,
+	         &ent->n_numaux);
+	assert(n == SYMESZ);
+}
+
+static void
+pack_aout(int order, unsigned char *buf, AOUTHDR *aout)
+{
+	int n;
+
+	n = unpack(order,
+	           buf,
+	           "ssllllll",
+	           aout->magic,
+	           aout->vstamp,
+	           aout->tsize,
+	           aout->dsize,
+	           aout->bsize,
+	           aout->entry,
+	           aout->text_start,
+	           aout->data_start);
+	assert(n == AOUTSZ);
+}
+
+static void
+pack_reloc(int order, unsigned char *buf, RELOC *rel)
+{
+	int n;
+
+	n = pack(order,
+	         buf,
+	         "lls",
+	         rel->r_vaddr,
+	         rel->r_symndx,
+	         rel->r_type);
+	assert(n == RELSZ);
+}
+
+static void
+pack_line(int order, unsigned char *buf, LINENO *lp)
+{
+	int n;
+
+	n = pack(order,
+	         buf,
+	         "lls",
+	         lp->l_symndx,
+	         lp->l_paddr,
+	         lp->l_lnno);
+	assert(n == LINESZ);
+}
+
+static int
+writehdr(Obj *obj, FILE *fp)
+{
+	FILHDR *hdr;
+	struct coff32 *coff;
+	unsigned char buf[FILHSZ];
+
+	coff  = obj->data;
+	hdr = &coff->hdr;
+
+	pack_hdr(ORDER(obj->type), buf, hdr);
+	if (fwrite(buf, FILHSZ, 1, fp) != 1)
+		return 0;
+
+	return 1;
+}
+
+static int
+writescns(Obj *obj, FILE *fp)
+{
+	/* TODO */
+}
+
+static int
+writeents(Obj *obj, FILE *fp)
+{
+	/* TODO */
+}
+
+static int
+writestr(Obj *obj, FILE *fp)
+{
+	/* TODO */
+}
+
+int
+coff32write(Obj *obj, FILE *fp)
+{
+	struct coff32 *coff;
+
+	coff  = obj->data;
+	coff->strsiz = 0;
+	free(coff->strtbl);
+
+	if (!writehdr(obj, fp))
+		return -1;
+	if (!writescns(obj, fp))
+		return -1;
+	if (!writeents(obj, fp))
+		return -1;
+	if (!writestr(obj, fp))
+		return -1;
+
+	return 0;
+}
--- /dev/null
+++ b/src/libmach/formats.lst
@@ -1,0 +1,1 @@
+coff32
--- a/src/libmach/libmach.h
+++ b/src/libmach/libmach.h
@@ -5,10 +5,7 @@
 #define ORDER(t) (((t) >> 10) & 0x1f)
 
 enum objformat {
-	COFF16,
 	COFF32,
-	ELF32,
-	ELF64,
 	NFORMATS,
 };
 
@@ -26,23 +23,34 @@
 	BIG_ENDIAN,
 };
 
-struct format {
-	int (*probe)(unsigned char *buf, char **name);
-	void (*strip)(Obj *obj);
-	int (*new)(Obj *obj);
-	int (*read)(Obj *obj, FILE *fp);
-	int (*write)(Obj *obj, FILE *fp);
-	void (*del)(Obj *obj);
-	long (*index)(int type, long nsyms, Symdef *def, FILE *fp);
+enum freeflags {
+	FREESYM,
+	FREESECT,
 };
 
+typedef long (*indexfun_t)(int, long, Symdef *, FILE *);
+typedef int (*newfun_t)(Obj *obj);
+typedef int (*readfun_t)(Obj *obj, FILE *fp);
+typedef void (*delfun_t)(Obj *new);
+typedef void (*stripfun_t)(Obj *obj);
+typedef int (*probefun_t)(unsigned char *buf, char **name);
+typedef int (*writefun_t)(Obj *obj, FILE *fp);
+
+/* common functions */
 extern int pack(int order, unsigned char *dst, char *fmt, ...);
 extern int unpack(int order, unsigned char *src, char *fmt, ...);
 extern int objpos(Obj *obj, FILE *fp, long pos);
+extern void objfree(Obj *obj, int what);
 
 /* idx functions */
 extern long coff32idx(int order, long nsyms, Symdef *def, FILE *fp);
 
 
-/* globals */
-extern struct format *objfmt[];
+/* coff32 functions */
+extern long coff32index(int type, long nsyms, Symdef *head, FILE *fp);
+extern int coff32new(Obj *obj);
+extern void coff32del(Obj *obj);
+extern int coff32read(Obj *obj, FILE *fp);
+extern int coff32write(Obj *obj, FILE *fp);
+extern void coff32strip(Obj *obj);
+extern int coff32probe(unsigned char *buf, char **name);
--- /dev/null
+++ b/src/libmach/mklst
@@ -1,0 +1,9 @@
+#!/bin/sh
+
+set -e
+
+rm -f $1
+trap 'r=$?;rm -f $$.tmp;exit $r' HUP EXIT QUIT TERM
+
+(echo OBJS=\\
+ find . -name '*.o' | sed 's/$/\\/') > $$.tmp && mv $$.tmp $1
--- /dev/null
+++ b/src/libmach/mktbl
@@ -1,0 +1,35 @@
+#!/bin/sh
+
+for i
+do
+	case "$1" in
+	-t)
+		target=$2
+		shift 2
+		;;
+	-o)
+		out=$2
+		shift 2
+		;;
+	-*)
+		echo mktbl [-t target][-o file] >&2
+		exit 1
+		;;
+	*)
+		break
+		;;
+	esac
+done
+
+cat < formats.lst > $out <<EOF
+#include <stdio.h>
+#include <scc/mach.h>
+#include "libmach.h"
+
+${target}fun_t ${target}v[] = {
+`while read i
+ do
+	printf "\t%s," ${i}${target}
+ done`
+};
+EOF
--- /dev/null
+++ b/src/libmach/objdel.c
@@ -1,0 +1,14 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+int
+objdel(Obj *obj)
+{
+	if (objreset(obj) < 0)
+		return -1;
+	free(obj);
+}
--- a/src/libmach/object.c
+++ /dev/null
@@ -1,276 +1,0 @@
-static char sccsid[] = "@(#) ./libmach/object.c";
-
-#include <limits.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <scc/mach.h>
-
-#include "libmach.h"
-
-int
-objtype(FILE *fp, char **name)
-{
-	int n, i;
-	int (*fn)(unsigned char *, char **);
-	struct format **bp, *op;
-	fpos_t pos;
-	unsigned char buf[NBYTES];
-
-	fgetpos(fp, &pos);
-	n = fread(buf, NBYTES, 1, fp);
-	fsetpos(fp, &pos);
-
-	if (n != 1 || ferror(fp))
-		return -1;
-
-	for (bp = objfmt; bp < &objfmt[NFORMATS]; ++bp) {
-		op = *bp;
-		if (!op || !op->probe)
-			continue;
-		n = (*op->probe)(buf, name);
-		if (n == -1)
-			continue;
-		return n;
-	}
-
-	return -1;
-}
-
-int
-objpos(Obj *obj, FILE *fp, long pos)
-{
-	if (fsetpos(fp, &obj->pos))
-		return 0;
-	if (fseek(fp, pos, SEEK_CUR) < 0)
-		return 0;
-	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
-objwrite(Obj *obj, FILE *fp)
-{
-	int fmt;
-	struct format *op;
-
-	fmt = FORMAT(obj->type);
-	if (fmt >= NFORMATS)
-		return -1;
-	op = objfmt[fmt];
-	if ((*op->write)(obj, fp) < 0)
-		return -1;
-	return 0;
-}
-
-int
-objread(Obj *obj, FILE *fp)
-{
-	int fmt;
-	struct format *op;
-
-	fmt = FORMAT(obj->type);
-	if (fmt >= NFORMATS)
-		return -1;
-	op = objfmt[fmt];
-	if ((*op->read)(obj, fp) < 0)
-		return -1;
-	return 0;
-}
-
-Obj *
-objnew(int type)
-{
-	Obj *obj;
-	int fmt;
-	struct format *op;
-
-	fmt = FORMAT(type);
-	if (fmt >= NFORMATS)
-		return NULL;
-
-	if ((obj = malloc(sizeof(*obj))) == NULL)
-		return NULL;
-
-	obj->type = type;
-	obj->head = NULL;
-	obj->sections = NULL;
-	memset(obj->htab, 0, sizeof(obj->htab));
-
-	op = objfmt[fmt];
-	if ((*op->new)(obj) < 0) {
-		free(obj);
-		return NULL;
-	}
-
-	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;
-}
-
-static void
-delsyms(Obj *obj)
-{
-	Symbol *sym, *next;
-
-	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));
-}
-
-static void
-delsecs(Obj *obj)
-{
-	int i;
-
-	for (i = 0; i < obj->nsecs; i++)
-		free(obj->sections[i].name);
-	free(obj->sections);
-	obj->sections = NULL;
-}
-
-int
-objreset(Obj *obj)
-{
-	int fmt;
-	struct format *op;
-
-	fmt = FORMAT(obj->type);
-	if (fmt < NFORMATS)
-		return -1;
-	op = objfmt[fmt];
-	(*op->del)(obj);
-	delsyms(obj);
-	delsecs(obj);
-	return 0;
-}
-
-int
-objdel(Obj *obj)
-{
-	if (objreset(obj) < 0)
-		return -1;
-	free(obj);
-}
-
-int
-objstrip(Obj *obj)
-{
-	int fmt;
-	struct format *op;
-
-	fmt = FORMAT(obj->type);
-	if (fmt >= NFORMATS)
-		return -1;
-	op = objfmt[fmt];
-	(*op->strip)(obj);
-	delsyms(obj);
-	return 0;
-}
-
-int
-objsize(Obj *obj,
-        unsigned long long *text,
-        unsigned long long *data,
-        unsigned long long *bss)
-{
-	Section *sp, *secs = obj->sections;
-	unsigned long long *p;
-
-	*text = 0;
-	*data = 0;
-	*bss = 0;
-	for (sp =secs; sp < &secs[obj->nsecs]; sp++) {
-		switch (sp->type) {
-		case 'T':
-			p = text;
-			break;
-		case 'D':
-			p = data;
-			break;
-		case 'B':
-			p = bss;
-			break;
-		default:
-			continue;
-		}
-
-		if (*p > ULLONG_MAX - sp->size)
-			return -1;
-		*p += sp->size;
-	}
-	return 0;
-}
-
-long
-arindex(int type, long nsyms, Symdef *head, FILE *fp)
-{
-	int fmt;
-	struct format *op;
-
-	fmt = FORMAT(type);
-	if (fmt >= NFORMATS)
-		return -1;
-	op = objfmt[fmt];
-	return (*op->index)(type, nsyms, head, fp);
-}
-
-int
-addr2line(Obj *obj, unsigned long long addr, char *fname, int *line)
-{
-	/* TODO */
-	return -1;
-}
--- a/src/libmach/objfmt.c
+++ /dev/null
@@ -1,11 +1,0 @@
-#include <stdio.h>
-
-#include <scc/mach.h>
-#include "libmach.h"
-
-extern struct format objcoff32;
-
-struct format *objfmt[] = {
-	[COFF32] = &objcoff32,
-	[NFORMATS] = NULL,
-};
--- /dev/null
+++ b/src/libmach/objfree.c
@@ -1,0 +1,42 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+static void
+delsyms(Obj *obj)
+{
+	Symbol *sym, *next;
+
+	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));
+}
+
+static void
+delsecs(Obj *obj)
+{
+	int i;
+
+	for (i = 0; i < obj->nsecs; i++)
+		free(obj->sections[i].name);
+	free(obj->sections);
+	obj->sections = NULL;
+}
+
+void
+objfree(Obj *obj, int what)
+{
+	if (what & FREESYM)
+		delsyms(obj);
+	if (what & FREESECT)
+		delsecs(obj);
+}
--- /dev/null
+++ b/src/libmach/objlookup.c
@@ -1,0 +1,42 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/mach.h>
+
+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;
+}
--- /dev/null
+++ b/src/libmach/objnew.c
@@ -1,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+extern newfun_t newv[];
+
+Obj *
+objnew(int type)
+{
+	Obj *obj;
+	int fmt;
+	newfun_t fn;
+
+	fmt = FORMAT(type);
+	if (fmt >= NFORMATS)
+		return NULL;
+
+	if ((obj = malloc(sizeof(*obj))) == NULL)
+		return NULL;
+
+	obj->type = type;
+	obj->head = NULL;
+	obj->sections = NULL;
+	memset(obj->htab, 0, sizeof(obj->htab));
+
+	fn = newv[fmt];
+	if ((*fn)(obj) < 0) {
+		free(obj);
+		return NULL;
+	}
+
+	return obj;
+}
--- /dev/null
+++ b/src/libmach/objpos.c
@@ -1,0 +1,15 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+int
+objpos(Obj *obj, FILE *fp, long pos)
+{
+	if (fsetpos(fp, &obj->pos))
+		return 0;
+	if (fseek(fp, pos, SEEK_CUR) < 0)
+		return 0;
+	return 1;
+}
--- /dev/null
+++ b/src/libmach/objread.c
@@ -1,0 +1,23 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+extern readfun_t readv[];
+
+int
+objread(Obj *obj, FILE *fp)
+{
+	int fmt;
+	readfun_t fn;
+
+	fmt = FORMAT(obj->type);
+	if (fmt >= NFORMATS)
+		return -1;
+
+	fn = readv[fmt];
+	if ((*fn)(obj, fp) < 0)
+		return -1;
+	return 0;
+}
--- /dev/null
+++ b/src/libmach/objreset.c
@@ -1,0 +1,22 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+extern delfun_t delv[];
+
+int
+objreset(Obj *obj)
+{
+	int fmt;
+	delfun_t fn;
+
+	fmt = FORMAT(obj->type);
+	if (fmt < NFORMATS)
+		return -1;
+	fn = delv[fmt];
+	(*fn)(obj);
+	objfree(obj, FREESYM | FREESECT);
+	return 0;
+}
--- /dev/null
+++ b/src/libmach/objsize.c
@@ -1,0 +1,40 @@
+#include <limits.h>
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+int
+objsize(Obj *obj,
+        unsigned long long *text,
+        unsigned long long *data,
+        unsigned long long *bss)
+{
+	Section *sp, *secs = obj->sections;
+	unsigned long long *p;
+
+	*text = 0;
+	*data = 0;
+	*bss = 0;
+	for (sp =secs; sp < &secs[obj->nsecs]; sp++) {
+		switch (sp->type) {
+		case 'T':
+			p = text;
+			break;
+		case 'D':
+			p = data;
+			break;
+		case 'B':
+			p = bss;
+			break;
+		default:
+			continue;
+		}
+
+		if (*p > ULLONG_MAX - sp->size)
+			return -1;
+		*p += sp->size;
+	}
+	return 0;
+}
--- /dev/null
+++ b/src/libmach/objstrip.c
@@ -1,0 +1,38 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+extern stripfun_t stripv[];
+
+/* TODO: It is better to move this to a common place */
+static void
+delsyms(Obj *obj)
+{
+	Symbol *sym, *next;
+
+	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));
+}
+
+int
+objstrip(Obj *obj)
+{
+	int fmt;
+	stripfun_t fn;
+
+	fmt = FORMAT(obj->type);
+	if (fmt >= NFORMATS)
+		return -1;
+	fn = stripv[fmt];
+	(*fn)(obj);
+	delsyms(obj);
+	return 0;
+}
--- /dev/null
+++ b/src/libmach/objtraverse.c
@@ -1,0 +1,17 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+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;
+}
--- /dev/null
+++ b/src/libmach/objtype.c
@@ -1,0 +1,32 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+extern probefun_t probev[];
+
+int
+objtype(FILE *fp, char **name)
+{
+	int n, i;
+	probefun_t *fn;
+	fpos_t pos;
+	unsigned char buf[NBYTES];
+
+	fgetpos(fp, &pos);
+	n = fread(buf, NBYTES, 1, fp);
+	fsetpos(fp, &pos);
+
+	if (n != 1 || ferror(fp))
+		return -1;
+
+	for (fn = probev; fn < &probev[NFORMATS]; ++fn) {
+		n = (*fn)(buf, name);
+		if (n == -1)
+			continue;
+		return n;
+	}
+
+	return -1;
+}
--- /dev/null
+++ b/src/libmach/objwrite.c
@@ -1,0 +1,22 @@
+#include <stdio.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+extern writefun_t writev[];
+
+int
+objwrite(Obj *obj, FILE *fp)
+{
+	int fmt;
+	writefun_t fn;
+
+	fmt = FORMAT(obj->type);
+	if (fmt >= NFORMATS)
+		return -1;
+	fn = writev[fmt];
+	if ((*fn)(obj, fp) < 0)
+		return -1;
+	return 0;
+}