shithub: scc

Download patch

ref: 43bc7a79ff2c3392462b87e4abd03e27e0d55f57
parent: 2ea762ec4b8f9122b81773feb127f391f631ddcb
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Fri Jul 6 02:44:05 EDT 2018

[ld] Rewrite it again

--- a/ld/coff32.c
+++ b/ld/coff32.c
@@ -9,6 +9,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "../inc/coff32/aouthdr.h"
 #include "../inc/coff32/filehdr.h"
 #include "../inc/coff32/scnhdr.h"
 #include "../inc/coff32/syms.h"
@@ -15,24 +16,128 @@
 #include "../inc/scc.h"
 #include "ld.h"
 
-static FILHDR *
-getfhdr(Obj *obj, unsigned char *buff, FILHDR *hdr)
+#define NUMSCN_MAX 65536
+#define NUMENT_MAX 2147483648
+
+typedef int (*packfun)(unsigned char *, char *, ...);
+static long textpc = 0x1000;
+
+static void
+pack_hdr(packfun fun, unsigned char *buff, FILHDR *hdr)
 {
 	int n;
 
-	n = (*obj->unpack)(buff,
-	                   "sslllss",
-	                   &hdr->f_magic,
-	                   &hdr->f_nscns,
-	                   &hdr->f_timdat,
-	                   &hdr->f_symptr,
-	                   &hdr->f_nsyms,
-	                   &hdr->f_opthdr,
-	                   &hdr->f_flags);
+	n = (*fun)(buff,
+	           "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);
-	return hdr;
 }
 
+static void
+unpack_hdr(packfun fun, unsigned char *buff, FILHDR *hdr)
+{
+	int n;
+
+	n = (*fun)(buff,
+	           "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(packfun fun, unsigned char *buff, SCNHDR *scn)
+{
+	int n;
+
+	n = (*fun)(buff,
+                  "'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(packfun fun, unsigned char *buff, SCNHDR *scn)
+{
+	int n;
+
+	n = (*fun)(buff,
+                  "'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_aout(packfun fun, unsigned char *buff, AOUTHDR *aout)
+{
+}
+
+static void
+unpack_ent(packfun fun, unsigned char *buff, SYMENT *ent)
+{
+	int n;
+
+	n = (*fun)(buff,
+		   "'8lsscc",
+		   &ent->n_name,
+		   &ent->n_value,
+		   &ent->n_scnum,
+		   &ent->n_type,
+		   &ent->n_sclass,
+		   &ent->n_numaux);
+	assert(n == SYMESZ);
+}
+
+/*
+ * check overflow in: off + ptr + nitem*size
+ */
+static char *
+symname(Obj *obj, SYMENT *ent)
+{
+	long off;
+
+	if (ent->n_zeroes != 0)
+		return ent->n_name;
+
+	off = ent->n_offset;
+	if (off >= obj->strsiz) {
+		fprintf(stderr,
+		        "ld: invalid offset in symbol table: %zd\n", off);
+		return "";
+	}
+
+	return &obj->strtbl[off];
+}
+
 static int
 readstr(Obj *obj, long off)
 {
@@ -67,50 +172,25 @@
 	return 0;
 }
 
-static SCNHDR *
-getscn(Obj *obj, unsigned char *buff, SCNHDR *scn)
-{
-	int n;
-
-	n = (*obj->unpack)(buff,
-	                   "'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);
-	return scn;
-}
-
 static int
 readsects(Obj *obj, long off)
 {
 	unsigned a, nsec, i;
 	unsigned char buff[SCNHSZ];
-	SCNHDR *scn, *p;
+	SCNHDR *scns, *p;
 	FILHDR *hdr;
-	Symbol *sym, **sec;
+	Symbol *sym;
+	Section *sp;
 
 	hdr = obj->filhdr;
 	nsec = hdr->f_nscns;
 
-	scn = NULL;
-	sec = NULL;
-	if (nsec <= SIZE_MAX / sizeof(*scn))
-		scn = malloc(nsec * sizeof(*scn));
-
-	if (nsec <= SIZE_MAX / sizeof(Symbol *))
-		sec = malloc(nsec * sizeof(Symbol *));
-
-	if (!scn || !sec)
+	scns = NULL;
+	if (nsec <= SIZE_MAX / sizeof(*scns))
+		scns = malloc(nsec * sizeof(*scns));
+	if (!scns)
 		outmem();
-	obj->scnhdr = scn;
+	obj->scnhdr = scns;
 
 	if (fseek(obj->fp, off, SEEK_SET) == EOF)
 		return -1;
@@ -117,44 +197,30 @@
 
 	a = obj->align - 1;
 	for (i = 0; i < nsec; ++i) {
-		p = &scn[i];
+		p = &scns[i];
 		if (fread(buff, SCNHSZ, 1, obj->fp) != 1)
 			return -1;
-		getscn(obj, buff, p);
+		unpack_scn(obj->unpack, buff, p);
+		sp = slookup(p->s_name);
+		p->s_vaddr = sp->base + sp->size;
+		sp->size += p->s_size;
 	}
 
 	return 0;
 }
 
-static void
-getent(Obj *obj, unsigned char *buff, SYMENT *ent)
-{
-	int n;
-	long off, zero;
-	char *name;
-
-	n = (*obj->unpack)(buff,
-		           "'8lsscc",
-		           &ent->n_name,
-		           &ent->n_value,
-		           &ent->n_scnum,
-		           &ent->n_type,
-		           &ent->n_sclass,
-		           &ent->n_numaux);
-	assert(n == SYMESZ);
-
-	name = ent->n_name;
-	if (!name[0] && !name[1] && !name[2] && !name[3])
-		(*obj->unpack)(buff, "ll", &ent->n_zeroes, &ent->n_offset);
-}
-
 static int
 readents(Obj *obj, long off)
 {
 	SYMENT *ent, *ents;
+	SCNHDR *scn, *scns = obj->scnhdr;
 	FILHDR *hdr = obj->filhdr;;
 	long nsyms = hdr->f_nsyms;
+	unsigned nsect;
 	unsigned char buff[SYMESZ];
+	char *s;
+	int aux;
+	Symbol *sym;
 
 
 	if (fseek(obj->fp, off, SEEK_SET) == EOF)
@@ -167,18 +233,55 @@
 		outmem();
 	obj->enthdr = ents;
 
+	aux = 0;
 	for (ent = ents; ent < &ents[nsyms]; ++ent) {
 		if (fread(buff, SYMESZ, 1, obj->fp) != 1)
 			return -1;
-		getent(obj, buff, ent);
+		unpack_ent(obj->unpack, buff, ent);
+		s = ent->n_name;
+		if (!s[0] && !s[1] && !s[2] && !s[3])
+			(*obj->unpack)(buff, "ll", &ent->n_zeroes, &ent->n_offset);
+
+		if (aux > 0) {
+			aux--;
+			continue;
+		}
+		aux = ent->n_numaux;
+
+		scn = NULL;
+		switch (ent->n_scnum) {
+		case N_DEBUG:
+			continue;
+		case N_ABS:
+			break;
+		case N_UNDEF:
+			/* TODO: deal wth common blocks */
+			break;
+		default:
+			nsect = ent->n_scnum-1;
+			if (nsect >= hdr->f_nscns)
+				corrupted(obj->fname, obj->member);
+			scn = &scns[nsect];
+			ent->n_value += scn->s_vaddr;
+		}
+
+		if (ent->n_sclass == C_EXT && ent->n_scnum != N_UNDEF) {
+			Symbol *sym = lookup(symname(obj, ent), INSTALL);
+
+			if (sym->flags & SDEFINED) {
+				redefined(obj, sym);
+			} else {
+				sym->flags |= SDEFINED;
+				sym->where = obj;
+				if (scn)
+					sym->section = slookup(scn->s_name);
+			}
+		}
 	}
 
 	return 0;
 }
 
-/*
- * check overflow in: off + ptr + nitem*size
- */
 static long
 fileptr(long off, long ptr, long nitem, long size)
 {
@@ -202,8 +305,8 @@
 	return off;
 }
 
-static void
-readobj(Obj *obj)
+Obj *
+load(Obj *obj)
 {
 	unsigned char buff[FILHSZ];
 	FILHDR *hdr;
@@ -216,7 +319,7 @@
 
 	if ((hdr = malloc(sizeof(*hdr))) == NULL)
 		outmem();
-	getfhdr(obj, buff, hdr);
+	unpack_hdr(obj->unpack, buff, hdr);
 	obj->filhdr = hdr;
 
 	stroff = fileptr(pos, hdr->f_symptr, hdr->f_nsyms, SYMESZ);
@@ -232,7 +335,7 @@
 		goto bad_file;
 	if (readents(obj, symoff) < 0)
 		goto bad_file;
-	return;
+	return add(obj);
 
 bad_file:
 	fprintf(stderr,
@@ -242,86 +345,7 @@
 	exit(EXIT_FAILURE);
 }
 
-static char *
-symname(Obj *obj, SYMENT *ent)
-{
-	long off;
-
-	if (ent->n_zeroes != 0)
-		return ent->n_name;
-
-	off = ent->n_offset;
-	if (off >= obj->strsiz) {
-		fprintf(stderr,
-		        "ld: invalid offset in symbol table: %zd\n", off);
-		return "";
-	}
-
-	return &obj->strtbl[off];
-}
-
 Obj *
-load(Obj *obj)
-{
-	FILHDR *hdr = obj->filhdr;
-	SCNHDR *scn, *scns = obj->scnhdr;;
-	SYMENT *ent, *ents = obj->enthdr;
-	int nsect, aux;
-
-	readobj(obj);
-
-	for (scn = scns; scn < &scns[hdr->f_nscns]; ++scn) {
-		/* TODO: padding */
-		Section *sect = slookup(scn->s_name);
-		scn->s_vaddr = sect->base + sect->size;
-		sect->size += scn->s_size;
-	}
-
-	aux = 0;
-	for (ent = ents; ent < &ents[hdr->f_nsyms]; ++ent) {
-		if (aux > 0) {
-			--aux;
-			continue;
-		}
-		aux = ent->n_numaux;
-
-		scn = NULL;
-		switch (ent->n_scnum) {
-		case N_DEBUG:
-			continue;
-		case N_ABS:
-			break;
-		case N_UNDEF:
-			/* TODO: deal wth common blocks */
-			break;
-		default:
-			nsect = ent->n_scnum-1;
-			if (nsect >= hdr->f_nscns)
-				corrupted(obj->fname, obj->member);
-			scn = &scns[nsect];
-			ent->n_value += scn->s_vaddr;
-		}
-
-		if (ent->n_sclass == C_EXT && ent->n_scnum != N_UNDEF) {
-			Symbol *sym = lookup(symname(obj, ent), INSTALL);
-
-			if (sym->flags & SDEFINED) {
-				redefined(obj, sym);
-			} else {
-				sym->flags |= SDEFINED;
-				sym->where = obj;
-				if (scn)
-					sym->section = slookup(scn->s_name);
-			}
-		}
-	}
-
-	/* TODO: Check if the object in library is needed: delobj(obj) */
-
-	return add(obj);
-}
-
-Obj *
 probe(char *fname, char *member, FILE *fp)
 {
 	int c;
@@ -330,6 +354,7 @@
 	unsigned short magic;
 	unsigned align;
 	int (*unpack)(unsigned char *, char *, ...);
+	int (*pack)(unsigned char *, char *, ...);
 	Obj *obj;
 
 	pos = ftell(fp);
@@ -348,6 +373,7 @@
 	case COFF_I386MAGIC:
 	case COFF_Z80MAGIC:
 		unpack = lunpack;
+		pack = lpack;
 		align = 2;
 		break;
 	default:
@@ -360,4 +386,113 @@
 	obj->offset = pos;
 
 	return obj;
+}
+
+static void
+wrhdr(FILE *fp)
+{
+	FILHDR hdr;
+	Section *sp;
+	unsigned char buff[FILHSZ];
+
+	if (numsects > NUMSCN_MAX || numsymbols > NUMENT_MAX) {
+		fprintf(stderr, "ld: too many symbols or sections\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * we set the timestamp to 0 to make the output
+	 * reproductible and to avoid a not standard use
+	 * of time()
+	 */
+	hdr.f_symptr = 0;
+	hdr.f_magic = COFF_Z80MAGIC;
+	hdr.f_nscns = numsects;
+	hdr.f_symptr = 0;
+	hdr.f_timdat = 0;
+	hdr.f_nsyms = 0;
+	hdr.f_opthdr = AOUTSZ;
+	hdr.f_flags = F_EXEC | F_AR32WR; /* TODO: set the correct endianess */
+
+	if (!sflag) {
+		hdr.f_symptr = 0; /* TODO: set correct value here */
+		hdr.f_flags |= F_SYMS;
+		hdr.f_nsyms = numsymbols;
+	}
+
+	pack_hdr(lpack, buff, &hdr);
+	fwrite(buff, FILHSZ, 1, fp);
+}
+
+static void
+wraout(FILE *fp)
+{
+	AOUTHDR aout;
+	unsigned char buff[AOUTSZ];
+	Symbol *sym;
+	long addr;
+
+	if ((sym = lookup(entry, NOINSTALL)) != NULL) {
+		addr = sym->value;
+	} else {
+		fprintf(stderr,
+		        "ld: warning: cannot find entry symbol '%s'; defaulting to 0\n",
+		        entry);
+		addr = 0;
+	} 
+
+	aout.magic = ZMAGIC;
+	aout.vstamp = 0;
+	aout.entry = addr;
+	aout.tsize = tsize;
+	aout.dsize = dsize;
+	aout.bsize = bsize;
+	aout.text_start = textpc;
+	aout.data_start = textpc + dsize;
+
+	pack_aout(lpack, buff, &aout);
+	fwrite(buff, AOUTSZ, 1, fp);
+}
+
+static void
+wrscn(FILE *fp, Section *sp, long pc)
+{
+	SCNHDR scn;
+	unsigned char buff[SCNHSZ];
+
+	strcpy(scn.s_name, sp->name);
+	scn.s_paddr = pc;
+	scn.s_vaddr = pc;
+	scn.s_size = sp->size;
+	scn.s_scnptr = 0; /* TODO: file ptr */
+	scn.s_relptr = 0;
+	scn.s_lnnoptr = 0;
+	scn.s_nrelloc = 0;
+	scn.s_nlnno = 0;
+	scn.s_flags = 0; /* TODO: Add flags */
+
+	pack_scn(lpack, buff, &scn);
+	fwrite(buff, SCNHSZ, 1, fp);
+}
+
+void
+writeout(FILE *fp)
+{
+	Section *sp;
+	long pc = textpc;
+
+	wrhdr(fp);
+	wraout(fp);
+
+	for (sp = sectlst; sp; sp = sp->next) {
+		wrscn(fp, sp, pc);
+		pc += sp->size;
+	}
+
+	/* TODO: run over all the files */
+
+	if (fflush(fp) != EOF) {
+		perror("ld: error writing output file");
+		exit(EXIT_FAILURE);
+	}
 }
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -62,7 +62,9 @@
 /* object format */
 extern Obj *probe(char *fname, char *member, FILE *fp);
 extern Obj *load(Obj *obj);
+extern void writeout(FILE *fp);
 
+
 /*
  * Definition of globals variables
  */
@@ -74,3 +76,10 @@
 extern int dflag;
 extern int gflag;
 extern Obj *objlst;
+extern Section *sectlst;
+extern long numsects;
+extern long numsymbols;
+extern TUINT tsize, dsize, bsize;
+extern char *output;
+extern char *entry;
+extern char *datasiz;
--- a/ld/main.c
+++ b/ld/main.c
@@ -12,7 +12,7 @@
 #include "../inc/syslibs.h"
 #include "ld.h"
 
-char *output = "a.out", *entry, *datasiz;
+char *output = "a.out", *entry = "start", *datasiz;
 int pass;
 int sflag;		/* discard all the symbols */
 int xflag;		/* discard local symbols */
@@ -21,6 +21,8 @@
 int dflag;		/* define common even with rflag */
 int gflag;              /* preserve debug symbols */
 
+static int done;
+
 void
 redefined(Obj *obj, Symbol *sym)
 {
@@ -48,6 +50,13 @@
 	exit(EXIT_FAILURE);
 }
 
+static void
+cleanup(void)
+{
+	if (!done)
+		remove(output);
+}
+
 static int
 object(char *fname, char *member, FILE *fp)
 {
@@ -162,6 +171,16 @@
 static void
 pass2(int argc, char *argv[])
 {
+	FILE *fp;
+
+	if ((fp = fopen(output, "wb")) != NULL) {
+		writeout(fp);
+		if (fclose(fp) != EOF)
+			return;
+	}
+
+	fprintf(stderr, "ld: %s: %s\n", output, strerror(errno));
+	exit(EXIT_FAILURE);
 }
 
 static void
@@ -258,8 +277,12 @@
 	if (argc == 0)
 		usage();
 
+	atexit(cleanup);
+
 	pass1(argc, argv);
 	pass2(argc, argv);
+
+	done = 1;
 
 	return 0;
 }
--- a/ld/obj.c
+++ b/ld/obj.c
@@ -10,9 +10,12 @@
 
 #define NR_SYM_HASH 64
 
+TUINT tsize, dsize, bsize;
+
 Obj *objlst;
 static Obj *objtail;
 
+long numsects, numsymbols;
 static Symbol *secttail;
 static Symbol *symtbl[NR_SYM_HASH];
 
@@ -100,6 +103,7 @@
 		sectlst = sp;
 	else
 		prev->next = sp;
+	numsects++;
 
 	return sp;
 }
@@ -143,6 +147,7 @@
 	sym->hash = symtbl[h];
 	symtbl[h] = sym;
 	sym->name = s;
+	numsymbols++;
 
 	return sym;
 }