diff options
author | H. Peter Anvin <hpa@zytor.com> | 2002-04-30 20:58:18 +0000 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2002-04-30 20:58:18 +0000 |
commit | 41bf8002b2fa402bd344a290fcc9f65de328859c (patch) | |
tree | fa1638dfbf73e3a6b96ce99cda1cd5ad9c1adf61 /rdoff | |
parent | ef7468f4ec05f23e8d866493593d7c1f07df5e03 (diff) | |
download | nasm-41bf8002b2fa402bd344a290fcc9f65de328859c.tar.gz nasm-41bf8002b2fa402bd344a290fcc9f65de328859c.tar.bz2 nasm-41bf8002b2fa402bd344a290fcc9f65de328859c.zip |
NASM 0.98
Diffstat (limited to 'rdoff')
43 files changed, 5515 insertions, 1052 deletions
diff --git a/rdoff/Changes b/rdoff/Changes new file mode 100644 index 0000000..34163a9 --- /dev/null +++ b/rdoff/Changes @@ -0,0 +1,63 @@ +Differences between RDOFF versions 1 & 2 +======================================== + +This document is designed primarily for people maintaining code which +uses RDOFF version 1, and would like to upgrade that code to work +with version 2. + +The main changes are summarised here: + +Overall format +============== + +The overall format has changed somewhat since version 1, in order +to make RDOFF more flexible. After the file type identifier (which +has been changed to 'RDOFF2', obviously), there is now a 4 byte +integer describing the length of the object module. This allows +multiple objects to be concatenated, while the loader can easily +build an index of the locations of each object. This isn't as +pointless as it sounds; I'm using RDOFF in a microkernel operating +system, and this is the ideal way of loading multiple driver modules +at boot time. + +There are also no longer a fixed number of segments; instead there +is a list of segments, immediately following the header. +Each segment is preceded by a 10 byte header giving information about +that segment. This header has the following format: + +Length Description +2 Type +2 Number +2 Reserved +4 Length + +'Type' is a number describing what sort of segment it is (eg text, data, +comment, debug info). See 'rdoff2.txt' for a list of the segment types. +'Number' is the number used to refer to the segment in the header records. +Not all segments will be loaded; it is only intended that one code +and one data segment will be loaded into memory. It is possible, however, +for a loaded segment to contain a reference to an unloaded segment. +This is an error, and should be flagged at load time. Or maybe you should +load the segment... its up to you, really. + +The segment's data immediately follows the end of the segment header. + +HEADER RECORDS +============== + +All of the header records have changed in this version, but not +substantially. Each record type has had a content-length code added, +a single byte immediately following the type byte. This contains the +length of the rest of the record (excluding the type and length bytes, +but including the terminating nulls on any strings in the record). + +There are two new record types, Segment Relocation (6), and FAR import (7). +The record formats are identical to Relocation (1) and import (2). They are +only of real use on systems using segmented architectures. Systems using +a flat model should treat FAR import (7) exactly the same as an import (2), +and should either flag segment relocation as an error, or attempt to figure +out whether it is a reference to a code or data symbol, and set the value +referenced to the according selector value. I am opting for the former +approach, and would recommend that others working on 32 bit flat systems +do the same. + diff --git a/rdoff/Makefile.in b/rdoff/Makefile.in index d9a9311..c55851d 100644 --- a/rdoff/Makefile.in +++ b/rdoff/Makefile.in @@ -1,3 +1,4 @@ +# $Id$ # # Auto-configuring Makefile for RDOFF object file utils; part of the # Netwide Assembler @@ -7,24 +8,25 @@ # redistributable under the licence given in the file "Licence" # distributed in the NASM archive. -top_srcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ -bindir = @bindir@ -mandir = @mandir@ +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +mandir = @mandir@ -CC = @CC@ -CFLAGS = @CFLAGS@ @GCCFLAGS@ -I$(top_srcdir) +CC = @CC@ +CFLAGS = @CFLAGS@ @GCCFLAGS@ -I$(srcdir) -I$(top_srcdir) +LDFLAGS = @LDFLAGS@ -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ -LN_S = @LN_S@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +LN_S = @LN_S@ -LDRDFLIBS = rdoff.o nasmlib.o symtab.o collectn.o rdlib.o -RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o +LDRDFLIBS = rdoff.o nasmlib.o symtab.o collectn.o rdlib.o segtab.o hash.o +RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o hash.o .c.o: $(CC) -c $(CFLAGS) $< @@ -32,18 +34,17 @@ RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com rdfdump: rdfdump.o - $(CC) -o rdfdump rdfdump.o - + $(CC) $(LDFLAGS) -o rdfdump rdfdump.o ldrdf: ldrdf.o $(LDRDFLIBS) - $(CC) -o ldrdf ldrdf.o $(LDRDFLIBS) + $(CC) $(LDFLAGS) -o ldrdf ldrdf.o $(LDRDFLIBS) rdx: rdx.o $(RDXLIBS) - $(CC) -o rdx rdx.o $(RDXLIBS) + $(CC) $(LDFLAGS) -o rdx rdx.o $(RDXLIBS) rdflib: rdflib.o - $(CC) -o rdflib rdflib.o + $(CC) $(LDFLAGS) -o rdflib rdflib.o rdf2bin: rdf2bin.o $(RDXLIBS) nasmlib.o - $(CC) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o + $(CC) $(LDFLAGS) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o rdf2com: - $(LN_S) rdf2bin rdf2com + rm -f rdf2com && $(LN_S) rdf2bin rdf2com rdf2bin.o: rdf2bin.c rdfdump.o: rdfdump.c @@ -55,6 +56,7 @@ 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 +segtab.o: segtab.c nasmlib.o: $(top_srcdir)/nasmlib.c $(CC) -c $(CFLAGS) $(top_srcdir)/nasmlib.c @@ -62,17 +64,15 @@ nasmlib.o: $(top_srcdir)/nasmlib.c clean: rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com -distclean: clean - rm -f Makefile *~ *.bak - -cleaner: clean +spotless: clean + rm -f Makefile -spotless: distclean +distclean: spotless install: rdfdump ldrdf rdx rdflib rdf2bin rdf2com - $(INSTALL_PROGRAM) rdfdump $(bindir)/rdfdump - $(INSTALL_PROGRAM) ldrdf $(bindir)/ldrdf - $(INSTALL_PROGRAM) rdx $(bindir)/rdx - $(INSTALL_PROGRAM) rdflib $(bindir)/rdflib - $(INSTALL_PROGRAM) rdf2bin $(bindir)/rdf2bin - cd $(bindir); $(LN_S) rdf2bin rdf2com + $(INSTALL_PROGRAM) rdfdump $(INSTALLROOT)$(bindir)/rdfdump + $(INSTALL_PROGRAM) ldrdf $(INSTALLROOT)$(bindir)/ldrdf + $(INSTALL_PROGRAM) rdx $(INSTALLROOT)$(bindir)/rdx + $(INSTALL_PROGRAM) rdflib $(INSTALLROOT)$(bindir)/rdflib + $(INSTALL_PROGRAM) rdf2bin $(INSTALLROOT)$(bindir)/rdf2bin + cd $(INSTALLROOT)$(bindir) && rm -f rdf2com && $(LN_S) rdf2bin rdf2com diff --git a/rdoff/Makefile.sc b/rdoff/Makefile.sc index 816cc98..fca911a 100644 --- a/rdoff/Makefile.sc +++ b/rdoff/Makefile.sc @@ -1,112 +1,57 @@ -# 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 = sc - -CCFLAGS = -I..\ -c -a1 -mn -Nc -w2 -w7 -o+time -5 - -LINK = link - -LINKFLAGS = /noi /exet:NT /su:console - - - -OBJ=obj - -EXE=.exe - - - -NASMLIB = ..\nasmlib.$(OBJ) - -NASMLIB_H = ..\nasmlib.h - -LDRDFLIBS = rdoff.$(OBJ) $(NASMLIB) symtab.$(OBJ) collectn.$(OBJ) rdlib.$(OBJ) - -RDXLIBS = rdoff.$(OBJ) rdfload.$(OBJ) symtab.$(OBJ) collectn.$(OBJ) - - - -.c.$(OBJ): - - $(CC) $(CCFLAGS) $*.c - - - -all : rdfdump$(EXE) ldrdf$(EXE) rdx$(EXE) rdflib$(EXE) rdf2bin$(EXE) rdf2com$(EXE) - - - -rdfdump$(EXE) : rdfdump.$(OBJ) - - $(LINK) $(LINKFLAGS) rdfdump.$(OBJ), rdfdump$(EXE); - -ldrdf$(EXE) : ldrdf.$(OBJ) $(LDRDFLIBS) - - $(LINK) $(LINKFLAGS) ldrdf.$(OBJ) $(LDRDFLIBS), ldrdf$(EXE); - -rdx$(EXE) : rdx.$(OBJ) $(RDXLIBS) - - $(LINK) $(LINKFLAGS) rdx.$(OBJ) $(RDXLIBS), rdx$(EXE); - -rdflib$(EXE) : rdflib.$(OBJ) - - $(LINK) $(LINKFLAGS) rdflib.$(OBJ), rdflib$(EXE); - -rdf2bin$(EXE) : rdf2bin.$(OBJ) $(RDXLIBS) $(NASMLIB) - - $(LINK) $(LINKFLAGS) rdf2bin.$(OBJ) $(RDXLIBS) $(NASMLIB), rdf2bin$(EXE); - -rdf2com$(EXE) : rdf2bin$(EXE) - - copy rdf2bin$(EXE) rdf2com$(EXE) - - - -rdf2bin.$(OBJ) : rdf2bin.c - -rdfdump.$(OBJ) : rdfdump.c - -rdoff.$(OBJ) : rdoff.c rdoff.h - -ldrdf.$(OBJ) : ldrdf.c rdoff.h $(NASMLIB_H) symtab.h collectn.h rdlib.h - -symtab.$(OBJ) : symtab.c symtab.h - -collectn.$(OBJ) : collectn.c collectn.h - -rdx.$(OBJ) : rdx.c rdoff.h rdfload.h symtab.h - -rdfload.$(OBJ) : rdfload.c rdfload.h rdoff.h collectn.h symtab.h - -rdlib.$(OBJ) : rdlib.c rdlib.h - -rdflib.$(OBJ) : rdflib.c - - - -clean : - - del *.$(OBJ) rdfdump$(EXE) ldrdf$(EXE) rdx$(EXE) rdflib$(EXE) rdf2bin$(EXE) - - - - - +# 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 = sc
+CCFLAGS = -I..\ -c -a1 -mn -Nc -w2 -w7 -o+time -5
+LINK = link
+LINKFLAGS = /noi /exet:NT /su:console
+
+OBJ=obj
+EXE=.exe
+
+NASMLIB = ..\nasmlib.$(OBJ)
+NASMLIB_H = ..\nasmlib.h
+LDRDFLIBS = rdoff.$(OBJ) $(NASMLIB) symtab.$(OBJ) collectn.$(OBJ) rdlib.$(OBJ)
+RDXLIBS = rdoff.$(OBJ) rdfload.$(OBJ) symtab.$(OBJ) collectn.$(OBJ)
+
+.c.$(OBJ):
+ $(CC) $(CCFLAGS) $*.c
+
+all : rdfdump$(EXE) ldrdf$(EXE) rdx$(EXE) rdflib$(EXE) rdf2bin$(EXE) rdf2com$(EXE)
+
+rdfdump$(EXE) : rdfdump.$(OBJ)
+ $(LINK) $(LINKFLAGS) rdfdump.$(OBJ), rdfdump$(EXE);
+ldrdf$(EXE) : ldrdf.$(OBJ) $(LDRDFLIBS)
+ $(LINK) $(LINKFLAGS) ldrdf.$(OBJ) $(LDRDFLIBS), ldrdf$(EXE);
+rdx$(EXE) : rdx.$(OBJ) $(RDXLIBS)
+ $(LINK) $(LINKFLAGS) rdx.$(OBJ) $(RDXLIBS), rdx$(EXE);
+rdflib$(EXE) : rdflib.$(OBJ)
+ $(LINK) $(LINKFLAGS) rdflib.$(OBJ), rdflib$(EXE);
+rdf2bin$(EXE) : rdf2bin.$(OBJ) $(RDXLIBS) $(NASMLIB)
+ $(LINK) $(LINKFLAGS) rdf2bin.$(OBJ) $(RDXLIBS) $(NASMLIB), rdf2bin$(EXE);
+rdf2com$(EXE) : rdf2bin$(EXE)
+ copy rdf2bin$(EXE) rdf2com$(EXE)
+
+rdf2bin.$(OBJ) : rdf2bin.c
+rdfdump.$(OBJ) : rdfdump.c
+rdoff.$(OBJ) : rdoff.c rdoff.h
+ldrdf.$(OBJ) : ldrdf.c rdoff.h $(NASMLIB_H) symtab.h collectn.h rdlib.h
+symtab.$(OBJ) : symtab.c symtab.h
+collectn.$(OBJ) : collectn.c collectn.h
+rdx.$(OBJ) : rdx.c rdoff.h rdfload.h symtab.h
+rdfload.$(OBJ) : rdfload.c rdfload.h rdoff.h collectn.h symtab.h
+rdlib.$(OBJ) : rdlib.c rdlib.h
+rdflib.$(OBJ) : rdflib.c
+
+clean :
+ del *.$(OBJ) rdfdump$(EXE) ldrdf$(EXE) rdx$(EXE) rdflib$(EXE) rdf2bin$(EXE)
+
+
+
\ No newline at end of file diff --git a/rdoff/Makefile.unx b/rdoff/Makefile.unx index f155839..89d439f 100644 --- a/rdoff/Makefile.unx +++ b/rdoff/Makefile.unx @@ -25,8 +25,8 @@ INSTALL_PROGRAM = ${INSTALL} INSTALL_DATA = ${INSTALL} -m 644 LN_S = ln -s -LDRDFLIBS = rdoff.o nasmlib.o symtab.o collectn.o rdlib.o -RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o +LDRDFLIBS = rdoff.o ../nasmlib.o symtab.o hash.o collectn.o rdlib.o segtab.o +RDXLIBS = rdoff.o rdfload.o symtab.o hash.o collectn.o .c.o: $(CC) -c $(CFLAGS) $*.c @@ -51,12 +51,14 @@ 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 rdlib.h -symtab.o: symtab.c symtab.h +symtab.o: symtab.c symtab.h hash.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 +hash.o: hash.c hash.h +segtab.o: segtab.c segtab.h nasmlib.o: ../nasmlib.c ../nasmlib.h ../names.c ../nasm.h $(CC) -c $(CFLAGS) ../nasmlib.c diff --git a/rdoff/README b/rdoff/README index bea5ecb..29f9aa0 100644 --- a/rdoff/README +++ b/rdoff/README @@ -1,22 +1,45 @@ -RDOFF Utils v0.2 +RDOFF Utils v0.3 ================ 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: +RDOFF version 2 object files. Note that these programs (with the +exception of 'rdfdump') will NOT work with version 1 object files. See +the subdirectory v1 for programs that perform that task. + +Note: If you do not have a v1 subdirectory, you may have unpacked the +ZIP file without specifying the 'restore directory structure' option - +delete these files, and run your ZIP extracter again with this option +turned on ('-d' for PKUNZIP). + +RDOFF version 1 is no longer really supported, you should be using +v2 instead now. + +There is also a 'Changes' file, which documents the differences between +RDOFF 1 and 2, and an 'rdoff2.txt' file, with complete documentation for the +new format. + +Here is a brief summary of the programs' 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. +of the segments. Usage: rdfdump [-v] filename The -v flag specifies that the hex dump (see above) should be printed. +Changes from previous versions: + +* rdfdump supports both version 1 and 2 of RDOFF. +* rdfdump now gives warnings if the RDOFF2 format is violated (it + looks for incorrect lengths for header records, and checks the + overall length count at the start of the file) + ldrdf ===== @@ -66,19 +89,84 @@ Usage: Valid commands are: - c Create the library + c Create (or truncate) 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...) + t List modules in the library -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 +A remove command will be added soon (it is already documented +as existing, but I haven't had time to implement it... 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). +Library functions +================= + +The files 'rdoff.c', 'rdoff.h', 'rdfload.c' and 'rdfload.h' contain +code which you may find useful. They retain the same interface as +the previous version, so any code that used them previously should +still work OK (maybe). 'rdoff.c' contains at the top a line: + +#define STRICT_ERRORS + +Comment this line out if you wish to use record types other than the +7 predefined types; it will then not report such records as an error, +but accept them gracefully, and read them byte for byte into +a 'generic record' (see the definition of GenericRec in 'rdoff.h'). + +If you are using these functions to write RDF modules (rather than +just reading them), then please note the existance of a new function +'rdfaddsegment(rdf_headerbuf,long)'. This must be called once for +each segment in your object, to tell the header writing functions +how long the segment is. + +BUGS +==== + +This product has recently undergone a major revision, and as such there +are probably several bugs left over from the testing phase (although the +previous version had quite a few that have now been fixed!). Could you +please report any bugs to me at the address below, including the following +information: + + - A description of the bug + - What you think the program should be doing + - Which programs you are using + - Which operating system you are using, and which C compiler was used to + compile the programs (or state that the pre-compiled versions were used). + - If appropriate, any of the following: + * source code (preferably cut down to a minimum that will still assemble + and show the bug) + * the output of rdfdump on produced modules (or send the module if the + problem is in code generated) + * exact descriptions of error messages/symptoms/etc + +TODO +==== + +There are still various things unimplemented that I would like to add. +If you want to find out what these are, search near the top of each *.c +file for a comment containing the word 'TODO'. A brief list is given here: + +- Improve the performace of ldrdf (there are several enhancements I can think + of that wouldn't be too hard to add) +- Stop assuming that we're on a little endian machine +- Make everything work with both formats (?) +- Add extra functions to ldrdf (strip symbols/keep symbol list) +- Check for more bugs + +One last thing I have to say: good luck! Whatever it is that you want to use +RDOFF for, I hope its a success. People out there are using it for many +diverse applications, from operating system boot-loaders to loadable modules +in games. Whatever your application is, I hope that it works, and that you +have a good time writing it. + + + Julian Hall <jules@earthcorp.com> diff --git a/rdoff/hash.c b/rdoff/hash.c new file mode 100644 index 0000000..c22d182 --- /dev/null +++ b/rdoff/hash.c @@ -0,0 +1,95 @@ +/* hash.h Routines to calculate a CRC32 hash value + * + * These routines donated to the NASM effort by Graeme Defty. + * + * 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 "hash.h" + +typedef unsigned int crc32; + +const crc32 consttab[] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; + +unsigned +hash (const char *name) +{ + register const char *n; + register crc32 hashval = 0xffffffff; + + for (n=name; *n ; n++) + hashval = (hashval>>8) ^ consttab[(hashval^*n) & 0xff]; + + hashval ^= 0xffffffff; + + return (hashval); + +} + diff --git a/rdoff/hash.h b/rdoff/hash.h new file mode 100644 index 0000000..2ccf9b9 --- /dev/null +++ b/rdoff/hash.h @@ -0,0 +1,12 @@ +/* hash.h Routines to calculate a CRC32 hash value + * + * These routines donated to the NASM effort by Graeme Defty. + * + * 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. + */ + +unsigned hash (const char* name); + diff --git a/rdoff/ldrdf.c b/rdoff/ldrdf.c index 9e4a215..72f8725 100644 --- a/rdoff/ldrdf.c +++ b/rdoff/ldrdf.c @@ -1,4 +1,4 @@ -/* ldrdf.c RDOFF Object File linker/loader main program +/* 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 @@ -6,18 +6,23 @@ * 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. +/* + * TODO: actually get this new version working! + * - finish off write_output() - appears to be done + * - implement library searching - appears to be done + * - maybe we only want to do one pass, for performance reasons? + * this makes things a little harder, but unix 'ld' copes... + * - implement command line options - appears to be done + * - improve symbol table implementation - done, thanks to Graeme Defty + * - keep a cache of symbol names in each library module so + * we don't have to constantly recheck the file + * - general performance improvements * - * 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. (Could make this an - * external utility) + * BUGS & LIMITATIONS: this program doesn't support multiple code, data + * or bss segments, therefore for 16 bit programs whose code, data or BSS + * segment exceeds 64K in size, it will not work. This program probably + * wont work if compiled by a 16 bit compiler. Try DJGPP if you're running + * under DOS. '#define STINGY_MEMORY' may help a little. */ #include <stdio.h> @@ -25,704 +30,1088 @@ #include <string.h> #include "rdoff.h" -#include "nasmlib.h" #include "symtab.h" #include "collectn.h" #include "rdlib.h" +#include "segtab.h" -#define LDRDF_VERSION "0.30" +#define LDRDF_VERSION "1.00 alpha 1" -/* global variables - those to set options: */ +#define RDF_MAXSEGS 64 +/* #define STINGY_MEMORY */ -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 */ +/* ======================================================================= + * Types & macros that are private to this program + */ + +struct segment_infonode { + int dest_seg; /* output segment to be placed into, -1 to + skip linking this segment */ + long reloc; /* segment's relocation factor */ +}; -/* 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; + rdffile f; /* the RDOFF file structure */ + struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing + with each segment? */ + void * header; + char * name; + struct modulenode * next; + long bss_reloc; }; +#include "ldsegs.h" + #define newstr(str) strcpy(malloc(strlen(str) + 1),str) #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2) +/* ========================================================================== + * Function prototypes of private utility functions + */ -struct modulenode *modules = NULL,*lastmodule = NULL; +void processmodule(const char * filename, struct modulenode * mod); +int allocnewseg(int16 type,int16 reserved); +int findsegment(int16 type,int16 reserved); +void symtab_add(const char * symbol, int segment, long offset); +int symtab_get(const char * symbol, int * segment, long * offset); -/* the linked list of libraries to be searched for missing imported - symbols */ +/* ========================================================================= + * Global data structures. + */ -struct librarynode * libraries = NULL, * lastlib = NULL; +/* a linked list of modules that will be included in the output */ +struct modulenode * modules = NULL; +struct modulenode * lastmodule = NULL; -void *symtab; /* The symbol table */ +/* a linked list of libraries to be searched for unresolved imported symbols */ +struct librarynode * libraries = NULL; +struct librarynode * lastlib = NULL; -rdf_headerbuf * newheader ; /* New header to be written to output */ +/* the symbol table */ +void * symtab = NULL; -/* loadmodule - find the characteristics of a module and add it to the - * list of those being linked together */ +/* the header of the output file, built up stage by stage */ +rdf_headerbuf * newheader = NULL; -void loadmodule(char *filename) +/* The current state of segment allocation, including information about + * which output segment numbers have been allocated, and their types and + * amount of data which has already been allocated inside them. + */ +struct SegmentHeaderRec outputseg[RDF_MAXSEGS]; +int nsegs = 0; +long bss_length; + +/* global options which affect how the program behaves */ +struct ldrdfoptions { + int verbose; + int align; + int warnUnresolved; + int strip; +} options; + +int errorcount = 0; /* determines main program exit status */ + +/* ========================================================================= + * Utility functions + */ + + +/* + * initsegments() + * + * sets up segments 0, 1, and 2, the initial code data and bss segments + */ + +void initsegments() { - 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); - - 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); - } + nsegs = 3; + outputseg[0].type = 1; + outputseg[0].number = 0; + outputseg[0].reserved = 0; + outputseg[0].length = 0; + outputseg[1].type = 2; + outputseg[1].number = 1; + outputseg[1].reserved = 0; + outputseg[1].length = 0; + outputseg[2].type = 0xFFFF; /* reserved segment type */ + outputseg[2].number = 2; + outputseg[2].reserved = 0; + outputseg[2].length = 0; + bss_length = 0; } -/* load_library add a library to list of libraries to search - * for undefined symbols +/* + * loadmodule + * + * Determine the characteristics of a module, and decide what to do with + * each segment it contains (including determining destination segments and + * relocation factors for segments that are kept). */ -void load_library(char * name) +void loadmodule(const char * filename) { - if (verbose) - printf("adding library %s to search path\n",name); - - if (! lastlib) { - lastlib = libraries = malloc(sizeof(struct librarynode)); + if (options.verbose) + printf("loading `%s'\n", filename); + + /* allocate a new module entry on the end of the modules list */ + if (!modules) + { + modules = malloc (sizeof(*modules)); + lastmodule = modules; } else { - lastlib->next = malloc(sizeof(struct librarynode)); - lastlib = lastlib->next; + lastmodule->next = malloc (sizeof(*modules)); + lastmodule = lastmodule->next; } - if (! lastlib) { + if ( ! lastmodule) + { 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; -} + /* open the file using 'rdfopen', which returns nonzero on error */ -/* build_symbols() step through each module's header, and locate - * exported symbols, placing them in a global table - */ + if (rdfopen(&lastmodule->f, filename) != 0) + { + rdfperror("ldrdf", filename); + exit(1); + } -long bsslength; + /* + * store information about the module, and determine what segments + * it contains, and what we should do with them (determine relocation + * factor if we decide to keep them) + */ -void mod_addsymbols(struct modulenode * mod) + lastmodule->header = NULL; + lastmodule->name = strdup(filename); + lastmodule->next = NULL; + + processmodule(filename, lastmodule); +} + +/* + * processmodule() + * + * step through each segment, determine what exactly we're doing with + * it, and if we intend to keep it, determine (a) which segment to + * put it in and (b) whereabouts in that segment it will end up. + * (b) is fairly easy, cos we're now keeping track of how big each segment + * in our output file is... + */ + +void processmodule(const char * filename, struct modulenode * mod) { - rdfheaderrec *r; - symtabEnt e; - long cbBss; - - mod->bssrel = bsslength; - cbBss = 0; - rdfheaderrewind(&mod->f); - while ((r = rdfgetheaderrec(&mod->f))) + struct segconfig sconf; + int seg, outseg; + void * header; + rdfheaderrec * hr; + long bssamount = 0; + + for (seg = 0; seg < mod->f.nsegs; seg++) { + /* + * get the segment configuration for this type from the segment + * table. getsegconfig() is a macro, defined in ldsegs.h. + */ + getsegconfig(sconf, mod->f.seg[seg].type); + + if (options.verbose > 1) { + printf ("%s %04x [%04x:%10s] ", filename, mod->f.seg[seg].number, + mod->f.seg[seg].type, sconf.typedesc); + } + /* + * sconf->dowhat tells us what to do with a segment of this type. + */ + switch (sconf.dowhat) { + case SEG_IGNORE: + /* + * Set destination segment to -1, to indicate that this segment + * should be ignored for the purpose of output, ie it is left + * out of the linked executable. + */ + mod->seginfo[seg].dest_seg = -1; + if (options.verbose > 1) printf("IGNORED\n"); + break; - if (r->type == 5) /* Allocate BSS */ - cbBss += r->b.amount; + case SEG_NEWSEG: + /* + * The configuration tells us to create a new segment for + * each occurrence of this segment type. + */ + outseg = allocnewseg(sconf.mergetype, + mod->f.seg[seg].reserved); + mod->seginfo[seg].dest_seg = outseg; + mod->seginfo[seg].reloc = 0; + outputseg[outseg].length = mod->f.seg[seg].length; + if (options.verbose > 1) + printf ("=> %04x:%08lx (+%04lx)\n", outseg, + mod->seginfo[seg].reloc, + mod->f.seg[seg].length); + break; - if (r->type != 3) continue; /* ignore all but export recs */ + case SEG_MERGE: + /* + * The configuration tells us to merge the segment with + * a previously existing segment of type 'sconf.mergetype', + * if one exists. Otherwise a new segment is created. + * This is handled transparently by 'findsegment()'. + */ + outseg = findsegment(sconf.mergetype, + mod->f.seg[seg].reserved); + mod->seginfo[seg].dest_seg = outseg; + + /* + * We need to add alignment to these segments. + */ + if (outputseg[outseg].length % options.align != 0) + outputseg[outseg].length += + options.align - (outputseg[outseg].length % options.align); + + mod->seginfo[seg].reloc = outputseg[outseg].length; + outputseg[outseg].length += mod->f.seg[seg].length; - 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); + if (options.verbose > 1) + printf ("=> %04x:%08lx (+%04lx)\n", outseg, + mod->seginfo[seg].reloc, + mod->f.seg[seg].length); } - 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); - } -} + /* + * extract symbols from the header, and dump them into the + * symbol table + */ + header = malloc(mod->f.header_len); + if (!header) { + fprintf(stderr, "ldrdf: not enough memory\n"); + exit(1); + } + if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) { + rdfperror("ldrdf", filename); + exit(1); + } + while ((hr = rdfgetheaderrec (&mod->f))) + { + switch(hr->type) { + case 2: /* imported symbol - define with seg = -1 */ + case 7: + symtab_add(hr->i.label, -1, 0); + break; -/* 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. */ + case 3: /* exported symbol */ + if (mod->seginfo[(int)hr->e.segment].dest_seg == -1) + continue; + symtab_add(hr->e.label, mod->seginfo[(int)hr->e.segment].dest_seg, + mod->seginfo[(int)hr->e.segment].reloc + hr->e.offset); + break; -void scan_libraries(void) -{ - struct modulenode * mod, * nm; - struct librarynode * lib; - rdfheaderrec * r; - int found; - char * tmp; + case 5: /* BSS reservation */ + /* + * first, amalgamate all BSS reservations in this module + * into one, because we allow this in the output format. + */ + bssamount += hr->b.amount; + break; + } + } - if (verbose) printf("Scanning libraries for unresolved symbols...\n"); + if (bssamount != 0) + { + /* + * handle the BSS segment - first pad the existing bss length + * to the correct alignment, then store the length in bss_reloc + * for this module. Then add this module's BSS length onto + * bss_length. + */ + if (bss_length % options.align != 0) + bss_length += options.align - (bss_length % options.align); + + mod->bss_reloc = bss_length; + if (options.verbose > 1) { + printf ("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n", + filename, bss_length, bssamount); + } + bss_length += bssamount; + } - mod = modules; +#ifdef STINGY_MEMORY + /* + * we free the header buffer here, to save memory later. + * this isn't efficient, but probably halves the memory usage + * of this program... + */ + mod->f.header_loc = NULL; + free(header); - while (mod) - { - rdfheaderrewind(&mod->f); +#endif - 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; +/* + * allocnewseg() + * findsegment() + * + * These functions manipulate the array of output segments, and are used + * by processmodule(). allocnewseg() allocates a segment in the array, + * initialising it to be empty. findsegment() first scans the array for + * a segment of the type requested, and if one isn't found allocates a + * new one. + */ +int allocnewseg(int16 type,int16 reserved) +{ + outputseg[nsegs].type = type; + outputseg[nsegs].number = nsegs; + outputseg[nsegs].reserved = reserved; + outputseg[nsegs].length = 0; + outputseg[nsegs].offset = 0; + outputseg[nsegs].data = NULL; + + return nsegs++; +} - tmp = newstr(r->i.label); - while (! found && lib) - { - /* move this to an outer loop...! */ - nm = malloc(sizeof(struct modulenode)); +int findsegment(int16 type,int16 reserved) +{ + int i; - if (rdl_searchlib(lib,tmp,&nm->f)) - { /* found a module in the library */ + for (i = 0; i < nsegs; i++) + if (outputseg[i].type == type) return i; - /* create a modulenode for it */ + return allocnewseg(type,reserved); +} - if (! nm) { - fprintf(stderr,"ldrdf: out of memory\n"); - exit(1); - } +/* + * symtab_add() + * + * inserts a symbol into the global symbol table, which associates symbol + * names either with addresses, or a marker that the symbol hasn't been + * resolved yet, or possibly that the symbol has been defined as + * contained in a dynamic [load time/run time] linked library. + * + * segment = -1 => not yet defined + * segment = -2 => defined as dll symbol + * + * If the symbol is already defined, and the new segment >= 0, then + * if the original segment was < 0 the symbol is redefined, otherwise + * a duplicate symbol warning is issued. If new segment == -1, this + * routine won't change a previously existing symbol. It will change + * to segment = -2 only if the segment was previously < 0. + */ - nm->name = newstrcat(lib->name,nm->f.name); - if (verbose >= 2) printf("found in '%s'\n",nm->name); +void symtab_add(const char * symbol, int segment, long offset) +{ + symtabEnt * ste; - nm->coderel = lastmodule->coderel + lastmodule->f.code_len; - if (nm->coderel % align != 0) - nm->coderel += align - (nm->coderel % align); + ste = symtabFind(symtab, symbol); + if (ste) + { + if (ste->segment >= 0) { + /* + * symbol previously defined + */ + if (segment < 0) return; + fprintf (stderr, "warning: `%s' redefined\n", symbol); + return; + } - nm->datarel = lastmodule->datarel + lastmodule->f.data_len; - if (nm->datarel % align != 0) - nm->datarel += align - (nm->datarel % align); + /* + * somebody wanted the symbol, and put an undefined symbol + * marker into the table + */ + if (segment == -1) return; + /* + * we have more information now - update the symbol's entry + */ + ste->segment = segment; + ste->offset = offset; + ste->flags = 0; + return; + } + /* + * this is the first declaration of this symbol + */ + ste = malloc(sizeof(symtabEnt)); + if (!ste) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + ste->name = strdup(symbol); + ste->segment = segment; + ste->offset = offset; + ste->flags = 0; + symtabInsert(symtab, ste); +} - nm->header = malloc(nm->f.header_len); - if (! nm->header) - { - fprintf(stderr,"ldrdf: out of memory\n"); - exit(1); - } +/* + * symtab_get() + * + * Retrieves the values associated with a symbol. Undefined symbols + * are assumed to have -1:0 associated. Returns 1 if the symbol was + * successfully located. + */ - if (rdfloadseg(&nm->f,RDOFF_HEADER,nm->header)) - { - rdfperror("ldrdf",nm->name); - exit(1); - } +int symtab_get(const char * symbol, int * segment, long * offset) +{ + symtabEnt * ste = symtabFind(symtab, symbol); + if (!ste) { + *segment = -1; + *offset = 0; + return 0; + } + else + { + *segment = ste->segment; + *offset = ste->offset; + return 1; + } +} - nm->next = NULL; - found = 1; - lastmodule->next = nm; - lastmodule = nm; +/* + * add_library() + * + * checks that a library can be opened and is in the correct format, + * then adds it to the linked list of libraries. + */ - 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); +void add_library(const char * name) +{ + if (rdl_verify(name)) { + rdl_perror("ldrdf", name); + errorcount++; + return; + } + if (! libraries) + { + lastlib = libraries = malloc(sizeof(*libraries)); + if (! libraries) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + } + else + { + lastlib->next = malloc(sizeof(*libraries)); + if (!lastlib->next) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + lastlib = lastlib->next; + } + if (rdl_open(lastlib, name)) { + rdl_perror("ldrdf", name); + errorcount++; + return; + } +} - /* add the module's info to the symbol table */ - mod_addsymbols(nm); - } - else +/* + * search_libraries() + * + * scans through the list of libraries, attempting to match symbols + * defined in library modules against symbols that are referenced but + * not defined (segment = -1 in the symbol table) + * + * returns 1 if any extra library modules are included, indicating that + * another pass through the library list should be made (possibly). + */ + +int search_libraries() +{ + struct librarynode * cur; + rdffile f; + int i; + void * header; + int segment; + long offset; + int doneanything = 0, keepfile; + rdfheaderrec * hr; + + cur = libraries; + + while (cur) + { + if (options.verbose > 2) + printf("scanning library `%s'...\n", cur->name); + + for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) + { + if (options.verbose > 3) + printf(" looking in module `%s'\n", f.name); + + header = malloc(f.header_len); + if (!header) { + fprintf(stderr, "ldrdf: not enough memory\n"); + exit(1); + } + if (rdfloadseg(&f, RDOFF_HEADER, header)) { + rdfperror("ldrdf", f.name); + errorcount++; + return 0; + } + + keepfile = 0; + + while ((hr = rdfgetheaderrec (&f))) + { + /* we're only interested in exports, so skip others: */ + if (hr->type != 3) continue; + + /* + * Find the symbol in the symbol table. If the symbol isn't + * defined, we aren't interested, so go on to the next. + * If it is defined as anything but -1, we're also not + * interested. But if it is defined as -1, insert this + * module into the list of modules to use, and go + * immediately on to the next module... + */ + if (! symtab_get(hr->e.label, &segment, &offset) + || segment != -1) { - if (rdl_error) { - rdl_perror("ldrdf",lib->name); - exit(1); - } - free(nm); + continue; } - lib = lib->next; + + doneanything = 1; + keepfile = 1; + + /* + * as there are undefined symbols, we can assume that + * there are modules on the module list by the time + * we get here. + */ + lastmodule->next = malloc(sizeof(*lastmodule->next)); + if (!lastmodule->next) { + fprintf(stderr, "ldrdf: not enough memory\n"); + exit(1); + } + lastmodule = lastmodule->next; + memcpy(&lastmodule->f, &f, sizeof(f)); + lastmodule->name = strdup(f.name); + processmodule(f.name, lastmodule); + break; } - free(tmp); - if (!found && verbose >= 2) printf("not found\n"); + if (!keepfile) + rdfclose(&f); } - mod = mod->next; + if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND) + rdl_perror("ldrdf", cur->name); + cur = cur->next; } + + return doneanything; } -/* load_segments() allocates memory for & loads the code & data segs - * from the RDF modules +/* + * write_output() + * + * this takes the linked list of modules, and walks through it, merging + * all the modules into a single output module, and then writes this to a + * file. */ - -char *text,*data; -long textlength,datalength; - -void load_segments(void) +void write_output(const char * filename) { - 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); + FILE * f = fopen(filename, "wb"); + rdf_headerbuf * rdfheader = rdfnewheader(); + struct modulenode * cur; + int i, availableseg, seg, localseg, isrelative; + void * header; + rdfheaderrec * hr, newrec; + symtabEnt * se; + segtab segs; + long offset; + byte * data; + + if (!f) { + fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename); + 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 */ - 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); - } - rdfclose(&mod->f); /* close file; segments remain */ - mod = mod->next; - } -} + if (!rdfheader) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + + if (options.verbose) + printf ("\nbuilding output module (%d segments)\n", nsegs); -/* link_segments() step through relocation records in each module's - * header, fixing up references. - */ + /* + * Allocate the memory for the segments. We may be better off + * building the output module one segment at a time when running + * under 16 bit DOS, but that would be a slower way of doing this. + * And you could always use DJGPP... + */ + for (i = 0; i < nsegs; i++) + { + outputseg[i].data = malloc(outputseg[i].length); + if (!outputseg[i].data) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + } -void link_segments(void) -{ - struct modulenode *mod; - Collection imports; - symtabEnt *s; - long rel,relto; - 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))) { - if (verbose >= 3) printf("record type: %d\n",r->type); - 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; + /* + * initialise availableseg, used to allocate segment numbers for + * imported and exported labels... + */ + availableseg = nsegs; + + /* + * Step through the modules, performing required actions on each one + */ + for (cur = modules; cur; cur=cur->next) + { + /* + * Read the actual segment contents into the correct places in + * the newly allocated segments + */ + + for (i = 0; i < cur->f.nsegs; i++) + { + int dest = cur->seginfo[i].dest_seg; + + if (dest == -1) continue; + if (rdfloadseg(&cur->f, i, + outputseg[dest].data + cur->seginfo[i].reloc)) + { + rdfperror("ldrdf", cur->name); + exit(1); } - else + } + + /* + * Perform fixups, and add new header records where required + */ + + header = malloc(cur->f.header_len); + if (!header) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + + if (cur->f.header_loc) + rdfheaderrewind(&cur->f); + else + if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) { - bRelative = 0; /* non-relative - need to relocate - * at load time */ - relto = 0; /* placate optimiser warnings */ + rdfperror("ldrdf", cur->name); + exit(1); } + + /* + * we need to create a local segment number -> location + * table for the segments in this module. + */ + init_seglocations(&segs); + for (i = 0; i < cur->f.nsegs; i++) + { + add_seglocation(&segs, cur->f.seg[i].number, + cur->seginfo[i].dest_seg, cur->seginfo[i].reloc); + } + /* + * and the BSS segment (doh!) + */ + add_seglocation (&segs, 2, 2, cur->bss_reloc); - /* 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; + while ((hr = rdfgetheaderrec(&cur->f))) + { + switch(hr->type) { + case 1: /* relocation record - need to do a fixup */ + /* + * First correct the offset stored in the segment from + * the start of the segment (which may well have changed). + * + * To do this we add to the number stored the relocation + * factor associated with the segment that contains the + * target segment. + * + * The relocation could be a relative relocation, in which + * case we have to first subtract the amount we've relocated + * the containing segment by. + */ + + if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) + { + fprintf(stderr, "%s: reloc to undefined segment %04x\n", + cur->name, (int) hr->r.refseg); + errorcount++; 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; - } + isrelative = (hr->r.segment & 64) == 64; + hr->r.segment &= 63; + + if (hr->r.segment == 2 || + (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1) + { + fprintf(stderr, "%s: reloc from %s segment (%d)\n", + cur->name, + hr->r.segment == 2 ? "BSS" : "unknown", + hr->r.segment); + errorcount++; + break; + } - /* Add the relocation factor to the datum specified: */ + if (hr->r.length != 1 && hr->r.length != 2 && hr->r.length!=4) + { + fprintf(stderr, "%s: nonstandard length reloc " + "(%d bytes)\n", cur->name, hr->r.length); + errorcount++; + break; + } - if (verbose >= 3) - printf(" - relocating %d:%08lx by %08lx\n",r->r.segment, - r->r.offset,rel); + /* + * okay, now the relocation is in the segment pointed to by + * cur->seginfo[localseg], and we know everything else is + * okay to go ahead and do the relocation + */ + data = outputseg[cur->seginfo[localseg].dest_seg].data; + data += cur->seginfo[localseg].reloc + hr->r.offset; + + /* + * data now points to the reference that needs + * relocation. Calculate the relocation factor. + * Factor is: + * offset of referred object in segment [in offset] + * (- relocation of localseg, if ref is relative) + * For simplicity, the result is stored in 'offset'. + * Then add 'offset' onto the value at data. + */ + + if (isrelative) offset -= cur->seginfo[localseg].reloc; + switch (hr->r.length) + { + case 1: + offset += *data; + if (offset < -127 || offset > 128) + fprintf(stderr, "warning: relocation out of range " + "at %s(%02x:%08lx)\n", cur->name, + (int)hr->r.segment, hr->r.offset); + *data = (char) offset; + break; + case 2: + offset += * (short *)data; + if (offset < -32767 || offset > 32768) + fprintf(stderr, "warning: relocation out of range " + "at %s(%02x:%08lx)\n", cur->name, + (int)hr->r.segment, hr->r.offset); + * (short *)data = (short) offset; + break; + case 4: + * (long *)data += offset; + /* we can't easily detect overflow on this one */ + break; + } - /**** The following code is non-portable. Rewrite it... ****/ - switch(r->r.length) { - case 1: - seg[r->r.offset] += (char) rel; + /* + * If the relocation was relative between two symbols in + * the same segment, then we're done. + * + * Otherwise, we need to output a new relocation record + * with the references updated segment and offset... + */ + if (! isrelative + || cur->seginfo[localseg].dest_seg != seg) + { + hr->r.segment = cur->seginfo[localseg].dest_seg; + hr->r.offset += cur->seginfo[localseg].reloc; + hr->r.refseg = seg; + rdfaddheader(rdfheader, hr); + } break; - case 2: - *(int16 *)(seg + r->r.offset) += (int16) rel; + + case 2: /* import symbol */ + case 7: + /* + * scan the global symbol table for the symbol + * and associate its location with the segment number + * for this module + */ + se = symtabFind(symtab, hr->i.label); + if (!se || se->segment == -1) { + if (options.warnUnresolved) { + fprintf(stderr, "warning: unresolved reference to `%s'" + " in module `%s'\n", hr->i.label, cur->name); + } + /* + * we need to allocate a segment number for this + * symbol, and store it in the symbol table for + * future reference + */ + if (!se) { + se=malloc(sizeof(*se)); + if (!se) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + se->name = strdup(hr->i.label); + se->flags = 0; + se->segment = availableseg++; + se->offset = 0; + symtabInsert(symtab, se); + } + else { + se->segment = availableseg++; + se->offset = 0; + } + /* + * output a header record that imports it to the + * recently allocated segment number... + */ + newrec = *hr; + newrec.i.segment = se->segment; + rdfaddheader(rdfheader, &newrec); + } + + add_seglocation(&segs, hr->i.segment, se->segment, se->offset); + break; - case 4: - *(long *)(seg + r->r.offset) += rel; + + case 3: /* export symbol */ + /* + * need to insert an export for this symbol into the new + * header, unless we're stripping symbols [unless this + * symbol is in an explicit keep list]. *** FIXME *** + */ + if (options.strip) + break; + + if (hr->e.segment == 2) { + seg = 2; + offset = cur->bss_reloc; + } + else { + localseg = rdffindsegment(&cur->f, hr->e.segment); + if (localseg == -1) { + fprintf(stderr, "%s: exported symbol `%s' from " + "unrecognised segment\n", cur->name, + hr->e.label); + errorcount++; + break; + } + offset = cur->seginfo[localseg].reloc; + seg = cur->seginfo[localseg].dest_seg; + } + + hr->e.segment = seg; + hr->e.offset += offset; + rdfaddheader(rdfheader, hr); 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 6: /* segment fixup */ + /* + * modify the segment numbers if necessary, and + * pass straight through to the output module header + * + * *** FIXME *** + */ + if (hr->r.segment == 2) { + fprintf(stderr, "%s: segment fixup in BSS section\n", + cur->name); + errorcount++; + break; + } + localseg = rdffindsegment(&cur->f, hr->r.segment); + if (localseg == -1) { + fprintf(stderr, "%s: segment fixup in unrecognised" + " segment (%d)\n", cur->name, hr->r.segment); + errorcount++; + break; + } + hr->r.segment = cur->seginfo[localseg].dest_seg; + hr->r.offset += cur->seginfo[localseg].reloc; - case 3: /* export; dump to output new version */ - s = symtabFind(symtab, r->e.label); - if (! s) { - fprintf(stderr,"ldrdf: internal error - undefined symbol %s " - "exported in header of '%s'\n",r->e.label,mod->name); - continue; + if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) + { + fprintf(stderr, "%s: segment fixup to undefined " + "segment %04x\n", cur->name, (int)hr->r.refseg); + errorcount++; + break; + } + hr->r.refseg = seg; + rdfaddheader(rdfheader, hr); + break; } - r->e.offset = s->offset; - rdfaddheader(newheader,r); - break; - - case 4: /* DLL record */ - rdfaddheader(newheader,r); /* copy straight to output */ - 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) -{ - FILE * fp; - rdfheaderrec r; + free(header); + done_seglocations(&segs); + + } - if (verbose) printf("writing output to '%s'\n",filename); + /* + * combined BSS reservation for the entire results + */ + newrec.type = 5; + newrec.b.reclen = 4; + newrec.b.amount = bss_length; + rdfaddheader(rdfheader, &newrec); - fp = fopen(filename,"wb"); - if (! fp) + /* + * Write the header + */ + for (i = 0; i < nsegs; i++) { - fprintf(stderr,"ldrdf: could not open '%s' for writing\n",filename); - exit(1); + if (i == 2) continue; + rdfaddsegment (rdfheader, outputseg[i].length); } - + rdfwriteheader(f, rdfheader); + rdfdoneheader(rdfheader); + /* + * Step through the segments, one at a time, writing out into + * the output file + */ - /* 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) + for (i = 0; i < nsegs; i++) { - fprintf(stderr,"ldrdf: error writing %s\n",filename); - exit(1); + int16 s; + long l; + + if (i == 2) continue; + + s = translateshort(outputseg[i].type); + fwrite(&s, 2, 1, f); + s = translateshort(outputseg[i].number); + fwrite(&s, 2, 1, f); + s = translateshort(outputseg[i].reserved); + fwrite(&s, 2, 1, f); + l = translatelong(outputseg[i].length); + fwrite(&l, 4, 1, f); + + fwrite(outputseg[i].data, outputseg[i].length, 1, f); } - /* 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); + fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f); } - -/* 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. +/* ========================================================================= + * Main program */ -const char *usagemsg = "usage:\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" -" -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" -" -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) +void usage() { - fputs(usagemsg,stderr); + printf("usage:\n"); + printf(" ldrdf [options] object modules ... [-llibrary ...]\n"); + printf(" ldrdf -r\n"); + printf("options:\n"); + printf(" -v[=n] increases verbosity by 1, or sets it to n\n"); + printf(" -a nn sets segment alignment value (default 16)\n"); + printf(" -s strips exported symbols\n"); + printf(" -x warn about unresolved symbols\n"); + printf(" -o name write output in file 'name'\n"); + printf("\n"); + printf("Note: no library searching is performed. Please specify full\n"); + printf("paths to all files referenced.\n"); + exit(0); } -int main(int argc,char **argv) +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); + char * outname = "aout.rdf"; + int moduleloaded = 0; + + options.verbose = 0; + options.align = 16; + options.warnUnresolved = 0; + options.strip = 0; + + argc --, argv ++; + if (argc == 0) usage(); + while (argc && **argv == '-' && argv[0][1] != 'l') + { + switch(argv[0][1]) { + case 'r': + printf("ldrdf (linker for RDF files) version " LDRDF_VERSION "\n"); + printf( _RDOFF_H "\n"); + exit(0); + case 'v': + if (argv[0][2] == '=') { + options.verbose = argv[0][3] - '0'; + if (options.verbose < 0 || options.verbose > 9) { + fprintf(stderr, "ldrdf: verbosity level must be a number" + " between 0 and 9\n"); + exit(1); + } + } + else + options.verbose++; + break; + case 'a': + options.align = atoi(argv[1]); + if (options.align <= 0) { + fprintf(stderr, + "ldrdf: -a expects a positive number argument\n"); + exit(1); + } + argv++, argc--; + break; + case 's': + options.strip = 1; + break; + case 'x': + options.warnUnresolved = 1; + break; + case 'o': + outname = argv[1]; + argv++, argc--; + break; + default: + usage(); + } + argv++, argc--; } - 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); + + if (options.verbose > 4) { + printf("ldrdf invoked with options:\n"); + printf(" section alignment: %d bytes\n", options.align); + printf(" output name: `%s'\n", outname); + if (options.strip) + printf(" strip symbols\n"); + if (options.warnUnresolved) + printf(" warn about unresolved symbols\n"); + printf("\n"); } - else if (procsw && !strcmp(*argv,"-o")) { - ofilename = *++argv; - --argc; - if (execute) { - fprintf(stderr,"ldrdf: -o and -x switches incompatible\n"); + + symtab = symtabNew(); + initsegments(); + + if (!symtab) { + fprintf(stderr, "ldrdf: out of memory\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"); + + while (argc) + { + if (!strncmp(*argv, "-l", 2)) /* library */ + add_library(*argv + 2); + else { + loadmodule(*argv); + moduleloaded = 1; + } + argv++, argc--; } - 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); + + if (! moduleloaded) { + printf("ldrdf: nothing to do. ldrdf -h for usage\n"); + return 0; } - else if (procsw && !strcmp(*argv,"-v")) { - verbose++; - if (verbose == 1) printf("verbose mode selected\n"); + + + search_libraries(); + + if (options.verbose > 2) + { + printf ("symbol table:\n"); + symtabDump(symtab, stdout); } - 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); + + write_output(outname); + + if (errorcount > 0) exit(1); - } - 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; - } - 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 */ - - 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 */ - - 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; + + return 0; } + diff --git a/rdoff/ldrdf1.c b/rdoff/ldrdf1.c new file mode 100644 index 0000000..9e4a215 --- /dev/null +++ b/rdoff/ldrdf1.c @@ -0,0 +1,728 @@ +/* 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 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. (Could make this an + * external utility) + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "rdoff.h" +#include "nasmlib.h" +#include "symtab.h" +#include "collectn.h" +#include "rdlib.h" + +#define LDRDF_VERSION "0.30" + +/* 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; +}; + +#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 */ + +/* 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); + + 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 + * from the RDF modules + */ + +char *text,*data; +long textlength,datalength; + +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 */ + 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); + } + rdfclose(&mod->f); /* close file; segments remain */ + mod = mod->next; + } +} + +/* 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; + 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))) { + if (verbose >= 3) printf("record type: %d\n",r->type); + 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 */ + relto = 0; /* placate optimiser warnings */ + } + + /* 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) { + 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; + + case 4: /* DLL record */ + rdfaddheader(newheader,r); /* copy straight to output */ + 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) +{ + 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) + { + 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" +" [-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" +" -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" +" -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) +{ + 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 && !strncmp(*argv,"-l",2)) { + load_library(*argv + 2); + } + 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 */ + + 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 */ + + 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/ldsegs.h b/rdoff/ldsegs.h new file mode 100644 index 0000000..8b516fa --- /dev/null +++ b/rdoff/ldsegs.h @@ -0,0 +1,55 @@ +/* + * ldsegs.h Data for 'ldrdf' to determine what to do with different + * types of segment. This may be useful in other contexts also. + */ + +#ifndef UI16 +#define UI16 unsigned short +#endif + +struct segconfig { + UI16 typelow, typehi;/* range of seg nos for which this is valid */ + char * typedesc; /* a description of the segment type */ + UI16 dowhat; /* one of the SEG_xxxx values below */ + UI16 mergetype; /* if SEG_MERGE what type segment do we merge with? + 0 -> same type of segment. This type is also + used with SEG_NEWSEG. */ +}; + +#define SEG_IGNORE 0 +#define SEG_NEWSEG 1 +#define SEG_MERGE 2 + +#define SEGCONFIGMAX 11 + +struct segconfig sconft[SEGCONFIGMAX] = { + {0x0000, 0x0000, "NULL segment", 0, 0}, + {0x0001, 0x0001, "text", 2, 0}, + {0x0002, 0x0002, "data", 2, 0}, + {0x0003, 0x0003, "comment(ignored)", 0, 0}, + {0x0004, 0x0005, "comment(kept)", 2, 0}, + {0x0006, 0x0007, "debug information", 2, 0}, + {0x0008, 0x001F, "reserved(general extensions)", 1, 0}, + {0x0020, 0x0FFF, "reserved(MOSCOW)", 1, 0}, + {0x1000, 0x7FFF, "reserved(system dependant)", 1, 0}, + {0x8000, 0xFFFE, "reserved(other)", 1, 0}, + {0xFFFF, 0xFFFF, "invalid segment", 0, 0}}; + +#define getsegconfig(target,number) \ + { \ + int _i; \ + int _t = number; \ + for (_i = 0; _i < SEGCONFIGMAX; _i++) \ + if (_t >= sconft[_i].typelow && _t <= sconft[_i].typehi) \ + { \ + target = sconft[_i]; \ + if (target.mergetype == 0) target.mergetype = _t; \ + break; \ + } \ + if (_i == SEGCONFIGMAX) \ + { \ + fprintf(stderr, "PANIC: can't find segment %04X in segconfig\n",\ + _t); \ + exit(1); \ + } \ + } diff --git a/rdoff/rdf2bin.c b/rdoff/rdf2bin.c index 97b45b4..21ea97d 100644 --- a/rdoff/rdf2bin.c +++ b/rdoff/rdf2bin.c @@ -77,7 +77,7 @@ int main(int argc, char **argv) printf("relocating %s: origin=%lx, align=%d\n",*argv,origin,align); m->textrel = origin; - m->datarel = origin + m->f.code_len; + m->datarel = origin + m->f.seg[0].length; if (m->datarel % align != 0) { codepad = align - (m->datarel % align); m->datarel += codepad; @@ -85,7 +85,7 @@ int main(int argc, char **argv) else codepad = 0; - m->bssrel = m->datarel + m->f.data_len; + m->bssrel = m->datarel + m->f.seg[1].length; if (m->bssrel % align != 0) { datapad = align - (m->bssrel % align); m->bssrel += datapad; @@ -112,9 +112,9 @@ int main(int argc, char **argv) return 1; } - if (fwrite(m->t,1,m->f.code_len,of) != m->f.code_len || + if (fwrite(m->t,1,m->f.seg[0].length,of) != m->f.seg[0].length || fwrite(padding,1,codepad,of) != codepad || - fwrite(m->d,1,m->f.data_len,of) != m->f.data_len) + fwrite(m->d,1,m->f.seg[1].length,of) != m->f.seg[1].length) { fprintf(stderr,"rdf2bin: error writing to %s\n", *argv); return 1; diff --git a/rdoff/rdfdump.c b/rdoff/rdfdump.c index 080c2e7..cb79a64 100644 --- a/rdoff/rdfdump.c +++ b/rdoff/rdfdump.c @@ -4,6 +4,8 @@ FILE *infile; +typedef unsigned short int16; + long translatelong(long in) { /* translate from little endian to local representation */ long r; @@ -18,7 +20,7 @@ long translatelong(long in) { /* translate from little endian to return r; } -int translateshort(short in) { +int translateshort(int16 in) { int r; unsigned char *i; @@ -27,70 +29,136 @@ int translateshort(short in) { return r; } -void print_header(long length) { + +void print_header(long length, int rdf_version) { char buf[129],t,s,l; + unsigned char reclen; long o,ll; - short rs; + int16 rs; while (length > 0) { fread(&t,1,1,infile); + if (rdf_version >= 2) { + fread(&reclen,1,1,infile); + } switch(t) { case 1: /* relocation record */ + case 6: /* segment relocation */ 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, + printf(" %s: location (%04x:%08lx), length %d, " + "referred seg %04x\n", t == 1 ? "relocation" : "seg relocation", + (int)s,translatelong(o),(int)l, translateshort(rs)); - length -= 9; + if (rdf_version >= 2 && reclen != 8) + printf(" warning: reclen != 8\n"); + if (rdf_version == 1) length -= 9; + if (rdf_version == 1 && t == 6) + printf(" warning: seg relocation not supported in RDOFF1\n"); break; case 2: /* import record */ + case 7: /* import far symbol */ fread(&rs,2,1,infile); ll = 0; - do { - fread(&buf[ll],1,1,infile); - } while (buf[ll++]); - printf(" import: segment %04x = %s\n",translateshort(rs),buf); - length -= ll + 3; + + if (rdf_version == 1) { + do { + fread(&buf[ll],1,1,infile); + } while (buf[ll++]); + } + else + { + for (;ll < reclen - 2; ll++) + fread(&buf[ll],1,1,infile); + } + + printf(" %simport: segment %04x = %s\n",t == 7 ? "far " : "", + translateshort(rs),buf); + if (rdf_version == 1) length -= ll + 3; + if (rdf_version == 1 && t == 7) + printf (" warning: far import not supported in RDOFF1\n"); break; case 3: /* export record */ fread(&s,1,1,infile); fread(&o,4,1,infile); ll = 0; - do { - fread(&buf[ll],1,1,infile); - } while (buf[ll++]); + + if (rdf_version == 1) { + do { + fread(&buf[ll],1,1,infile); + } while (buf[ll++]); + } + else + { + for (; ll < reclen - 5; ll ++) + fread(&buf[ll],1,1,infile); + } printf(" export: (%04x:%08lx) = %s\n",(int)s,translatelong(o),buf); - length -= ll + 6; + if (rdf_version == 1) length -= ll + 6; break; case 4: /* DLL record */ ll = 0; - do { - fread(&buf[ll],1,1,infile); - } while (buf[ll++]); + + if (rdf_version == 1) { + do { + fread(&buf[ll],1,1,infile); + } while (buf[ll++]); + } + else + { + for (; ll < reclen - 1; ll++) + fread(&buf[ll],1,1,infile); + } printf(" dll: %s\n",buf); - length -= ll + 1; + if (rdf_version == 1) length -= ll + 1; break; case 5: /* BSS reservation */ fread(&ll,4,1,infile); printf(" bss reservation: %08lx bytes\n",translatelong(ll)); - length -= 5; + if (rdf_version == 1) length -= 5; + if (rdf_version > 1 && reclen != 4) + printf(" warning: reclen != 4\n"); break; default: - printf(" unrecognised record (type %d)\n",(int)t); - length --; + printf(" unrecognised record (type %d",(int)t); + if (rdf_version > 1) printf(", length %d",(int)reclen); + printf(")\n"); + if (rdf_version == 1) length --; } + if (rdf_version != 1) length -= 2 + reclen; } } +char * knowntypes[8] = {"NULL", "text", "data", "object comment", + "linked comment", "loader comment", + "symbolic debug", "line number debug"}; + +char * translatesegmenttype(int16 type) { + if (type < 8) return knowntypes[type]; + if (type < 0x0020) return "reserved"; + if (type < 0x1000) return "reserved - moscow"; + if (type < 0x8000) return "reserved - system dependant"; + if (type < 0xFFFF) return "reserved - other"; + if (type == 0xFFFF) return "invalid type code"; + return "type code out of range"; +} + int main(int argc,char **argv) { char id[7]; long l; + int16 s; int verbose = 0; long offset; + int foundnullsegment = 0; + int version; + long segmentcontentlength = 0; + int nsegments = 0; + long headerlength = 0; + long objectlength = 0; - puts("RDOFF Dump utility v1.1 (C) Copyright 1996 Julian R Hall"); + puts("RDOFF Dump utility v2.0 (C) Copyright 1996 Julian R Hall"); if (argc < 2) { fputs("Usage: rdfdump [-v] <filename>\n",stderr); @@ -121,46 +189,103 @@ int main(int argc,char **argv) { } printf("File %s: RDOFF version %c\n\n",argv[1],id[5]); - if (id[5] < '1' || id[5] > '1') { + if (id[5] < '1' || id[5] > '2') { fprintf(stderr,"rdfdump: unknown RDOFF version '%c'\n",id[5]); exit(1); } + version = id[5] - '0'; - 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); - offset = 0; - while(l--) { - fread(id,1,1,infile); - if (verbose) { - if (offset % 16 == 0) - printf("\n%08lx ", offset); - printf(" %02x",(int) (unsigned char)id[0]); - offset++; - } + if (version > 1) { + fread(&l, 4, 1, infile); + objectlength = translatelong(l); + printf("Object content size: %ld bytes\n", objectlength); } - if (verbose) printf("\n\n"); fread(&l,4,1,infile); - l = translatelong(l); - printf("Data segment length = %ld bytes\n",l); + headerlength = translatelong(l); + printf("Header (%ld bytes):\n",headerlength); + print_header(headerlength, version); + + if (version == 1) { + fread(&l,4,1,infile); + l = translatelong(l); + printf("\nText segment length = %ld bytes\n",l); + offset = 0; + while(l--) { + fread(id,1,1,infile); + if (verbose) { + if (offset % 16 == 0) + printf("\n%08lx ", offset); + printf(" %02x",(int) (unsigned char)id[0]); + offset++; + } + } + if (verbose) printf("\n\n"); + + fread(&l,4,1,infile); + l = translatelong(l); + printf("Data segment length = %ld bytes\n",l); - if (verbose) + if (verbose) + { + offset = 0; + while (l--) { + fread(id,1,1,infile); + if (offset % 16 == 0) + printf("\n%08lx ", offset); + printf(" %02x",(int) (unsigned char) id[0]); + offset++; + } + printf("\n"); + } + } + else { - offset = 0; - while (l--) { - fread(id,1,1,infile); - if (offset % 16 == 0) - printf("\n%08lx ", offset); - printf(" %02x",(int) (unsigned char) id[0]); - offset++; - } - printf("\n"); + do { + fread(&s,2,1,infile); + s = translateshort(s); + if (!s) { + printf("\nNULL segment\n"); + foundnullsegment = 1; + break; + } + printf("\nSegment:\n Type = %04X (%s)\n",(int)s, + translatesegmenttype(s)); + nsegments++; + + fread(&s,2,1,infile); + printf(" Number = %04X\n",(int)translateshort(s)); + fread(&s,2,1,infile); + printf(" Resrvd = %04X\n",(int)translateshort(s)); + fread(&l,4,1,infile); + l = translatelong(l); + printf(" Length = %ld bytes\n",l); + segmentcontentlength += l; + + offset = 0; + while(l--) { + fread(id,1,1,infile); + if (verbose) { + if (offset % 16 == 0) + printf("\n%08lx ", offset); + printf(" %02x",(int) (unsigned char)id[0]); + offset++; + } + } + if (verbose) printf("\n"); + } while (!feof(infile)); + if (! foundnullsegment) + printf("\nWarning: unexpected end of file - " + "NULL segment not found\n"); + + printf("\nTotal number of segments: %d\n", nsegments); + printf("Total segment content length: %ld bytes\n",segmentcontentlength); + + /* calculate what the total object content length should have been */ + l = segmentcontentlength + 10 * (nsegments+1) + headerlength + 4; + if (l != objectlength) + printf("Warning: actual object length (%ld) != " + "stored object length (%ld)\n", l, objectlength); } fclose(infile); return 0; diff --git a/rdoff/rdflib.c b/rdoff/rdflib.c index 5846562..7a00fc6 100644 --- a/rdoff/rdflib.c +++ b/rdoff/rdflib.c @@ -1,12 +1,22 @@ /* 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. */ +/* + * 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 'RDLDD' 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. The module name of the directory + * must be '.dir'. + * + * All module names beginning with '.' are reserved + * for possible future extensions. The linker ignores all such modules, + * assuming they have the format of a six byte type & version identifier + * followed by long content size, followed by data. + */ #include <stdio.h> #include <errno.h> @@ -15,7 +25,7 @@ /* 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) + remove a module from a library (requires given name) (not implemented) extract a module from the library (requires given name and filename) list modules */ @@ -25,7 +35,7 @@ const char *usage = " where x is one of:\n" " c - create library\n" " a - add module (operands = filename module-name)\n" - " r - remove (module-name)\n" + " r - remove (module-name) [not implemented]\n" " x - extract (module-name filename)\n" " t - list\n"; @@ -48,26 +58,27 @@ static void longtolocal(long * l) #endif } -void copybytes(FILE *fp, FILE *fp2, int n) +char copybytes(FILE *fp, FILE *fp2, int n) { - int i,t; + int i, t = 0; for (i = 0 ; i < n; i++ ) { t = fgetc(fp); if (t == EOF) { - fprintf(stderr,"ldrdf: premature end of file in '%s'\n", + fprintf(stderr,"rdflib: premature end of file in '%s'\n", _argv[2]); exit(1); } if (fp2) if (fputc(t, fp2) == EOF) { - fprintf(stderr,"ldrdf: write error\n"); + fprintf(stderr,"rdflib: write error\n"); exit(1); } } + return (char) t; /* return last char read */ } long copylong(FILE *fp, FILE *fp2) @@ -82,14 +93,14 @@ long copylong(FILE *fp, FILE *fp2) t = fgetc(fp); if (t == EOF) { - fprintf(stderr,"ldrdf: premature end of file in '%s'\n", + fprintf(stderr,"rdflib: premature end of file in '%s'\n", _argv[2]); exit(1); } if (fp2) if (fputc(t, fp2) == EOF) { - fprintf(stderr,"ldrdf: write error\n"); + fprintf(stderr,"rdflib: write error\n"); exit(1); } *p++ = t; @@ -101,8 +112,9 @@ long copylong(FILE *fp, FILE *fp2) int main(int argc, char **argv) { FILE *fp, *fp2; - char *p, buf[256]; + char *p, buf[256], c; int i; + long l; _argv = argv; @@ -117,8 +129,8 @@ int main(int argc, char **argv) case 'c': /* create library */ fp = fopen(argv[2],"wb"); if (! fp) { - fprintf(stderr,"ldrdf: could not open '%s'\n",argv[2]); - perror("ldrdf"); + fprintf(stderr,"rdflib: could not open '%s'\n",argv[2]); + perror("rdflib"); exit(1); } fclose(fp); @@ -126,29 +138,29 @@ int main(int argc, char **argv) case 'a': /* add module */ if (argc < 5) { - fprintf(stderr,"ldrdf: required parameter missing\n"); + fprintf(stderr,"rdflib: 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"); + fprintf(stderr,"rdflib: could not open '%s'\n",argv[2]); + perror("rdflib"); exit(1); } fp2 = fopen(argv[3],"rb"); if (! fp) { - fprintf(stderr,"ldrdf: could not open '%s'\n",argv[3]); - perror("ldrdf"); + fprintf(stderr,"rdflib: could not open '%s'\n",argv[3]); + perror("rdflib"); exit(1); } p = argv[4]; do { if ( fputc(*p,fp) == EOF ) { - fprintf(stderr,"ldrdf: write error\n"); + fprintf(stderr,"rdflib: write error\n"); exit(1); } } while (*p++); @@ -160,7 +172,7 @@ int main(int argc, char **argv) } if ( fputc(i, fp) == EOF ) { - fprintf(stderr,"ldrdf: write error\n"); + fprintf(stderr,"rdflib: write error\n"); exit(1); } } @@ -170,15 +182,19 @@ int main(int argc, char **argv) case 'x': if (argc < 5) { - fprintf(stderr,"ldrdf: required parameter missing\n"); + fprintf(stderr,"rdflib: required parameter missing\n"); + exit(1); + } + case 't': + if (argc < 3) { + fprintf(stderr, "rdflib: required paramenter missing\n"); exit(1); } - fp = fopen(argv[2],"rb"); if (! fp) { - fprintf(stderr,"ldrdf: could not open '%s'\n",argv[2]); - perror("ldrdf"); + fprintf(stderr,"rdflib: could not open '%s'\n",argv[2]); + perror("rdflib"); exit(1); } @@ -191,25 +207,60 @@ int main(int argc, char **argv) if (feof(fp)) break; - /* check against desired name */ - if (! strcmp(buf,argv[3]) ) - { - fp2 = fopen(argv[4],"wb"); - if (! fp2) + fp2 = NULL; + if (argv[1][0] == 'x') { + /* check against desired name */ + if (! strcmp(buf,argv[3]) ) { - fprintf(stderr,"ldrdf: could not open '%s'\n", argv[4]); - perror("ldrdf"); - exit(1); + fp2 = fopen(argv[4],"wb"); + if (! fp2) + { + fprintf(stderr,"rdflib: could not open '%s'\n",argv[4]); + perror("rdflib"); + exit(1); + } } } else - fp2 = NULL; + printf("%-40s ", buf); + + /* step over the RDOFF file, extracting type information for + * the listing, and copying it if fp2 != NULL */ + + if (buf[0] == '.') { + + if (argv[1][0] == 't') + for (i = 0; i < 6; i++) + printf("%c", copybytes(fp,fp2,1)); + else + copybytes(fp,fp2,6); - /* 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 */ + l = copylong(fp,fp2); + + if (argv[1][0] == 't') printf(" %ld bytes content\n", l); + + copybytes(fp,fp2,l); + } + else if ((c=copybytes(fp,fp2,6)) >= '2') /* version 2 or above */ + { + l = copylong(fp,fp2); + + if (argv[1][0] == 't') + printf("RDOFF%c %ld bytes content\n", c, l); + copybytes(fp,fp2, l); /* entire object */ + } + else + { + if (argv[1][0] == 't') + printf("RDOFF1\n"); + /* + * version 1 object, so we don't have an object content + * length field. + */ + copybytes(fp,fp2, copylong(fp,fp2)); /* header */ + copybytes(fp,fp2, copylong(fp,fp2)); /* text */ + copybytes(fp,fp2, copylong(fp,fp2)); /* data */ + } if (fp2) break; @@ -217,16 +268,16 @@ int main(int argc, char **argv) fclose(fp); if (fp2) fclose(fp2); - else + else if (argv[1][0] == 'x') { - fprintf(stderr,"ldrdf: module '%s' not found in '%s'\n", + fprintf(stderr,"rdflib: module '%s' not found in '%s'\n", argv[3],argv[2]); exit(1); } break; default: - fprintf(stderr,"ldrdf: command '%c' not recognised\n", + fprintf(stderr,"rdflib: command '%c' not recognised\n", argv[1][0]); exit(1); } diff --git a/rdoff/rdfload.c b/rdoff/rdfload.c index b848344..5b98103 100644 --- a/rdoff/rdfload.c +++ b/rdoff/rdfload.c @@ -10,6 +10,13 @@ * with instructions of how to obtain a copy via ftp. */ +/* + * TODO: this has been modified from previous version only in very + * simplistic ways. Needs to be improved drastically, especially: + * - support for more than the 2 standard segments + * - support for segment relocations (hard to do in ANSI C) + */ + #include <stdlib.h> #include <stdio.h> @@ -49,8 +56,8 @@ 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 */ + f->t = malloc (f->f.seg[0].length); + f->d = malloc (f->f.seg[1].length); /* BSS seg allocated later */ hdr = malloc (f->f.header_len); if (! f->t || ! f->d || !hdr) { @@ -135,7 +142,7 @@ int rdf_relocate(rdfmodule * m) if ((r->r.segment & 63) == 0) seg = m->t; else if ((r->r.segment & 63) == 1) seg = m->d; else - return 1; + continue; /* relocation not in a loaded segment */ /* it doesn't matter in this case that the code is non-portable, as the entire concept of executing a module like this is @@ -167,6 +174,11 @@ int rdf_relocate(rdfmodule * m) strcpy(e.name,r->e.label); symtabInsert(m->symtab,&e); break; + + case 6: /* segment relocation */ + fprintf(stderr, "%s: segment relocation not supported by this " + "loader\n", m->f.name); + return 1; } } return 0; diff --git a/rdoff/rdlib.c b/rdoff/rdlib.c index bc8d1e3..ed78a00 100644 --- a/rdoff/rdlib.c +++ b/rdoff/rdlib.c @@ -1,22 +1,113 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "rdoff.h" #include "rdlib.h" +/* + * format of rdoff library files: + * repeat + * null terminated module name (max 255 chars) + * RDOFF module + * until eof + */ + +/* + * TODO + * + * No support exists yet for special modules. But we aren't using + * any special modules yet. They are only defined now so that their + * existance doesn't break older versions of the linker... presently + * anything whose name begins with '.' is ignored. + */ + int rdl_error = 0; -char *rdl_errors[3] = { +char *rdl_errors[5] = { "no error","could not open file", "invalid file structure", + "file contains modules of an unsupported RDOFF version", + "module not found" }; +int rdl_verify(const char * filename) +{ + FILE * fp = fopen(filename, "rb"); + char buf[257]; + int i; + long length; + static char lastverified[256]; + static int lastresult = -1; + + if (lastresult != -1 && !strcmp(filename, lastverified)) + return lastresult; + + strcpy(lastverified, filename); + + if (!fp) + return (rdl_error = lastresult = 1); + + while (!feof(fp)) + { + i = 0; + + while (fread(buf + i,1,1,fp) == 1 && buf[i] && i < 257) + i++; + if (feof(fp)) break; + + fread(buf, 6, 1, fp); + buf[6] = 0; + if (buf[0] == '.') { + /* + * a special module, eg a directory. + * Format of such a module is defined to be: + * six char type identifier (which we've already read) + * long count bytes content + * content + * so we can handle it uniformaly with RDOFF2 modules... + * do nothing here. :-) + */ + } + else if (strncmp(buf, "RDOFF", 5)) { + return rdl_error = lastresult = 2; + } + else if (buf[5] != '2') { + return rdl_error = lastresult = 3; + } + + fread(&length, 4, 1, fp); + fseek(fp, length, SEEK_CUR); /* skip over the module */ + } + fclose(fp); + return lastresult = 0; /* library in correct format */ +} + +int rdl_open (struct librarynode * lib, const char * name) +{ + int i = rdl_verify(name); + if (i) return i; + + lib->fp = NULL; + lib->name = strdup(name); + lib->referenced = 0; + lib->next = NULL; + return 0; +} + +void rdl_close (struct librarynode * lib) +{ + if (lib->fp) + fclose(lib->fp); + free(lib->name); +} int rdl_searchlib (struct librarynode * lib, const char * label, rdffile * f) { - char buf[257]; - int i; + char buf[512]; + int i, t; void * hdr; rdfheaderrec * r; + long l; rdl_error = 0; lib->referenced ++; @@ -35,18 +126,36 @@ int rdl_searchlib (struct librarynode * lib, while (! feof(lib->fp) ) { - i = 1; - while (fread(buf + i,1,1,lib->fp) == 1 && buf[i] && i < 257) + /* + * read the module name from the file, and prepend + * the library name and '.' to it. + */ + strcpy(buf, lib->name); + + i = strlen(lib->name); + buf[i++] = '.'; t = i; + while (fread(buf + i,1,1,lib->fp) == 1 && buf[i] && i < 512) i++; - buf[0] = ':'; + buf[i] = 0; + if (feof(lib->fp)) break; - + if (!strcmp(buf + t, ".dir")) /* skip over directory */ + { + fread (&l, 4, 1, lib->fp); + fseek (lib->fp, l, SEEK_CUR); + continue; + } + /* + * open the RDOFF module + */ if ( rdfopenhere(f,lib->fp,&lib->referenced,buf) ) { - rdl_error = 2; + rdl_error = 16 * rdf_errno; return 0; } - + /* + * read in the header, and scan for exported symbols + */ hdr = malloc(f->header_len); rdfloadseg(f,RDOFF_HEADER,hdr); @@ -65,11 +174,14 @@ int rdl_searchlib (struct librarynode * lib, } /* find start of next module... */ - i = f->data_ofs + f->data_len; + i = f->eof_offset; rdfclose(f); fseek(lib->fp,i,SEEK_SET); } + /* + * close the file if nobody else is using it + */ lib->referenced --; if (! lib->referenced) { @@ -79,9 +191,86 @@ int rdl_searchlib (struct librarynode * lib, return 0; } +int rdl_openmodule (struct librarynode * lib, int moduleno, rdffile * f) +{ + char buf[512]; + int i, cmod, t; + long length; + + lib->referenced++; + + if (!lib->fp) + { + lib->fp = fopen(lib->name, "rb"); + if (!lib->fp) { + lib->referenced--; + return (rdl_error = 1); + } + } + else + rewind(lib->fp); + + cmod = -1; + while (!feof(lib->fp)) + { + strcpy(buf, lib->name); + i = strlen(buf); + buf[i++] = '.'; t = i; + while (fread(buf + i,1,1,lib->fp) == 1 && buf[i] && i < 512) + i++; + buf[i] = 0; + if (feof(lib->fp)) break; + + if (buf[t] != '.') /* special module - not counted in the numbering */ + cmod++; /* of RDOFF modules - must be referred to by name */ + + if (cmod == moduleno) { + rdl_error = 16 * + rdfopenhere(f, lib->fp, &lib->referenced, buf); + lib->referenced--; + if (!lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return rdl_error; + } + + fread(buf, 6, 1, lib->fp); + buf[6] = 0; + if (buf[t] == '.') { + /* do nothing */ + } + else if (strncmp(buf, "RDOFF", 5)) { + if (! --lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return rdl_error = 2; + } + else if (buf[5] != '2') { + if (! --lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return rdl_error = 3; + } + + fread(&length, 4, 1, lib->fp); + fseek(lib->fp, length, SEEK_CUR); /* skip over the module */ + } + if (! --lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return rdl_error = 4; /* module not found */ +} + void rdl_perror(const char *apname, const char *filename) { - fprintf(stderr,"%s:%s:%s\n",apname,filename,rdl_errors[rdl_error]); + if (rdl_error >= 16) + rdfperror(apname, filename); + else + fprintf(stderr,"%s:%s:%s\n",apname,filename,rdl_errors[rdl_error]); } diff --git a/rdoff/rdlib.h b/rdoff/rdlib.h index 94592ce..28c6ee7 100644 --- a/rdoff/rdlib.h +++ b/rdoff/rdlib.h @@ -11,8 +11,17 @@ struct librarynode { extern int rdl_error; +#define RDL_EOPEN 1 +#define RDL_EINVALID 2 +#define RDL_EVERSION 3 +#define RDL_ENOTFOUND 4 + +int rdl_verify (const char * filename); +int rdl_open (struct librarynode * lib, const char * filename); int rdl_searchlib (struct librarynode * lib, const char * label, rdffile * f); +int rdl_openmodule (struct librarynode * lib, int module, rdffile * f); + void rdl_perror(const char *apname, const char *filename); diff --git a/rdoff/rdoff.c b/rdoff/rdoff.c index 96620ec..7f4937a 100644 --- a/rdoff/rdoff.c +++ b/rdoff/rdoff.c @@ -4,11 +4,19 @@ * 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. */ /* TODO: The functions in this module assume they are running * on a little-endian machine. This should be fixed to * make it portable. + * + * This module no longer supports RDOFF1. If anybody *really* + * needs the functionality of supporting both types at the + * same time, I'll add it back in. */ #include <stdio.h> @@ -22,115 +30,146 @@ #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \ s1),s2) +/* + * Comment this out to allow the module to read & write header record types + * that it isn't aware of. With this defined, unrecognised header records + * will generate error number 8, reported as 'unknown extended header record'. + */ + +#define STRICT_ERRORS + /* ======================================================================== * Code for memory buffers (for delayed writing of header until we know * how long it is). * ======================================================================== */ -memorybuffer * newmembuf(){ - memorybuffer * t; +memorybuffer * newmembuf() +{ + memorybuffer * t; - t = malloc(sizeof(memorybuffer)); + t = malloc(sizeof(memorybuffer)); - t->length = 0; - t->next = NULL; - return t; + 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 */ +void membufwrite(memorybuffer *b, void *data, int bytes) +{ + int16 w; + long l; - b->next = newmembuf(); - membufwrite(b->next,data,bytes); - } + if (b->next) { /* memory buffer full - use next buffer */ + membufwrite(b->next,data,bytes); + return; + } - 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; + 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); + return; + } - case -2: - w = * (int16 *) data ; - b->buffer[b->length++] = w & 0xFF; - w >>= 8 ; - b->buffer[b->length++] = w & 0xFF; - break; + 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; - default: - while(bytes--) { - b->buffer[b->length++] = *(* (unsigned char **) &data); + case -2: + w = * (int16 *) data ; + b->buffer[b->length++] = w & 0xFF; + w >>= 8 ; + b->buffer[b->length++] = w & 0xFF; + break; - (* (unsigned char **) &data)++ ; + default: + while(bytes--) { + b->buffer[b->length++] = *(* (unsigned char **) &data); + + (* (unsigned char **) &data)++ ; + } + break; } - break; - } } void membufdump(memorybuffer *b,FILE *fp) { - if (!b) return; + if (!b) return; - fwrite (b->buffer, 1, b->length, fp); + fwrite (b->buffer, 1, b->length, fp); - membufdump(b->next,fp); + membufdump(b->next,fp); } int membuflength(memorybuffer *b) { - if (!b) return 0; - return b->length + membuflength(b->next); + if (!b) return 0; + return b->length + membuflength(b->next); } void freemembuf(memorybuffer *b) { - if (!b) return; - freemembuf(b->next); - free(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; +/* + * translatelong() and translateshort() + * + * translate from little endian to local representation + */ +long translatelong(long in) +{ + long r; + unsigned char *i; - i = (unsigned char *)∈ - r = i[3]; - r = (r << 8) + i[2]; - r = (r << 8) + i[1]; - r = (r << 8) + *i; + i = (unsigned char *)∈ + r = i[3]; + r = (r << 8) + i[2]; + r = (r << 8) + i[1]; + r = (r << 8) + *i; - return r; + return r; } -const char *RDOFFId = "RDOFF1"; /* written to the start of RDOFF files */ +int16 translateshort(int16 in) +{ + int16 r; + unsigned char * i; + + i = (unsigned char *)∈ + r = (i[1] << 8) + i[0]; + + return r; +} + +const char *RDOFFId = "RDOFF2"; /* written to the start of RDOFF files */ -const char *rdf_errors[7] = { +const char *rdf_errors[11] = { "no error occurred","could not open file","invalid file format", "error reading file","unknown error","header not read", - "out of memory"}; + "out of memory", "RDOFF v1 not supported", + "unknown extended header record", + "header record of known type but unknown length", + "no such segment"}; int rdf_errno = 0; @@ -145,13 +184,15 @@ int rdfopen(rdffile *f, const char *name) fp = fopen(name,"rb"); if (!fp) return rdf_errno = 1; /* error 1: file open error */ - return rdfopenhere(f,fp,NULL,""); + return rdfopenhere(f,fp,NULL,name); } -int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name) +int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name) { char buf[8]; long initpos; + long l; + int16 s; if (translatelong(0x01020304) != 0x01020304) { /* fix this to be portable! */ @@ -168,38 +209,61 @@ int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name) if (strcmp(buf,RDOFFId)) { fclose(f->fp); + if (!strcmp(buf,"RDOFF1")) + return rdf_errno = 7; /* error 7: RDOFF 1 not supported */ return rdf_errno = 2; /* error 2: invalid file format */ } - if (fread(&f->header_len,1,4,f->fp) != 4) { + if (fread(&l,1,4,f->fp) != 4 || + fread(&f->header_len,1,4,f->fp) != 4) { fclose(f->fp); return rdf_errno = 3; /* error 3: file read error */ } f->header_ofs = ftell(f->fp); + f->eof_offset = f->header_ofs + translatelong(l) - 4; 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; + if (fread(&s,1,2,f->fp) != 2) { + 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; - } + f->nsegs = 0; - if (fread(&f->data_len,1,4,f->fp) != 4) { - fclose(f->fp); - return rdf_errno = 3; + while (s != 0) + { + f->seg[f->nsegs].type = s; + if (fread(&f->seg[f->nsegs].number,1,2,f->fp) != 2 || + fread(&f->seg[f->nsegs].reserved,1,2,f->fp) != 2 || + fread(&f->seg[f->nsegs].length,1,4,f->fp) != 4) + { + fclose(f->fp); + return rdf_errno = 3; + } + + f->seg[f->nsegs].offset = ftell(f->fp); + if (fseek(f->fp,f->seg[f->nsegs].length,SEEK_CUR)) { + fclose(f->fp); + return rdf_errno = 2; + } + f->nsegs++; + + if (fread(&s,1,2,f->fp) != 2) { + fclose(f->fp); + return rdf_errno = 3; + } } - f->data_ofs = ftell(f->fp); + if (f->eof_offset != ftell(f->fp) + 8) /* +8 = skip null segment header */ + { + fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset " + "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8); + } fseek(f->fp,initpos,SEEK_SET); f->header_loc = NULL; @@ -211,7 +275,7 @@ int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name) int rdfclose(rdffile *f) { - if (! f->refcount || ! *--f->refcount) + if (! f->refcount || ! --(*f->refcount)) fclose(f->fp); free(f->name); @@ -228,6 +292,14 @@ void rdfperror(const char *app,const char *name) } +int rdffindsegment(rdffile * f, int segno) +{ + int i; + for (i = 0; i < f->nsegs; i++) + if (f->seg[i].number == segno) return i; + return -1; +} + int rdfloadseg(rdffile *f,int segment,void *buffer) { long fpos; @@ -235,22 +307,20 @@ int rdfloadseg(rdffile *f,int segment,void *buffer) switch(segment) { case RDOFF_HEADER: - fpos = f->header_ofs; - 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; + fpos = f->header_ofs; + slen = f->header_len; + f->header_loc = (byte *)buffer; + f->header_fp = 0; + break; default: - fpos = 0; - slen = 0; + if (segment < f->nsegs) { + fpos = f->seg[segment].offset; + slen = f->seg[segment].length; + f->seg[segment].data = (byte *)buffer; + } + else { + return rdf_errno = 10; /* no such segment */ + } } if (fseek(f->fp,fpos,SEEK_SET)) @@ -291,8 +361,15 @@ rdfheaderrec *rdfgetheaderrec(rdffile *f) if (f->header_fp >= f->header_len) return 0; RI8(r.type); + RI8(r.g.reclen); + switch(r.type) { case 1: /* Relocation record */ + case 6: + if (r.r.reclen != 8) { + rdf_errno = 9; + return NULL; + } RI8(r.r.segment); RI32(r.r.offset); RI8(r.r.length); @@ -300,6 +377,7 @@ rdfheaderrec *rdfgetheaderrec(rdffile *f) break; case 2: /* Imported symbol record */ + case 7: RI16(r.i.segment); RS(r.i.label,32); break; @@ -315,12 +393,21 @@ rdfheaderrec *rdfgetheaderrec(rdffile *f) break; case 5: /* BSS reservation record */ + if (r.r.reclen != 4) { + rdf_errno = 9; + return NULL; + } RI32(r.b.amount); break; default: - rdf_errno = 2; /* invalid file */ +#ifdef STRICT_ERRORS + rdf_errno = 8; /* unknown header record */ return NULL; +#else + for (i = 0; i < r.g.reclen; i++) + RI8(r.g.data[i]); +#endif } return &r; } @@ -333,65 +420,92 @@ void rdfheaderrewind(rdffile *f) rdf_headerbuf * rdfnewheader(void) { - return newmembuf(); + rdf_headerbuf * hb = malloc(sizeof(hb)); + if (hb == NULL) return NULL; + + hb->buf = newmembuf(); + hb->nsegments = 0; + hb->seglength = 0; + + return hb; } int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r) { +#ifndef STRICT_ERRORS + int i; +#endif + membufwrite(h->buf,&r->type,1); + membufwrite(h->buf,&r->g.reclen,1); + 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 */ + case 6: + membufwrite(h->buf,&r->r.segment,1); + membufwrite(h->buf,&r->r.offset,-4); + membufwrite(h->buf,&r->r.length,1); + membufwrite(h->buf,&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); + case 7: + membufwrite(h->buf,&r->i.segment,-2); + membufwrite(h->buf,&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); + membufwrite(h->buf,&r->e.segment,1); + membufwrite(h->buf,&r->e.offset,-4); + membufwrite(h->buf,&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); + membufwrite(h->buf,&r->d.libname,strlen(r->d.libname) + 1); break ; case 5: /* BSS */ - membufwrite(h,&r->type,1); - membufwrite(h,&r->b.amount,-4); + membufwrite(h->buf,&r->b.amount,-4); break ; default: - return (rdf_errno = 2); +#ifdef STRICT_ERRORS + return (rdf_errno = 8); +#else + for (i = 0; i < r->g.reclen; i++) + membufwrite(h->buf, r->g.data[i], 1); +#endif } return 0; } +int rdfaddsegment(rdf_headerbuf *h, long seglength) +{ + h->nsegments ++; + h->seglength += seglength; + return 0; +} + int rdfwriteheader(FILE * fp, rdf_headerbuf * h) { - long l; + long l, l2; fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ; - l = translatelong ( membuflength (h) ); - fwrite (&l, 4, 1, fp); + l = membuflength (h->buf); + l2 = l + 14 + 10*h->nsegments + h->seglength; + l = translatelong(l); + l2 = translatelong(l2); + fwrite (&l2, 4, 1, fp); /* object length */ + fwrite (&l, 4, 1, fp); /* header length */ - membufdump(h, fp); + membufdump(h->buf, fp); return 0; /* no error handling in here... CHANGE THIS! */ } void rdfdoneheader(rdf_headerbuf * h) { - freemembuf(h); + freemembuf(h->buf); + free(h); } diff --git a/rdoff/rdoff.h b/rdoff/rdoff.h index 0f74b80..e23ffa4 100644 --- a/rdoff/rdoff.h +++ b/rdoff/rdoff.h @@ -4,28 +4,39 @@ * 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. */ #ifndef _RDOFF_H -#define _RDOFF_H "RDOFF1 support routines v0.1" +#define _RDOFF_H "RDOFF2 support routines v0.3" + +/* Some systems don't define this automatically */ +extern char *strdup(const char *); -typedef short int16; /* not sure if this will be required to be altered - at all... best to typedef it just in case */ +typedef unsigned short int16; +typedef unsigned char byte; + +#define RDF_MAXSEGS 64 /* 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, + byte type; /* must be 1 */ + byte reclen; /* content length */ + byte 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 */ + byte length; /* 1 2 or 4 bytes */ int16 refseg; /* segment to which reference refers to */ }; struct ImportRec { - char type; /* must be 2 */ + byte type; /* must be 2 */ + byte reclen; /* content length */ 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 @@ -35,42 +46,71 @@ struct ImportRec { }; struct ExportRec { - char type; /* must be 3 */ - char segment; /* segment referred to (0/1) */ + byte type; /* must be 3 */ + byte reclen; /* content length */ + byte 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 */ + byte type; /* must be 4 */ + byte reclen; /* content length */ char libname[128]; /* name of library to link with at load time */ }; struct BSSRec { - char type; /* must be 5 */ + byte type; /* must be 5 */ + byte reclen; /* content length */ long amount; /* number of bytes BSS to reserve */ }; - + +/* GenericRec - contains the type and length field, plus a 128 byte + char array 'data', which will probably never be used! */ + +struct GenericRec { + byte type; + byte reclen; + char data[128]; +}; + typedef union RDFHeaderRec { char type; /* invariant throughout all below */ - struct RelocRec r; /* type == 1 */ - struct ImportRec i; /* type == 2 */ + struct GenericRec g; + struct RelocRec r; /* type == 1 / 6 */ + struct ImportRec i; /* type == 2 / 7 */ struct ExportRec e; /* type == 3 */ struct DLLRec d; /* type == 4 */ struct BSSRec b; /* type == 5 */ } rdfheaderrec; +struct SegmentHeaderRec { + /* information from file */ + int16 type; + int16 number; + int16 reserved; + long length; + + /* information built up here */ + long offset; + byte *data; /* pointer to segment data if it exists in memory */ +}; + 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 header_ofs; - long code_ofs; - long data_ofs; - char *header_loc; /* keep location of header */ + + byte *header_loc; /* keep location of header */ long header_fp; /* current location within header for reading */ + + struct SegmentHeaderRec seg[RDF_MAXSEGS]; + int nsegs; + + long eof_offset; /* offset of the first byte beyond the end of this + module */ + char *name; /* name of module in libraries */ int *refcount; /* pointer to reference count on file, or NULL */ } rdffile; @@ -79,11 +119,15 @@ typedef struct RDFFileInfo { * on 80x86 machines for efficiency */ typedef struct memorybuffer { int length; - char buffer[BUF_BLOCK_LEN]; + byte buffer[BUF_BLOCK_LEN]; struct memorybuffer *next; } memorybuffer; -typedef memorybuffer rdf_headerbuf; +typedef struct { + memorybuffer * buf; /* buffer containing header records */ + int nsegments; /* number of segments to be written */ + long seglength; /* total length of all the segments */ +} rdf_headerbuf; /* segments used by RDOFF, understood by rdoffloadseg */ #define RDOFF_CODE 0 @@ -96,10 +140,15 @@ typedef memorybuffer rdf_headerbuf; extern int rdf_errno; +/* utility functions */ +int16 translateshort(int16 in); +long translatelong(long in); + /* RDOFF file manipulation functions */ int rdfopen(rdffile *f,const char *name); -int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name); +int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name); int rdfclose(rdffile *f); +int rdffindsegment(rdffile * f, int segno); int rdfloadseg(rdffile *f,int segment,void *buffer); rdfheaderrec *rdfgetheaderrec(rdffile *f); /* returns static storage */ void rdfheaderrewind(rdffile *f); /* back to start of header */ @@ -107,11 +156,14 @@ 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 + rdfaddsegment to notify the header routines that a segment exists, and + to tell it how long the segment will be. + rdfwriteheader to write the file id, object length, and header to a file, and then rdfdoneheader to dispose of the header */ rdf_headerbuf *rdfnewheader(void); int rdfaddheader(rdf_headerbuf *h,rdfheaderrec *r); +int rdfaddsegment(rdf_headerbuf *h, long seglength); int rdfwriteheader(FILE *fp,rdf_headerbuf *h); void rdfdoneheader(rdf_headerbuf *h); diff --git a/rdoff/rdx.c b/rdoff/rdx.c index 28ffc42..5a3058d 100644 --- a/rdoff/rdx.c +++ b/rdoff/rdx.c @@ -29,7 +29,7 @@ int main(int argc, char **argv) if (argc < 2) { - puts("usage: rdf <rdoff-executable> [params]\n"); + puts("usage: rdx <rdoff-executable> [params]\n"); exit(255); } @@ -37,7 +37,7 @@ int main(int argc, char **argv) if (! m) { - rdfperror("rdf",argv[1]); + rdfperror("rdx",argv[1]); exit(255); } diff --git a/rdoff/segtab.c b/rdoff/segtab.c new file mode 100644 index 0000000..f3168fc --- /dev/null +++ b/rdoff/segtab.c @@ -0,0 +1,142 @@ +#include <stdio.h> +#include <stdlib.h> +#include "segtab.h" + +struct segtabnode { + int localseg; + int destseg; + long offset; + + struct segtabnode * left; + struct segtabnode * right; + /* + * counts of how many are left or right, for use in reorganising + * the tree + */ + int leftcount; + int rightcount; +}; + +/* + * init_seglocations() + * add_seglocation() + * get_seglocation() + * done_seglocation() + * + * functions used by write_output() to manipulate associations + * between segment numbers and locations (which are built up on a per + * module basis, but we only need one module at a time...) + * + * implementation: we build a binary tree. + */ + + +void init_seglocations(segtab * root) +{ + *root = NULL; +} + +void descend_tree_add(struct segtabnode * * node, + int localseg, int destseg, long offset) +{ + struct segtabnode * n; + + if (*node == NULL) { + *node = malloc (sizeof (**node)); + if (!*node) { + fprintf(stderr, "segment table: out of memory\n"); + exit(1); + } + (*node)->localseg = localseg; + (*node)->offset = offset; + (*node)->left = NULL; + (*node)->leftcount = 0; + (*node)->right = NULL; + (*node)->rightcount = 0; + (*node)->destseg = destseg; + return; + } + + if (localseg < (*node)->localseg) + { + (*node)->leftcount++; + descend_tree_add(&(*node)->left, localseg, destseg, offset); + + if ((*node)->leftcount > (*node)->rightcount + 2) { + n = * node; + *node = n->left; + n->left = (*node)->right; + n->leftcount = (*node)->rightcount; + (*node)->right = n; + (*node)->rightcount = n->leftcount + n->rightcount + 1; + } + } + else + { + (*node)->rightcount++; + descend_tree_add(&(*node)->right, localseg, destseg, offset); + + if ((*node)->rightcount > (*node)->leftcount + 2) { + n = * node; + *node = n->right; + n->right= (*node)->left; + n->rightcount = (*node)->leftcount; + (*node)->left = n; + (*node)->leftcount = n->leftcount + n->rightcount + 1; + } + } +} + +void add_seglocation(segtab * root, int localseg, int destseg, long offset) +{ + descend_tree_add((struct segtabnode **) root, localseg, destseg, offset); +} + +int get_seglocation(segtab * root, int localseg, int * destseg, long * offset) +{ + struct segtabnode * n = (struct segtabnode *) *root; + + while (n && n->localseg != localseg) + { + if (localseg < n->localseg) + n = n->left; + else + n = n->right; + } + if (n) { + *destseg = n->destseg; + *offset = n->offset; + return 1; + } + else + return 0; +} + +void freenode(struct segtabnode * n) +{ + if (!n) return; + freenode (n->left); + freenode (n->right); + free(n); +} + +void done_seglocations(segtab * root) +{ + freenode(*root); + *root = NULL; +} + +#if 0 +void printnode(int i, struct segtabnode * n) +{ + if (!n) return; + printnode(i + 1, n->left); + printf ("%*s%d %d %ld\n", i, "", n->localseg, n->destseg, n->offset); + printnode(i + 1, n->right); +} + +void printtable() +{ + printnode(0,root); +} +#endif diff --git a/rdoff/segtab.h b/rdoff/segtab.h new file mode 100644 index 0000000..b5d96fa --- /dev/null +++ b/rdoff/segtab.h @@ -0,0 +1,7 @@ +typedef void * segtab; + +void init_seglocations(segtab * r); +void add_seglocation(segtab * r, int localseg, int destseg, long offset); +int get_seglocation(segtab * r, int localseg, int * destseg, long * offset); +void done_seglocations(segtab * r); + diff --git a/rdoff/symtab.c b/rdoff/symtab.c index 3fc363e..4959a5d 100644 --- a/rdoff/symtab.c +++ b/rdoff/symtab.c @@ -1,4 +1,6 @@ -/* symtab.c Routines to maintain and manipulate a symbol table +/* symtab.c Routines to maintain and manipulate a symbol table + * + * These routines donated to the NASM effort by Graeme Defty. * * The Netwide Assembler is copyright (C) 1996 Simon Tatham and * Julian Hall. All rights reserved. The software is @@ -7,74 +9,117 @@ */ #include <stdio.h> #include <stdlib.h> +#include <malloc.h> #include "symtab.h" +#include "hash.h" -/* TODO: Implement a hash table, not this stupid implementation which - is too slow to be of practical use */ +#define SYMTABSIZE 64 +#define slotnum(x) (hash((x)) % SYMTABSIZE) +/* ------------------------------------- */ /* Private data types */ -typedef struct tagSymtab { - symtabEnt ent; - struct tagSymtab * next; -} symtabList; +typedef struct tagSymtabNode { + struct tagSymtabNode * next; + symtabEnt ent; +} symtabNode; + +typedef symtabNode *(symtabTab[SYMTABSIZE]); -typedef symtabList * _symtab; +typedef symtabTab *symtab; -void *symtabNew(void) +/* ------------------------------------- */ +void * +symtabNew(void) { - void *p = malloc(sizeof(_symtab)); - if (p == NULL) { + symtab mytab; + + mytab = (symtabTab *) calloc(SYMTABSIZE ,sizeof(symtabNode *)); + if (mytab == NULL) { fprintf(stderr,"symtab: out of memory\n"); exit(3); } - *(_symtab *)p = NULL; - return p; + return mytab; } -void symtabDone(void *symtab) +/* ------------------------------------- */ +void +symtabDone(void *stab) { - /* DO SOMETHING HERE! */ + symtab mytab = (symtab)stab; + int i; + symtabNode *this, *next; + + for (i=0; i < SYMTABSIZE; ++i) { + + for (this = (*mytab)[i]; this; this=next) + { next = this->next; free (this); } + + } + free (*mytab); } -void symtabInsert(void *symtab,symtabEnt *ent) +/* ------------------------------------- */ +void +symtabInsert(void *stab, symtabEnt *ent) { - symtabList *l = malloc(sizeof(symtabList)); + symtab mytab = (symtab) stab; + symtabNode *node; + int slot; - if (l == NULL) { + node = malloc(sizeof(symtabNode)); + if (node == NULL) { fprintf(stderr,"symtab: out of memory\n"); exit(3); } - l->ent = *ent; - l->next = *(_symtab *)symtab; - *(_symtab *)symtab = l; + slot = slotnum(ent->name); + + node->ent = *ent; + node->next = (*mytab)[slot]; + (*mytab)[slot] = node; } -symtabEnt *symtabFind(void *symtab,char *name) +/* ------------------------------------- */ +symtabEnt * +symtabFind(void *stab, const char *name) { - symtabList *l = *(_symtab *)symtab; - - while (l) { - if (!strcmp(l->ent.name,name)) { - return &(l->ent); - } - l = l->next; - } - return NULL; + symtab mytab = (symtab) stab; + int slot = slotnum(name); + symtabNode *node = (*mytab)[slot]; + + while (node) { + if (!strcmp(node->ent.name,name)) { + return &(node->ent); + } + node = node->next; + } + + return NULL; } -void symtabDump(void *symtab,FILE *of) +/* ------------------------------------- */ +void +symtabDump(void *stab, 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; - } + symtab mytab = (symtab)stab; + int i; + + fprintf(of, "Symbol table is ...\n"); + for (i=0; i < SYMTABSIZE; ++i) { + symtabNode *l = (symtabNode *)(*mytab)[i]; + + if (l) { + fprintf(of, " ... slot %d ...\n", i); + } + 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; + } + } + fprintf(of, "........... end of Symbol table.\n"); } - diff --git a/rdoff/symtab.h b/rdoff/symtab.h index 5780d44..c1fe031 100644 --- a/rdoff/symtab.h +++ b/rdoff/symtab.h @@ -8,7 +8,7 @@ typedef struct { char *name; - long segment; + int segment; long offset; long flags; } symtabEnt; @@ -16,7 +16,7 @@ typedef struct { void *symtabNew(void); void symtabDone(void *symtab); void symtabInsert(void *symtab,symtabEnt *ent); -symtabEnt *symtabFind(void *symtab,char *name); +symtabEnt *symtabFind(void *symtab,const char *name); void symtabDump(void *symtab,FILE *of); diff --git a/rdoff/test/rdfseg.asm b/rdoff/test/rdfseg.asm new file mode 100644 index 0000000..4c6f587 --- /dev/null +++ b/rdoff/test/rdfseg.asm @@ -0,0 +1,20 @@ + ;; program to test inter-segment production and linkage of RDF objects + + ;; [1] should produce segment base ref + ;; [2] should produce standard relocation + +[GLOBAL _main] +[EXTERN _puts: far] +[BITS 16] + +_main: + mov ax, seg _message ; 0000 [1] + mov ds, ax ; 0003 + mov dx, _message ; 0005 [2] + call far _puts ; 0008 [2][1] + xor ax,ax ; 000D + int 21h ; 000F + +[SECTION .data] +_message: db 'Hello, World', 10, 13, 0 +
\ No newline at end of file diff --git a/rdoff/test/rdfseg2.asm b/rdoff/test/rdfseg2.asm new file mode 100644 index 0000000..2b9e4fd --- /dev/null +++ b/rdoff/test/rdfseg2.asm @@ -0,0 +1,12 @@ + ;; library function for rdfseg - this file is linked as a far segment + +[BITS 16] +[GLOBAL _puts] +_puts: + ;; can't remember how to print a string in DOS, but if anyone wants + ;; to actually test this program, it should be fairly easy to put + ;; in here! + + retf + +
\ No newline at end of file diff --git a/rdoff/v1/README b/rdoff/v1/README new file mode 100644 index 0000000..56ad81b --- /dev/null +++ b/rdoff/v1/README @@ -0,0 +1,5 @@ +This directory contains programs for working with RDOFF version 1 object +files. RDOFF version 1 is no longer supported - you should now be using +RDOFF2. If you are working with your own code, the changes you will need +to make are very simple, and are outlined in the document Changes in the +nasm/rdoff directory. diff --git a/rdoff/v1/collectn.c b/rdoff/v1/collectn.c new file mode 100644 index 0000000..c265c95 --- /dev/null +++ b/rdoff/v1/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/v1/collectn.h b/rdoff/v1/collectn.h new file mode 100644 index 0000000..2dc786e --- /dev/null +++ b/rdoff/v1/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/v1/ldrdf.c b/rdoff/v1/ldrdf.c new file mode 100644 index 0000000..9e4a215 --- /dev/null +++ b/rdoff/v1/ldrdf.c @@ -0,0 +1,728 @@ +/* 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 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. (Could make this an + * external utility) + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "rdoff.h" +#include "nasmlib.h" +#include "symtab.h" +#include "collectn.h" +#include "rdlib.h" + +#define LDRDF_VERSION "0.30" + +/* 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; +}; + +#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 */ + +/* 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); + + 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 + * from the RDF modules + */ + +char *text,*data; +long textlength,datalength; + +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 */ + 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); + } + rdfclose(&mod->f); /* close file; segments remain */ + mod = mod->next; + } +} + +/* 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; + 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))) { + if (verbose >= 3) printf("record type: %d\n",r->type); + 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 */ + relto = 0; /* placate optimiser warnings */ + } + + /* 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) { + 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; + + case 4: /* DLL record */ + rdfaddheader(newheader,r); /* copy straight to output */ + 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) +{ + 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) + { + 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" +" [-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" +" -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" +" -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) +{ + 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 && !strncmp(*argv,"-l",2)) { + load_library(*argv + 2); + } + 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 */ + + 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 */ + + 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/v1/rdf.doc index 300c2bc..300c2bc 100644 --- a/rdoff/rdf.doc +++ b/rdoff/v1/rdf.doc diff --git a/rdoff/v1/rdf2bin.c b/rdoff/v1/rdf2bin.c new file mode 100644 index 0000000..97b45b4 --- /dev/null +++ b/rdoff/v1/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/v1/rdfdump.c b/rdoff/v1/rdfdump.c new file mode 100644 index 0000000..080c2e7 --- /dev/null +++ b/rdoff/v1/rdfdump.c @@ -0,0 +1,167 @@ +#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 *)∈ + 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 *)∈ + r = (i[1] << 8) + *i; + + return r; +} +void print_header(long length) { + char buf[129],t,s,l; + long o,ll; + 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); + ll = 0; + do { + fread(&buf[ll],1,1,infile); + } while (buf[ll++]); + printf(" import: segment %04x = %s\n",translateshort(rs),buf); + length -= ll + 3; + break; + case 3: /* export record */ + fread(&s,1,1,infile); + fread(&o,4,1,infile); + ll = 0; + do { + fread(&buf[ll],1,1,infile); + } while (buf[ll++]); + printf(" export: (%04x:%08lx) = %s\n",(int)s,translatelong(o),buf); + length -= ll + 6; + break; + case 4: /* DLL record */ + ll = 0; + do { + fread(&buf[ll],1,1,infile); + } while (buf[ll++]); + printf(" dll: %s\n",buf); + length -= ll + 1; + break; + case 5: /* BSS reservation */ + fread(&ll,4,1,infile); + printf(" bss reservation: %08lx bytes\n",translatelong(ll)); + 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; + long offset; + + 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); + offset = 0; + while(l--) { + fread(id,1,1,infile); + if (verbose) { + if (offset % 16 == 0) + printf("\n%08lx ", offset); + printf(" %02x",(int) (unsigned char)id[0]); + offset++; + } + } + if (verbose) printf("\n\n"); + + fread(&l,4,1,infile); + l = translatelong(l); + printf("Data segment length = %ld bytes\n",l); + + if (verbose) + { + offset = 0; + while (l--) { + fread(id,1,1,infile); + if (offset % 16 == 0) + printf("\n%08lx ", offset); + printf(" %02x",(int) (unsigned char) id[0]); + offset++; + } + printf("\n"); + } + fclose(infile); + return 0; +} diff --git a/rdoff/v1/rdflib.c b/rdoff/v1/rdflib.c new file mode 100644 index 0000000..5846562 --- /dev/null +++ b/rdoff/v1/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/v1/rdfload.c b/rdoff/v1/rdfload.c new file mode 100644 index 0000000..b848344 --- /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; +} diff --git a/rdoff/v1/rdfload.h b/rdoff/v1/rdfload.h new file mode 100644 index 0000000..5e264b9 --- /dev/null +++ b/rdoff/v1/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/v1/rdlib.c b/rdoff/v1/rdlib.c new file mode 100644 index 0000000..bc8d1e3 --- /dev/null +++ b/rdoff/v1/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/v1/rdlib.h b/rdoff/v1/rdlib.h new file mode 100644 index 0000000..94592ce --- /dev/null +++ b/rdoff/v1/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/v1/rdoff.c b/rdoff/v1/rdoff.c new file mode 100644 index 0000000..96620ec --- /dev/null +++ b/rdoff/v1/rdoff.c @@ -0,0 +1,397 @@ +/* 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 <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). + * ======================================================================== */ + + +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 *)∈ + 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) +{ + 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! */ + fputs("*** this program requires a little endian machine\n",stderr); + fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304)); + exit(3); + } + + f->fp = fp; + initpos = ftell(fp); + + 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 */ + } + + 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...? */ + } + + 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); + 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) +{ + 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) +{ + long fpos; + long slen; + + switch(segment) { + case RDOFF_HEADER: + fpos = f->header_ofs; + 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/v1/rdoff.h b/rdoff/v1/rdoff.h new file mode 100644 index 0000000..0f74b80 --- /dev/null +++ b/rdoff/v1/rdoff.h @@ -0,0 +1,118 @@ +/* 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 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) + * 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 + +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 */ +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/rdoff.txt b/rdoff/v1/rdoff.txt index 7ee86d6..7ee86d6 100644 --- a/rdoff/rdoff.txt +++ b/rdoff/v1/rdoff.txt diff --git a/rdoff/v1/rdx.c b/rdoff/v1/rdx.c new file mode 100644 index 0000000..28ffc42 --- /dev/null +++ b/rdoff/v1/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/v1/symtab.c b/rdoff/v1/symtab.c new file mode 100644 index 0000000..3fc363e --- /dev/null +++ b/rdoff/v1/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/v1/symtab.h b/rdoff/v1/symtab.h new file mode 100644 index 0000000..5780d44 --- /dev/null +++ b/rdoff/v1/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); + + |