shithub: scc

Download patch

ref: 94f52c8e839f1c5372ea532db9c8b91bd39d127c
parent: 506afb042bf4c22f832f0d38e2af69826c9fd022
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Aug 19 06:20:44 EDT 2019

[ld] Add structures for sections and segments

--- a/src/cmd/ld/ld.h
+++ b/src/cmd/ld/ld.h
@@ -4,6 +4,7 @@
 typedef struct objlst Objlst;
 typedef struct symbol Symbol;
 typedef struct section Section;
+typedef struct segment Segment;
 
 struct section {
 	char *name;
@@ -12,9 +13,19 @@
 	unsigned flags;
 	int type;
 	FILE *fp;
+	Section *hash;
 	Section *next;
 };
 
+struct segment {
+	char *name;
+	int type;
+	unsigned nsec;
+	unsigned long long base;
+	unsigned long size;
+	Section **sections;
+};
+
 struct objlst {
 	struct obj *obj;
 	struct objlst *next;
@@ -42,12 +53,12 @@
 /* symbol.c */
 extern Symbol *lookup(char *name);
 extern Symbol *install(char *name);
-extern int debugsym(void);
+extern Section *section(char *name);
+extern void debugsym(void);
+extern void debugsec(void);
 
 /* globals */
 extern char *filename, *membname;
-extern unsigned long textsiz, datasiz, bsssiz;
-extern unsigned long textbase, database, bssbase;
 extern int sflag;
 extern int xflag;
 extern int Xflag;
@@ -56,3 +67,5 @@
 extern int gflag;
 extern char *Dflag;
 extern Objlst *objhead;
+extern Section *sechead;
+extern Segment text, rodata, data, bss;
--- a/src/cmd/ld/main.c
+++ b/src/cmd/ld/main.c
@@ -11,8 +11,6 @@
 char *output = "a.out", *entry = "start";
 
 char *filename, *membname;
-unsigned long textsiz, datasiz, bsssiz;
-unsigned long textbase, database, bssbase;
 
 int sflag;        /* discard all the symbols */
 int xflag;        /* discard local symbols */
@@ -65,6 +63,7 @@
 	pass2(argc, argv);
 	pass3(argc, argv);
 	debugsym();
+	debugsec();
 }
 
 static void
--- a/src/cmd/ld/pass1.c
+++ b/src/cmd/ld/pass1.c
@@ -25,17 +25,32 @@
 Objlst *objhead;
 
 static Symbol *
+undef(char *name)
+{
+	Symbol *sym = install(name);
+
+	sym->next = &refhead;
+	sym->prev = refhead.prev;
+	refhead.prev->next = sym;
+	refhead.prev = sym;
+
+	return sym;
+}
+
+static Symbol *
 define(Objsym *osym, Obj *obj)
 {
 	Symbol *sym = lookup(osym->name);
 
 	if (!sym) {
-		sym = install(osym->name);
+		sym = undef(osym->name);
 	} else if (sym->def && sym->def->type != 'C') {
 		error("%s: symbol redefined", osym->name);
 		return NULL;
 	}
 
+	/* TODO: deal with C symbols */
+
 	sym->obj = obj;
 	sym->def = osym;
 	sym->size = osym->size;
@@ -48,23 +63,9 @@
 	return sym;
 }
 
-static Symbol *
-undef(char *name)
-{
-	Symbol *sym = install(name);
-
-	refhead.next->prev = sym;
-	sym->next = refhead.next;
-	refhead.next = sym;
-	sym->prev = &refhead;
-
-	return sym;
-}
-
 static int
 moreundef(void)
 {
-
 	return refhead.next != &refhead;
 }
 
