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