commit 7e83e0d7e754524182a18311e4f41444b90f985a
parent 546ffbebb56d57c920421134ff54efcdc0631530
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Thu, 10 May 2018 20:42:38 +0100
[ld/coff32] Load sections and symbols in pass1
This is other step in having a linker working for coff32.
Diffstat:
M | ld/coff32.c | | | 151 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
M | ld/ld.h | | | 12 | ++++++++---- |
M | ld/main.c | | | 8 | +++++++- |
M | ld/obj.c | | | 17 | ++++++++++------- |
4 files changed, 144 insertions(+), 44 deletions(-)
diff --git a/ld/coff32.c b/ld/coff32.c
@@ -14,7 +14,6 @@ static char sccsid[] = "@(#) ./ld/coff32.c";
#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 @@ getfhdr(unsigned char *buff, FILHDR *hdr)
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;
-
- obj = newobj(fname);
- obj->hdr = getfhdr(buff, hdr);
+ outmem();
+ getfhdr(buff, hdr);
+ obj->filhdr = 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));
diff --git a/ld/ld.h b/ld/ld.h
@@ -4,7 +4,10 @@ typedef struct symbol Symbol;
struct obj {
char *fname;
- void *hdr;
+ char *member;
+ FILE *fp;
+ void *filhdr;
+ void *sechdr;
char *strtbl;
struct obj *next;
};
@@ -13,14 +16,15 @@ struct symbol {
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);
diff --git a/ld/main.c b/ld/main.c
@@ -12,11 +12,17 @@ static char sccsid[] = "@(#) ./ld/main.c";
#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)
{
diff --git 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 @@ Obj *objlst;
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)