ref: c31d542ae4bfebfe4d44b0b4003ae9c9dc613b51
parent: a56932d42e29b8563691512e5be88d1d1faf553b
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Thu May 10 16:42:38 EDT 2018
[ld/coff32] Load sections and symbols in pass1 This is other step in having a linker working for coff32.
--- a/ld/coff32.c
+++ b/ld/coff32.c
@@ -14,7 +14,6 @@
#include "ld.h"
static int (*unpack)(unsigned char *, char *, ...);
-static long strtbl, symtbl, sectbl;
static FILHDR *
getfhdr(unsigned char *buff, FILHDR *hdr)
@@ -22,59 +21,147 @@
int n;
n = (*unpack)(buff,
- "sslllss",
- &hdr->f_magic,
- &hdr->f_nscns,
- &hdr->f_timdat,
- &hdr->f_symptr,
- &hdr->f_nsyms,
- &hdr->f_opthdr,
- &hdr->f_flags);
+ "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 int
+readstr(Obj *obj, long off)
+{
+ unsigned char buff[4];
+ char *str;
+ size_t siz;
+
+ if (fseek(obj->fp, off, SEEK_SET) == EOF)
+ return -1;
+
+ if (fread(buff, 4, 1, obj->fp) != 1)
+ return -1;
+
+ (*unpack)(buff, "l", &siz);
+
+ if (siz > SIZE_MAX || (str = malloc(siz)) == NULL)
+ outmem();
+
+ if (fread(str, siz, 1, obj->fp) != 1)
+ return -1;
+
+ obj->strtbl = str;
+ return 0;
+}
+
+static SCNHDR *
+getscn(unsigned char *buff, SCNHDR *scn)
+{
+ int n;
+
+ n = (*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 i;
+ unsigned char buff[SCNHSZ];
+ SCNHDR scn;
+ FILHDR *hdr;
+
+ if (fseek(obj->fp, off, SEEK_SET) == EOF)
+ return -1;
+
+ hdr = obj->filhdr;
+ for (i = 0; i < hdr->f_nscns; i++) {
+ if (fread(buff, SCNHSZ, 1, obj->fp) != 1)
+ return -1;
+ getscn(buff, &scn);
+ }
+}
+
static void
+getsym(unsigned char *buff, SYMENT *ent)
+{
+ int n;
+
+ n = (*unpack)(buff,
+ "'8lsscc",
+ &ent->n_name,
+ &ent->n_value,
+ &ent->n_scnum,
+ &ent->n_type,
+ &ent->n_sclass,
+ &ent->n_numaux);
+ assert(n == SYMESZ);
+}
+
+static int
+loadobj(Obj *obj, long off)
+{
+ unsigned i;
+ unsigned char buff[SYMESZ];
+ SYMENT sym;
+ FILHDR *hdr;
+
+ for (i = 0; i < hdr->f_nsyms; i++) {
+ if (fread(buff, SYMESZ, 1, obj->fp) != 1)
+ return -1;
+ getsym(buff, &sym);
+ }
+}
+
+static void
pass1(char *fname, char *member, FILE *fp)
{
unsigned char buff[FILHSZ];
FILHDR *hdr;
Obj *obj;
- long siz, pos = ftell(fp);
- char *str;
+ char *strtbl;
+ long symoff, secoff, stroff, pos;
+ obj = newobj(fname, member);
+ obj->fp = fp;
+
+ pos = ftell(fp);
if (fread(buff, FILHSZ, 1, fp) != 1)
goto bad_file;
if ((hdr = malloc(sizeof(*hdr))) == NULL)
- goto out_of_memory;
+ outmem();
+ getfhdr(buff, hdr);
+ obj->filhdr = hdr;
- obj = newobj(fname);
- obj->hdr = getfhdr(buff, hdr);
-
/* TODO: Check overflow */
- strtbl = pos + hdr->f_symptr + hdr->f_nsyms* SYMESZ;
- symtbl = pos + hdr->f_symptr;
- sectbl = pos + FILHSZ + hdr->f_opthdr;
+ stroff = pos + hdr->f_symptr + hdr->f_nsyms*SYMESZ;
+ symoff = pos + hdr->f_symptr;
+ secoff = pos + FILHSZ + hdr->f_opthdr;
- if (fseek(fp, strtbl, SEEK_SET) == EOF)
+ if (readstr(obj, stroff) < 0)
goto bad_file;
-
- if (fread(buff, 4, 1, fp) != 1)
+ if (loadobj(obj, symoff) < 0)
goto bad_file;
-
- (*unpack)(buff, "l", &siz);
-
- if (siz > SIZE_MAX || (str = malloc(siz)) == NULL)
- goto out_of_memory;
-
- if (fread(str, siz, 1, fp) != 1)
+ if (readsects(obj, secoff) < 0)
goto bad_file;
- obj->strtbl = str;
-
-out_of_memory:
- die("ld: out of memory");
bad_file:
if (ferror(fp))
die("ld: %s: %s", fname, strerror(errno));
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -4,7 +4,10 @@
struct obj {
char *fname;
- void *hdr;
+ char *member;
+ FILE *fp;
+ void *filhdr;
+ void *sechdr;
char *strtbl;
struct obj *next;
};
@@ -13,14 +16,15 @@
char *name;
};
-#ifdef stdin
struct objfile {
int (*probe)(char *fname, char *member, FILE *fp);
void (*pass1)(char *fname, char *member, FILE *fp);
void (*pass2)(char *fname, char *member, FILE *fp);
};
-#endif
/* obj.c */
-extern Obj *newobj(char *fname);
+extern Obj *newobj(char *fname, char *member);
extern Symbol *lookup(char *name);
+
+/* main.c */
+extern void outmem(void);
--- a/ld/main.c
+++ b/ld/main.c
@@ -12,10 +12,16 @@
#include "../inc/syslibs.h"
#include "ld.h"
-char *argv0;
char *output = "a.out", *entry, *datasiz;
int pass;
int sflag, xflag, Xflag, rflag, dflag;
+
+void
+outmem(void)
+{
+ fputs("ld: out of memory\n", stderr);
+ exit(EXIT_FAILURE);
+}
static int
object(char *fname, char *member, FILE *fp)
--- a/ld/obj.c
+++ b/ld/obj.c
@@ -1,5 +1,6 @@
static char sccsid[] = "@(#) ./ld/obj.c";
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -10,18 +11,20 @@
static Obj *tail;
Obj *
-newobj(char *fname)
+newobj(char *fname, char *member)
{
Obj *obj;
- char *s;
- size_t len = strlen(fname);
+ char *s, *t;
+ size_t l1 = strlen(member), l2 = strlen(fname);
obj = malloc(sizeof(*obj));
- s = malloc(len+1);
- if (!obj || !s)
- die("ld: out of memory");
+ s = malloc(l1+1);
+ t = malloc(l2+1);
+ if (!obj || !s || !t)
+ outmem();
- obj->fname = memcpy(s, fname, len);
+ obj->fname = memcpy(s, fname, l1);
+ obj->member = memcpy(t, member, l2);
obj->next = NULL;
if (!objlst)