shithub: scc

Download patch

ref: 92f9a64740292aba5d19f9562ab63d3f7645e491
parent: c85bc69f741a003f6ebccdae4168a8527c775823
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Tue May 29 09:27:43 EDT 2018

[ld/coff32] Improve the linker

This is a WIP

--- a/ld/Makefile
+++ b/ld/Makefile
@@ -26,6 +26,7 @@
 coff32.o: ./../inc/coff32/syms.h
 coff32.o: ./../inc/scc.h
 coff32.o: ./ld.h
+formats.o: ./../inc/scc.h
 formats.o: ./ld.h
 main.o: ./../inc/ar.h
 main.o: ./../inc/scc.h
--- a/ld/coff32.c
+++ b/ld/coff32.c
@@ -1,7 +1,9 @@
 static char sccsid[] = "@(#) ./ld/coff32.c";
 
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -14,6 +16,7 @@
 #include "ld.h"
 
 static int (*unpack)(unsigned char *, char *, ...);
+static int align;
 
 static FILHDR *
 getfhdr(unsigned char *buff, FILHDR *hdr)
@@ -48,6 +51,13 @@
 
 	(*unpack)(buff, "l", &siz);
 
+	siz -= 4;
+	if (siz == 0) {
+		obj->strtbl = NULL;
+		obj->strsiz = 0;
+		return 0;
+	}
+
 	if (siz > SIZE_MAX || (str = malloc(siz)) == NULL)
 		outmem();
 
@@ -55,6 +65,8 @@
 		return -1;
 
 	obj->strtbl = str;
+	obj->strsiz = siz;
+
 	return 0;
 }
 
