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 < §ab[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