ref: 32d7bdbcc2afd6aecc33ddb49ea5668fd76ff9f6
parent: 6661a93cfca897396c2803b9cd028068ad7c9a84
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Jun 4 04:33:48 EDT 2018
[ld/coff32] Implement load() This function loads all the headers of the coff file and it installs all the global symbols in the hash table. After this patch we are ready to begin with the second pass.
--- a/ld/coff32.c
+++ b/ld/coff32.c
@@ -100,17 +100,16 @@
hdr = obj->filhdr;
nsec = hdr->f_nscns;
- if (nsec > SIZE_MAX / sizeof(*scn))
- return -1;
+ scn = NULL;
+ sec = NULL;
+ if (nsec <= SIZE_MAX / sizeof(*scn))
+ scn = malloc(nsec * sizeof(*scn));
- if (nsec > SIZE_MAX / sizeof(Symbol *))
- return -1;
+ if (nsec <= SIZE_MAX / sizeof(Symbol *))
+ sec = malloc(nsec * sizeof(Symbol *));
- scn = malloc(nsec * sizeof(*scn));
- sec = malloc(nsec * sizeof(Symbol *));
if (!scn || !sec)
outmem();
- obj->sections = sec;
obj->scnhdr = scn;
if (fseek(obj->fp, off, SEEK_SET) == EOF)
@@ -154,7 +153,7 @@
{
SYMENT *ent, *ents;
FILHDR *hdr = obj->filhdr;;
- long i, nsyms = hdr->f_nsyms;
+ long nsyms = hdr->f_nsyms;
unsigned char buff[SYMESZ];
@@ -161,14 +160,10 @@
if (fseek(obj->fp, off, SEEK_SET) == EOF)
return -1;
- if (nsyms > SIZE_MAX/sizeof(SYMENT)) {
- fprintf(stderr,
- "ld: %s: overflow in size of symbol redirection\n",
- obj->fname);
- exit(EXIT_FAILURE);
- }
-
- if ((ents = malloc((nsyms * sizeof(SYMENT)))) == NULL)
+ ents = NULL;
+ if (nsyms <= SIZE_MAX/sizeof(SYMENT))
+ ents = malloc((nsyms * sizeof(SYMENT)));
+ if (!ents)
outmem();
obj->enthdr = ents;
@@ -175,7 +170,7 @@
for (ent = ents; ent < &ents[nsyms]; ++ent) {
if (fread(buff, SYMESZ, 1, obj->fp) != 1)
return -1;
- getent(obj, buff, &ents[i]);
+ getent(obj, buff, ent);
}
return 0;
@@ -297,6 +292,63 @@
return 0;
}
+static Obj *
+load(Obj *obj)
+{
+ FILHDR *hdr = obj->filhdr;
+ SCNHDR *scn, *scns = obj->scnhdr;;
+ SYMENT *ent, *ents = obj->enthdr;
+ int nsect, aux;
+
+ 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);
+ }
+ }
+ }
+
+ return obj;
+}
+
static void
pass1(Obj *obj)
{
@@ -310,6 +362,7 @@
}
add(obj);
+ load(obj);
}
static void
@@ -324,16 +377,16 @@
{
int c;
int c1, c2;
- fpos_t pos;
+ long pos;
unsigned short magic;
unsigned align;
int (*unpack)(unsigned char *, char *, ...);
Obj *obj;
- fgetpos(fp, &pos);
+ pos = ftell(fp);
c1 = getc(fp);
c2 = getc(fp);
- fsetpos(fp, &pos);
+ fseek(fp, pos, SEEK_SET);
if (ferror(fp))
die("ld: %s: %s", fname, strerror(errno));
@@ -356,6 +409,7 @@
obj->unpack = unpack;
obj->align = align;
obj->fmt = &coff32;
+ obj->offset = pos;
return obj;
}
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -5,6 +5,7 @@
typedef struct obj Obj;
typedef struct symbol Symbol;
typedef struct objfmt Fmt;
+typedef struct section Section;
struct obj {
char *fname;
@@ -17,9 +18,6 @@
void *scnhdr;
void *enthdr;
- Symbol **symbols;
- Symbol **sections;
-
char *strtbl;
size_t strsiz;
@@ -26,24 +24,31 @@
int (*unpack)(unsigned char *, char *, ...);
int align;
- struct obj *next, *prev;
+ struct obj *next;
};
-enum symflgs {
- SSECT = 1 << 0,
+enum symflg {
+ SDEFINED = 1 << 1,
};
struct symbol {
char *name;
- char type;
- short flags;
+ unsigned char flags;
long size;
TUINT base;
TUINT value;
+ Section *section;
Obj *where;
struct symbol *hash, *next;
};
+struct section {
+ char *name;
+ TUINT base;
+ TUINT size;
+ struct section *next;
+};
+
struct objfmt {
Obj *(*probe)(char *fname, char *member, FILE *fp);
void (*pass1)(Obj *obj);
@@ -52,13 +57,15 @@
/* obj.c */
extern Obj *newobj(char *fname, char *member, FILE *fp);
-extern void add(Obj *obj);
+extern Obj *add(Obj *obj);
extern void delobj(Obj *obj);
-extern void newsect(Symbol *sym);
+extern Section *slookup(char *name);
extern Symbol *lookup(char *name, int install);
/* main.c */
extern void outmem(void);
+extern void corrupted(char *fname, char *member);
+extern void redefined(Obj *obj, Symbol *sym);
/*
* Definition of globals variables
--- a/ld/main.c
+++ b/ld/main.c
@@ -22,6 +22,26 @@
int gflag; /* preserve debug symbols */
void
+redefined(Obj *obj, Symbol *sym)
+{
+ /* TODO: add infotmation about where it is defined */
+ fprintf(stderr,
+ "ld: %s: redifinition of symbol '%s'\n",
+ obj->fname, sym->name);
+}
+
+void
+corrupted(char *fname, char *member)
+{
+ char *fmt;
+
+ fmt = (member) ?
+ "ld: %s(%s): corrupted file\n" : "ld: %s: corrupted file\n";
+ fprintf(stderr, fmt, fname, member);
+ exit(EXIT_FAILURE);
+}
+
+void
outmem(void)
{
fputs("ld: out of memory\n", stderr);
--- a/ld/obj.c
+++ b/ld/obj.c
@@ -13,14 +13,14 @@
Obj *objlst;
static Obj *objtail;
-Symbol *sectlst;
static Symbol *secttail;
static Symbol *symtbl[NR_SYM_HASH];
-void
+Section *sectlst;
+
+Obj *
add(Obj *obj)
{
- obj->prev = objlst;
obj->next = NULL;
if (!objlst) {
@@ -35,8 +35,6 @@
delobj(Obj *obj)
{
free(obj->strtbl);
- free(obj->sections);
- free(obj->symbols);
free(obj->scnhdr);
free(obj->filhdr);
free(obj->fname);
@@ -77,20 +75,33 @@
return obj;
}
-void
-newsect(Symbol *sym)
+Section *
+slookup(char *name)
{
- if (sym->flags & SSECT)
- return;
+ char *s;
+ Section *prev, *sp;
+ size_t len = strlen(name);
- if (!sectlst) {
- secttail = sectlst = sym;
- } else {
- secttail->next = sym;
- secttail = sym;
+ for (prev = sp = sectlst; sp; prev = sp, sp = sp->next) {
+ if (!memcmp(sp->name, name, len))
+ return sp;
}
- sym->flags |= SSECT;
+ sp = malloc(sizeof(*sp));
+ s = malloc(len);
+ if (!sp || !s)
+ outmem();
+ sp->name = s;
+ sp->base = 0;
+ sp->size = 0;
+ sp->next = NULL;
+
+ if (!prev)
+ sectlst = sp;
+ else
+ prev->next = sp;
+
+ return sp;
}
static unsigned
@@ -132,7 +143,6 @@
sym->hash = symtbl[h];
symtbl[h] = sym;
sym->name = s;
- sym->type = 'U';
return sym;
}