@@ -84,8 +96,9 @@
 {
 	unsigned nsec, i;
 	unsigned char buff[SCNHSZ];
-	SCNHDR *scn;
+	SCNHDR *scn, *p;
 	FILHDR *hdr;
+	Symbol *sym;
 
 	hdr = obj->filhdr;
 	nsec = hdr->f_nscns;
@@ -98,10 +111,20 @@
 	if (fseek(obj->fp, off, SEEK_SET) == EOF)
 		return -1;
 
-	for (i = 0; i < nsec; i++) {
+	for (p = scn; p < &scn[nsec]; ++p) {
 		if (fread(buff, SCNHSZ, 1, obj->fp) != 1)
 			return -1;
-		getscn(buff, &scn[i]);
+		getscn(buff, p);
+		sym = lookup(p->s_name);
+
+		sym->size = (sym->size + align-1) & align-1;
+		if (sym->size > ULLONG_MAX - p->s_size) {
+			fprintf(stderr,
+			        "ld: %s: overflow in section '%s'\n",
+			        obj->fname, p->s_name);
+			exit(EXIT_FAILURE);
+		}
+		sym->size += p->s_size;
 	}
 	obj->scnhdr = scn;
 
@@ -130,31 +153,156 @@
 		(*unpack)(buff, "ll", &ent->n_zeroes, &ent->n_offset);
 }
 
+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 char
+typeof(Obj *obj, SYMENT *ent)
+{
+	SCNHDR *sec;
+	FILHDR *hdr;
+	int c, n;
+	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:
+		sec = obj->scnhdr;
+		hdr = obj->filhdr;
+		n = ent->n_scnum;
+		if (n > hdr->f_nscns)
+			return '?';
+		sec = &sec[n-1];
+		flags = sec->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 TUINT
+getval(Obj *obj, SYMENT *ent)
+{
+	FILHDR *hdr = obj->filhdr;;
+	SCNHDR *scn = obj->scnhdr;
+
+	if (ent->n_scnum > hdr->f_nscns) {
+		fprintf(stderr,
+		        "ld: %s: incorrect section number\n",
+		        obj->fname,
+		        ent->n_scnum);
+		exit(EXIT_FAILURE);
+	}
+
+	scn = &scn[ent->n_scnum-1];
+
+	/*
+	 * TODO: We have to add the composed size of the segment minus
+	 * the size of the fragment
+	 */
+	return ent->n_value - scn->s_size;
+}
+
 static int
 readsyms(Obj *obj, long off)
 {
-	unsigned i, nsym;
-	unsigned char buff[SYMESZ];
-	SYMENT *ent;
-	FILHDR *hdr;
+	int type;
+	unsigned i;
+	FILHDR *hdr = obj->filhdr;;
 
-	hdr = obj->filhdr;
-	nsym = hdr->f_nsyms;
-	if (nsym > SIZE_MAX / sizeof(*ent))
+	if (fseek(obj->fp, off, SEEK_SET) == EOF)
 		return -1;
 
-	if ((ent = malloc(nsym * sizeof(*ent))) == NULL)
+	if (hdr->f_nsyms > SIZE_MAX / sizeof(Symbol *)) {
+		fprintf(stderr,
+		        "ld: %s: overflow in size of symbol redirection\n",
+		        obj->fname);
+		exit(EXIT_FAILURE);
+	}
+	obj->symbols = malloc(sizeof(Symbol *) * sizeof(Symbol *));
+	if (!obj->symbols)
 		outmem();
 
-	if (fseek(obj->fp, off, SEEK_SET) == EOF)
-		return -1;
+	hdr = obj->filhdr;
+	for (i = 0; i < hdr->f_nsyms; i++) {
+		Symbol *sym;
+		TUINT value;
+		SYMENT ent;
+		unsigned char buff[SYMESZ];
+		char *name;
 
-	for (i = 0; i < nsym; i++) {
 		if (fread(buff, SYMESZ, 1, obj->fp) != 1)
 			return -1;
-		getsym(buff, &ent[i]);
+		getsym(buff, &ent);
+		name = symname(obj, &ent);
+		type = typeof(obj, &ent);
+		sym = lookup(name);
+
+		switch (sym->type) {
+		case 'U':
+			sym->type = type;
+			sym->value = ent.n_value;
+			if (type == 'C')
+				sym->size = ent.n_value;
+			break;
+		case 'C':
+			switch (type) {
+			case 'U':
+			case 'C':
+				if (ent.n_value > sym->size)
+					sym->size = ent.n_value;
+				break;
+			default:
+				sym->type = type;
+				sym->value = ent.n_value;
+				break;
+			}
+			break;
+		default:
+			if (type != 'U') {
+				fprintf(stderr,
+				        "ld: %s: redifinition of symbol '%s'\n",
+				        obj->fname, sym->name);
+			}
+			break;
+		}
+
+		obj->symbols[i] = sym;
 	}
-	obj->enthdr = ent;
 
 	return 0;
 }
@@ -183,10 +331,10 @@
 
 	if (readstr(obj, stroff) < 0)
 		goto bad_file;
-	if (readsyms(obj, symoff) < 0)
-		goto bad_file;
 	if (readsects(obj, secoff) < 0)
 		goto bad_file;
+	if (readsyms(obj, symoff) < 0)
+		goto bad_file;
 	return;
 
 bad_file:
@@ -199,10 +347,17 @@
 pass1(char *fname, char *member, FILE *fp)
 {
 	Obj *obj;
+	SYMENT *ent;
+	FILHDR *hdr;
+	unsigned n, nsyms;
+	int islib = member != NULL;
 
 	obj = newobj(fname, member);
 	obj->fp = fp;
 	readobj(obj);
+
+	hdr = obj->filhdr;
+	nsyms = hdr->f_nsyms;
 }
 
 static void
@@ -232,6 +387,8 @@
 
 	switch (magic) {
 	case COFF_Z80MAGIC:
+		unpack = lunpack;
+		align = 2;
 		return 1;
 	default:
 		return 0;
--- a/ld/formats.c
+++ b/ld/formats.c
@@ -2,6 +2,7 @@
 
 #include <stdio.h>
 
+#include "../inc/scc.h"
 #include "ld.h"
 
 /* TODO: Autogenerate this file */
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -8,13 +8,19 @@
 	FILE *fp;
 	void *filhdr;
 	void *scnhdr;
-	void *enthdr;
+	Symbol **symbols;
 	char *strtbl;
+	size_t strsiz;
 	struct obj *next;
 };
 
 struct symbol {
 	char *name;
+	char type;
+	short flags;
+	long size;
+	TUINT base;
+	TUINT value;
 	struct symbol *hash;
 };
 
@@ -30,3 +36,14 @@
 
 /* main.c */
 extern void outmem(void);
+
+/*
+ * Definition of globals variables
+ */
+extern int pass;
+extern int sflag;
+extern int xflag;
+extern int Xflag;
+extern int rflag;
+extern int dflag;
+extern int gflag;
--- a/ld/main.c
+++ b/ld/main.c
@@ -19,6 +19,7 @@
 int Xflag;		/* discard locals starting with 'L' */
 int rflag;		/* preserve relocation bits */
 int dflag;		/* define common even with rflag */
+int gflag;              /* preserve debug symbols */
 
 void
 outmem(void)
--- a/ld/obj.c
+++ b/ld/obj.c
@@ -46,18 +46,25 @@
 	return obj;
 }
 
+static unsigned
+hash(char *s)
+{
+	unsigned h, c;
+
+	for (h = 0; c = *s; ++s)
+		h = h*33 ^ c;
+	return h & NR_SYM_HASH-1;
+}
+
 Symbol *
 lookup(char *name)
 {
-	unsigned h, c;
+	unsigned h;
 	char *s;
 	size_t len;
 	Symbol *sym;
 
-	for (h = 0; c = *name; ++s)
-		h = h*33 ^ c;
-	h &= NR_SYM_HASH-1;
-
+	h = hash(name);
 	for (sym = symtbl[h]; sym; sym = sym->hash) {
 		s = sym->name;
 		if (*name == *s && !strcmp(name, s))
@@ -69,11 +76,13 @@
 	s = malloc(len);
 	if (!sym || !s)
 		outmem();
+	memset(sym, 0, sizeof(*sym));
+	memcpy(s, name, len);
+
 	sym->hash = symtbl[h];
 	symtbl[h] = sym;
 	sym->name = s;
-	memset(sym, 0, sizeof(*sym));
-	memcpy(sym->name, name, len);
+	sym->type = 'U';
 
 	return sym;
 }