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;
}