summaryrefslogtreecommitdiff
path: root/rdoff/rdfload.c
diff options
context:
space:
mode:
Diffstat (limited to 'rdoff/rdfload.c')
-rw-r--r--rdoff/rdfload.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/rdoff/rdfload.c b/rdoff/rdfload.c
new file mode 100644
index 00000000..ad340b36
--- /dev/null
+++ b/rdoff/rdfload.c
@@ -0,0 +1,173 @@
+/* rdfload.c RDOFF Object File loader library
+ *
+ * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
+ * Julian Hall. All rights reserved. The software is
+ * redistributable under the licence given in the file "Licence"
+ * distributed in the NASM archive.
+ *
+ * Permission to use this file in your own projects is granted, as long
+ * as acknowledgement is given in an appropriate manner to its authors,
+ * with instructions of how to obtain a copy via ftp.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "rdfload.h"
+#include "symtab.h"
+#include "rdoff.h"
+#include "collectn.h"
+
+extern int rdf_errno;
+
+rdfmodule * rdfload(const char *filename)
+{
+ rdfmodule * f = malloc(sizeof(rdfmodule));
+ long bsslength = 0;
+ char * hdr;
+ rdfheaderrec *r;
+
+ if (f == NULL)
+ {
+ rdf_errno = 6; /* out of memory */
+ return NULL;
+ }
+
+ f->symtab = symtabNew();
+ if (!f->symtab)
+ {
+ free(f);
+ rdf_errno = 6;
+ return NULL;
+ }
+
+ /* open the file */
+ if ( rdfopen( &(f->f), filename ) ) {
+ free(f);
+ return NULL;
+ }
+
+ /* read in text and data segments, and header */
+
+ f->t = malloc (f->f.code_len);
+ f->d = malloc (f->f.data_len); /* BSS seg allocated later */
+ hdr = malloc (f->f.header_len);
+
+ if (! f->t || ! f->d || !hdr) {
+ rdf_errno = 6;
+ rdfclose(&f->f);
+ if (f->t) free(f->t);
+ if (f->d) free(f->d);
+ free(f);
+ return NULL;
+ }
+
+ if ( rdfloadseg (&f->f,RDOFF_HEADER,hdr) ||
+ rdfloadseg (&f->f,RDOFF_CODE,f->t) ||
+ rdfloadseg (&f->f,RDOFF_DATA,f->d) )
+ {
+ rdfclose(&f->f);
+ free(f->t);
+ free(f->d);
+ free(f);
+ free(hdr);
+ return NULL;
+ }
+
+ rdfclose(&f->f);
+
+ /* Allocate BSS segment; step through header and count BSS records */
+
+ while ( ( r = rdfgetheaderrec (&f->f) ) )
+ {
+ if (r->type == 5)
+ bsslength += r->b.amount;
+ }
+
+ f->b = malloc ( bsslength );
+ if (! f->b )
+ {
+ free(f->t);
+ free(f->d);
+ free(f);
+ free(hdr);
+ rdf_errno = 6;
+ return NULL;
+ }
+
+ rdfheaderrewind (&f->f);
+
+ f->textrel = (long)f->t;
+ f->datarel = (long)f->d;
+ f->bssrel = (long)f->b;
+
+ return f;
+}
+
+int rdf_relocate(rdfmodule * m)
+{
+ rdfheaderrec * r;
+ Collection imports;
+ symtabEnt e;
+ long rel;
+ unsigned char * seg;
+
+ rdfheaderrewind ( & m->f );
+ collection_init(&imports);
+
+ while ( (r = rdfgetheaderrec ( & m->f ) ) )
+ {
+ switch (r->type)
+ {
+ case 1: /* Relocation record */
+
+ /* calculate relocation factor */
+
+ if (r->r.refseg == 0) rel = m->textrel;
+ else if (r->r.refseg == 1) rel = m->datarel;
+ else if (r->r.refseg == 2) rel = m->bssrel;
+ else
+ /* We currently do not support load-time linkage.
+ This should be added some time soon... */
+
+ return 1; /* return error code */
+
+ if ((r->r.segment & 63) == 0) seg = m->t;
+ else if ((r->r.segment & 63) == 1) seg = m->d;
+ else
+ return 1;
+
+ /* it doesn't matter in this case that the code is non-portable,
+ as the entire concept of executing a module like this is
+ non-portable */
+ switch(r->r.length) {
+ case 1:
+ seg[r->r.offset] += (char) rel;
+ break;
+ case 2:
+ *(int16 *)(seg + r->r.offset) += (int16) rel;
+ break;
+ case 4:
+ *(long *)(seg + r->r.offset) += rel;
+ break;
+ }
+ break;
+
+ case 3: /* export record - add to symtab */
+ e.segment = r->e.segment;
+ e.offset = r->e.offset +
+ (e.segment == 0 ? m->textrel : /* 0 -> code */
+ e.segment == 1 ? m->datarel : /* 1 -> data */
+ m->bssrel) ; /* 2 -> bss */
+ e.flags = 0;
+ e.name = malloc(strlen(r->e.label) + 1);
+ if (! e.name)
+ return 1;
+
+ strcpy(e.name,r->e.label);
+ symtabInsert(m->symtab,&e);
+ break;
+ }
+ }
+ return 0;
+}