summaryrefslogtreecommitdiff
path: root/rdoff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2002-04-30 20:51:32 +0000
committerH. Peter Anvin <hpa@zytor.com>2002-04-30 20:51:32 +0000
commitea6e34db64c7da7cb885197316c6b5e7d048bdb9 (patch)
tree78e728348f8fe09e394a51c3617e6261de0f4001 /rdoff
downloadnasm-ea6e34db64c7da7cb885197316c6b5e7d048bdb9.tar.gz
NASM 0.91nasm-0.91
Diffstat (limited to 'rdoff')
-rw-r--r--rdoff/Makefile43
-rw-r--r--rdoff/collectn.c40
-rw-r--r--rdoff/collectn.h22
-rw-r--r--rdoff/ldrdf.c540
-rw-r--r--rdoff/rdf.doc99
-rw-r--r--rdoff/rdfdump.c156
-rw-r--r--rdoff/rdfload.c173
-rw-r--r--rdoff/rdfload.h29
-rw-r--r--rdoff/rdoff.c367
-rw-r--r--rdoff/rdoff.h112
-rw-r--r--rdoff/rdx.c61
-rw-r--r--rdoff/symtab.c80
-rw-r--r--rdoff/symtab.h22
13 files changed, 1744 insertions, 0 deletions
diff --git a/rdoff/Makefile b/rdoff/Makefile
new file mode 100644
index 00000000..2e55dde1
--- /dev/null
+++ b/rdoff/Makefile
@@ -0,0 +1,43 @@
+# Makefile for RDOFF object file utils; part of the Netwide Assembler
+#
+# 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.
+#
+# This Makefile is designed for use under Unix (probably fairly
+# portably).
+
+CC = gcc
+CCFLAGS = -c -O -g -Wall -ansi -pedantic -I..
+LINK = gcc
+LINKFLAGS = -o
+DLINKFLAGS = -o
+LIBRARIES =
+STRIP = strip
+LDRDFLIBS = rdoff.o ../nasmlib.o symtab.o collectn.o
+RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o
+
+.c.o:
+ $(CC) $(CCFLAGS) $*.c
+
+all : rdfdump ldrdf rdx
+
+rdfdump : rdfdump.o
+ $(LINK) $(LINKFLAGS) rdfdump rdfdump.o
+ldrdf : ldrdf.o $(LDRDFLIBS)
+ $(LINK) $(LINKFLAGS) ldrdf ldrdf.o $(LDRDFLIBS)
+rdx : rdx.o $(RDXLIBS)
+ $(LINK) $(LINKFLAGS) rdx rdx.o $(RDXLIBS)
+
+rdfdump.o : rdfdump.c
+rdoff.o : rdoff.c rdoff.h
+ldrdf.o : ldrdf.c rdoff.h ../nasmlib.h symtab.h collectn.h
+symtab.o : symtab.c symtab.h
+collectn.o : collectn.c collectn.h
+rdx.o : rdx.c rdoff.h rdfload.h symtab.h
+rdfload.o : rdfload.c rdfload.h rdoff.h collectn.h symtab.h
+
+clean :
+ rm -f *.o *~ rdfdump ldrdf rdx
+ make -C test clean
diff --git a/rdoff/collectn.c b/rdoff/collectn.c
new file mode 100644
index 00000000..c265c95f
--- /dev/null
+++ b/rdoff/collectn.c
@@ -0,0 +1,40 @@
+/* collectn.c Implements variable length pointer arrays [collections]
+ *
+ * This file is public domain.
+ */
+
+#include "collectn.h"
+#include <stdlib.h>
+
+void collection_init(Collection * c)
+{
+ int i;
+
+ for (i = 0; i < 32; i++) c->p[i] = NULL;
+ c->next = NULL;
+}
+
+void ** colln(Collection * c, int index)
+{
+ while (index >= 32) {
+ index -= 32;
+ if (c->next == NULL) {
+ c->next = malloc(sizeof(Collection));
+ collection_init(c->next);
+ }
+ c = c->next;
+ }
+ return &(c->p[index]);
+}
+
+void collection_reset(Collection *c)
+{
+ int i;
+ if (c->next) {
+ collection_reset(c->next);
+ free(c->next);
+ }
+
+ c->next = NULL;
+ for (i = 0; i < 32; i++) c->p[i] = NULL;
+}
diff --git a/rdoff/collectn.h b/rdoff/collectn.h
new file mode 100644
index 00000000..b3f2d52a
--- /dev/null
+++ b/rdoff/collectn.h
@@ -0,0 +1,22 @@
+/* collectn.h Header file for 'collection' abstract data type
+ *
+ * This file is public domain, and does not come under the NASM license.
+ * It, along with 'collectn.c' implements what is basically a variable
+ * length array (of pointers)
+ */
+
+#ifndef _COLLECTN_H
+#define _COLLECTN_H
+
+typedef struct tagCollection {
+ void *p[32]; /* array of pointers to objects */
+
+ struct tagCollection *next;
+} Collection;
+
+void collection_init(Collection * c);
+void ** colln(Collection * c, int index);
+void collection_reset(Collection * c);
+
+#endif
+
diff --git a/rdoff/ldrdf.c b/rdoff/ldrdf.c
new file mode 100644
index 00000000..ce86b7e6
--- /dev/null
+++ b/rdoff/ldrdf.c
@@ -0,0 +1,540 @@
+/* ldrdf.c RDOFF Object File linker/loader main program
+ *
+ * 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.
+ */
+
+/* TODO: Make the system skip a module (other than the first) if none
+ * of the other specified modules contain a reference to it.
+ * May require the system to make an extra pass of the modules to be
+ * loaded eliminating those that aren't required.
+ *
+ * Support libaries (.a files - requires a 'ranlib' type utility)
+ *
+ * -s option to strip resolved symbols from exports.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "nasm.h"
+#include "rdoff.h"
+#include "nasmlib.h"
+#include "symtab.h"
+#include "collectn.h"
+
+#define LDRDF_VERSION "0.11"
+
+/* global variables - those to set options: */
+
+int verbose = 0; /* reflects setting of command line switch */
+int align = 16;
+int errors = 0; /* set by functions to cause halt after current
+ stage of processing */
+
+/* the linked list of modules that must be loaded & linked */
+
+struct modulenode {
+ rdffile f; /* the file */
+ long coderel; /* module's code relocation factor */
+ long datarel; /* module's data relocation factor */
+ long bssrel; /* module's bss data reloc. factor */
+ void * header; /* header location, if loaded */
+ char * name; /* filename */
+ struct modulenode *next;
+};
+
+struct modulenode *modules = NULL,*lastmodule = NULL;
+
+void *symtab; /* The symbol table */
+
+rdf_headerbuf * newheader ; /* New header to be written to output */
+
+/* loadmodule - find the characteristics of a module and add it to the
+ * list of those being linked together */
+
+void loadmodule(char *filename)
+{
+ struct modulenode *prev;
+ if (! modules) {
+ modules = malloc(sizeof(struct modulenode));
+ lastmodule = modules;
+ prev = NULL;
+ }
+ else {
+ lastmodule->next = malloc(sizeof(struct modulenode));
+ prev = lastmodule;
+ lastmodule = lastmodule->next;
+ }
+
+ if (! lastmodule) {
+ fputs("ldrdf: not enough memory\n",stderr);
+ exit(1);
+ }
+
+ if (rdfopen(&lastmodule->f,filename)) {
+ rdfperror("ldrdf",filename);
+ exit(1);
+ }
+
+ lastmodule->header = NULL; /* header hasn't been loaded */
+ lastmodule->name = filename;
+ lastmodule->next = NULL;
+
+ if (prev) {
+ lastmodule->coderel = prev->coderel + prev->f.code_len;
+ if (lastmodule->coderel % align != 0)
+ lastmodule->coderel += align - (lastmodule->coderel % align);
+ lastmodule->datarel = prev->datarel + prev->f.data_len;
+ if (lastmodule->datarel % align != 0)
+ lastmodule->datarel += align - (lastmodule->datarel % align);
+ }
+ else {
+ lastmodule->coderel = 0;
+ lastmodule->datarel = 0;
+ }
+
+ if (verbose)
+ printf("%s code = %08lx (+%04lx), data = %08lx (+%04lx)\n",filename,
+ lastmodule->coderel,lastmodule->f.code_len,
+ lastmodule->datarel,lastmodule->f.data_len);
+
+}
+
+/* load_segments() allocates memory for & loads the code & data segs
+ * from the RDF modules
+ */
+
+char *text,*data;
+long textlength,datalength,bsslength;
+
+void load_segments(void)
+{
+ struct modulenode *mod;
+
+ if (!modules) {
+ fprintf(stderr,"ldrdf: nothing to do\n");
+ exit(0);
+ }
+ if (!lastmodule) {
+ fprintf(stderr,"ldrdf: panic: module list exists, but lastmodule=NULL\n");
+ exit(3);
+ }
+
+ if (verbose)
+ printf("loading modules into memory\n");
+
+ /* The following stops 16 bit DOS from crashing whilst attempting to
+ work using segments > 64K */
+ if (sizeof(int) == 2) { /* expect a 'code has no effect' warning on 32 bit
+ platforms... */
+ if (lastmodule->coderel + lastmodule->f.code_len > 65535 ||
+ lastmodule->datarel + lastmodule->f.data_len > 65535) {
+ fprintf(stderr,"ldrdf: segment length has exceeded 64K; use a 32 bit "
+ "version.\nldrdf: code size = %05lx, data size = %05lx\n",
+ lastmodule->coderel + lastmodule->f.code_len,
+ lastmodule->datarel + lastmodule->f.data_len);
+ exit(1);
+ }
+ }
+
+ text = malloc(textlength = lastmodule->coderel + lastmodule->f.code_len);
+ data = malloc(datalength = lastmodule->datarel + lastmodule->f.data_len);
+
+ if (!text || !data) {
+ fprintf(stderr,"ldrdf: out of memory\n");
+ exit(1);
+ }
+
+ mod = modules;
+ while (mod) { /* load the segments for each module */
+ mod->header = malloc(mod->f.header_len);
+ if (!mod->header) {
+ fprintf(stderr,"ldrdf: out of memory\n");
+ exit(1);
+ }
+ if (rdfloadseg(&mod->f,RDOFF_HEADER,mod->header) ||
+ rdfloadseg(&mod->f,RDOFF_CODE,&text[mod->coderel]) ||
+ rdfloadseg(&mod->f,RDOFF_DATA,&data[mod->datarel])) {
+ rdfperror("ldrdf",mod->name);
+ exit(1);
+ }
+ rdfclose(&mod->f); /* close file; segments remain */
+ mod = mod->next;
+ }
+}
+
+/* build_symbols() step through each module's header, and locate
+ * exported symbols, placing them in a global table
+ */
+
+void build_symbols()
+{
+ struct modulenode *mod;
+ rdfheaderrec *r;
+ symtabEnt e;
+ long bssloc,cbBss;
+
+ if (verbose) printf("building global symbol table:\n");
+ newheader = rdfnewheader();
+
+ symtab = symtabNew();
+ bssloc = 0; /* keep track of location of BSS symbols */
+
+ for (mod = modules; mod; mod = mod->next)
+ {
+ mod->bssrel = bssloc;
+ cbBss = 0;
+ rdfheaderrewind(&mod->f);
+ while ((r = rdfgetheaderrec(&mod->f)))
+ {
+
+ if (r->type == 5) /* Allocate BSS */
+ cbBss += r->b.amount;
+
+ if (r->type != 3) continue; /* ignore all but export recs */
+
+ e.segment = r->e.segment;
+ e.offset = r->e.offset +
+ (e.segment == 0 ? mod->coderel : /* 0 -> code */
+ e.segment == 1 ? mod->datarel : /* 1 -> data */
+ mod->bssrel) ; /* 2 -> bss */
+ e.flags = 0;
+ e.name = malloc(strlen(r->e.label) + 1);
+ if (! e.name)
+ {
+ fprintf(stderr,"ldrdf: out of memory\n");
+ exit(1);
+ }
+ strcpy(e.name,r->e.label);
+ symtabInsert(symtab,&e);
+ }
+ bssloc += cbBss;
+ }
+ if (verbose)
+ {
+ symtabDump(symtab,stdout);
+ printf("BSS length = %ld bytes\n\n",bssloc);
+ }
+ bsslength = bssloc;
+}
+
+/* link_segments() step through relocation records in each module's
+ * header, fixing up references.
+ */
+
+void link_segments(void)
+{
+ struct modulenode *mod;
+ Collection imports;
+ symtabEnt *s;
+ long rel,relto = 0; /* placate gcc */
+ char *seg;
+ rdfheaderrec *r;
+ int bRelative;
+
+ if (verbose) printf("linking segments\n");
+
+ collection_init(&imports);
+
+ for (mod = modules; mod; mod = mod->next) {
+ if (verbose >= 2) printf("* processing %s\n",mod->name);
+ rdfheaderrewind(&mod->f);
+ while((r = rdfgetheaderrec(&mod->f))) {
+ switch(r->type) {
+ case 1: /* relocation record */
+ if (r->r.segment >= 64) { /* Relative relocation; */
+ bRelative = 1; /* need to find location relative */
+ r->r.segment -= 64; /* to start of this segment */
+ relto = r->r.segment == 0 ? mod->coderel : mod->datarel;
+ }
+ else
+ bRelative = 0; /* non-relative - need to relocate
+ * at load time */
+
+ /* calculate absolute offset of reference, not rel to beginning of
+ segment */
+ r->r.offset += r->r.segment == 0 ? mod->coderel : mod->datarel;
+
+ /* calculate the relocation factor to apply to the operand -
+ the base address of one of this modules segments if referred
+ segment is 0 - 2, or the address of an imported symbol
+ otherwise. */
+
+ if (r->r.refseg == 0) rel = mod->coderel;
+ else if (r->r.refseg == 1) rel = mod->datarel;
+ else if (r->r.refseg == 2) rel = mod->bssrel;
+ else { /* cross module link - find reference */
+ s = *colln(&imports,r->r.refseg - 2);
+ if (!s) {
+ fprintf(stderr,"ldrdf: link to undefined segment %04x in"
+ " %s:%d\n", r->r.refseg,mod->name,r->r.segment);
+ errors = 1;
+ break;
+ }
+ rel = s->offset;
+
+ r->r.refseg = s->segment; /* change referred segment,
+ so that new header is
+ correct */
+ }
+
+ if (bRelative) /* Relative - subtract current segment start */
+ rel -= relto;
+ else
+ { /* Add new relocation header */
+ rdfaddheader(newheader,r);
+ }
+
+ /* Work out which segment we're making changes to ... */
+ if (r->r.segment == 0) seg = text;
+ else if (r->r.segment == 1) seg = data;
+ else {
+ fprintf(stderr,"ldrdf: relocation in unknown segment %d in "
+ "%s\n", r->r.segment,mod->name);
+ errors = 1;
+ break;
+ }
+
+ /* Add the relocation factor to the datum specified: */
+
+ if (verbose >= 3)
+ printf(" - relocating %d:%08lx by %08lx\n",r->r.segment,
+ r->r.offset,rel);
+
+ /**** The following code is non-portable. Rewrite it... ****/
+ 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 2: /* import record */
+ s = symtabFind(symtab, r->i.label);
+ if (s == NULL) {
+ /* Need to add support for dynamic linkage */
+ fprintf(stderr,"ldrdf: undefined symbol %s in module %s\n",
+ r->i.label,mod->name);
+ errors = 1;
+ }
+ else
+ {
+ *colln(&imports,r->i.segment - 2) = s;
+ if (verbose >= 2)
+ printf("imported %s as %04x\n", r->i.label, r->i.segment);
+ }
+ break;
+
+ case 3: /* export; dump to output new version */
+ s = symtabFind(symtab, r->e.label);
+ if (! s) continue; /* eh? probably doesn't matter... */
+
+ r->e.offset = s->offset;
+ rdfaddheader(newheader,r);
+ break;
+
+ case 4: /* DLL record */
+ rdfaddheader(newheader,r); /* copy straight to output */
+ break;
+ }
+ }
+ collection_reset(&imports);
+ }
+}
+
+/* write_output() write linked program out to a file */
+
+void write_output(char *filename)
+{
+ FILE * fp;
+ rdfheaderrec r;
+
+ fp = fopen(filename,"wb");
+ if (! fp)
+ {
+ fprintf(stderr,"ldrdf: could not open '%s' for writing\n",filename);
+ exit(1);
+ }
+
+
+ /* add BSS length count to header... */
+ if (bsslength)
+ {
+ r.type = 5;
+ r.b.amount = bsslength;
+ rdfaddheader(newheader,&r);
+ }
+
+ /* Write header */
+ rdfwriteheader(fp,newheader);
+ rdfdoneheader(newheader);
+ newheader = NULL;
+
+ /* Write text */
+ if (fwrite(&textlength,1,4,fp) != 4
+ || fwrite(text,1,textlength,fp) !=textlength)
+ {
+ fprintf(stderr,"ldrdf: error writing %s\n",filename);
+ exit(1);
+ }
+
+ /* Write data */
+ if (fwrite(&datalength,1,4,fp) != 4 ||
+ fwrite(data,1,datalength,fp) != datalength)
+ {
+ fprintf (stderr,"ldrdf: error writing %s\n", filename);
+ exit(1);
+ }
+ fclose(fp);
+}
+
+
+/* main program: interpret command line, and pass parameters on to
+ * individual module loaders & the linker
+ *
+ * Command line format:
+ * ldrdf [-o outfile | -x] [-r xxxx] [-v] [--] infile [infile ...]
+ *
+ * Default action is to output a file named 'aout.rdx'. -x specifies
+ * that the linked object program should be executed, rather than
+ * written to a file. -r specifies that the object program should
+ * be prelocated at address 'xxxx'. This option cannot be used
+ * in conjunction with -x.
+ */
+
+const char *usagemsg = "usage:\n"
+" ldrdf [-o outfile | -x] [-a x] [-v] [-p x] [--] infile [infile ...]\n\n"
+" ldrdf -h displays this message\n"
+" ldrdf -r displays version information\n\n"
+" -o selects output filename (default is aout.rdx)\n"
+" -x causes ldrdx to link & execute rather than write to file\n"
+" -a x causes object program to be statically relocated to address 'x'\n"
+" -v turns on verbose mode\n"
+" -p x causes segments to be aligned (padded) to x byte boundaries\n"
+" (default is 16 bytes)\n";
+
+void usage(void)
+{
+ fputs(usagemsg,stderr);
+}
+
+int main(int argc,char **argv)
+{
+ char *ofilename = "aout.rdx";
+ long relocateaddr = -1; /* -1 if no relocation is to occur */
+ int execute = 0; /* 1 to execute after linking, 0 otherwise */
+ int procsw = 1; /* set to 0 by '--' */
+ int tmp;
+
+ if (argc == 1) {
+ usage();
+ exit(1);
+ }
+
+ /* process command line switches, and add modules specified to linked list
+ of modules, keeping track of total memory required to load them */
+
+ while(argv++,--argc) {
+ if (procsw && !strcmp(*argv,"-h")) { /* Help command */
+ usage(); exit(1);
+ }
+ else if (procsw && !strcmp(*argv,"-r")) {
+ printf("ldrdf version %s (%s) (%s)\n",LDRDF_VERSION,_RDOFF_H,
+ sizeof(int) == 2 ? "16 bit" : "32 bit");
+ exit(1);
+ }
+ else if (procsw && !strcmp(*argv,"-o")) {
+ ofilename = *++argv;
+ --argc;
+ if (execute) {
+ fprintf(stderr,"ldrdf: -o and -x switches incompatible\n");
+ exit(1);
+ }
+ if (verbose > 1) printf("output filename set to '%s'\n",ofilename);
+ }
+ else if (procsw && !strcmp(*argv,"-x")) {
+ execute++;
+ if (verbose > 1) printf("will execute linked object\n");
+ }
+ else if (procsw && !strcmp(*argv,"-a")) {
+ relocateaddr = readnum(*++argv,&tmp);
+ --argc;
+ if (tmp) {
+ fprintf(stderr,"ldrdf: error in parameter to '-a' switch: '%s'\n",
+ *argv);
+ exit(1);
+ }
+ if (execute) {
+ fprintf(stderr,"ldrdf: -a and -x switches incompatible\n");
+ exit(1);
+ }
+ if (verbose) printf("will relocate to %08lx\n",relocateaddr);
+ }
+ else if (procsw && !strcmp(*argv,"-v")) {
+ verbose++;
+ if (verbose == 1) printf("verbose mode selected\n");
+ }
+ else if (procsw && !strcmp(*argv,"-p")) {
+ align = readnum(*++argv,&tmp);
+ --argc;
+ if (tmp) {
+ fprintf(stderr,"ldrdf: error in parameter to '-p' switch: '%s'\n",
+ *argv);
+ exit(1);
+ }
+ if (align != 1 && align != 2 && align != 4 && align != 8 && align != 16
+ && align != 32 && align != 256) {
+ fprintf(stderr,"ldrdf: %d is an invalid alignment factor - must be"
+ "1,2,4,8,16 or 256\n",align);
+ exit(1);
+ }
+ if (verbose > 1) printf("alignment %d selected\n",align);
+ }
+ else if (procsw && !strcmp(*argv,"--")) {
+ procsw = 0;
+ }
+ else { /* is a filename */
+ if (verbose > 1) printf("processing module %s\n",*argv);
+ loadmodule(*argv);
+ }
+ }
+
+ /* we should be scanning for unresolved references, and removing
+ unreferenced modules from the list of modules here, so that
+ we know about the final size once libraries have been linked in */
+
+ load_segments(); /* having calculated size of reqd segments, load
+ each rdoff module's segments into memory */
+
+ build_symbols(); /* build a global symbol table...
+ perhaps this should be done before load_segs? */
+
+ link_segments(); /* step through each module's header, and resolve
+ references to the global symbol table.
+ This also does local address fixups. */
+
+ if (errors) {
+ fprintf(stderr,"ldrdf: there were errors - aborted\n");
+ exit(errors);
+ }
+ if (execute) {
+ fprintf(stderr,"ldrdf: module execution not yet supported\n");
+ exit(1);
+ }
+ if (relocateaddr != -1) {
+ fprintf(stderr,"ldrdf: static relocation not yet supported\n");
+ exit(1);
+ }
+
+ write_output(ofilename);
+ return 0;
+}
diff --git a/rdoff/rdf.doc b/rdoff/rdf.doc
new file mode 100644
index 00000000..300c2bc5
--- /dev/null
+++ b/rdoff/rdf.doc
@@ -0,0 +1,99 @@
+RDOFF: Relocatable Dynamically-linked Object File Format
+========================================================
+
+RDOFF was designed initially to test the object-file production
+interface to NASM. It soon became apparent that it could be enhanced
+for use in serious applications due to its simplicity; code to load
+and execute an RDOFF object module is very simple. It also contains
+enhancements to allow it to be linked with a dynamic link library at
+either run- or load- time, depending on how complex you wish to make
+your loader.
+
+The RDOFF format (version 1.1, as produced by NASM v0.91) is defined
+as follows:
+
+The first six bytes of the file contain the string 'RDOFF1'. Other
+versions of the format may contain other last characters other than
+'1' - all little endian versions of the file will always contain an
+ASCII character with value greater than 32. If RDOFF is used on a
+big-endian machine at some point in the future, the version will be
+encoded in decimal rather than ASCII, so will be below 32.
+
+All multi-byte fields follwing this are encoded in either little- or
+big-endian format depending on the system described by this version
+information. Object files should be encoded in the endianness of
+their target machine; files of incorrect endianness will be rejected
+by the loader - this means that loaders do not need to convert
+endianness, as RDOFF has been designed with simplicity of loading at
+the forefront of the design requirements.
+
+The next 4 byte field is the length of the header in bytes. The
+header consists of a sequence of variable length records. Each
+record's type is identified by the first byte of the record. Record
+types 1-4 are currently supported. Record type 5 will be added in
+the near future, when I implement BSS segments. Record type 6 may be
+to do with debugging, when I get debugging implemented.
+
+Type 1: Relocation
+==================
+
+Offset Length Description
+0 1 Type (contains 1)
+1 1 Segment that contains reference (0 = text, 1 = data)
+ Add 64 to this number to indicate a relative linkage
+ to an external symbol (see notes)
+2 4 Offset of reference
+6 1 Length of reference (1,2 or 4 bytes)
+7 2 Segment to which reference is made (0 = text, 1 =
+ data, 2 = BSS [when implemented]) others are external
+ symbols.
+
+Total length = 9 bytes
+
+Type 2: Symbol Import
+=====================
+
+0 1 Type (2)
+1 2 Segment number that will be used in references to this
+ symbol.
+3 ? Null terminated string containing label (up to 32
+ chars) to match against exports in linkage.
+
+Type 3: Symbol Export
+=====================
+
+0 1 Type (3)
+1 1 Segment containing object to be exported (0/1/2)
+2 4 Offset within segment
+6 ? Null terminate string containing label to export (32
+ char maximum length)
+
+Type 4: Dynamic Link Library
+============================
+
+0 1 Type (4)
+1 ? Library name (up to 128 chars)
+
+Type 5: Reserve BSS
+===================
+
+0 1 Type (5)
+1 4 Amount of BSS space to reserve in bytes
+
+Total length: 5 bytes
+
+-----------------------------------------------------------------------------
+
+Following the header is the text (code) segment. This is preceded by
+a 4-byte integer, which is its length in bytes. This is followed by
+the length of the data segment (also 4 bytes), and finally the data
+segment.
+
+Notes
+=====
+
+Relative linking: The number stored at the address is offset
+required from the imported symbol, with the address of the end of
+the instruction subtracted from it. This means that the linker can
+simply add the address of the label relative to the beginning of the
+current segment to it.
diff --git a/rdoff/rdfdump.c b/rdoff/rdfdump.c
new file mode 100644
index 00000000..4d4f4df5
--- /dev/null
+++ b/rdoff/rdfdump.c
@@ -0,0 +1,156 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+FILE *infile;
+
+long translatelong(long in) { /* translate from little endian to
+ local representation */
+ long r;
+ unsigned char *i;
+
+ i = (unsigned char *)&in;
+ r = i[3];
+ r = (r << 8) + i[2];
+ r = (r << 8) + i[1];
+ r = (r << 8) + *i;
+
+ return r;
+}
+
+int translateshort(short in) {
+ int r;
+ unsigned char *i;
+
+ i = (unsigned char *)&in;
+ r = (i[1] << 8) + *i;
+
+ return r;
+}
+void print_header(long length) {
+ unsigned char buf[129],t,s,l;
+ long o;
+ short rs;
+
+ while (length > 0) {
+ fread(&t,1,1,infile);
+ switch(t) {
+ case 1: /* relocation record */
+ fread(&s,1,1,infile);
+ fread(&o,4,1,infile);
+ fread(&l,1,1,infile);
+ fread(&rs,2,1,infile);
+ printf(" relocation: location (%04x:%08lx), length %d, "
+ "referred seg %04x\n",(int)s,translatelong(o),(int)l,
+ translateshort(rs));
+ length -= 9;
+ break;
+ case 2: /* import record */
+ fread(&rs,2,1,infile);
+ l = 0;
+ do {
+ fread(&buf[l],1,1,infile);
+ } while (buf[l++]);
+ printf(" import: segment %04x = %s\n",translateshort(rs),buf);
+ length -= l + 3;
+ break;
+ case 3: /* export record */
+ fread(&s,1,1,infile);
+ fread(&o,4,1,infile);
+ l = 0;
+ do {
+ fread(&buf[l],1,1,infile);
+ } while (buf[l++]);
+ printf(" export: (%04x:%08lx) = %s\n",(int)s,translatelong(o),buf);
+ length -= l + 6;
+ break;
+ case 4: /* DLL record */
+ l = 0;
+ do {
+ fread(&buf[l],1,1,infile);
+ } while (buf[l++]);
+ printf(" dll: %s\n",buf);
+ length -= l + 1;
+ break;
+ case 5: /* BSS reservation */
+ fread(&l,4,1,infile);
+ printf(" bss reservation: %08lx bytes\n",translatelong(l));
+ length -= 5;
+ break;
+ default:
+ printf(" unrecognised record (type %d)\n",(int)t);
+ length --;
+ }
+ }
+}
+
+int main(int argc,char **argv) {
+ char id[7];
+ long l;
+ int verbose = 0;
+
+ puts("RDOFF Dump utility v1.1 (C) Copyright 1996 Julian R Hall");
+
+ if (argc < 2) {
+ fputs("Usage: rdfdump [-v] <filename>\n",stderr);
+ exit(1);
+ }
+
+ if (! strcmp (argv[1], "-v") )
+ {
+ verbose = 1;
+ if (argc < 3)
+ {
+ fputs("required parameter missing\n",stderr);
+ exit(1);
+ }
+ argv++;
+ }
+
+ infile = fopen(argv[1],"rb");
+ if (! infile) {
+ fprintf(stderr,"rdfdump: Could not open %s",argv[1]);
+ exit(1);
+ }
+
+ fread(id,6,1,infile);
+ if (strncmp(id,"RDOFF",5)) {
+ fputs("rdfdump: File does not contain valid RDOFF header\n",stderr);
+ exit(1);
+ }
+
+ printf("File %s: RDOFF version %c\n\n",argv[1],id[5]);
+ if (id[5] < '1' || id[5] > '1') {
+ fprintf(stderr,"rdfdump: unknown RDOFF version '%c'\n",id[5]);
+ exit(1);
+ }
+
+ fread(&l,4,1,infile);
+ l = translatelong(l);
+ printf("Header (%ld bytes):\n",l);
+ print_header(l);
+
+ fread(&l,4,1,infile);
+ l = translatelong(l);
+ printf("\nText segment length = %ld bytes\n",l);
+ while(l--) {
+ fread(id,1,1,infile);
+ if (verbose) printf(" %02x",(int) (unsigned char)id[0]);
+ }
+ if (verbose) printf("\n\n");
+
+ fread(&l,4,1,infile);
+ l = translatelong(l);
+ printf("Data segment length = %ld bytes\n",l);
+
+ if (verbose)
+ {
+ while (l--) {
+ fread(id,1,1,infile);
+ printf(" %02x",(int) (unsigned char) id[0]);
+ }
+ printf("\n");
+ }
+ fclose(infile);
+ return 0;
+}
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;
+}
diff --git a/rdoff/rdfload.h b/rdoff/rdfload.h
new file mode 100644
index 00000000..5e264b93
--- /dev/null
+++ b/rdoff/rdfload.h
@@ -0,0 +1,29 @@
+/* rdfload.h RDOFF Object File loader library header file
+ *
+ * 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.
+ *
+ * See the file 'rdfload.c' for special license information for this
+ * file.
+ */
+
+#ifndef _RDFLOAD_H
+#define _RDFLOAD_H
+
+#include "rdoff.h"
+
+typedef struct RDFModuleStruct {
+ rdffile f; /* file structure */
+ unsigned char * t, * d, * b; /* text, data, and bss segments */
+ long textrel;
+ long datarel;
+ long bssrel;
+ void * symtab;
+} rdfmodule;
+
+rdfmodule * rdfload(const char * filename);
+int rdf_relocate(rdfmodule * m);
+
+#endif
diff --git a/rdoff/rdoff.c b/rdoff/rdoff.c
new file mode 100644
index 00000000..9a969ad0
--- /dev/null
+++ b/rdoff/rdoff.c
@@ -0,0 +1,367 @@
+/* rdoff.c library of routines for manipulating rdoff files
+ *
+ * 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.
+ */
+
+/* TODO: The functions in this module assume they are running
+ * on a little-endian machine. This should be fixed to
+ * make it portable.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rdoff.h"
+
+/* ========================================================================
+ * Code for memory buffers (for delayed writing of header until we know
+ * how long it is).
+ * ======================================================================== */
+
+
+memorybuffer * newmembuf(){
+ memorybuffer * t;
+
+ t = malloc(sizeof(memorybuffer));
+
+ t->length = 0;
+ t->next = NULL;
+ return t;
+}
+
+void membufwrite(memorybuffer *b, void *data, int bytes) {
+ int16 w;
+ long l;
+
+ if (b->next) { /* memory buffer full - use next buffer */
+ membufwrite(b->next,data,bytes);
+ return;
+ }
+ if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
+ || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
+
+ /* buffer full and no next allocated... allocate and initialise next
+ * buffer */
+
+ b->next = newmembuf();
+ membufwrite(b->next,data,bytes);
+ }
+
+ switch(bytes) {
+ case -4: /* convert to little-endian */
+ l = * (long *) data ;
+ b->buffer[b->length++] = l & 0xFF;
+ l >>= 8 ;
+ b->buffer[b->length++] = l & 0xFF;
+ l >>= 8 ;
+ b->buffer[b->length++] = l & 0xFF;
+ l >>= 8 ;
+ b->buffer[b->length++] = l & 0xFF;
+ break;
+
+ case -2:
+ w = * (int16 *) data ;
+ b->buffer[b->length++] = w & 0xFF;
+ w >>= 8 ;
+ b->buffer[b->length++] = w & 0xFF;
+ break;
+
+ default:
+ while(bytes--) {
+ b->buffer[b->length++] = *(* (unsigned char **) &data);
+
+ (* (unsigned char **) &data)++ ;
+ }
+ break;
+ }
+}
+
+void membufdump(memorybuffer *b,FILE *fp)
+{
+ if (!b) return;
+
+ fwrite (b->buffer, 1, b->length, fp);
+
+ membufdump(b->next,fp);
+}
+
+int membuflength(memorybuffer *b)
+{
+ if (!b) return 0;
+ return b->length + membuflength(b->next);
+}
+
+void freemembuf(memorybuffer *b)
+{
+ if (!b) return;
+ freemembuf(b->next);
+ free(b);
+}
+
+/* =========================================================================
+ General purpose routines and variables used by the library functions
+ ========================================================================= */
+
+long translatelong(long in) { /* translate from little endian to
+ local representation */
+ long r;
+ unsigned char *i;
+
+ i = (unsigned char *)&in;
+ r = i[3];
+ r = (r << 8) + i[2];
+ r = (r << 8) + i[1];
+ r = (r << 8) + *i;
+
+ return r;
+}
+
+const char *RDOFFId = "RDOFF1"; /* written to the start of RDOFF files */
+
+const char *rdf_errors[7] = {
+ "no error occurred","could not open file","invalid file format",
+ "error reading file","unknown error","header not read",
+ "out of memory"};
+
+int rdf_errno = 0;
+
+/* ========================================================================
+ The library functions
+ ======================================================================== */
+
+int rdfopen(rdffile *f, const char *name)
+{
+ char buf[8];
+
+ if (translatelong(0x01020304) != 0x01020304)
+ { /* fix this to be portable! */
+ fputs("*** this program requires a little endian machine\n",stderr);
+ fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304));
+ exit(3);
+ }
+
+
+ f->fp = fopen(name,"rb");
+ if (!f->fp) return rdf_errno = 1; /* error 1: file open error */
+
+ fread(buf,6,1,f->fp); /* read header */
+ buf[6] = 0;
+
+ if (strcmp(buf,RDOFFId)) {
+ fclose(f->fp);
+ return rdf_errno = 2; /* error 2: invalid file format */
+ }
+
+ if (fread(&f->header_len,1,4,f->fp) != 4) {
+ fclose(f->fp);
+ return rdf_errno = 3; /* error 3: file read error */
+ }
+
+ if (fseek(f->fp,f->header_len,SEEK_CUR)) {
+ fclose(f->fp);
+ return rdf_errno = 2; /* seek past end of file...? */
+ }
+
+ if (fread(&f->code_len,1,4,f->fp) != 4) {
+ fclose(f->fp);
+ return rdf_errno = 3;
+ }
+
+ f->code_ofs = ftell(f->fp);
+ if (fseek(f->fp,f->code_len,SEEK_CUR)) {
+ fclose(f->fp);
+ return rdf_errno = 2;
+ }
+
+ if (fread(&f->data_len,1,4,f->fp) != 4) {
+ fclose(f->fp);
+ return rdf_errno = 3;
+ }
+
+ f->data_ofs = ftell(f->fp);
+ rewind(f->fp);
+ f->header_loc = NULL;
+ return 0;
+}
+
+int rdfclose(rdffile *f)
+{
+ fclose(f->fp);
+ return 0;
+}
+
+void rdfperror(const char *app,const char *name)
+{
+ fprintf(stderr,"%s:%s: %s\n",app,name,rdf_errors[rdf_errno]);
+}
+
+int rdfloadseg(rdffile *f,int segment,void *buffer)
+{
+ long fpos;
+ long slen;
+
+ switch(segment) {
+ case RDOFF_HEADER:
+ fpos = 10;
+ slen = f->header_len;
+ f->header_loc = (char *)buffer;
+ f->header_fp = 0;
+ break;
+ case RDOFF_CODE:
+ fpos = f->code_ofs;
+ slen = f->code_len;
+ break;
+ case RDOFF_DATA:
+ fpos = f->data_ofs;
+ slen = f->data_len;
+ break;
+ default:
+ fpos = 0;
+ slen = 0;
+ }
+
+ if (fseek(f->fp,fpos,SEEK_SET))
+ return rdf_errno = 4;
+
+ if (fread(buffer,1,slen,f->fp) != slen)
+ return rdf_errno = 3;
+
+ return 0;
+}
+
+/* Macros for reading integers from header in memory */
+
+#define RI8(v) v = f->header_loc[f->header_fp++]
+#define RI16(v) { v = (f->header_loc[f->header_fp] + \
+ (f->header_loc[f->header_fp+1] << 8)); \
+ f->header_fp += 2; }
+
+#define RI32(v) { v = (f->header_loc[f->header_fp] + \
+ (f->header_loc[f->header_fp+1] << 8) + \
+ (f->header_loc[f->header_fp+2] << 16) + \
+ (f->header_loc[f->header_fp+3] << 24)); \
+ f->header_fp += 4; }
+
+#define RS(str,max) { for(i=0;i<max;i++){\
+ RI8(str[i]); if (!str[i]) break;} str[i]=0; }
+
+rdfheaderrec *rdfgetheaderrec(rdffile *f)
+{
+ static rdfheaderrec r;
+ int i;
+
+ if (!f->header_loc) {
+ rdf_errno = 5;
+ return NULL;
+ }
+
+ if (f->header_fp >= f->header_len) return 0;
+
+ RI8(r.type);
+ switch(r.type) {
+ case 1: /* Relocation record */
+ RI8(r.r.segment);
+ RI32(r.r.offset);
+ RI8(r.r.length);
+ RI16(r.r.refseg);
+ break;
+
+ case 2: /* Imported symbol record */
+ RI16(r.i.segment);
+ RS(r.i.label,32);
+ break;
+
+ case 3: /* Exported symbol record */
+ RI8(r.e.segment);
+ RI32(r.e.offset);
+ RS(r.e.label,32);
+ break;
+
+ case 4: /* DLL record */
+ RS(r.d.libname,127);
+ break;
+
+ case 5: /* BSS reservation record */
+ RI32(r.b.amount);
+ break;
+
+ default:
+ rdf_errno = 2; /* invalid file */
+ return NULL;
+ }
+ return &r;
+}
+
+void rdfheaderrewind(rdffile *f)
+{
+ f->header_fp = 0;
+}
+
+
+rdf_headerbuf * rdfnewheader(void)
+{
+ return newmembuf();
+}
+
+int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
+{
+ switch (r->type)
+ {
+ case 1:
+ membufwrite(h,&r->type,1);
+ membufwrite(h,&r->r.segment,1);
+ membufwrite(h,&r->r.offset,-4);
+ membufwrite(h,&r->r.length,1);
+ membufwrite(h,&r->r.refseg,-2); /* 9 bytes written */
+ break;
+
+ case 2: /* import */
+ membufwrite(h,&r->type,1);
+ membufwrite(h,&r->i.segment,-2);
+ membufwrite(h,&r->i.label,strlen(r->i.label) + 1);
+ break ;
+
+ case 3: /* export */
+ membufwrite(h,&r->type,1);
+ membufwrite(h,&r->e.segment,1);
+ membufwrite(h,&r->e.offset,-4);
+ membufwrite(h,&r->e.label,strlen(r->e.label) + 1);
+ break ;
+
+ case 4: /* DLL */
+ membufwrite(h,&r->type,1);
+ membufwrite(h,&r->d.libname,strlen(r->d.libname) + 1);
+ break ;
+
+ case 5: /* BSS */
+ membufwrite(h,&r->type,1);
+ membufwrite(h,&r->b.amount,-4);
+ break ;
+
+ default:
+ return (rdf_errno = 2);
+ }
+ return 0;
+}
+
+int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
+{
+ long l;
+
+ fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ;
+
+ l = translatelong ( membuflength (h) );
+ fwrite (&l, 4, 1, fp);
+
+ membufdump(h, fp);
+
+ return 0; /* no error handling in here... CHANGE THIS! */
+}
+
+void rdfdoneheader(rdf_headerbuf * h)
+{
+ freemembuf(h);
+}
diff --git a/rdoff/rdoff.h b/rdoff/rdoff.h
new file mode 100644
index 00000000..b022400b
--- /dev/null
+++ b/rdoff/rdoff.h
@@ -0,0 +1,112 @@
+/* rdoff.h RDOFF Object File manipulation routines header file
+ *
+ * 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.
+ */
+
+#ifndef _RDOFF_H
+#define _RDOFF_H "RDOFF1 support routines v0.1"
+
+typedef short int16; /* not sure if this will be required to be altered
+ at all... best to typedef it just in case */
+
+/* the records that can be found in the RDOFF header */
+
+struct RelocRec {
+ char type; /* must be 1 */
+ char segment; /* only 0 for code, or 1 for data supported,
+ but add 64 for relative refs (ie do not require
+ reloc @ loadtime, only linkage) */
+ long offset; /* from start of segment in which reference is loc'd */
+ char length; /* 1 2 or 4 bytes */
+ int16 refseg; /* segment to which reference refers to */
+};
+
+struct ImportRec {
+ char type; /* must be 2 */
+ int16 segment; /* segment number allocated to the label for reloc
+ records - label is assumed to be at offset zero
+ in this segment, so linker must fix up with offset
+ of segment and of offset within segment */
+ char label[33]; /* zero terminated... should be written to file until
+ the zero, but not after it - max len = 32 chars */
+};
+
+struct ExportRec {
+ char type; /* must be 3 */
+ char segment; /* segment referred to (0/1) */
+ long offset; /* offset within segment */
+ char label[33]; /* zero terminated as above. max len = 32 chars */
+};
+
+struct DLLRec {
+ char type; /* must be 4 */
+ char libname[128]; /* name of library to link with at load time */
+};
+
+struct BSSRec {
+ char type; /* must be 5 */
+ long amount; /* number of bytes BSS to reserve */
+};
+
+typedef union RDFHeaderRec {
+ char type; /* invariant throughout all below */
+ struct RelocRec r; /* type == 1 */
+ struct ImportRec i; /* type == 2 */
+ struct ExportRec e; /* type == 3 */
+ struct DLLRec d; /* type == 4 */
+ struct BSSRec b; /* type == 5 */
+} rdfheaderrec;
+
+typedef struct RDFFileInfo {
+ FILE *fp; /* file descriptor; must be open to use this struct */
+ int rdoff_ver; /* should be 1; any higher => not guaranteed to work */
+ long header_len;
+ long code_len;
+ long data_len;
+ long code_ofs;
+ long data_ofs;
+ char *header_loc; /* keep location of header */
+ long header_fp; /* current location within header for reading */
+} rdffile;
+
+#define BUF_BLOCK_LEN 4088 /* selected to match page size (4096)
+ * on 80x86 machines for efficiency */
+typedef struct memorybuffer {
+ int length;
+ char buffer[BUF_BLOCK_LEN];
+ struct memorybuffer *next;
+} memorybuffer;
+
+typedef memorybuffer rdf_headerbuf;
+
+/* segments used by RDOFF, understood by rdoffloadseg */
+#define RDOFF_CODE 0
+#define RDOFF_DATA 1
+#define RDOFF_HEADER -1
+/* mask for 'segment' in relocation records to find if relative relocation */
+#define RDOFF_RELATIVEMASK 64
+/* mask to find actual segment value in relocation records */
+#define RDOFF_SEGMENTMASK 63
+
+/* RDOFF file manipulation functions */
+int rdfopen(rdffile *f,const char *name);
+int rdfclose(rdffile *f);
+int rdfloadseg(rdffile *f,int segment,void *buffer);
+rdfheaderrec *rdfgetheaderrec(rdffile *f); /* returns static storage */
+void rdfheaderrewind(rdffile *f); /* back to start of header */
+void rdfperror(const char *app,const char *name);
+
+/* functions to write a new RDOFF header to a file -
+ use rdfnewheader to allocate a header, rdfaddheader to add records to it,
+ rdfwriteheader to write 'RDOFF1', length of header, and the header itself
+ to a file, and then rdfdoneheader to dispose of the header */
+
+rdf_headerbuf *rdfnewheader(void);
+int rdfaddheader(rdf_headerbuf *h,rdfheaderrec *r);
+int rdfwriteheader(FILE *fp,rdf_headerbuf *h);
+void rdfdoneheader(rdf_headerbuf *h);
+
+#endif /* _RDOFF_H */
diff --git a/rdoff/rdx.c b/rdoff/rdx.c
new file mode 100644
index 00000000..28ffc427
--- /dev/null
+++ b/rdoff/rdx.c
@@ -0,0 +1,61 @@
+/* rdx.c RDOFF Object File loader program
+ *
+ * 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.
+ */
+
+/* note: most of the actual work of this program is done by the modules
+ "rdfload.c", which loads and relocates the object file, and by "rdoff.c",
+ which contains general purpose routines to manipulate RDOFF object
+ files. You can use these files in your own program to load RDOFF objects
+ and execute the code in them in a similar way to what is shown here. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rdfload.h"
+#include "rdoff.h"
+#include "symtab.h"
+
+typedef int (*main_fn) (int,char**); /* Main function prototype */
+
+int main(int argc, char **argv)
+{
+ rdfmodule * m;
+ main_fn code;
+ symtabEnt * s;
+
+ if (argc < 2)
+ {
+ puts("usage: rdf <rdoff-executable> [params]\n");
+ exit(255);
+ }
+
+ m = rdfload(argv[1]);
+
+ if (! m)
+ {
+ rdfperror("rdf",argv[1]);
+ exit(255);
+ }
+
+ rdf_relocate(m); /* in this instance, the default relocation
+ values will work fine, but they may need changing
+ in other cases... */
+
+ s = symtabFind(m->symtab, "_main");
+ if (! s)
+ {
+ fprintf(stderr,"rdx: could not find symbol '_main' in '%s'\n",argv[1]);
+ exit(255);
+ }
+
+ code = (main_fn) s->offset;
+
+ argv++, argc--; /* remove 'rdx' from command line */
+
+ return code(argc,argv); /* execute */
+}
+
diff --git a/rdoff/symtab.c b/rdoff/symtab.c
new file mode 100644
index 00000000..c0ff3e56
--- /dev/null
+++ b/rdoff/symtab.c
@@ -0,0 +1,80 @@
+/* symtab.c Routines to maintain and manipulate a symbol table
+ *
+ * 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.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "symtab.h"
+
+/* TODO: Implement a hash table, not this stupid implementation which
+ is too slow to be of practical use */
+
+/* Private data types */
+
+typedef struct tagSymtab {
+ symtabEnt ent;
+ struct tagSymtab * next;
+} symtabList;
+
+typedef symtabList * _symtab;
+
+void *symtabNew(void)
+{
+ void *p = malloc(sizeof(_symtab));
+ if (p == NULL) {
+ fprintf(stderr,"symtab: out of memory\n");
+ exit(3);
+ }
+ *(_symtab *)p = NULL;
+
+ return p;
+}
+
+void symtabDone(void *symtab)
+{
+ /* DO SOMETHING HERE! */
+}
+
+void symtabInsert(void *symtab,symtabEnt *ent)
+{
+ symtabList *l = malloc(sizeof(symtabList));
+
+ if (l == NULL) {
+ fprintf(stderr,"symtab: out of memory\n");
+ exit(3);
+ }
+
+ l->ent = *ent;
+ l->next = *(_symtab *)symtab;
+ *(_symtab *)symtab = l;
+}
+
+symtabEnt *symtabFind(void *symtab,char *name)
+{
+ symtabList *l = *(_symtab *)symtab;
+
+ while (l) {
+ if (!strcmp(l->ent.name,name)) {
+ return &(l->ent);
+ }
+ l = l->next;
+ }
+ return NULL;
+}
+
+void symtabDump(void *symtab,FILE *of)
+{
+ symtabList *l = *(_symtab *)symtab;
+
+ while(l) {
+ fprintf(of,"%32s %s:%08lx (%ld)\n",l->ent.name,
+ l->ent.segment ? "data" : "code" ,
+ l->ent.offset, l->ent.flags);
+ l = l->next;
+ }
+}
+
diff --git a/rdoff/symtab.h b/rdoff/symtab.h
new file mode 100644
index 00000000..5780d447
--- /dev/null
+++ b/rdoff/symtab.h
@@ -0,0 +1,22 @@
+/* symtab.h Header file for symbol table manipulation routines
+ *
+ * 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.
+ */
+
+typedef struct {
+ char *name;
+ long segment;
+ long offset;
+ long flags;
+} symtabEnt;
+
+void *symtabNew(void);
+void symtabDone(void *symtab);
+void symtabInsert(void *symtab,symtabEnt *ent);
+symtabEnt *symtabFind(void *symtab,char *name);
+void symtabDump(void *symtab,FILE *of);
+
+