@@ -71,10 +72,9 @@
 static void
 listundef(void)
 {
-	Symbol *sym, *p;
+	Symbol *sym;
 
-	p = &refhead;
-	for (sym = p->next; sym != p; sym = sym->next) {
+	for (sym = refhead.next; sym != &refhead; sym = sym->next) {
 		fprintf(stderr,
 		        "ld: symbol '%s' not defined\n",
 		        sym->name);
@@ -84,10 +84,9 @@
 static int
 is_needed(Obj *obj)
 {
-	Symbol *sym, *p;
+	Symbol *sym;
 
-	p = &refhead;
-	for (sym = p->next; sym != p; sym = sym->next) {
+	for (sym = refhead.next; sym != &refhead; sym = sym->next) {
 		if (objlookup(obj, sym->name, 0))
 			return 1;
 	}
@@ -228,6 +227,7 @@
 			newobject(fp, t, OUTLIB);
 			added = 1;
 		}
+
 		if (!added)
 			break;
 	}
--- a/src/cmd/ld/pass2.c
+++ b/src/cmd/ld/pass2.c
@@ -6,41 +6,79 @@
 
 #include "ld.h"
 
-static unsigned long long
-sectsize(int type)
+Segment text = {.type = 'T'};
+Segment rodata = {.type = 'R'};
+Segment data = {.type = 'D'};
+Segment bss = {.type = 'B'};
+Segment debug = {.type = 'N'};
+
+static void
+mksecs(void)
 {
-	unsigned long long size;
 	Objlst *lp;
 	Objsect *sp;
+	Section *sec;
 
-	size = 0;
 	for (lp = objhead; lp; lp = lp->next) {
 		for (sp = lp->obj->secs; sp; sp = sp->next) {
-			if (sp->type != type)
-				continue;
-			size += sp->size;
+			sec = section(sp->name);
+
+			if (sec->type == '?') {
+				sec->type = sp->type;
+				sec->flags = sp->flags;
+			}
+
+			if (sec->type != sp->type || sec->flags != sp->flags) {
+				error("incompatible definitions of section '%s'",
+				      sec->name);
+			}
+
+			sec->size += sp->size;
 		}
 	}
+}
 
-	return size;
+static void
+merge(Segment *seg)
+{
+	Section *sec, **p;
+	int n;
+
+	for (n = 0, sec = sechead; sec; sec = sec->next, ++n) {
+		if (sec->type != seg->type)
+			continue;
+		p = realloc(seg->sections, n * sizeof(*p));
+		if (!p) {
+			error("ou of memory");
+			exit(EXIT_FAILURE);
+		}
+		p[n] = sec;
+		seg->sections = p;
+		seg->size += sec->size;
+	}
+
+	seg->nsec = n;
 }
 
-/*
- * calculate the size of every segment
- */
+static void
+mksegs(void)
+{
+	merge(&text);
+	merge(&rodata);
+	merge(&data);
+	merge(&bss);
+	merge(&debug);
+}
+
 void
 pass2(int argc, char *argv[])
 {
 	unsigned long long n;
 	char *end;
-	Objsect *sp;
 
-	datasiz = bsssiz = textsiz = 0;
+	mksecs();
+	mksegs();
 
-	textsiz = sectsize('T');
-	datasiz = sectsize('D');
-	bsssiz = sectsize('B');
-
 	if (Dflag) {
 		n = strtoull(Dflag, &end, 0);
 		if (n == ULLONG_MAX || *end != '\0') {
@@ -47,7 +85,8 @@
 			error("incorrect -D value");
 			exit(EXIT_FAILURE);
 		}
-		if (n > datasiz)
-			datasiz = n;
+
+		if (n > data.size)
+			data.size = n;
 	}
 }
--- a/src/cmd/ld/pass3.c
+++ b/src/cmd/ld/pass3.c
@@ -46,14 +46,15 @@
 	Obj *obj;
 	Objlst *lst;
 	Objsect *sp;
-	unsigned long long *base, text, data, bss;
+	Segment *seg;
 
 	/*
 	 * TODO: deal with page aligment
 	 */
-	textbase = text = 0x100;
-	database = data = textsiz;
-	bssbase = bss = data+datasiz;
+	text.base = 0x100;
+	rodata.base = text.base + text.size;
+	data.base = rodata.base + rodata.size;
+	bss.base = data.base + data.size;
 
 	for (lst = objhead; lst; lst = lst->next) {
 		obj = lst->obj;
@@ -60,19 +61,21 @@
 		for (sp = obj->secs; sp; sp = sp->next) {
 			switch (sp->type) {
 			case 'T':
-				base = &text;
+				seg = &text;
 				break;
+			/* TODO: what happens with rodata? */
 			case 'D':
-				base = &data;
+				seg = &data;
 				break;
 			case 'B':
-				base = &bss;
+				seg = &bss;
 				break;
 			default:
 				abort();
 			}
-			sp->base = *base;
-			*base += sp->size;
+			sp->base = seg->base + seg->size;
+			/* TODO: deal with symbol aligment */
+			seg->size += sp->size;
 		}
 		rebase(obj);
 	}
--- a/src/cmd/ld/symbol.c
+++ b/src/cmd/ld/symbol.c
@@ -8,9 +8,14 @@
 #include "ld.h"
 
 #define NR_SYMBOL 128
+#define NR_SECTIONS 32
 
 static Symbol *symtab[NR_SYMBOL];
+static Section *sectab[NR_SECTIONS];
+static Section *seclast;
 
+Section *sechead;
+
 Symbol *
 lookup(char *name)
 {
@@ -35,9 +40,11 @@
 	char *s;
 
 	h = genhash(name) % NR_SYMBOL;
+
 	len = strlen(name) + 1;
+	s = malloc(len);
 	sym = malloc(sizeof(*sym));
-	if ((s = malloc(len)) == NULL) {
+	if (!s || !sym) {
 		error("out of memory");
 		exit(EXIT_FAILURE);
 	}
@@ -53,18 +60,82 @@
 	return sym;
 }
 
+Section *
+section(char *name)
+{
+	unsigned h;
+	size_t len;
+	char *s;
+	Section *sec;
+
+	h = genhash(name) % NR_SECTIONS;
+	for (sec = sectab[h]; sec; sec = sec->hash) {
+		if (!strcmp(name, sec->name))
+			return sec;
+	}
+
+	len = strlen(name) + 1;
+	s = malloc(len);
+	sec = malloc(sizeof(*sec));
+	if (!s || !sec) {
+		error("out of memory");
+		exit(EXIT_FAILURE);
+	}
+
+	sec->name = memcpy(s, name, len);
+	sec->type = '?';
+	sec->base = 0;
+	sec->size = 0;
+	sec->flags = 0;
+	sec->hash = sectab[h];
+	sectab[h] = sec;
+
+	if (!sechead)
+		sechead = sec;
+	else
+		seclast->next = sec;
+	sec->next = NULL;
+
+	return seclast = sec;
+}
+
 #ifndef NDEBUG
-int
+void
 debugsym(void)
 {
 	Symbol **symp, *sym;
 
+	fputs("Symbols:\n", stderr);
 	for (symp = symtab; symp < &symtab[NR_SYMBOL]; symp++) {
 		for (sym = *symp; sym; sym = sym->hash)
 			fprintf(stderr,
-			        "sym: %s (%#x)\n",
+			        "sym: %s (%#llx)\n",
 			        sym->name,
 			        sym->value);
+	}
+}
+
+void
+debugsec(void)
+{
+	Section **secp, *sec;
+
+	fputs("Sections:\n", stderr);
+	for (secp = sectab; secp < &sectab[NR_SECTIONS]; secp++) {
+		for (sec = *secp; sec; sec = sec->hash)
+			fprintf(stderr,
+			        "sec: %s - %c (%#llx,%#lx)\n",
+			        sec->name,
+			        sec->type,
+			        sec->base,
+			        sec->size);
+	}
+
+	for (sec = sechead; sec; sec = sec->next) {
+		fprintf(stderr,
+		        "%s %s",
+		        sec->name,
+			sec->next ? "->" : "\n");
 	}
 }
 #endif