diff options
author | H. Peter Anvin <hpa@zytor.com> | 2002-04-30 20:52:08 +0000 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2002-04-30 20:52:08 +0000 |
commit | d7ed89eac9580f280fe0017b22c8e38ca75ed8e3 (patch) | |
tree | 98c4fcdd286b44e14f79aa65271e5caa1c2c7be4 /rdoff | |
parent | ea8382740dbe5e1607742d0a7c7c139dffcc5ae5 (diff) | |
download | nasm-d7ed89eac9580f280fe0017b22c8e38ca75ed8e3.tar.gz nasm-d7ed89eac9580f280fe0017b22c8e38ca75ed8e3.tar.bz2 nasm-d7ed89eac9580f280fe0017b22c8e38ca75ed8e3.zip |
NASM 0.94
Diffstat (limited to 'rdoff')
-rw-r--r-- | rdoff/Makefile | 26 | ||||
-rw-r--r-- | rdoff/README | 85 | ||||
-rw-r--r-- | rdoff/collectn.h | 2 | ||||
-rw-r--r-- | rdoff/ldrdf.c | 362 | ||||
-rw-r--r-- | rdoff/rdf.doc | 99 | ||||
-rw-r--r-- | rdoff/rdf2bin.c | 125 | ||||
-rw-r--r-- | rdoff/rdfdump.c | 32 | ||||
-rw-r--r-- | rdoff/rdflib.c | 235 | ||||
-rw-r--r-- | rdoff/rdfload.c | 12 | ||||
-rw-r--r-- | rdoff/rdlib.c | 88 | ||||
-rw-r--r-- | rdoff/rdlib.h | 18 | ||||
-rw-r--r-- | rdoff/rdoff.c | 52 | ||||
-rw-r--r-- | rdoff/rdoff.h | 8 | ||||
-rw-r--r-- | rdoff/rdoff.txt | 114 | ||||
-rw-r--r-- | rdoff/symtab.c | 2 |
15 files changed, 1029 insertions, 231 deletions
diff --git a/rdoff/Makefile b/rdoff/Makefile index 2e55dde..78eca4e 100644 --- a/rdoff/Makefile +++ b/rdoff/Makefile @@ -9,19 +9,19 @@ # portably). CC = gcc -CCFLAGS = -c -O -g -Wall -ansi -pedantic -I.. +CCFLAGS = -c -g -Wall -ansi -pedantic -I.. LINK = gcc -LINKFLAGS = -o +LINKFLAGS = -g -o DLINKFLAGS = -o -LIBRARIES = +LIBRARIES = STRIP = strip -LDRDFLIBS = rdoff.o ../nasmlib.o symtab.o collectn.o +LDRDFLIBS = rdoff.o ../nasmlib.o symtab.o collectn.o rdlib.o RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o .c.o: $(CC) $(CCFLAGS) $*.c -all : rdfdump ldrdf rdx +all : rdfdump ldrdf rdx rdflib rdf2bin rdf2com rdfdump : rdfdump.o $(LINK) $(LINKFLAGS) rdfdump rdfdump.o @@ -29,15 +29,25 @@ ldrdf : ldrdf.o $(LDRDFLIBS) $(LINK) $(LINKFLAGS) ldrdf ldrdf.o $(LDRDFLIBS) rdx : rdx.o $(RDXLIBS) $(LINK) $(LINKFLAGS) rdx rdx.o $(RDXLIBS) +rdflib : rdflib.o + $(LINK) $(LINKFLAGS) rdflib rdflib.o +rdf2bin : rdf2bin.o $(RDXLIBS) ../nasmlib.o + $(LINK) $(LINKFLAGS) rdf2bin rdf2bin.o $(RDXLIBS) ../nasmlib.o +rdf2com : + ln -s rdf2bin rdf2com +rdf2bin.o : rdf2bin.c rdfdump.o : rdfdump.c rdoff.o : rdoff.c rdoff.h -ldrdf.o : ldrdf.c rdoff.h ../nasmlib.h symtab.h collectn.h +ldrdf.o : ldrdf.c rdoff.h ../nasmlib.h symtab.h collectn.h rdlib.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 +rdlib.o : rdlib.c rdlib.h +rdflib.o : rdflib.c clean : - rm -f *.o *~ rdfdump ldrdf rdx - make -C test clean + rm -f *.o *~ rdfdump ldrdf rdx rdflib rdf2bin + + diff --git a/rdoff/README b/rdoff/README new file mode 100644 index 0000000..54f3b2a --- /dev/null +++ b/rdoff/README @@ -0,0 +1,85 @@ +RDOFF Utils v0.2 +================ + +The files contained in this directory are the C source code of a set +of tools (and general purpose library files) for the manipulation of +RDOFF version 1 object files. Here is a brief summary of their usage: + +rdfdump +======= + +This tool prints a list of the header records in an RDOFF object in +human-readable form, and optionally prints a hex dump of the contents +of the code and data segments. + +Usage: + rdfdump [-v] filename + +The -v flag specifies that the hex dump (see above) should be printed. + +ldrdf +===== + +This tool is a version of unix 'ld' (or DOS 'link') for use with RDOFF +files. It is capable of linking RDOFF objects, and libraries produced +with the 'rdlib' utility discussed below. + +In normal usage, its command line takes the form: + + ldrdf [-o output-file] object files [-llibrary ...] + +Libraries must be specified with their path as no search is performed. +Modules in libraries are not linked to the program unless they are +referred to. + +Most of its options are not implemented, but those that are are listed here: + + -v increase verbosity level. Currently 4 verbosity levels are + available: default (which only prints error information), normal + (which prints information about the produced object, -v), medium + (which prints information about what the program is doing, -v -v) + and high (which prints all available information, -v -v -v). + + -p change alignment value to which multiple segments combigned into + a single segment should be aligned (must be either 1, 2, 4, 8, + 16, 32 or 256. Default is 16). + +The default output filename is 'aout.rdx'. + +rdx +=== + +This program simply loads and executes an RDOFF object, by calling +'_main', which it expects to be a C-style function, which will accept +two parameters, argc and argv in normal C style. + +rdflib +====== + +This program creates a library file for use with ldrdf. + +It is supplied with a shell script 'makelib' which should probably be used +to create libraries. + +Usage: + rdflib command library [optional arguments] + +Valid commands are: + + c Create the library + a Add a module (requires a filename and a name to give the + module, ie 'rdflib a libc.rdl strcpy.rdf strcpy' puts the + file 'strcpy.rdf' into 'libc.rdl', and calls it 'strcpy'. + x Extract (arguments are the opposite to the 'a' command, + ie you'd do 'rdflib x libc.rdl strcpy strcpy.rdf to get + a copy of strcpy.rdf back out again...) + +Remove and List commands will be added soon (they're already documented +as existing, but I haven't had time to implement them... if anyone +else wants to do this, they're welcome to. The file format should be +amply documented in the source code... look at 'rdflib.c' and 'rdlib.c', +and the relevant sections of 'ldrdf.c' to see how libraries can be +handled). + +Julian Hall (jules@dcs.warwick.ac.uk) + diff --git a/rdoff/collectn.h b/rdoff/collectn.h index b3f2d52..2dc786e 100644 --- a/rdoff/collectn.h +++ b/rdoff/collectn.h @@ -10,7 +10,7 @@ typedef struct tagCollection { void *p[32]; /* array of pointers to objects */ - + struct tagCollection *next; } Collection; diff --git a/rdoff/ldrdf.c b/rdoff/ldrdf.c index ce86b7e..e2541fa 100644 --- a/rdoff/ldrdf.c +++ b/rdoff/ldrdf.c @@ -11,21 +11,27 @@ * May require the system to make an extra pass of the modules to be * loaded eliminating those that aren't required. * + * Support all the existing documented options... + * * Support libaries (.a files - requires a 'ranlib' type utility) + * (I think I've got this working, so I've upped the version) * - * -s option to strip resolved symbols from exports. + * -s option to strip resolved symbols from exports. (Could make this an + * external utility) */ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "nasm.h" #include "rdoff.h" #include "nasmlib.h" #include "symtab.h" #include "collectn.h" +#include "rdlib.h" -#define LDRDF_VERSION "0.11" +#define LDRDF_VERSION "0.30" /* global variables - those to set options: */ @@ -46,8 +52,17 @@ struct modulenode { struct modulenode *next; }; +#define newstr(str) strcpy(malloc(strlen(str) + 1),str) +#define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2) + + struct modulenode *modules = NULL,*lastmodule = NULL; +/* the linked list of libraries to be searched for missing imported + symbols */ + +struct librarynode * libraries = NULL, * lastlib = NULL; + void *symtab; /* The symbol table */ rdf_headerbuf * newheader ; /* New header to be written to output */ @@ -101,6 +116,218 @@ void loadmodule(char *filename) lastmodule->coderel,lastmodule->f.code_len, lastmodule->datarel,lastmodule->f.data_len); + lastmodule->header = malloc(lastmodule->f.header_len); + if (!lastmodule->header) { + fprintf(stderr,"ldrdf: out of memory\n"); + exit(1); + } + + if (rdfloadseg(&lastmodule->f,RDOFF_HEADER,lastmodule->header)) + { + rdfperror("ldrdf",filename); + exit(1); + } +} + +/* load_library add a library to list of libraries to search + * for undefined symbols + */ + +void load_library(char * name) +{ + if (verbose) + printf("adding library %s to search path\n",name); + + if (! lastlib) { + lastlib = libraries = malloc(sizeof(struct librarynode)); + } + else + { + lastlib->next = malloc(sizeof(struct librarynode)); + lastlib = lastlib->next; + } + + if (! lastlib) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + strcpy (lastlib->name = malloc (1+strlen(name)), name); + lastlib->fp = NULL; + lastlib->referenced = 0; + lastlib->next = NULL; +} + + +/* build_symbols() step through each module's header, and locate + * exported symbols, placing them in a global table + */ + +long bsslength; + +void mod_addsymbols(struct modulenode * mod) +{ + rdfheaderrec *r; + symtabEnt e; + long cbBss; + + mod->bssrel = bsslength; + 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); + } + bsslength += cbBss; +} + +void build_symbols() +{ + struct modulenode *mod; + + if (verbose) printf("building global symbol table:\n"); + newheader = rdfnewheader(); + + symtab = symtabNew(); + bsslength = 0; /* keep track of location of BSS symbols */ + + for (mod = modules; mod; mod = mod->next) + { + mod_addsymbols( mod ); + } + if (verbose) + { + symtabDump(symtab,stdout); + printf("BSS length = %ld bytes\n\n",bsslength); + } +} + + +/* scan_libraries() search through headers of modules for undefined + * symbols, and scan libraries for those symbols, + * adding library modules found to list of modules + * to load. */ + +void scan_libraries(void) +{ + struct modulenode * mod, * nm; + struct librarynode * lib; + rdfheaderrec * r; + int found; + char * tmp; + + if (verbose) printf("Scanning libraries for unresolved symbols...\n"); + + mod = modules; + + while (mod) + { + rdfheaderrewind(&mod->f); + + while ((r = rdfgetheaderrec(&mod->f))) + { + if (r->type != 2) continue; /* not an import record */ + if ( symtabFind (symtab,r->i.label) ) + continue; /* symbol already defined */ + + /* okay, we have an undefined symbol... step through + the libraries now */ + if (verbose >= 2) { + printf("undefined symbol '%s'...",r->i.label); + fflush(stdout); + } + + lib = libraries; + found = 0; + + tmp = newstr(r->i.label); + while (! found && lib) + { + /* move this to an outer loop...! */ + nm = malloc(sizeof(struct modulenode)); + + if (rdl_searchlib(lib,tmp,&nm->f)) + { /* found a module in the library */ + + /* create a modulenode for it */ + + if (! nm) { + fprintf(stderr,"ldrdf: out of memory\n"); + exit(1); + } + + nm->name = newstrcat(lib->name,nm->f.name); + if (verbose >= 2) printf("found in '%s'\n",nm->name); + + nm->coderel = lastmodule->coderel + lastmodule->f.code_len; + if (nm->coderel % align != 0) + nm->coderel += align - (nm->coderel % align); + + nm->datarel = lastmodule->datarel + lastmodule->f.data_len; + if (nm->datarel % align != 0) + nm->datarel += align - (nm->datarel % align); + + nm->header = malloc(nm->f.header_len); + if (! nm->header) + { + fprintf(stderr,"ldrdf: out of memory\n"); + exit(1); + } + + if (rdfloadseg(&nm->f,RDOFF_HEADER,nm->header)) + { + rdfperror("ldrdf",nm->name); + exit(1); + } + + nm->next = NULL; + found = 1; + lastmodule->next = nm; + lastmodule = nm; + + if (verbose) + printf("%s code = %08lx (+%04lx), data = %08lx " + "(+%04lx)\n",lastmodule->name, + lastmodule->coderel,lastmodule->f.code_len, + lastmodule->datarel,lastmodule->f.data_len); + + /* add the module's info to the symbol table */ + mod_addsymbols(nm); + } + else + { + if (rdl_error) { + rdl_perror("ldrdf",lib->name); + exit(1); + } + free(nm); + } + lib = lib->next; + } + free(tmp); + if (!found && verbose >= 2) printf("not found\n"); + } + mod = mod->next; + } } /* load_segments() allocates memory for & loads the code & data segs @@ -108,7 +335,7 @@ void loadmodule(char *filename) */ char *text,*data; -long textlength,datalength,bsslength; +long textlength,datalength; void load_segments(void) { @@ -150,77 +377,17 @@ void load_segments(void) 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); + if (verbose >= 2) printf(" loading %s\n",mod->name); + if (rdfloadseg(&mod->f,RDOFF_CODE,&text[mod->coderel]) || + rdfloadseg(&mod->f,RDOFF_DATA,&data[mod->datarel])) { + rdfperror("ldrdf",mod->name); + exit(1); } - bssloc += cbBss; + rdfclose(&mod->f); /* close file; segments remain */ + mod = mod->next; } - 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. */ @@ -230,7 +397,7 @@ void link_segments(void) struct modulenode *mod; Collection imports; symtabEnt *s; - long rel,relto = 0; /* placate gcc */ + long rel,relto; char *seg; rdfheaderrec *r; int bRelative; @@ -243,6 +410,7 @@ void link_segments(void) if (verbose >= 2) printf("* processing %s\n",mod->name); rdfheaderrewind(&mod->f); while((r = rdfgetheaderrec(&mod->f))) { + if (verbose >= 3) printf("record type: %d\n",r->type); switch(r->type) { case 1: /* relocation record */ if (r->r.segment >= 64) { /* Relative relocation; */ @@ -275,19 +443,19 @@ void link_segments(void) break; } rel = s->offset; - - r->r.refseg = s->segment; /* change referred segment, + + r->r.refseg = s->segment; /* change referred segment, so that new header is correct */ } if (bRelative) /* Relative - subtract current segment start */ - rel -= relto; - else + 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; @@ -326,7 +494,7 @@ void link_segments(void) r->i.label,mod->name); errors = 1; } - else + else { *colln(&imports,r->i.segment - 2) = s; if (verbose >= 2) @@ -336,8 +504,11 @@ void link_segments(void) case 3: /* export; dump to output new version */ s = symtabFind(symtab, r->e.label); - if (! s) continue; /* eh? probably doesn't matter... */ - + if (! s) { + fprintf(stderr,"ldrdf: internal error - undefined symbol %s " + "exported in header of '%s'\n",r->e.label,mod->name); + continue; + } r->e.offset = s->offset; rdfaddheader(newheader,r); break; @@ -347,10 +518,14 @@ void link_segments(void) break; } } + if (rdf_errno != 0) { + rdfperror("ldrdf",mod->name); + exit(1); + } collection_reset(&imports); } } - + /* write_output() write linked program out to a file */ void write_output(char *filename) @@ -358,14 +533,16 @@ void write_output(char *filename) FILE * fp; rdfheaderrec r; + if (verbose) printf("writing output to '%s'\n",filename); + 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) { @@ -412,7 +589,8 @@ void write_output(char *filename) */ const char *usagemsg = "usage:\n" -" ldrdf [-o outfile | -x] [-a x] [-v] [-p x] [--] infile [infile ...]\n\n" +" ldrdf [-o outfile | -x] [-a x] [-v] [-p x] [--] infile [infile ...]\n" +" [-l<libname> ...]\n\n" " ldrdf -h displays this message\n" " ldrdf -r displays version information\n\n" " -o selects output filename (default is aout.rdx)\n" @@ -420,7 +598,9 @@ const char *usagemsg = "usage:\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"; +" (default is 16 bytes)\n" +" -l<name> causes 'name' to be linked in as a library. Note no search is\n" +" performed - the entire pathname MUST be specified.\n"; void usage(void) { @@ -499,6 +679,9 @@ int main(int argc,char **argv) } if (verbose > 1) printf("alignment %d selected\n",align); } + else if (procsw && !strncmp(*argv,"-l",2)) { + load_library(*argv + 2); + } else if (procsw && !strcmp(*argv,"--")) { procsw = 0; } @@ -512,12 +695,15 @@ int main(int argc,char **argv) unreferenced modules from the list of modules here, so that we know about the final size once libraries have been linked in */ + build_symbols(); /* build a global symbol table... */ + + scan_libraries(); /* check for imported symbols not in table, + and ensure the relevant library modules + are loaded */ + 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. */ diff --git a/rdoff/rdf.doc b/rdoff/rdf.doc deleted file mode 100644 index 300c2bc..0000000 --- a/rdoff/rdf.doc +++ /dev/null @@ -1,99 +0,0 @@ -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/rdf2bin.c b/rdoff/rdf2bin.c new file mode 100644 index 0000000..97b45b4 --- /dev/null +++ b/rdoff/rdf2bin.c @@ -0,0 +1,125 @@ +/* rdf2bin: convert an RDOFF object file to flat binary */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "rdfload.h" +#include "rdoff.h" +#include "nasmlib.h" + +long origin = 0; +int align = 16; + +char *getfilename(char * pathname) +{ + char * lastslash = pathname - 1; + char * i = pathname; + + while ( *i ) { + if (*i == '/') lastslash = i; + i++; + } + return lastslash + 1; +} + +int main(int argc, char **argv) +{ + rdfmodule * m; + int tmp; + FILE *of; + char * padding; + int codepad, datapad; + + if (argc < 2) { + puts("Usage: rdf2bin [-o relocation-origin] [-p segment-alignment] " + "input-file output-file"); + puts(" rdf2com [-p segment-alignment] input-file output-file"); + return 1; + } + + if (! nasm_stricmp(getfilename(*argv),"rdf2com")) { + origin = 0x100; + } + argv++, argc--; + + while (argc > 2) { + if (! strcmp(*argv,"-o")) { + argv++, argc--; + origin = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr,"rdf2bin: invalid parameter: %s\n",*argv); + return 1; + } + } else if (! strcmp(*argv,"-p")) { + argv++, argc--; + align = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr,"rdf2bin: invalid parameter: %s\n",*argv); + return 1; + } + } else + break; + + argv++, argc--; + } + if (argc < 2) { + puts("rdf2bin: required parameter missing"); + return -1; + } + m = rdfload(*argv); + + if (! m) + { + rdfperror("rdf2bin",*argv); + return 1; + } + printf("relocating %s: origin=%lx, align=%d\n",*argv,origin,align); + + m->textrel = origin; + m->datarel = origin + m->f.code_len; + if (m->datarel % align != 0) { + codepad = align - (m->datarel % align); + m->datarel += codepad; + } + else + codepad = 0; + + m->bssrel = m->datarel + m->f.data_len; + if (m->bssrel % align != 0) { + datapad = align - (m->bssrel % align); + m->bssrel += datapad; + } + else + datapad = 0; + + printf("code: %08lx\ndata: %08lx\nbss: %08lx\n", + m->textrel, m->datarel, m->bssrel); + + rdf_relocate(m); + + argv++; + + of = fopen(*argv,"wb"); + if (!of) { + fprintf(stderr,"rdf2bin: could not open output file %s\n",*argv); + return 1; + } + + padding = malloc(align); + if (!padding) { + fprintf(stderr,"rdf2bin: out of memory\n"); + return 1; + } + + if (fwrite(m->t,1,m->f.code_len,of) != m->f.code_len || + fwrite(padding,1,codepad,of) != codepad || + fwrite(m->d,1,m->f.data_len,of) != m->f.data_len) + { + fprintf(stderr,"rdf2bin: error writing to %s\n", *argv); + return 1; + } + + fclose(of); + return 0; +} diff --git a/rdoff/rdfdump.c b/rdoff/rdfdump.c index 4d4f4df..bc55a97 100644 --- a/rdoff/rdfdump.c +++ b/rdoff/rdfdump.c @@ -17,7 +17,7 @@ long translatelong(long in) { /* translate from little endian to return r; } - + int translateshort(short in) { int r; unsigned char *i; @@ -28,8 +28,8 @@ int translateshort(short in) { return r; } void print_header(long length) { - unsigned char buf[129],t,s,l; - long o; + char buf[129],t,s,l; + long o,ll; short rs; while (length > 0) { @@ -39,7 +39,7 @@ void print_header(long length) { fread(&s,1,1,infile); fread(&o,4,1,infile); fread(&l,1,1,infile); - fread(&rs,2,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)); @@ -47,34 +47,34 @@ void print_header(long length) { break; case 2: /* import record */ fread(&rs,2,1,infile); - l = 0; + ll = 0; do { - fread(&buf[l],1,1,infile); - } while (buf[l++]); + fread(&buf[ll],1,1,infile); + } while (buf[ll++]); printf(" import: segment %04x = %s\n",translateshort(rs),buf); - length -= l + 3; + length -= ll + 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++]); + fread(&buf[ll],1,1,infile); + } while (buf[ll++]); printf(" export: (%04x:%08lx) = %s\n",(int)s,translatelong(o),buf); - length -= l + 6; + length -= ll + 6; break; case 4: /* DLL record */ l = 0; do { - fread(&buf[l],1,1,infile); - } while (buf[l++]); + fread(&buf[ll],1,1,infile); + } while (buf[ll++]); printf(" dll: %s\n",buf); - length -= l + 1; + length -= ll + 1; break; case 5: /* BSS reservation */ - fread(&l,4,1,infile); - printf(" bss reservation: %08lx bytes\n",translatelong(l)); + fread(&ll,4,1,infile); + printf(" bss reservation: %08lx bytes\n",translatelong(ll)); length -= 5; break; default: diff --git a/rdoff/rdflib.c b/rdoff/rdflib.c new file mode 100644 index 0000000..5846562 --- /dev/null +++ b/rdoff/rdflib.c @@ -0,0 +1,235 @@ +/* rdflib - manipulate RDOFF library files (.rdl) */ + +/* an rdoff library is simply a sequence of RDOFF object files, each + preceded by the name of the module, an ASCII string of up to 255 + characters, terminated by a zero. There may be an optional + directory placed on the end of the file. The format of the + directory will be 'RDL' followed by a version number, followed by + the length of the directory, and then the directory, the format of + which has not yet been designed. */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> + +/* functions supported: + create a library (no extra operands required) + add a module from a library (requires filename and name to give mod.) + remove a module from a library (requires given name) + extract a module from the library (requires given name and filename) + list modules */ + +const char *usage = + "usage:\n" + " rdflib x libname [extra operands]\n\n" + " where x is one of:\n" + " c - create library\n" + " a - add module (operands = filename module-name)\n" + " r - remove (module-name)\n" + " x - extract (module-name filename)\n" + " t - list\n"; + +char **_argv; + +#define _ENDIANNESS 0 /* 0 for little, 1 for big */ + +static void longtolocal(long * l) +{ +#if _ENDIANNESS + unsigned char t; + unsigned char * p = (unsigned char *) l; + + t = p[0]; + p[0] = p[3]; + p[3] = t; + t = p[1]; + p[1] = p[2]; + p[2] = p[1]; +#endif +} + +void copybytes(FILE *fp, FILE *fp2, int n) +{ + int i,t; + + for (i = 0 ; i < n; i++ ) + { + t = fgetc(fp); + if (t == EOF) + { + fprintf(stderr,"ldrdf: premature end of file in '%s'\n", + _argv[2]); + exit(1); + } + if (fp2) + if (fputc(t, fp2) == EOF) + { + fprintf(stderr,"ldrdf: write error\n"); + exit(1); + } + } +} + +long copylong(FILE *fp, FILE *fp2) +{ + long l; + int i,t; + unsigned char * p = (unsigned char *) &l; + + + for (i = 0 ; i < 4; i++ ) /* skip magic no */ + { + t = fgetc(fp); + if (t == EOF) + { + fprintf(stderr,"ldrdf: premature end of file in '%s'\n", + _argv[2]); + exit(1); + } + if (fp2) + if (fputc(t, fp2) == EOF) + { + fprintf(stderr,"ldrdf: write error\n"); + exit(1); + } + *p++ = t; + } + longtolocal (&l); + return l; +} + +int main(int argc, char **argv) +{ + FILE *fp, *fp2; + char *p, buf[256]; + int i; + + _argv = argv; + + if (argc < 3 || !strncmp(argv[1],"-h",2) || !strncmp(argv[1],"--h",3)) + { + printf(usage); + exit(1); + } + + switch(argv[1][0]) + { + case 'c': /* create library */ + fp = fopen(argv[2],"wb"); + if (! fp) { + fprintf(stderr,"ldrdf: could not open '%s'\n",argv[2]); + perror("ldrdf"); + exit(1); + } + fclose(fp); + break; + + case 'a': /* add module */ + if (argc < 5) { + fprintf(stderr,"ldrdf: required parameter missing\n"); + exit(1); + } + fp = fopen(argv[2],"ab"); + if (! fp) + { + fprintf(stderr,"ldrdf: could not open '%s'\n",argv[2]); + perror("ldrdf"); + exit(1); + } + + fp2 = fopen(argv[3],"rb"); + if (! fp) + { + fprintf(stderr,"ldrdf: could not open '%s'\n",argv[3]); + perror("ldrdf"); + exit(1); + } + + p = argv[4]; + do { + if ( fputc(*p,fp) == EOF ) { + fprintf(stderr,"ldrdf: write error\n"); + exit(1); + } + } while (*p++); + + while (! feof (fp2) ) { + i = fgetc (fp2); + if (i == EOF) { + break; + } + + if ( fputc(i, fp) == EOF ) { + fprintf(stderr,"ldrdf: write error\n"); + exit(1); + } + } + fclose(fp2); + fclose(fp); + break; + + case 'x': + if (argc < 5) { + fprintf(stderr,"ldrdf: required parameter missing\n"); + exit(1); + } + + fp = fopen(argv[2],"rb"); + if (! fp) + { + fprintf(stderr,"ldrdf: could not open '%s'\n",argv[2]); + perror("ldrdf"); + exit(1); + } + + fp2 = NULL; + while (! feof(fp) ) { + /* read name */ + p = buf; + while( ( *(p++) = (char) fgetc(fp) ) ) + if (feof(fp)) break; + + if (feof(fp)) break; + + /* check against desired name */ + if (! strcmp(buf,argv[3]) ) + { + fp2 = fopen(argv[4],"wb"); + if (! fp2) + { + fprintf(stderr,"ldrdf: could not open '%s'\n", argv[4]); + perror("ldrdf"); + exit(1); + } + } + else + fp2 = NULL; + + /* step over the RDOFF file, copying it if fp2 != NULL */ + copybytes(fp,fp2,6); /* magic number */ + copybytes(fp,fp2, copylong(fp,fp2)); /* header */ + copybytes(fp,fp2, copylong(fp,fp2)); /* text */ + copybytes(fp,fp2, copylong(fp,fp2)); /* data */ + + if (fp2) + break; + } + fclose(fp); + if (fp2) + fclose(fp2); + else + { + fprintf(stderr,"ldrdf: module '%s' not found in '%s'\n", + argv[3],argv[2]); + exit(1); + } + break; + + default: + fprintf(stderr,"ldrdf: command '%c' not recognised\n", + argv[1][0]); + exit(1); + } + return 0; +} + diff --git a/rdoff/rdfload.c b/rdoff/rdfload.c index ad340b3..b848344 100644 --- a/rdoff/rdfload.c +++ b/rdoff/rdfload.c @@ -27,7 +27,7 @@ rdfmodule * rdfload(const char *filename) char * hdr; rdfheaderrec *r; - if (f == NULL) + if (f == NULL) { rdf_errno = 6; /* out of memory */ return NULL; @@ -48,7 +48,7 @@ rdfmodule * rdfload(const char *filename) } /* 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); @@ -107,11 +107,11 @@ rdfmodule * rdfload(const char *filename) int rdf_relocate(rdfmodule * m) { rdfheaderrec * r; - Collection imports; + Collection imports; symtabEnt e; long rel; unsigned char * seg; - + rdfheaderrewind ( & m->f ); collection_init(&imports); @@ -155,7 +155,7 @@ int rdf_relocate(rdfmodule * m) case 3: /* export record - add to symtab */ e.segment = r->e.segment; - e.offset = r->e.offset + + e.offset = r->e.offset + (e.segment == 0 ? m->textrel : /* 0 -> code */ e.segment == 1 ? m->datarel : /* 1 -> data */ m->bssrel) ; /* 2 -> bss */ @@ -168,6 +168,6 @@ int rdf_relocate(rdfmodule * m) symtabInsert(m->symtab,&e); break; } - } + } return 0; } diff --git a/rdoff/rdlib.c b/rdoff/rdlib.c new file mode 100644 index 0000000..bc8d1e3 --- /dev/null +++ b/rdoff/rdlib.c @@ -0,0 +1,88 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "rdoff.h" +#include "rdlib.h" + +int rdl_error = 0; + +char *rdl_errors[3] = { + "no error","could not open file", "invalid file structure", +}; + +int rdl_searchlib (struct librarynode * lib, + const char * label, rdffile * f) +{ + char buf[257]; + int i; + void * hdr; + rdfheaderrec * r; + + rdl_error = 0; + lib->referenced ++; + + if (! lib->fp) + { + lib->fp = fopen(lib->name,"rb"); + + if (! lib->fp) { + rdl_error = 1; + return 0; + } + } + else + rewind(lib->fp); + + while (! feof(lib->fp) ) + { + i = 1; + while (fread(buf + i,1,1,lib->fp) == 1 && buf[i] && i < 257) + i++; + buf[0] = ':'; + + if (feof(lib->fp)) break; + + if ( rdfopenhere(f,lib->fp,&lib->referenced,buf) ) { + rdl_error = 2; + return 0; + } + + hdr = malloc(f->header_len); + rdfloadseg(f,RDOFF_HEADER,hdr); + + while ((r = rdfgetheaderrec(f))) + { + if (r->type != 3) /* not an export */ + continue; + + if (! strcmp(r->e.label, label) ) /* match! */ + { + free(hdr); /* reset to 'just open' */ + f->header_loc = NULL; /* state... */ + f->header_fp = 0; + return 1; + } + } + + /* find start of next module... */ + i = f->data_ofs + f->data_len; + rdfclose(f); + fseek(lib->fp,i,SEEK_SET); + } + + lib->referenced --; + if (! lib->referenced) + { + fclose(lib->fp); + lib->fp = NULL; + } + return 0; +} + +void rdl_perror(const char *apname, const char *filename) +{ + fprintf(stderr,"%s:%s:%s\n",apname,filename,rdl_errors[rdl_error]); +} + + + diff --git a/rdoff/rdlib.h b/rdoff/rdlib.h new file mode 100644 index 0000000..94592ce --- /dev/null +++ b/rdoff/rdlib.h @@ -0,0 +1,18 @@ +/* rdlib.h Functions for manipulating librarys of RDOFF object files */ + + +struct librarynode { + char * name; + FILE * fp; /* initialised to NULL - always check*/ + int referenced; /* & open if required. Close afterwards */ + struct librarynode * next; /* if ! referenced. */ +}; + + +extern int rdl_error; + +int rdl_searchlib (struct librarynode * lib, + const char * label, rdffile * f); +void rdl_perror(const char *apname, const char *filename); + + diff --git a/rdoff/rdoff.c b/rdoff/rdoff.c index 9a969ad..96620ec 100644 --- a/rdoff/rdoff.c +++ b/rdoff/rdoff.c @@ -13,9 +13,15 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <errno.h> #include "rdoff.h" +#define newstr(str) strcpy(malloc(strlen(str) + 1),str) +#define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \ + s1),s2) + /* ======================================================================== * Code for memory buffers (for delayed writing of header until we know * how long it is). @@ -42,7 +48,7 @@ void membufwrite(memorybuffer *b, void *data, int bytes) { } 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 */ @@ -84,7 +90,7 @@ void membufdump(memorybuffer *b,FILE *fp) if (!b) return; fwrite (b->buffer, 1, b->length, fp); - + membufdump(b->next,fp); } @@ -134,7 +140,18 @@ int rdf_errno = 0; int rdfopen(rdffile *f, const char *name) { + FILE * fp; + + fp = fopen(name,"rb"); + if (!fp) return rdf_errno = 1; /* error 1: file open error */ + + return rdfopenhere(f,fp,NULL,""); +} + +int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name) +{ char buf[8]; + long initpos; if (translatelong(0x01020304) != 0x01020304) { /* fix this to be portable! */ @@ -143,9 +160,8 @@ int rdfopen(rdffile *f, const char *name) exit(3); } - - f->fp = fopen(name,"rb"); - if (!f->fp) return rdf_errno = 1; /* error 1: file open error */ + f->fp = fp; + initpos = ftell(fp); fread(buf,6,1,f->fp); /* read header */ buf[6] = 0; @@ -160,6 +176,8 @@ int rdfopen(rdffile *f, const char *name) return rdf_errno = 3; /* error 3: file read error */ } + f->header_ofs = ftell(f->fp); + if (fseek(f->fp,f->header_len,SEEK_CUR)) { fclose(f->fp); return rdf_errno = 2; /* seek past end of file...? */ @@ -182,20 +200,32 @@ int rdfopen(rdffile *f, const char *name) } f->data_ofs = ftell(f->fp); - rewind(f->fp); + fseek(f->fp,initpos,SEEK_SET); f->header_loc = NULL; + + f->name = newstr(name); + f->refcount = refcount; + if (refcount) (*refcount)++; return 0; } int rdfclose(rdffile *f) { - fclose(f->fp); + if (! f->refcount || ! *--f->refcount) + fclose(f->fp); + free(f->name); + return 0; } void rdfperror(const char *app,const char *name) { fprintf(stderr,"%s:%s: %s\n",app,name,rdf_errors[rdf_errno]); + if (rdf_errno == 1 || rdf_errno == 3) + { + perror(app); + } + } int rdfloadseg(rdffile *f,int segment,void *buffer) @@ -205,7 +235,7 @@ int rdfloadseg(rdffile *f,int segment,void *buffer) switch(segment) { case RDOFF_HEADER: - fpos = 10; + fpos = f->header_ofs; slen = f->header_len; f->header_loc = (char *)buffer; f->header_fp = 0; @@ -224,8 +254,8 @@ int rdfloadseg(rdffile *f,int segment,void *buffer) } if (fseek(f->fp,fpos,SEEK_SET)) - return rdf_errno = 4; - + return rdf_errno = 4; + if (fread(buffer,1,slen,f->fp) != slen) return rdf_errno = 3; @@ -294,7 +324,7 @@ rdfheaderrec *rdfgetheaderrec(rdffile *f) } return &r; } - + void rdfheaderrewind(rdffile *f) { f->header_fp = 0; diff --git a/rdoff/rdoff.h b/rdoff/rdoff.h index b022400..0f74b80 100644 --- a/rdoff/rdoff.h +++ b/rdoff/rdoff.h @@ -50,7 +50,7 @@ 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 */ @@ -66,10 +66,13 @@ typedef struct RDFFileInfo { long header_len; long code_len; long data_len; + long header_ofs; long code_ofs; long data_ofs; char *header_loc; /* keep location of header */ long header_fp; /* current location within header for reading */ + char *name; /* name of module in libraries */ + int *refcount; /* pointer to reference count on file, or NULL */ } rdffile; #define BUF_BLOCK_LEN 4088 /* selected to match page size (4096) @@ -91,8 +94,11 @@ typedef memorybuffer rdf_headerbuf; /* mask to find actual segment value in relocation records */ #define RDOFF_SEGMENTMASK 63 +extern int rdf_errno; + /* RDOFF file manipulation functions */ int rdfopen(rdffile *f,const char *name); +int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name); int rdfclose(rdffile *f); int rdfloadseg(rdffile *f,int segment,void *buffer); rdfheaderrec *rdfgetheaderrec(rdffile *f); /* returns static storage */ diff --git a/rdoff/rdoff.txt b/rdoff/rdoff.txt new file mode 100644 index 0000000..7ee86d6 --- /dev/null +++ b/rdoff/rdoff.txt @@ -0,0 +1,114 @@ +The RDOFF version 1.1 Object File Format +======================================== + +I seem to keep writing this document... I don't know what keeps +happening to it. Anyway, this one will hopefully stay around for a +while. + +RDOFF is a relocatable object file format whose design goals were +mainly to keep it simple, so that an RDOFF object can be loaded and +executed by a very small piece of code (primarily so that it can be +used by the microkernel of an operating system to store system +modules, which can then go on to load and execute more complex object +files, eg ELF, if so desired), yet still be able to be cope with +everything required by the operating system; linkage of multiple +modules together (possibly with automatic loading of new libraries +that are referred to by the object) at load time, allowing static or +dynamic linking as required by the application. + +The overall format of the file is summarised in this table: + +Length (bytes) Description + 6 Contains the string 'RDOFF1' (little-endian targets), + or 'RDOFF' followed by the single byte 0x01 + (big-endian targets). + 4 Length of the header section + ? Header section (see above for length) + 4 Length of code section (.text) + ? Code section + 4 Length of data section (.data) + ? Data section + +Segments are referred to as numbers. Imported labels are implicitly +at offset zero from a segment; each is assigned a segment number when +it is imported. Segments in the object file itself are numbered: + 0 - text segemnt + 1 - data segment + 2 - bss segment + +The header consists of a sequence of records, each of which is +preceded by a byte to represent its type. + +These records are one of the following types: + +1: Relocation Record +-------------------- + + This record points to an address that will need either + relocation or linkage to an external segment when the object + is loaded or linked. + + Length Description + 1 Type identifier (must be 1) + 1 Segment number (0 or 1) plus 64 if the reference is + relative (and thus does not require relocation with + the base of the code, only by the difference between + the start of this segment, and the segment referred to + (see below) + 4 Offset from start of segment of item requiring reloc. + 1 Length of item (1, 2, or 4 bytes...) + 2 Segment number to which reference is made. + +2: Import Symbol Record +----------------------- + + This record defines a segment to start at the location of a + named symbol; this symbol may need to be fetched from an + external library. + + Length Description + 1 Type identifier (must be 2) + 2 Segment number to allocate + ? String containing label (null terminated, max length = + 32 chars) + +3: Export Symbol Record +----------------------- + + This record defines a symbol, to which external modules can + link using the above record type. + + Length Description + 1 Type identifier (must be 3) + 1 Segment containing symbol (0,1 or 2) + 4 Offset of symbol within segment + ? String containing label (null terminated, max length = + 32 chars) + +4: Import Library Record +------------------------ + + This record tells the loader that an extra library should be + loaded and linked to the module at either load- or run-time + (load time is easier, run-time is good, though...) + + Length Description + 1 Type identifier (must be 4) + ? Name of library (null terminated string, max len = 128) + +5: Reserve BSS Bytes +-------------------- + + This record tells the loader how much memory to reserve after + the executable code loaded from the object file for the BSS + segment (referred to as segment number 2). + A loader can safely assume that there will only be one of + these records per module, but the linker probably cannot... + NASM will only output one, but other utilities may be written + that do, and future versions of NASM may output more than one. + + Length Description + 1 Type identifier (must be 5) + 4 Number of bytes to reserve + + diff --git a/rdoff/symtab.c b/rdoff/symtab.c index c0ff3e5..3fc363e 100644 --- a/rdoff/symtab.c +++ b/rdoff/symtab.c @@ -62,7 +62,7 @@ symtabEnt *symtabFind(void *symtab,char *name) return &(l->ent); } l = l->next; - } + } return NULL; } |