diff options
Diffstat (limited to 'rdoff/v1/rdfload.c')
-rw-r--r-- | rdoff/v1/rdfload.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/rdoff/v1/rdfload.c b/rdoff/v1/rdfload.c new file mode 100644 index 00000000..b8483444 --- /dev/null +++ b/rdoff/v1/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; +} |