diff options
Diffstat (limited to 'rdoff')
50 files changed, 6651 insertions, 0 deletions
diff --git a/rdoff/Makefile.in b/rdoff/Makefile.in new file mode 100644 index 0000000..93f2e2a --- /dev/null +++ b/rdoff/Makefile.in @@ -0,0 +1,105 @@ +# +# Auto-configuring 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 license given in the file "LICENSE" +# distributed in the NASM archive. + +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +mandir = @mandir@ +datarootdir = @datarootdir@ + +CC = @CC@ +CFLAGS = @CFLAGS@ +BUILD_CFLAGS = $(CFLAGS) @DEFS@ +INTERNAL_CFLAGS = -I$(srcdir) -I$(top_srcdir) +ALL_CFLAGS = $(BUILD_CFLAGS) $(INTERNAL_CFLAGS) +LDFLAGS = @LDFLAGS@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +LN_S = @LN_S@ +MKDIR = mkdir + +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 + +# Binary suffixes +O = @OBJEXT@ +X = @EXEEXT@ + +PROGRAMS = rdfdump$(X) ldrdf$(X) rdx$(X) rdflib$(X) \ + rdf2bin$(X) rdf2com$(X) rdf2ith$(X) rdf2ihx$(X) rdf2srec$(X) + +.SUFFIXES: .c .i .s .$(O) .1 .man + +.c.$(O): + $(CC) -c $(ALL_CFLAGS) $< + +all: $(PROGRAMS) + +rdfdump$(X): rdfdump.$(O) rdoff.$(O) + $(CC) $(LDFLAGS) -o rdfdump$(X) rdfdump.$(O) rdoff.$(O) +ldrdf$(X): ldrdf.$(O) $(LDRDFLIBS) + $(CC) $(LDFLAGS) -o ldrdf$(X) ldrdf.$(O) $(LDRDFLIBS) +rdx$(X): rdx.$(O) $(RDXLIBS) + $(CC) $(LDFLAGS) -o rdx$(X) rdx.$(O) $(RDXLIBS) +rdflib$(X): rdflib.$(O) + $(CC) $(LDFLAGS) -o rdflib$(X) rdflib.$(O) +rdf2bin$(X): rdf2bin.$(O) $(RDXLIBS) nasmlib.$(O) + $(CC) $(LDFLAGS) -o rdf2bin$(X) rdf2bin.$(O) $(RDXLIBS) nasmlib.$(O) +rdf2com$(X): + rm -f rdf2com$(X) && $(LN_S) rdf2bin$(X) rdf2com$(X) +rdf2ith$(X): + rm -f rdf2ith$(X) && $(LN_S) rdf2bin$(X) rdf2ith$(X) +rdf2ihx$(X): + rm -f rdf2ihx$(X) && $(LN_S) rdf2bin$(X) rdf2ihx$(X) +rdf2srec$(X): + rm -f rdf2srec$(X) && $(LN_S) rdf2bin$(X) rdf2srec$(X) + +rdf2ihx.$(O): rdf2ihx.c +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 +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 +segtab.$(O): segtab.c + +nasmlib.$(O): $(top_srcdir)/nasmlib.c + cd .. && $(MAKE) nasmlib.$(O) + cp ../nasmlib.$(O) . + +clean: + rm -f *.$(O) $(PROGRAMS) + +spotless: clean + rm -f Makefile + +distclean: spotless + +install: all + $(MKDIR) -p $(INSTALLROOT)$(bindir) + $(INSTALL_PROGRAM) rdfdump$(X) $(INSTALLROOT)$(bindir)/rdfdump$(X) + $(INSTALL_PROGRAM) ldrdf$(X) $(INSTALLROOT)$(bindir)/ldrdf$(X) + $(INSTALL_PROGRAM) rdx$(X) $(INSTALLROOT)$(bindir)/rdx$(X) + $(INSTALL_PROGRAM) rdflib$(X) $(INSTALLROOT)$(bindir)/rdflib$(X) + $(INSTALL_PROGRAM) rdf2bin$(X) $(INSTALLROOT)$(bindir)/rdf2bin$(X) + cd $(INSTALLROOT)$(bindir) && rm -f rdf2com$(X) && $(LN_S) rdf2bin$(X) rdf2com$(X) + cd $(INSTALLROOT)$(bindir) && rm -f rdf2ith$(X) && $(LN_S) rdf2bin$(X) rdf2ith$(X) + cd $(INSTALLROOT)$(bindir) && rm -f rdf2ihx$(X) && $(LN_S) rdf2bin$(X) rdf2ihx$(X) + cd $(INSTALLROOT)$(bindir) && rm -f rdf2srec$(X) && $(LN_S) rdf2bin$(X) rdf2srec$(X) + $(MKDIR) -p $(INSTALLROOT)$(mandir)/man1 + $(INSTALL_DATA) $(srcdir)/*.1 $(INSTALLROOT)$(mandir)/man1/ diff --git a/rdoff/Mkfiles/Makefile.dj b/rdoff/Mkfiles/Makefile.dj new file mode 100644 index 0000000..5621ed6 --- /dev/null +++ b/rdoff/Mkfiles/Makefile.dj @@ -0,0 +1,75 @@ +# Generated automatically from Makefile.in by configure. +# +# Auto-configuring 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 license given in the file "LICENSE" +# distributed in the NASM archive. + +# You may need to adjust these values. + +prefix = /djgpp +CC = gcc -s +CFLAGS = -O2 -I.. + +# You _shouldn't_ need to adjust anything below this line. + +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +mandir = ${prefix}/man + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +LN_S = ln -s + +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 + +all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com + +rdfdump: rdfdump.o rdoff.o + $(CC) -o rdfdump rdfdump.o rdoff.o + +ldrdf: ldrdf.o $(LDRDFLIBS) + $(CC) -o ldrdf ldrdf.o $(LDRDFLIBS) +rdx: rdx.o $(RDXLIBS) + $(CC) -o rdx rdx.o $(RDXLIBS) +rdflib: rdflib.o + $(CC) -o rdflib rdflib.o +rdf2bin: rdf2bin.o $(RDXLIBS) nasmlib.o + $(CC) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o +rdf2com: + $(LN_S) rdf2bin rdf2com + +rdf2bin.o: rdf2bin.c +rdfdump.o: rdfdump.c +rdoff.o: rdoff.c rdoff.h +ldrdf.o: ldrdf.c rdoff.h ../nasmlib.h symtab.h collectn.h rdlib.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 + +clean: + rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com + +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 diff --git a/rdoff/Mkfiles/Makefile.emx b/rdoff/Mkfiles/Makefile.emx new file mode 100644 index 0000000..aa53588 --- /dev/null +++ b/rdoff/Mkfiles/Makefile.emx @@ -0,0 +1,76 @@ +# Generated automatically from Makefile.in by configure. +# $Id$ +# +# Auto-configuring 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 license given in the file "LICENSE" +# distributed in the NASM archive. + +top_srcdir = .. +srcdir = . +prefix = /usr/local +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +mandir = ${prefix}/man + +CC = gcc +CFLAGS = -s -Zomf -O2 -fomit-frame-pointer -Wall -ansi -pedantic -I$(srcdir) -I$(top_srcdir) +LDFLAGS = -s -Zomf -Zexe -Zcrtdll +LIBS = -lgcc + +INSTALL = .././install-sh -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +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) -o $@ $< + +all: rdfdump ldrdf rdx rdflib rdf2bin + +rdfdump: rdfdump.o rdoff.o + $(CC) $(LDFLAGS) -o rdfdump rdfdump.o rdoff.o $(LIBS) +ldrdf: ldrdf.o $(LDRDFLIBS) + $(CC) $(LDFLAGS) -o ldrdf ldrdf.o $(LDRDFLIBS) $(LIBS) +rdx: rdx.o $(RDXLIBS) + $(CC) $(LDFLAGS) -o rdx rdx.o $(RDXLIBS) $(LIBS) +rdflib: rdflib.o + $(CC) $(LDFLAGS) -o rdflib rdflib.o $(LIBS) +rdf2bin: rdf2bin.o $(RDXLIBS) nasmlib.o + $(CC) $(LDFLAGS) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o $(LIBS) + +rdf2bin.o: rdf2bin.c +rdfdump.o: rdfdump.c +rdoff.o: rdoff.c rdoff.h +ldrdf.o: ldrdf.c rdoff.h $(top_srcdir)/nasmlib.h symtab.h collectn.h rdlib.h +symtab.o: symtab.c symtab.h +collectn.o: collectn.c collectn.h +rdx.o: rdx.c rdoff.h rdfload.h symtab.h +rdfload.o: rdfload.c rdfload.h rdoff.h collectn.h symtab.h +rdlib.o: rdlib.c rdlib.h +rdflib.o: rdflib.c +segtab.o: segtab.c + +nasmlib.o: $(top_srcdir)/nasmlib.c + $(CC) -c $(CFLAGS) -o $@ $(top_srcdir)/nasmlib.c + +clean: + rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com + +spotless: clean + rm -f Makefile + +distclean: spotless + +install: rdfdump ldrdf rdx rdflib 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/Mkfiles/Makefile.sc b/rdoff/Mkfiles/Makefile.sc new file mode 100644 index 0000000..501d487 --- /dev/null +++ b/rdoff/Mkfiles/Makefile.sc @@ -0,0 +1,56 @@ +# 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 license given in the file "LICENSE" +# 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) + + diff --git a/rdoff/Mkfiles/Makefile.unx b/rdoff/Mkfiles/Makefile.unx new file mode 100644 index 0000000..9041b41 --- /dev/null +++ b/rdoff/Mkfiles/Makefile.unx @@ -0,0 +1,75 @@ +# Generated automatically from Makefile.in by configure. +# +# Auto-configuring 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 license given in the file "LICENSE" +# distributed in the NASM archive. + +# You may need to adjust these values. + +prefix = /usr/local +CC = cc +CFLAGS = -O -I.. + +# You _shouldn't_ need to adjust anything below this line. + +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +mandir = ${prefix}/man + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +LN_S = ln -s + +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 + +all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com + +rdfdump: rdfdump.o rdoff.o + $(CC) -o rdfdump rdfdump.o rdoff.o + +ldrdf: ldrdf.o $(LDRDFLIBS) + $(CC) -o ldrdf ldrdf.o $(LDRDFLIBS) +rdx: rdx.o $(RDXLIBS) + $(CC) -o rdx rdx.o $(RDXLIBS) +rdflib: rdflib.o + $(CC) -o rdflib rdflib.o +rdf2bin: rdf2bin.o $(RDXLIBS) nasmlib.o + $(CC) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o +rdf2com: + $(LN_S) rdf2bin rdf2com + +rdf2bin.o: rdf2bin.c +rdfdump.o: rdfdump.c +rdoff.o: rdoff.c rdoff.h +ldrdf.o: ldrdf.c rdoff.h ../nasmlib.h symtab.h collectn.h rdlib.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 + +clean: + rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com + +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 diff --git a/rdoff/Mkfiles/README b/rdoff/Mkfiles/README new file mode 100644 index 0000000..7e68499 --- /dev/null +++ b/rdoff/Mkfiles/README @@ -0,0 +1,4 @@ +These are pre-created Makefiles for various platforms, use them if +GNU autoconf/automake packages are not supported on your system. + +Copy appropriate Makefile to ../Makefile and run make. diff --git a/rdoff/README b/rdoff/README new file mode 100644 index 0000000..a5a6fd1 --- /dev/null +++ b/rdoff/README @@ -0,0 +1,185 @@ +******* +This file is getting obsolete. RDOFF documentation is written in Texinfo now. +Directory doc/ contains Texinfo source (rdoff.texi) and makefile for creating +different output formats (info, HTML, PostScript and PDF). +******* + +RDOFF Utilities, version 0.3.2 +============================== + +The files contained in this directory are the C source code of a set +of tools (and general purpose library files) for the manipulation of +RDOFF version 2 object files. Note that these programs (with the +exception of 'rdfdump') will NOT work with version 1 object files. +Version 1 of RDOFF is no longer supported. + +There is also a 'doc' directory with 'v1-v2' file, which documents the +differences between RDOFF 1 and 2, and an 'rdoff2.texi' (texinfo source), +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 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 +===== + +This tool is a version of unix 'ld' (or DOS 'link') for use with RDOFF +files. It is capable of linking RDOFF objects, and libraries produced +with the 'rdlib' utility discussed below. + +In normal usage, its command line takes the form: + + ldrdf [-o output-file] object files [-llibrary ...] + +Modules in libraries are not linked to the program unless they are +referred to. + +Most of its options are not implemented, but those that are are listed here: + + -2 redirect all output from stderr to stdout. It is useful for some + systems which don't have such a redirection in shell (e.g. DOS). + + -v increase verbosity level. Currently 4 verbosity levels are + available: default (which only prints error information), normal + (which prints information about the produced object, -v), medium + (which prints information about what the program is doing, -v -v) + and high (which prints all available information, -v -v -v). + + -a change alignment value to which multiple segments combigned into + a single segment should be aligned (must be either 1, 2, 4, 8, + 16, 32 or 256. Default is 16). + + -s strip exported symbols from output file. Symbols marked as + SYM_GLOBAL are never stripped. + + -x warn about unresolved symbols. + + -xe issue an error when at least one symbol is unresolved. + + -o name write output to file <name>. The default output filename + is 'aout.rdx'. + + -j path specify search path for object files. Default path is a + current directory. + + -L path specify search path for libraries. Default path is a + current directory. + + -g file embed 'file' as a first header record with type 'generic'. + + +rdx +=== + +This program simply loads and executes an RDOFF object, by calling +'_main', which it expects to be a C-style function, which will accept +two parameters, argc and argv in normal C style. + + +rdflib +====== + +This program creates a library file for use with ldrdf. + +It is supplied with a shell script 'makelib' which should probably be used +to create libraries. + +Usage: + rdflib command library [optional arguments] + +Valid commands are: + + c Create (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 + d Delete modules from library + r Replace a module in library with a new file + + +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 maintainers at the addresses 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 we 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 +- Check for more bugs + + +MAINTAINERS +=========== + +Yuri Zaporogets <yuriz@users.sf.net> - primary maintainer +Julian Hall <jules@dsf.org.uk> - original designer and author diff --git a/rdoff/collectn.c b/rdoff/collectn.c new file mode 100644 index 0000000..317c528 --- /dev/null +++ b/rdoff/collectn.c @@ -0,0 +1,45 @@ +/* + * collectn.c - implements variable length pointer arrays [collections]. + * + * This file is public domain. + */ + +#include "compiler.h" +#include <stdlib.h> +#include "collectn.h" + +void collection_init(Collection * c) +{ + int i; + + for (i = 0; i < 32; i++) + c->p[i] = NULL; + c->next = NULL; +} + +void **colln(Collection * c, int index) +{ + while (index >= 32) { + index -= 32; + if (c->next == NULL) { + c->next = malloc(sizeof(Collection)); + collection_init(c->next); + } + c = c->next; + } + return &(c->p[index]); +} + +void collection_reset(Collection * c) +{ + int i; + + if (c->next) { + collection_reset(c->next); + free(c->next); + } + + c->next = NULL; + for (i = 0; i < 32; i++) + c->p[i] = NULL; +} diff --git a/rdoff/collectn.h b/rdoff/collectn.h new file mode 100644 index 0000000..bcd75b8 --- /dev/null +++ b/rdoff/collectn.h @@ -0,0 +1,22 @@ +/* + * collectn.h - header file for 'collection' abstract data type. + * + * This file is public domain, and does not come under the NASM license. + * It, aint32_t with 'collectn.c' implements what is basically a variable + * length array (of pointers). + */ + +#ifndef RDOFF_COLLECTN_H +#define RDOFF_COLLECTN_H 1 + +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/doc/Makefile b/rdoff/doc/Makefile new file mode 100644 index 0000000..e4f24f5 --- /dev/null +++ b/rdoff/doc/Makefile @@ -0,0 +1,37 @@ +# +# Make info documentation +# + +AUXFILES = *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.dvi + +SRCS = rdoff.texi +OUTS = rdoff.info rdoff.html rdoff.ps rdoff.pdf + + +## Implicit rules +%.html : %.texi + makeinfo --html $< + +%.dvi : %.texi + texi2dvi $< + +%.ps: %.dvi + dvips $< + +%.pdf: %.dvi + dvipdf $< + + +## Explicit rules +all: info + +info: rdoff.info + +html: rdoff.html + +ps: rdoff.ps + +pdf: rdoff.pdf + +clean: + rm -f $(OUTS) $(AUXFILES) diff --git a/rdoff/doc/rdoff.texi b/rdoff/doc/rdoff.texi new file mode 100644 index 0000000..4431287 --- /dev/null +++ b/rdoff/doc/rdoff.texi @@ -0,0 +1,137 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename rdoff.info +@settitle Relocatable Dynamic Object File Format (RDOFF) +@afourpaper +@c %**end of header + +@titlepage +@title Relocatable Dynamic Object File Format (RDOFF) +@author Yuri Zaporogets @email{yuriz@@ukr.net} +@author Julian Hall @email{jules@@dsf.org.uk} +@end titlepage + +@ifinfo +Copyright @copyright{} 2002-2004 Netwide Assembler Project. +Written by Yuri Zaporogets @email{yuriz@@users.sf.net} +Based on various sources and notes written by Julian Hall @email{jules@@dsf.org.uk} +Distributed under GNU documentation license. +@end ifinfo + +@ifnottex +@node Top, Overview, (dir), (dir) +@top RDOFF + +RDOFF is a Relocatable Dynamic Object File Format. + +@end ifnottex + +@menu +* Overview:: Introduction. +* Structure:: Structure of RDOFF file. +* Utilities:: Description of RDOFF utilities. +@end menu + +@node Overview +@chapter Introduction + +RDOFF was designed initially to test the object-file production +interface to NASM. It soon became apparent that it could be enhanced +for use in serious applications due to its simplicity; code to load +and execute an RDOFF object module is very simple. It also contains +enhancements to allow it to be linked with a dynamic link library at +either run- or load- time, depending on how complex you wish to make +your loader. + +@node Structure +@chapter Structure of RDOFF file + +RDOFF module consists of three parts: + +@itemize +@item Master header +@item Header (may be omited) +@item Sections +@end itemize + +@dfn{Master header} contains signature, version and size information. + +@dfn{Header} consists of zero or more @ref{Records, records}. + +@dfn{Sections} represent actual contents of the file. Each section is prepended +by a section header. + +@node Records, , ,Structure +@section Records that may appear in RDOFF header + +@menu +* Relocation:: Relocation records. +* Import:: Declaring external symbols. +* Export:: Declaring public and exported symbols. +* DLL:: Specifying a run-time library name. +* BSS:: Reserving space in BSS section. +* Segment relocation:: Complexity of relocation in segmented systems. +* Far import:: External 'far' symbols. +* Module name:: Specifying module name. +* Common variable:: Declaring common variables. +* Generic record:: Embedding general-purpose data into the header. +@end menu + +@node Relocation +@subsection Relocation records + +@node Import +@subsection Declaring external and imported symbols + +@node Export +@subsection Declaring public and exported symbols + +@node DLL +@subsection Specifying a run-time library name + +@node BSS +@subsection Reserving space in BSS section + +@node Segment relocation +@subsection Complexity of relocation in segmented systems + +@node Far import +@subsection External 'far' symbols. + +@node Module name +@subsection Specifying module name. + +@node Common variable +@subsection Declaring common variables. + +@node Generic record +@subsection Embedding general-purpose data into the header. + + +@node Utilities +@chapter RDOFF utilities + +@menu +* rdfdump:: Dump the contents of RDOFF file. +* ldrdf:: RDOFF linker. +* rdflib:: RDOFF librarian. +* rdlar:: New RDOFF librarian/archiver. +* rdx:: Load and execute RDOFF module. +@end menu + +@node rdfdump +@section @command{rdfdump} - dump the contents of RDOFF file + +@node ldrdf +@section @command{ldrdf} - RDOFF linker + +@node rdflib +@section @command{rdflib} - RDOFF librarian + +@node rdlar +@section @command{rdlar} - new RDOFF librarian/archiver + +@node rdx +@section @command{rdx} - load and execute RDOFF module + +@bye diff --git a/rdoff/doc/v1-v2.txt b/rdoff/doc/v1-v2.txt new file mode 100644 index 0000000..800896b --- /dev/null +++ b/rdoff/doc/v1-v2.txt @@ -0,0 +1,62 @@ +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/hash.c b/rdoff/hash.c new file mode 100644 index 0000000..ad2b568 --- /dev/null +++ b/rdoff/hash.c @@ -0,0 +1,122 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * hash.h Routines to calculate a CRC32 hash value + * + * These routines donated to the NASM effort by Graeme Defty. + */ + +#include "compiler.h" + +#include "hash.h" + +const uint32_t 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 +}; + +uint32_t hash(const char *name) +{ + register const char *n; + register uint32_t 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..a6920e7 --- /dev/null +++ b/rdoff/hash.h @@ -0,0 +1,18 @@ +/* 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 license given in the file "LICENSE" + * distributed in the NASM archive. + */ + +#ifndef RDOFF_HASH_H +#define RDOFF_HASH_H 1 + +#include <inttypes.h> + +uint32_t hash(const char *name); + +#endif diff --git a/rdoff/ldrdf.1 b/rdoff/ldrdf.1 new file mode 100644 index 0000000..d0a2c21 --- /dev/null +++ b/rdoff/ldrdf.1 @@ -0,0 +1,41 @@ +.TH LDRDF 1 "September 6, 1999" "Debian Project" "Debian Manual" +.SH NAME +ldrdf \- link RDOFF objects and libraries produced by rdflib(1) +.SH SYNOPSIS +.B ldrdf +.RI "[-o " output-file ] +.I object-file\c +.RI "... [-l" library "...]" +.SH DESCRIPTION +.B ldrdf +is a version of unix +.BR ld (1) +(or DOS LINK) for use with RDOFF files. It is capable of linking RDOFF +objects, and libraries produced with the +.BR rdflib (1) +utility. +.PP +Libraries must be specified with their path as no search is performed. +Modules in libraries are not linked to the program unless they are +referred to. +.SH OPTIONS +.TP +.RI "-o " output-file +Specify an output file. The default output filename is +.RI ' aout.rdx '. +.TP +-v +Increase verbosity level. Currently 4 verbosity levels are available: +default (which only prints error information), normal (which prints +information about the produced object, -v), medium (which prints information +about what the program is doing, -v -v) and high (which prints all available +information, -v -v -v). +.TP +-p +Change alignment value to which multiple segments combigned into a single +segment should be aligned (must be either 1, 2, 4, 8, 16, 32 or 256; default +is 16). +.SH AUTHORS +Julian Hall <jules@earthcorp.com>. +.PP +This manual page was written by Matej Vela <vela@debian.org>. diff --git a/rdoff/ldrdf.c b/rdoff/ldrdf.c new file mode 100644 index 0000000..2ddada3 --- /dev/null +++ b/rdoff/ldrdf.c @@ -0,0 +1,1360 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * ldrdf.c - RDOFF Object File linker/loader main program. + */ + +/* + * TODO: + * - enhance search of required export symbols in libraries (now depends + * on modules order in library) + * - keep a cache of symbol names in each library module so + * we don't have to constantly recheck the file + * - general performance improvements + * + * 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 + * won't work if compiled by a 16 bit compiler. Try DJGPP if you're running + * under DOS. '#define STINGY_MEMORY' may help a little. + */ + +#include "compiler.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define RDOFF_UTILS + +#include "rdoff.h" +#include "symtab.h" +#include "collectn.h" +#include "rdlib.h" +#include "segtab.h" +#include "nasmlib.h" + +#define LDRDF_VERSION "1.07" + +/* #define STINGY_MEMORY */ + +/* ======================================================================= + * 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 */ + int32_t reloc; /* segment's relocation factor */ +}; + +struct modulenode { + 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; + int32_t 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 + */ + +void processmodule(const char *filename, struct modulenode *mod); +int allocnewseg(uint16_t type, uint16_t reserved); +int findsegment(uint16_t type, uint16_t reserved); +void symtab_add(const char *symbol, int segment, int32_t offset); +int symtab_get(const char *symbol, int *segment, int32_t *offset); + +/* ========================================================================= + * Global data structures. + */ + +/* a linked list of modules that will be included in the output */ +struct modulenode *modules = NULL; +struct modulenode *lastmodule = NULL; + +/* a linked list of libraries to be searched for unresolved imported symbols */ +struct librarynode *libraries = NULL; +struct librarynode *lastlib = NULL; + +/* the symbol table */ +void *symtab = NULL; + +/* objects search path */ +char *objpath = NULL; + +/* libraries search path */ +char *libpath = NULL; + +/* file to embed as a generic record */ +char *generic_rec_file = NULL; + +/* error file */ +static FILE *error_file; + +/* the header of the output file, built up stage by stage */ +rdf_headerbuf *newheader = NULL; + +/* 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; +int32_t bss_length; + +/* global options which affect how the program behaves */ +struct ldrdfoptions { + int verbose; + int align; + int dynalink; + int strip; + int respfile; + int stderr_redir; + int objpath; + int libpath; +} 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() +{ + 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; +} + +/* + * 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 loadmodule(const char *filename) +{ + 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 { + lastmodule->next = malloc(sizeof(*modules)); + lastmodule = lastmodule->next; + } + + if (!lastmodule) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + + /* open the file using 'rdfopen', which returns nonzero on error */ + if (rdfopen(&lastmodule->f, filename) != 0) { + rdfperror("ldrdf", filename); + exit(1); + } + + /* + * 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) + */ + 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, because we're now keeping track of how big each + * segment in our output file is... + */ +void processmodule(const char *filename, struct modulenode *mod) +{ + struct segconfig sconf; + int seg, outseg; + void *header; + rdfheaderrec *hr; + int32_t bssamount = 0; + int bss_was_referenced = 0; + + memset(&sconf, 0, sizeof sconf); + + 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; + + 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:%08"PRIx32" (+%04"PRIx32")\n", outseg, + mod->seginfo[seg].reloc, mod->f.seg[seg].length); + break; + + 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; + + if (options.verbose > 1) + printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg, + mod->seginfo[seg].reloc, mod->f.seg[seg].length); + } + + } + + /* + * 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 RDFREC_IMPORT: /* imported symbol */ + case RDFREC_FARIMPORT: + /* Define with seg = -1 */ + symtab_add(hr->i.label, -1, 0); + break; + + case RDFREC_GLOBAL:{ /* exported symbol */ + int destseg; + int32_t destreloc; + + if (hr->e.segment == 2) { + bss_was_referenced = 1; + destreloc = bss_length; + if (destreloc % options.align != 0) + destreloc += + options.align - (destreloc % options.align); + destseg = 2; + } else { + if ((destseg = + mod->seginfo[(int)hr->e.segment].dest_seg) == -1) + continue; + destreloc = mod->seginfo[(int)hr->e.segment].reloc; + } + symtab_add(hr->e.label, destseg, destreloc + hr->e.offset); + break; + } + + case RDFREC_BSS: /* 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; + + case RDFREC_COMMON:{ /* Common variable */ + symtabEnt *ste = symtabFind(symtab, hr->c.label); + + /* Is the symbol already in the table? */ + if (ste) + break; + + /* Align the variable */ + if (bss_length % hr->c.align != 0) + bss_length += hr->c.align - (bss_length % hr->c.align); + if (options.verbose > 1) { + printf("%s %04x common '%s' => 0002:%08"PRIx32" (+%04"PRIx32")\n", + filename, hr->c.segment, hr->c.label, + bss_length, hr->c.size); + } + + symtab_add(hr->c.label, 2, bss_length); + mod->bss_reloc = bss_length; + bss_length += hr->c.size; + break; + } + } + } + + if (bssamount != 0 || bss_was_referenced) { + /* + * 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:%08"PRIx32" (+%04"PRIx32")\n", + filename, bss_length, bssamount); + } + bss_length += bssamount; + } +#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); + +#endif + +} + +/* + * Return 1 if a given module is in the list, 0 otherwise. + */ +int lookformodule(const char *name) +{ + struct modulenode *curr = modules; + + while (curr) { + if (!strcmp(name, curr->name)) + return 1; + curr = curr->next; + } + return 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(uint16_t type, uint16_t 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++; +} + +int findsegment(uint16_t type, uint16_t reserved) +{ + int i; + + for (i = 0; i < nsegs; i++) + if (outputseg[i].type == type) + return i; + + return allocnewseg(type, reserved); +} + +/* + * 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. + */ +void symtab_add(const char *symbol, int segment, int32_t offset) +{ + symtabEnt *ste; + + ste = symtabFind(symtab, symbol); + if (ste) { + if (ste->segment >= 0) { + /* + * symbol previously defined + */ + if (segment < 0) + return; + fprintf(error_file, "warning: `%s' redefined\n", symbol); + return; + } + + /* + * 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); +} + +/* + * 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. + */ +int symtab_get(const char *symbol, int *segment, int32_t *offset) +{ + symtabEnt *ste = symtabFind(symtab, symbol); + if (!ste) { + *segment = -1; + *offset = 0; + return 0; + } else { + *segment = ste->segment; + *offset = ste->offset; + return 1; + } +} + +/* + * add_library() + * + * checks that a library can be opened and is in the correct format, + * then adds it to the linked list of libraries. + */ +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; + } + lastlib->next = NULL; + if (rdl_open(lastlib, name)) { + rdl_perror("ldrdf", name); + errorcount++; + return; + } +} + +/* + * 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; + int32_t offset; + int doneanything = 0, pass = 1, keepfile; + rdfheaderrec *hr; + + cur = libraries; + + while (cur) { + if (options.verbose > 2) + printf("scanning library `%s', pass %d...\n", cur->name, pass); + + for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) { + if (pass == 2 && lookformodule(f.name)) + continue; + + 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 != RDFREC_GLOBAL) + continue; + + /* + * If the symbol is marked as SYM_GLOBAL, somebody will be + * definitely interested in it.. + */ + if ((hr->e.flags & SYM_GLOBAL) == 0) { + /* + * otherwise the symbol is just public. Find it 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) + continue; + } + + 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); + lastmodule->next = NULL; + processmodule(f.name, lastmodule); + break; + } + if (!keepfile) { + free(f.name); + f.name = NULL; + f.fp = NULL; + } + } + if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND) + rdl_perror("ldrdf", cur->name); + + cur = cur->next; + if (cur == NULL && pass == 1) { + cur = libraries; + pass++; + } + } + + return doneanything; +} + +/* + * 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. + */ +void write_output(const char *filename) +{ + FILE *f; + rdf_headerbuf *rdfheader; + struct modulenode *cur; + int i, availableseg, seg, localseg, isrelative; + void *header; + rdfheaderrec *hr, newrec; + symtabEnt *se; + segtab segs; + int32_t offset; + uint8_t *data; + + if ((f = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename); + exit(1); + } + if ((rdfheader = rdfnewheader()) == NULL) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + + /* + * If '-g' option was given, first record in output file will be a + * `generic' record, filled with a given file content. + * This can be useful, for example, when constructing multiboot + * compliant kernels. + */ + if (generic_rec_file) { + FILE *ff; + + if (options.verbose) + printf("\nadding generic record from binary file %s\n", + generic_rec_file); + + hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec)); + if ((ff = fopen(generic_rec_file, "r")) == NULL) { + fprintf(stderr, "ldrdf: couldn't open %s for input\n", + generic_rec_file); + exit(1); + } + i = fread(hr->g.data, 1, sizeof(hr->g.data), ff); + fseek(ff, 0, SEEK_END); + if (ftell(ff) > (long)sizeof(hr->g.data)) { + fprintf(error_file, + "warning: maximum generic record size is %u, " + "rest of file ignored\n", + (unsigned int)sizeof(hr->g.data)); + } + fclose(ff); + + hr->g.type = 0; + hr->g.reclen = i; + rdfaddheader(rdfheader, hr); + free(hr); + } + + if (options.verbose) + printf("\nbuilding output module (%d segments)\n", nsegs); + + /* + * 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 = NULL; + if (!outputseg[i].length) + continue; + outputseg[i].data = malloc(outputseg[i].length); + if (!outputseg[i].data) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + } + + /* + * 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); + } + } + + /* + * 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)) { + 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); + + while ((hr = rdfgetheaderrec(&cur->f))) { + switch (hr->type) { + case RDFREC_RELOC: /* 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; + } + + isrelative = + (hr->r.segment & RDOFF_RELATIVEMASK) == + RDOFF_RELATIVEMASK; + hr->r.segment &= (RDOFF_RELATIVEMASK - 1); + + 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; + } + + 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; + } + + /* + * 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(error_file, + "warning: relocation out of range " + "at %s(%02x:%08"PRIx32")\n", cur->name, + (int)hr->r.segment, hr->r.offset); + *data = (char)offset; + break; + case 2: + offset += *(int16_t *)data; + if (offset < -32767 || offset > 32768) + fprintf(error_file, + "warning: relocation out of range " + "at %s(%02x:%08"PRIx32")\n", cur->name, + (int)hr->r.segment, hr->r.offset); + *(int16_t *)data = (int16_t)offset; + break; + case 4: + *(int32_t *)data += offset; + /* we can't easily detect overflow on this one */ + break; + } + + /* + * 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; + if (isrelative) + hr->r.segment += RDOFF_RELATIVEMASK; + rdfaddheader(rdfheader, hr); + } + break; + + case RDFREC_IMPORT: /* import symbol */ + case RDFREC_FARIMPORT: + /* + * 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.dynalink && !(hr->i.flags & SYM_IMPORT)) { + fprintf(error_file, + "error: unresolved reference to `%s'" + " in module `%s'\n", hr->i.label, + cur->name); + errorcount++; + } + /* + * 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 RDFREC_GLOBAL: /* export symbol */ + /* + * need to insert an export for this symbol into the new + * header, unless we're stripping symbols. Even if we're + * stripping, put the symbol if it's marked as SYM_GLOBAL. + */ + if (options.strip && !(hr->e.flags & SYM_GLOBAL)) + 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; + + case RDFREC_MODNAME: /* module name */ + /* + * Insert module name record if export symbols + * are not stripped. + * If module name begins with '$' - insert it anyway. + */ + if (options.strip && hr->m.modname[0] != '$') + break; + rdfaddheader(rdfheader, hr); + break; + + case RDFREC_DLL: /* DLL name */ + /* + * Insert DLL name if it begins with '$' + */ + if (hr->d.libname[0] != '$') + break; + rdfaddheader(rdfheader, hr); + break; + + case RDFREC_SEGRELOC: /* 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; + + 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; + + case RDFREC_COMMON: /* Common variable */ + /* Is this symbol already in the table? */ + se = symtabFind(symtab, hr->c.label); + if (!se) { + printf("%s is not in symtab yet\n", hr->c.label); + break; + } + /* Add segment location */ + add_seglocation(&segs, hr->c.segment, se->segment, + se->offset); + break; + } + } + + free(header); + done_seglocations(&segs); + + } + + /* + * combined BSS reservation for the entire results + */ + newrec.type = RDFREC_BSS; + newrec.b.reclen = 4; + newrec.b.amount = bss_length; + rdfaddheader(rdfheader, &newrec); + + /* + * Write the header + */ + for (i = 0; i < nsegs; i++) { + 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 + */ + for (i = 0; i < nsegs; i++) { + uint16_t s; + int32_t l; + + if (i == 2) + continue; + + s = translateint16_t(outputseg[i].type); + fwrite(&s, 2, 1, f); + s = translateint16_t(outputseg[i].number); + fwrite(&s, 2, 1, f); + s = translateint16_t(outputseg[i].reserved); + fwrite(&s, 2, 1, f); + l = translateint32_t(outputseg[i].length); + fwrite(&l, 4, 1, f); + + fwrite(outputseg[i].data, outputseg[i].length, 1, f); + } + + fwritezero(10, f); +} + +/* ========================================================================= + * Main program + */ + +void usage() +{ + printf("usage:\n" + " ldrdf [options] object modules ... [-llibrary ...]\n" + " ldrdf -r\n" + "options:\n" + " -v[=n] increase verbosity by 1, or set it to n\n" + " -a nn set segment alignment value (default 16)\n" + " -s strip public symbols\n" + " -dy Unix-style dynamic linking\n" + " -o name write output in file 'name'\n" + " -j path specify objects search path\n" + " -L path specify libraries search path\n" + " -g file embed 'file' as a first header record with type 'generic'\n"); + exit(0); +} + +int main(int argc, char **argv) +{ + char *outname = "aout.rdf"; + int moduleloaded = 0; + char *respstrings[128] = { 0, }; + + options.verbose = 0; + options.align = 16; + options.dynalink = 0; + options.strip = 0; + + error_file = stderr; + + argc--, argv++; + if (argc == 0) + usage(); + while (argc && *argv && **argv == '-' && argv[0][1] != 'l') { + switch (argv[0][1]) { + case 'r': + printf("ldrdf (linker for RDF files) version " LDRDF_VERSION + "\n"); + printf("RDOFF2 revision %s\n", RDOFF2_REVISION); + 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 'd': + if (argv[0][2] == 'y') + options.dynalink = 1; + break; + case 'o': + outname = argv[1]; + argv++, argc--; + break; + case 'j': + if (!objpath) { + options.objpath = 1; + objpath = argv[1]; + argv++, argc--; + break; + } else { + fprintf(stderr, + "ldrdf: more than one objects search path specified\n"); + exit(1); + } + case 'L': + if (!libpath) { + options.libpath = 1; + libpath = argv[1]; + argv++, argc--; + break; + } else { + fprintf(stderr, + "ldrdf: more than one libraries search path specified\n"); + exit(1); + } + case '@':{ + int i = 0; + char buf[256]; + FILE *f; + + options.respfile = 1; + if (argv[1] != NULL) + f = fopen(argv[1], "r"); + else { + fprintf(stderr, + "ldrdf: no response file name specified\n"); + exit(1); + } + + if (f == NULL) { + fprintf(stderr, + "ldrdf: unable to open response file\n"); + exit(1); + } + + argv++, argc--; + while (fgets(buf, sizeof(buf), f) != NULL) { + char *p; + if (buf[0] == '\n') + continue; + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; + if (i >= 128) { + fprintf(stderr, "ldrdf: too many input files\n"); + exit(1); + } + *(respstrings + i) = newstr(buf); + argc++, i++; + } + break; + } + case '2': + options.stderr_redir = 1; + error_file = stdout; + break; + case 'g': + generic_rec_file = argv[1]; + argv++, argc--; + break; + default: + usage(); + } + argv++, argc--; + } + + 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.dynalink) + printf(" Unix-style dynamic linking\n"); + if (options.objpath) + printf(" objects search path: %s\n", objpath); + if (options.libpath) + printf(" libraries search path: %s\n", libpath); + printf("\n"); + } + + symtab = symtabNew(); + initsegments(); + + if (!symtab) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + + while (argc) { + if (!*argv) + argv = respstrings; + if (!*argv) + break; + if (!strncmp(*argv, "-l", 2)) { + if (libpath && (argv[0][2] != '/')) + add_library(newstrcat(libpath, *argv + 2)); + else + add_library(*argv + 2); + } else { + if (objpath && (argv[0][0] != '/')) + loadmodule(newstrcat(objpath, *argv)); + else + loadmodule(*argv); + moduleloaded = 1; + } + argv++, argc--; + } + + if (!moduleloaded) { + printf("ldrdf: nothing to do. ldrdf -h for usage\n"); + return 0; + } + + search_libraries(); + + if (options.verbose > 2) { + printf("symbol table:\n"); + symtabDump(symtab, stdout); + } + + write_output(outname); + + if (errorcount > 0) + exit(1); + return 0; +} diff --git a/rdoff/ldsegs.h b/rdoff/ldsegs.h new file mode 100644 index 0000000..fcecdf6 --- /dev/null +++ b/rdoff/ldsegs.h @@ -0,0 +1,60 @@ +/* + * ldsegs.h Data for 'ldrdf' to determine what to do with different + * types of segment. This may be useful in other contexts also. + */ + +#ifndef RDOFF_LDSEGS_H +#define RDOFF_LDSEGS_H 1 + +#include <inttypes.h> + +struct segconfig { + uint16_t typelow, typehi; /* range of seg nos for which this is valid */ + char *typedesc; /* a description of the segment type */ + uint16_t dowhat; /* one of the SEG_xxxx values below */ + uint16_t 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); \ + } \ + } + +#endif diff --git a/rdoff/rdf2bin.1 b/rdoff/rdf2bin.1 new file mode 100644 index 0000000..d274d58 --- /dev/null +++ b/rdoff/rdf2bin.1 @@ -0,0 +1,65 @@ +.TH RDF2BIN 1 "September 6, 1999" "Debian Project" "Debian Manual" +.SH NAME +rdf2bin, rdf2com \- convert an RDOFF object file to flat binary +.SH SYNOPSIS +.B rdf2bin +.RI "[\-o " relocation-origin ] +.RI "[\-p " segment-alignment ] +.RI "[\-f " format ] +.I input-file +.I output-file +.br +.B rdf2com +.RI "[\-p " segment-alignment ] +.I input-file +.I output-file +.br +.B rdf2ith +.RI "[\-o " relocation-origin ] +.RI "[\-p " segment-alignment ] +.I input-file +.I output-file +.br +.B rdf2srec +.RI "[\-o " relocation-origin ] +.RI "[\-p " segment-alignment ] +.I input-file +.I output-file +.SH OPTIONS +.TP +.RI "\-o " relocation-origin +Relocate at origin +.IR relocation-origin . +If invoked as +.BR rdf2com , +the default relocation origin will be 0x100. Else, the default origin is 0. +.TP +.RI "\-p " segment-alignment +Pad segments until their size is a multiple of +.IR segment-alignment . +By default, 16 is used. +.TP +.RI "\-f " format +Specify the output format. The currently supported formats are binary +.RI ( bin ), +DOS COM (binary with origin 0x100) +.RI ( com ) +Intel hex +.RI ( ith +or +.IR ihx ), +and +Motorola S-Records +.RI ( srec ). +If not specified, the format is set by the command name. +.SH AUTHORS +Julian Hall <jules@earthcorp.com>, H. Peter Anvin <hpa@zytor.com>. +.PP +This manual page was written by Matej Vela <vela@debian.org>. +.SH BUGS +This utility currently only supports the classic segments +.IR .text , +.I .data +and +.IR .bss . + diff --git a/rdoff/rdf2bin.c b/rdoff/rdf2bin.c new file mode 100644 index 0000000..72e5104 --- /dev/null +++ b/rdoff/rdf2bin.c @@ -0,0 +1,430 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * rdf2bin.c - convert an RDOFF object file to flat binary + */ + +#include "compiler.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include "rdfload.h" +#include "nasmlib.h" + +const char *progname; + +static uint32_t origin = 0; +static bool origin_def = false; +static uint32_t align = 16; +static bool align_def = false; + +struct output_format { + const char *name; + const char *mode; + int (*init)(FILE *f); + int (*output)(FILE *f, void *data, uint32_t bytes, uint32_t where); + int (*fini)(FILE *f); +}; + +static int null_init_fini(FILE *f) +{ + (void)f; + return 0; +} + +static int com_init(FILE *f) +{ + (void)f; + if (!origin_def) + origin = 0x100; + return 0; +} + +static int output_bin(FILE *f, void *data, uint32_t bytes, uint32_t where) +{ + static uint32_t offset = 0; /* Current file offset, if applicable */ + size_t pad; + + if (where-origin < offset) { + fprintf(stderr, "%s: internal error: backwards movement\n", progname); + exit(1); + } + + pad = (where-origin) - offset; + if (fwritezero(pad, f) != pad) + return -1; + offset += pad; + + if (fwrite(data, 1, bytes, f) != bytes) + return -1; + offset += bytes; + + return 0; +} + +static int write_ith_record(FILE *f, unsigned int len, uint16_t addr, + uint8_t type, void *data) +{ + char buf[1+2+4+2+255*2+2+2]; + char *p = buf; + uint8_t csum, *dptr = data; + unsigned int i; + + if (len > 255) { + fprintf(stderr, "%s: internal error: invalid ith record size\n", + progname); + exit(1); + } + + csum = len + addr + (addr >> 8) + type; + for (i = 0; i < len; i++) + csum += dptr[i]; + csum = -csum; + + p += sprintf(p, ":%02X%04X%02X", len, addr, type); + for (i = 0; i < len; i++) + p += sprintf(p, "%02X", dptr[i]); + p += sprintf(p, "%02X\n", csum); + + if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf)) + return -1; + + return 0; +} + +static int output_ith(FILE *f, void *data, uint32_t bytes, uint32_t where) +{ + static uint32_t last = 0; /* Last address written */ + uint8_t abuf[2]; + uint8_t *dbuf = data; + uint32_t chunk; + + while (bytes) { + if ((where ^ last) & ~0xffff) { + abuf[0] = where >> 24; + abuf[1] = where >> 16; + if (write_ith_record(f, 2, 0, 4, abuf)) + return -1; + } + + /* Output up to 32 bytes, but always end on an aligned boundary */ + chunk = 32 - (where & 31); + if (bytes < chunk) + chunk = bytes; + + if (write_ith_record(f, chunk, (uint16_t)where, 0, dbuf)) + return -1; + + dbuf += chunk; + last = where + chunk - 1; + where += chunk; + bytes -= chunk; + } + return 0; +} + +static int fini_ith(FILE *f) +{ + /* XXX: entry point? */ + return write_ith_record(f, 0, 0, 1, NULL); +} + +static int write_srecord(FILE *f, unsigned int len, unsigned int alen, + uint32_t addr, uint8_t type, void *data) +{ + char buf[2+2+8+255*2+2+2]; + char *p = buf; + uint8_t csum, *dptr = data; + unsigned int i; + + if (len > 255) { + fprintf(stderr, "%s: internal error: invalid srec record size\n", + progname); + exit(1); + } + + switch (alen) { + case 2: + addr &= 0xffff; + break; + case 3: + addr &= 0xffffff; + break; + case 4: + break; + default: + fprintf(stderr, "%s: internal error: invalid srec address length\n", + progname); + exit(1); + } + + csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24); + for (i = 0; i < len; i++) + csum += dptr[i]; + csum = 0xff-csum; + + p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr); + for (i = 0; i < len; i++) + p += sprintf(p, "%02X", dptr[i]); + p += sprintf(p, "%02X\n", csum); + + if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf)) + return -1; + + return 0; +} + +static int init_srec(FILE *f) +{ + return write_srecord(f, 0, 2, 0, '0', NULL); +} + +static int fini_srec(FILE *f) +{ + /* XXX: entry point? */ + return write_srecord(f, 0, 4, 0, '7', NULL); +} + +static int output_srec(FILE *f, void *data, uint32_t bytes, uint32_t where) +{ + uint8_t *dbuf = data; + unsigned int chunk; + + while (bytes) { + /* Output up to 32 bytes, but always end on an aligned boundary */ + chunk = 32 - (where & 31); + if (bytes < chunk) + chunk = bytes; + + if (write_srecord(f, chunk, 4, where, '3', dbuf)) + return -1; + + dbuf += chunk; + where += chunk; + bytes -= chunk; + } + return 0; +} + +static struct output_format output_formats[] = { + { "bin", "wb", null_init_fini, output_bin, null_init_fini }, + { "com", "wb", com_init, output_bin, null_init_fini }, + { "ith", "wt", null_init_fini, output_ith, fini_ith }, + { "ihx", "wt", null_init_fini, output_ith, fini_ith }, + { "srec", "wt", init_srec, output_srec, fini_srec }, + { NULL, NULL, NULL, NULL, NULL } +}; + +static const char *getformat(const char *pathname) +{ + const char *p; + static char fmt_buf[16]; + + /* + * Search backwards for the string "rdf2" followed by a string + * of alphanumeric characters. This should handle path prefixes, + * as well as extensions (e.g. C:\FOO\RDF2SREC.EXE). + */ + for (p = strchr(pathname, '\0')-1 ; p >= pathname ; p--) { + if (!nasm_stricmp(p, "rdf2")) { + const char *q = p+4; + char *r = fmt_buf; + while (isalnum(*q) && r < fmt_buf+sizeof fmt_buf-1) + *r++ = *q++; + *r = '\0'; + if (fmt_buf[0]) + return fmt_buf; + } + } + return NULL; +} + +static void usage(void) +{ + fprintf(stderr, + "Usage: %s [options] input-file output-file\n" + "Options:\n" + " -o origin Specify the relocation origin\n" + " -p alignment Specify minimum segment alignment\n" + " -f format Select format (bin, com, ith, srec)\n" + " -q Run quiet\n" + " -v Run verbose\n", + progname); +} + +int main(int argc, char **argv) +{ + rdfmodule *m; + bool err; + FILE *of; + int codepad, datapad; + const char *format = NULL; + const struct output_format *fmt; + bool quiet = false; + + progname = argv[0]; + + if (argc < 2) { + usage(); + return 1; + } + + argv++, argc--; + + while (argc > 2) { + if (argv[0][0] == '-' && argv[0][1] && !argv[0][2]) { + switch (argv[0][1]) { + case 'o': + argv++, argc--; + origin = readnum(*argv, &err); + if (err) { + fprintf(stderr, "%s: invalid parameter: %s\n", + progname, *argv); + return 1; + } + origin_def = true; + break; + case 'p': + argv++, argc--; + align = readnum(*argv, &err); + if (err) { + fprintf(stderr, "%s: invalid parameter: %s\n", + progname, *argv); + return 1; + } + align_def = true; + break; + case 'f': + argv++, argc--; + format = *argv; + break; + case 'q': + quiet = true; + break; + case 'v': + quiet = false; + break; + case 'h': + usage(); + return 0; + default: + fprintf(stderr, "%s: unknown option: %s\n", + progname, *argv); + return 1; + } + } + argv++, argc--; + } + + if (argc < 2) { + usage(); + return 1; + } + + if (!format) + format = getformat(progname); + + if (!format) { + fprintf(stderr, "%s: unable to determine desired output format\n", + progname); + return 1; + } + + for (fmt = output_formats; fmt->name; fmt++) { + if (!nasm_stricmp(format, fmt->name)) + break; + } + + if (!fmt->name) { + fprintf(stderr, "%s: unknown output format: %s\n", progname, format); + return 1; + } + + m = rdfload(*argv); + + if (!m) { + rdfperror(progname, *argv); + return 1; + } + + if (!quiet) + printf("relocating %s: origin=%"PRIx32", align=%d\n", + *argv, origin, align); + + m->textrel = origin; + m->datarel = origin + m->f.seg[0].length; + if (m->datarel % align != 0) { + codepad = align - (m->datarel % align); + m->datarel += codepad; + } else + codepad = 0; + + m->bssrel = m->datarel + m->f.seg[1].length; + if (m->bssrel % align != 0) { + datapad = align - (m->bssrel % align); + m->bssrel += datapad; + } else + datapad = 0; + + if (!quiet) + printf("code: %08"PRIx32"\ndata: %08"PRIx32"\nbss: %08"PRIx32"\n", + m->textrel, m->datarel, m->bssrel); + + rdf_relocate(m); + + argv++; + + of = fopen(*argv, fmt->mode); + if (!of) { + fprintf(stderr, "%s: could not open output file %s: %s\n", + progname, *argv, strerror(errno)); + return 1; + } + + if (fmt->init(of) || + fmt->output(of, m->t, m->f.seg[0].length, m->textrel) || + fmt->output(of, m->d, m->f.seg[1].length, m->datarel) || + fmt->fini(of)) { + fprintf(stderr, "%s: error writing to %s: %s\n", + progname, *argv, strerror(errno)); + return 1; + } + + fclose(of); + return 0; +} diff --git a/rdoff/rdf2com.1 b/rdoff/rdf2com.1 new file mode 100644 index 0000000..43b3307 --- /dev/null +++ b/rdoff/rdf2com.1 @@ -0,0 +1 @@ +.so man1/rdf2bin.1 diff --git a/rdoff/rdf2ihx.1 b/rdoff/rdf2ihx.1 new file mode 100644 index 0000000..43b3307 --- /dev/null +++ b/rdoff/rdf2ihx.1 @@ -0,0 +1 @@ +.so man1/rdf2bin.1 diff --git a/rdoff/rdf2ith.1 b/rdoff/rdf2ith.1 new file mode 100644 index 0000000..43b3307 --- /dev/null +++ b/rdoff/rdf2ith.1 @@ -0,0 +1 @@ +.so man1/rdf2bin.1 diff --git a/rdoff/rdf2srec.1 b/rdoff/rdf2srec.1 new file mode 100644 index 0000000..43b3307 --- /dev/null +++ b/rdoff/rdf2srec.1 @@ -0,0 +1 @@ +.so man1/rdf2bin.1 diff --git a/rdoff/rdfdump.1 b/rdoff/rdfdump.1 new file mode 100644 index 0000000..cf61484 --- /dev/null +++ b/rdoff/rdfdump.1 @@ -0,0 +1,24 @@ +.TH RDFDUMP 1 "September 6, 1999" "Debian Project" "Debian Manual" +.SH NAME +rdfdump \- dumps an RDOFF object in human-readable form +.SH SYNOPSIS +.B rdfdump +[-v] +.RI < filename > +.SH DESCRIPTION +.B rdfdump +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 segments. +.PP +.B rdfdump +supports both version 1 and 2 of RDOFF. It will give 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). +.SH OPTIONS +.TP +-v +Print a hex dump of the contents of the segments. +.SH AUTHORS +Julian Hall <jules@earthcorp.com>. +.PP +This manual page was written by Matej Vela <vela@debian.org>. diff --git a/rdoff/rdfdump.c b/rdoff/rdfdump.c new file mode 100644 index 0000000..0e55c67 --- /dev/null +++ b/rdoff/rdfdump.c @@ -0,0 +1,347 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * rdfdump.c - dump RDOFF file header. + */ + +#include "compiler.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define RDOFF_UTILS + +#include "rdoff.h" + +#define PROGRAM_VERSION "2.3" + +FILE *infile; + +void print_header(int32_t length, int rdf_version) +{ + char buf[129], t, l, s, flags; + uint8_t reclen; + int32_t o, ll; + uint16_t rs; + + while (length > 0) { + fread(&t, 1, 1, infile); + if (rdf_version >= 2) { + fread(&reclen, 1, 1, infile); + } + switch (t) { + case RDFREC_GENERIC: /* generic record */ + printf(" generic record (length=%d)\n", (int)reclen); + fseek(infile, reclen, SEEK_CUR); + break; + + case RDFREC_RELOC: /* relocation record */ + case RDFREC_SEGRELOC: /* segment relocation */ + fread(&s, 1, 1, infile); + fread(&o, 4, 1, infile); + fread(&l, 1, 1, infile); + fread(&rs, 2, 1, infile); + printf(" %s: location (%04x:%08"PRIx32"), length %d, " + "referred seg %04x\n", + t == 1 ? "relocation" : "seg relocation", (int)s, + translateint32_t(o), (int)l, translateint16_t(rs)); + 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 RDFREC_IMPORT: /* import record */ + case RDFREC_FARIMPORT: /* import far symbol */ + fread(&flags, 1, 1, infile); + fread(&rs, 2, 1, infile); + ll = 0; + + if (rdf_version == 1) { + do { + fread(&buf[ll], 1, 1, infile); + } while (buf[ll++]); + } else { + for (; ll < reclen - 3; ll++) + fread(&buf[ll], 1, 1, infile); + } + + if (t == 7) + printf("far "); + printf((flags & SYM_IMPORT) ? " import" : " extern"); + if (flags & SYM_FUNCTION) + printf(" proc"); + if (flags & SYM_DATA) + printf(" data"); + printf(": segment %04x = %s\n", translateint16_t(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 RDFREC_GLOBAL: /* export record */ + fread(&flags, 1, 1, infile); + fread(&s, 1, 1, infile); + fread(&o, 4, 1, infile); + ll = 0; + + if (rdf_version == 1) { + do { + fread(&buf[ll], 1, 1, infile); + } while (buf[ll++]); + } else { + for (; ll < reclen - 6; ll++) + fread(&buf[ll], 1, 1, infile); + } + printf((flags & SYM_GLOBAL) ? " export" : " public"); + if (flags & SYM_FUNCTION) + printf(" proc"); + if (flags & SYM_DATA) + printf(" data"); + printf(": (%04x:%08"PRIx32") = %s\n", (int)s, translateint32_t(o), buf); + if (rdf_version == 1) + length -= ll + 6; + break; + + case RDFREC_DLL: /* DLL and Module records */ + case RDFREC_MODNAME: + ll = 0; + if (rdf_version == 1) { + do { + fread(&buf[ll], 1, 1, infile); + } while (buf[ll++]); + } else { + for (; ll < reclen; ll++) + fread(&buf[ll], 1, 1, infile); + } + if (t == 4) + printf(" dll: %s\n", buf); + else + printf(" module: %s\n", buf); + if (rdf_version == 1) + length -= ll + 1; + break; + + case RDFREC_BSS: /* BSS reservation */ + fread(&ll, 4, 1, infile); + printf(" bss reservation: %08"PRIx32" bytes\n", translateint32_t(ll)); + if (rdf_version == 1) + length -= 5; + if (rdf_version > 1 && reclen != 4) + printf(" warning: reclen != 4\n"); + break; + + case RDFREC_COMMON:{ + uint16_t seg, align; + uint32_t size; + + fread(&seg, 2, 1, infile); + fread(&size, 4, 1, infile); + fread(&align, 2, 1, infile); + for (ll = 0; ll < reclen - 8; ll++) + fread(buf + ll, 1, 1, infile); + printf(" common: segment %04x = %s, %"PRId32":%d\n", + translateint16_t(seg), buf, translateint32_t(size), + translateint16_t(align)); + break; + } + + default: + printf(" unrecognized record (type %d", (int)t); + if (rdf_version > 1) { + printf(", length %d", (int)reclen); + fseek(infile, reclen, SEEK_CUR); + } else + length--; + printf(")\n"); + } + if (rdf_version != 1) + length -= 2 + reclen; + } +} + +int main(int argc, char **argv) +{ + char id[7]; + int32_t l; + uint16_t s; + int verbose = 0; + int32_t offset; + int foundnullsegment = 0; + int version; + int32_t segmentcontentlength = 0; + int nsegments = 0; + int32_t headerlength = 0; + int32_t objectlength = 0; + + printf("RDOFF dump utility, version %s\n", PROGRAM_VERSION); + printf("RDOFF2 revision %s\n", RDOFF2_REVISION); + puts("Copyright (c) 1996,99 Julian R Hall\n" + "Improvements and fixes (c) 2002-2004 RET & COM Research."); + + 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\n", 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] > '2') { + fprintf(stderr, "rdfdump: unknown RDOFF version '%c'\n", id[5]); + exit(1); + } + version = id[5] - '0'; + + if (version > 1) { + fread(&l, 4, 1, infile); + objectlength = translateint32_t(l); + printf("Object content size: %"PRId32" bytes\n", objectlength); + } + + fread(&l, 4, 1, infile); + headerlength = translateint32_t(l); + printf("Header (%"PRId32" bytes):\n", headerlength); + print_header(headerlength, version); + + if (version == 1) { + fread(&l, 4, 1, infile); + l = translateint32_t(l); + printf("\nText segment length = %"PRId32" bytes\n", l); + offset = 0; + while (l--) { + fread(id, 1, 1, infile); + if (verbose) { + if (offset % 16 == 0) + printf("\n%08"PRIx32" ", offset); + printf(" %02x", (int)(uint8_t)id[0]); + offset++; + } + } + if (verbose) + printf("\n\n"); + + fread(&l, 4, 1, infile); + l = translateint32_t(l); + printf("Data segment length = %"PRId32" bytes\n", l); + + if (verbose) { + offset = 0; + while (l--) { + fread(id, 1, 1, infile); + if (offset % 16 == 0) + printf("\n%08"PRIx32" ", offset); + printf(" %02x", (int)(uint8_t)id[0]); + offset++; + } + printf("\n"); + } + } else { + do { + fread(&s, 2, 1, infile); + s = translateint16_t(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)translateint16_t(s)); + fread(&s, 2, 1, infile); + printf(" Resrvd = %04X\n", (int)translateint16_t(s)); + fread(&l, 4, 1, infile); + l = translateint32_t(l); + printf(" Length = %"PRId32" bytes\n", l); + segmentcontentlength += l; + + offset = 0; + while (l--) { + fread(id, 1, 1, infile); + if (verbose) { + if (offset % 16 == 0) + printf("\n%08"PRIx32" ", offset); + printf(" %02x", (int)(uint8_t)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: %"PRId32" 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 (%"PRId32") != " + "stored object length (%"PRId32")\n", l, objectlength); + } + fclose(infile); + return 0; +} diff --git a/rdoff/rdflib.1 b/rdoff/rdflib.1 new file mode 100644 index 0000000..bba1032 --- /dev/null +++ b/rdoff/rdflib.1 @@ -0,0 +1,39 @@ +.TH RDFLIB 1 "September 6, 1999" "Debian Project" "Debian Manual" +.SH NAME +rdflib \- manage a library file for use with ldrdf(1) +.SH SYNOPSIS +.B rdflib +.I command +.I arguments +.SH DESCRIPTION +.B rdflib +manages a library file which can be used by +.BR ldrdf (1). +It is supplied with a shell script +.B makelib +which should probably be used to create libraries. +.SH COMMANDS +.TP +.BI c " library-file" +Create (or truncate) a library. +.TP +.BI a " library-file object-file module" +Add the +.I object-file +to the library under the name +.IR module . +.TP +.BI x " library-file module object-file" +Extract a +.I module +from the library to the file +.IR object-file . +.TP +.B t " library-file" +Display a list of modules in the library. +.SH NOTES +A remove command will be added soon. +.SH AUTHORS +Julian Hall <jules@earthcorp.com>. +.PP +This manual page was written by Matej Vela <vela@debian.org>. diff --git a/rdoff/rdflib.c b/rdoff/rdflib.c new file mode 100644 index 0000000..1213bea --- /dev/null +++ b/rdoff/rdflib.c @@ -0,0 +1,428 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* 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. + * + * When a library is being created, special signature block is placed + * in the beginning of the file. It is a string 'RDLIB' followed by a + * version number, then int32_t content size and a int32_t time stamp. + * The module name of the signature block is '.sig'. + * + * + * 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 uint8_t type & version identifier followed by int32_t + * content size, followed by data. + */ + +#include "compiler.h" + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <inttypes.h> +#include <time.h> +#include <inttypes.h> + +/* functions supported: + * create a library (no extra operands required) + * add a module from a library (requires filename and name to give mod.) + * replace a module in a library (requires given name and filename) + * delete 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" + " x - extract (module-name filename)\n" + " r - replace (module-name filename)\n" + " d - delete (module-name)\n" " t - list\n"; + +/* Library signature */ +const char *rdl_signature = "RDLIB2", *sig_modname = ".sig"; + +char **_argv; + +#define _ENDIANNESS 0 /* 0 for little, 1 for big */ + +static void int32_ttolocal(int32_t *l) +{ +#if _ENDIANNESS + uint8_t t; + uint8_t *p = (uint8_t *)l; + + t = p[0]; + p[0] = p[3]; + p[3] = t; + t = p[1]; + p[1] = p[2]; + p[2] = p[1]; +#else + (void)l; /* placate optimizers */ +#endif +} + +char copybytes(FILE * fp, FILE * fp2, int n) +{ + int i, t = 0; + + for (i = 0; i < n; i++) { + t = fgetc(fp); + if (t == EOF) { + fprintf(stderr, "rdflib: premature end of file in '%s'\n", + _argv[2]); + exit(1); + } + if (fp2) + if (fputc(t, fp2) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } + return (char)t; /* return last char read */ +} + +int32_t copyint32_t(FILE * fp, FILE * fp2) +{ + int32_t l; + int i, t; + uint8_t *p = (uint8_t *)&l; + + for (i = 0; i < 4; i++) { /* skip magic no */ + t = fgetc(fp); + if (t == EOF) { + fprintf(stderr, "rdflib: premature end of file in '%s'\n", + _argv[2]); + exit(1); + } + if (fp2) + if (fputc(t, fp2) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + *p++ = t; + } + int32_ttolocal(&l); + return l; +} + +int main(int argc, char **argv) +{ + FILE *fp, *fp2 = NULL, *fptmp; + char *p, buf[256], c; + int i; + int32_t l; + time_t t; + char rdbuf[10]; + + _argv = argv; + + if (argc < 3 || !strncmp(argv[1], "-h", 2) + || !strncmp(argv[1], "--h", 3)) { + fputs(usage, stdout); + exit(1); + } + + switch (argv[1][0]) { + case 'c': /* create library */ + fp = fopen(argv[2], "wb"); + if (!fp) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[2]); + perror("rdflib"); + exit(1); + } + fwrite(sig_modname, 1, strlen(sig_modname) + 1, fp); + fwrite(rdl_signature, 1, strlen(rdl_signature), fp); + l = sizeof(t = time(NULL)); + fwrite(&l, sizeof(l), 1, fp); + fwrite(&t, 1, l, fp); + fclose(fp); + break; + + case 'a': /* add module */ + if (argc < 5) { + fprintf(stderr, "rdflib: required parameter missing\n"); + exit(1); + } + fp = fopen(argv[2], "ab"); + if (!fp) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[2]); + perror("rdflib"); + exit(1); + } + + fp2 = fopen(argv[3], "rb"); + if (!fp2) { + 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, "rdflib: write error\n"); + exit(1); + } + } while (*p++); + + while (!feof(fp2)) { + i = fgetc(fp2); + if (i == EOF) { + break; + } + + if (fputc(i, fp) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } + fclose(fp2); + fclose(fp); + break; + + case 'x': + if (argc < 5) { + fprintf(stderr, "rdflib: required parameter missing\n"); + exit(1); + } + case 't': + fp = fopen(argv[2], "rb"); + if (!fp) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[2]); + perror("rdflib"); + exit(1); + } + + fp2 = NULL; + while (!feof(fp)) { + /* read name */ + p = buf; + while ((*(p++) = (char)fgetc(fp))) + if (feof(fp)) + break; + + if (feof(fp)) + break; + + fp2 = NULL; + if (argv[1][0] == 'x') { + /* check against desired name */ + if (!strcmp(buf, argv[3])) { + fp2 = fopen(argv[4], "wb"); + if (!fp2) { + fprintf(stderr, "rdflib: could not open '%s'\n", + argv[4]); + perror("rdflib"); + exit(1); + } + } + } else + 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); + + l = copyint32_t(fp, fp2); + + if (argv[1][0] == 't') + printf(" %"PRId32" bytes content\n", l); + + copybytes(fp, fp2, l); + } else if ((c = copybytes(fp, fp2, 6)) >= '2') { /* version 2 or above */ + l = copyint32_t(fp, fp2); + + if (argv[1][0] == 't') + printf("RDOFF%c %"PRId32" 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, copyint32_t(fp, fp2)); /* header */ + copybytes(fp, fp2, copyint32_t(fp, fp2)); /* text */ + copybytes(fp, fp2, copyint32_t(fp, fp2)); /* data */ + } + + if (fp2) + break; + } + fclose(fp); + if (fp2) + fclose(fp2); + else if (argv[1][0] == 'x') { + fprintf(stderr, "rdflib: module '%s' not found in '%s'\n", + argv[3], argv[2]); + exit(1); + } + break; + + case 'r': /* replace module */ + argc--; + case 'd': /* delete module */ + if (argc < 4) { + fprintf(stderr, "rdflib: required parameter missing\n"); + exit(1); + } + + fp = fopen(argv[2], "rb"); + if (!fp) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[2]); + perror("rdflib"); + exit(1); + } + + if (argv[1][0] == 'r') { + fp2 = fopen(argv[4], "rb"); + if (!fp2) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[4]); + perror("rdflib"); + exit(1); + } + } + + fptmp = tmpfile(); + if (!fptmp) { + fprintf(stderr, "rdflib: could not open temporary file\n"); + perror("rdflib"); + exit(1); + } + + /* copy library into temporary file */ + fseek(fp, 0, SEEK_END); /* get file length */ + l = ftell(fp); + fseek(fp, 0, SEEK_SET); + copybytes(fp, fptmp, l); + rewind(fptmp); + freopen(argv[2], "wb", fp); + + while (!feof(fptmp)) { + /* read name */ + p = buf; + while ((*(p++) = (char)fgetc(fptmp))) + if (feof(fptmp)) + break; + + if (feof(fptmp)) + break; + + /* check against desired name */ + if (!strcmp(buf, argv[3])) { + fread(p = rdbuf, 1, sizeof(rdbuf), fptmp); + l = *(int32_t *)(p + 6); + fseek(fptmp, l, SEEK_CUR); + break; + } else { + fwrite(buf, 1, strlen(buf) + 1, fp); /* module name */ + if ((c = copybytes(fptmp, fp, 6)) >= '2') { + l = copyint32_t(fptmp, fp); /* version 2 or above */ + copybytes(fptmp, fp, l); /* entire object */ + } + } + } + + if (argv[1][0] == 'r') { + /* copy new module into library */ + p = argv[3]; + do { + if (fputc(*p, fp) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } while (*p++); + + while (!feof(fp2)) { + i = fgetc(fp2); + if (i == EOF) { + break; + } + if (fputc(i, fp) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } + fclose(fp2); + } + + /* copy rest of library if any */ + while (!feof(fptmp)) { + i = fgetc(fptmp); + if (i == EOF) { + break; + } + + if (fputc(i, fp) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } + + fclose(fp); + fclose(fptmp); + break; + + default: + fprintf(stderr, "rdflib: command '%c' not recognized\n", + argv[1][0]); + exit(1); + } + return 0; +} diff --git a/rdoff/rdfload.c b/rdoff/rdfload.c new file mode 100644 index 0000000..4fd3dbd --- /dev/null +++ b/rdoff/rdfload.c @@ -0,0 +1,212 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * rdfload.c RDOFF Object File loader library + */ + +/* + * 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 "compiler.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "rdfload.h" +#include "symtab.h" +#include "collectn.h" + +extern int rdf_errno; + +rdfmodule *rdfload(const char *filename) +{ + rdfmodule *f; + int32_t bsslength = 0; + char *hdr; + rdfheaderrec *r; + + f = malloc(sizeof(rdfmodule)); + if (f == NULL) { + rdf_errno = RDF_ERR_NOMEM; + return NULL; + } + + f->symtab = symtabNew(); + if (!f->symtab) { + free(f); + rdf_errno = RDF_ERR_NOMEM; + 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.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) { + rdf_errno = RDF_ERR_NOMEM; + 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 (bsslength && (!f->b)) { + free(f->t); + free(f->d); + free(f); + free(hdr); + rdf_errno = RDF_ERR_NOMEM; + return NULL; + } + + rdfheaderrewind(&f->f); + + f->textrel = (int32_t)(size_t)f->t; + f->datarel = (int32_t)(size_t)f->d; + f->bssrel = (int32_t)(size_t)f->b; + + return f; +} + +int rdf_relocate(rdfmodule * m) +{ + rdfheaderrec *r; + Collection imports; + symtabEnt e; + int32_t rel; + uint8_t *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 + 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 + non-portable */ + switch (r->r.length) { + case 1: + seg[r->r.offset] += (char)rel; + break; + case 2: + *(uint16_t *) (seg + r->r.offset) += (uint16_t) rel; + break; + case 4: + *(int32_t *)(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; + + 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/rdfload.h b/rdoff/rdfload.h new file mode 100644 index 0000000..87d7ecc --- /dev/null +++ b/rdoff/rdfload.h @@ -0,0 +1,31 @@ +/* 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 license given in the file "LICENSE" + * distributed in the NASM archive. + * + * See the file 'rdfload.c' for special license information for this + * file. + */ + +#ifndef RDOFF_RDFLOAD_H +#define RDOFF_RDFLOAD_H 1 + +#define RDOFF_UTILS + +#include "rdoff.h" + +typedef struct RDFModuleStruct { + rdffile f; /* file structure */ + uint8_t *t, *d, *b; /* text, data, and bss segments */ + uint32_t textrel; + uint32_t datarel; + uint32_t bssrel; + void *symtab; +} rdfmodule; + +rdfmodule *rdfload(const char *filename); +int rdf_relocate(rdfmodule * m); + +#endif diff --git a/rdoff/rdlar.c b/rdoff/rdlar.c new file mode 100644 index 0000000..98b0f8f --- /dev/null +++ b/rdoff/rdlar.c @@ -0,0 +1,490 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * rdlar.c - new librarian/archiver for RDOFF2. + */ + +#include "compiler.h" + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "rdlar.h" + +#define PROGRAM_VERSION "0.1" + +/** Constants **/ +const char commands[] = "adnrtx"; +const char modifiers[] = "cflouvV"; + +/** Global variables **/ +char *progname = "rdlar"; +char **_argv = NULL; +struct { + bool createok; + bool usefname; + bool align; + bool odate; + bool fresh; + int verbose; +} options = { +0, 0, 0, 0, 0, 0}; + +#define _ENDIANNESS 0 /* 0 for little, 1 for big */ + +/* + * Convert int32_t to little endian (if we were compiled on big-endian machine) + */ +static void int32_ttolocal(int32_t *l) +{ +#if _ENDIANNESS + uint8_t t; + uint8_t *p = (uint8_t *)l; + + t = p[0]; + p[0] = p[3]; + p[3] = t; + t = p[1]; + p[1] = p[2]; + p[2] = p[1]; +#endif +} + +/* + * Print version information + */ +void show_version(void) +{ + puts("New RDOFF2 librarian/archiver, version " PROGRAM_VERSION); +} + +/* + * Print usage instructions + */ +void usage(void) +{ + printf("Usage: %s [-]{%s}[%s] libfile [module-name] [files]\n", + progname, commands, modifiers); + puts(" commands:\n" + " a - add module(s) to the library\n" + " d - delete module(s) from the library\n" + " n - create the library\n" + " r - replace module(s)\n" + " t - display contents of library\n" + " x - extract module(s)\n" + " command specific modifiers:\n" + " o - preserve original dates\n" + " u - only replace modules that are newer than library contents\n" + " generic modifiers:\n" + " c - do not warn if the library had to be created\n" + " f - use file name as a module name\n" + " v - be verbose\n" + " V - display version information"); +} + +/* + * Print an error message and exit + */ +void error_exit(int errcode, bool useperror, const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", progname); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + putc('\n', stderr); + if (useperror) + perror(progname); + exit(errcode); +} + +/* + * Fill in and write a header + */ +void put_header(struct rdlm_hdr *hdr, FILE * libfp, char *modname) +{ + int n = 0; + + hdr->hdrsize = sizeof(*hdr); + if (modname) + hdr->hdrsize += (n = strlen(modname) + 1); + if (libfp == NULL) + return; + if (fwrite(hdr, 1, sizeof(*hdr), libfp) != sizeof(*hdr) || + (modname && (fwrite(modname, 1, n, libfp) != n))) + error_exit(3, true, "could not write header"); +} + +/* + * Copy n bytes from one file to another and return last character read. + */ +char copybytes(FILE * fp, FILE * fp2, int n) +{ + int i, t = 0; + + for (i = 0; i < n; i++) { + t = fgetc(fp); + if (t == EOF) + error_exit(1, false, "premature end of file in '%s'", + _argv[2]); + if (fp2) + if (fputc(t, fp2) == EOF) + error_exit(1, false, "write error"); + } + return (char)t; +} + +/* + * Copy uint32_t from one file to another. + * Return local presentation of int32_t. + */ +int32_t copyint32_t(FILE * fp, FILE * fp2) +{ + int32_t l; + int i, t; + uint8_t *p = (uint8_t *)&l; + + for (i = 0; i < 4; i++) { + t = fgetc(fp); + if (t == EOF) + error_exit(1, false, "premature end of file in '%s'", + _argv[2]); + if (fp2) + if (fputc(t, fp2) == EOF) + error_exit(1, false, "write error"); + *p++ = t; + } + int32_ttolocal(&l); + return l; +} + +/* + * Create a new library + */ +int create_library(char *libname) +{ + FILE *libfp; + struct rdlm_hdr hdr; + + hdr.magic = RDLAMAG; + hdr.hdrsize = 0; + hdr.date = time(NULL); + hdr.owner = getuid(); + hdr.group = getgid(); + hdr.mode = umask(022); + hdr.size = 0; + + libfp = fopen(libname, "wb"); + if (!libfp) + error_exit(1, true, "could not open '%s'\n", libname); + + /* Write library header */ + put_header(&hdr, libfp, NULL); + + fclose(libfp); + return true; +} + +/* + * Add a module to the library + */ +int add_module(FILE * libfp, const char *fname, char *modname) +{ + FILE *modfp; + struct rdlm_hdr hdr = { RDLMMAG, 0, 0, 0, 0, 0, 0 }; + struct stat finfo; + int i; + + if (options.verbose) + fprintf(stderr, "adding module %s\n", modname); + + /* Initialize some fields in the module header */ + if (stat(fname, &finfo) < 0) + error_exit(1, true, "could not stat '%s'", fname); + hdr.date = finfo.st_mtime; + hdr.owner = finfo.st_uid; + hdr.group = finfo.st_gid; + hdr.size = finfo.st_size; + + modfp = fopen(fname, "rb"); + if (!modfp) + error_exit(1, true, "could not open '%s'", fname); + + /* Write module header */ + put_header(&hdr, libfp, modname); + + /* Put the module itself */ + while (!feof(modfp)) { + i = fgetc(modfp); + if (i == EOF) + break; + if (fputc(i, libfp) == EOF) + error_exit(1, false, "write error"); + } + + fclose(modfp); + return true; +} + +/* + * Main + */ +int main(int argc, char **argv) +{ + FILE *libfp, *tmpfp, *modfp = NULL; + struct stat finfo; + struct rdlm_hdr hdr; + char buf[MAXMODNAMELEN], *p = NULL; + char c; + int i; + + progname = argv[0]; + _argv = argv; + + if (argc < 2) { + usage(); + exit(1); + } + + /* Check whether some modifiers were specified */ + for (i = 1; i < strlen(argv[1]); i++) { + switch (c = argv[1][i]) { + case 'c': + options.createok = true; + break; + case 'f': + options.usefname = true; + break; + case 'l': + options.align = true; + break; + case 'o': + options.odate = true; + break; + case 'u': + options.fresh = true; + break; + case 'v': + options.verbose++; + break; + case 'V': + show_version(); + exit(0); + default: + if (strchr(commands, c) == NULL) + error_exit(2, false, "invalid command or modifier '%c'", + c); + } + } + + if (argc < 3) + error_exit(2, false, "missing library name"); + + /* Process the command */ + if (argv[1][0] == '-') + argv[1]++; + switch (c = argv[1][0]) { + case 'a': /* add a module */ + if (argc < 4 || (!options.usefname && argc != 5)) + error_exit(2, false, "invalid number of arguments"); + + /* Check if a library already exists. If not - create it */ + if (access(argv[2], F_OK) < 0) { + if (!options.createok) + fprintf(stderr, "creating library %s\n", argv[2]); + create_library(argv[2]); + } + + libfp = fopen(argv[2], "ab"); + if (!libfp) + error_exit(1, true, "could not open '%s'", argv[2]); + + if (!options.usefname) + add_module(libfp, argv[4], argv[3]); + else + for (i = 3; i < argc; i++) + add_module(libfp, argv[i], argv[i]); + + fclose(libfp); + break; + + case 'n': /* create library */ + create_library(argv[2]); + break; + + case 'x': /* extract module(s) */ + if (!options.usefname) + argc--; + if (argc < 4) + error_exit(2, false, "required parameter missing"); + p = options.usefname ? argv[3] : argv[4]; + case 't': /* list library contents */ + libfp = fopen(argv[2], "rb"); + if (!libfp) + error_exit(1, true, "could not open '%s'\n", argv[2]); + + /* Read library header */ + if (fread(&hdr, 1, sizeof(hdr), libfp) != sizeof(hdr) || + hdr.magic != RDLAMAG) + error_exit(1, false, "invalid library format"); + + /* Walk through the library looking for requested module */ + while (!feof(libfp)) { + /* Read module header */ + i = fread(&hdr, 1, sizeof(hdr), libfp); + if (feof(libfp)) + break; + if (i != sizeof(hdr) || hdr.magic != RDLMMAG) + error_exit(1, false, "invalid module header"); + /* Read module name */ + i = hdr.hdrsize - sizeof(hdr); + if (i > sizeof(buf) || fread(buf, 1, i, libfp) != i) + error_exit(1, false, "invalid module name"); + if (c == 'x') { + /* Check against desired name */ + if (!strcmp(buf, argv[3])) { + if (options.verbose) + fprintf(stderr, + "extracting module %s to file %s\n", buf, + p); + modfp = fopen(p, "wb"); + if (!modfp) + error_exit(1, true, "could not open '%s'", p); + } + } else { + printf("%-40s ", buf); + if (options.verbose) { + printf("%ld bytes", hdr.size); + } + putchar('\n'); + } + + copybytes(libfp, modfp, hdr.size); + if (modfp) + break; + } + + fclose(libfp); + if (modfp) + fclose(modfp); + else if (c == 'x') + error_exit(1, false, "module '%s' not found in '%s'", + argv[3], argv[2]); + break; + + case 'r': /* replace module(s) */ + argc--; + if (stat(argv[4], &finfo) < 0) + error_exit(1, true, "could not stat '%s'", argv[4]); + case 'd': /* delete module(s) */ + if (argc < 4) + error_exit(2, false, "required parameter missing"); + + libfp = fopen(argv[2], "rb"); + if (!libfp) + error_exit(1, true, "could not open '%s'", argv[2]); + + /* Copy the library into a temporary file */ + tmpfp = tmpfile(); + if (!tmpfp) + error_exit(1, true, "could not open temporary file"); + + stat(argv[2], &finfo); + copybytes(libfp, tmpfp, finfo.st_size); + rewind(tmpfp); + freopen(argv[2], "wb", libfp); + + /* Read library header and write it to a new file */ + if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) || + hdr.magic != RDLAMAG) + error_exit(1, false, "invalid library format"); + put_header(&hdr, libfp, NULL); + + /* Walk through the library looking for requested module */ + while (!feof(tmpfp)) { + /* Read module header */ + if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) || + hdr.magic != RDLMMAG) + error_exit(1, false, "invalid module header"); + /* Read module name */ + i = hdr.hdrsize - sizeof(hdr); + if (i > sizeof(buf) || fread(buf, 1, i, tmpfp) != i) + error_exit(1, false, "invalid module name"); + /* Check against desired name */ + if (!strcmp(buf, argv[3]) && + (c == 'd' || !options.odate + || finfo.st_mtime <= hdr.date)) { + if (options.verbose) + fprintf(stderr, "deleting module %s\n", buf); + fseek(tmpfp, hdr.size, SEEK_CUR); + break; + } else { + put_header(&hdr, libfp, buf); + copybytes(tmpfp, libfp, hdr.size); + } + } + + if (c == 'r') { + /* Copy new module into library */ + p = options.usefname ? argv[4] : argv[3]; + add_module(libfp, argv[4], p); + } + + /* Copy rest of library if any */ + while (!feof(tmpfp)) { + if ((i = fgetc(tmpfp)) == EOF) + break; + + if (fputc(i, libfp) == EOF) + error_exit(1, false, "write error"); + } + + fclose(libfp); + fclose(tmpfp); + break; + + default: + error_exit(2, false, "invalid command '%c'\n", c); + } + + return 0; +} diff --git a/rdoff/rdlar.h b/rdoff/rdlar.h new file mode 100644 index 0000000..ee00f2e --- /dev/null +++ b/rdoff/rdlar.h @@ -0,0 +1,38 @@ +/* + * rdlar.h - definitions of new RDOFF library/archive format. + */ + +#ifndef RDOFF_RDLAR_H +#define RDOFF_RDLAR_H 1 + +#include <inttypes.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* For non-POSIX operating systems */ +#ifndef HAVE_GETUID +# define getuid() 0 +#endif +#ifndef HAVE_GETGID +# define getgid() 0 +#endif + +#define RDLAMAG 0x414C4452 /* Archive magic */ +#define RDLMMAG 0x4D4C4452 /* Member magic */ + +#define MAXMODNAMELEN 256 /* Maximum length of module name */ + +struct rdlm_hdr { + uint32_t magic; /* Must be RDLAMAG */ + uint32_t hdrsize; /* Header size + sizeof(module_name) */ + uint32_t date; /* Creation date */ + uint32_t owner; /* UID */ + uint32_t group; /* GID */ + uint32_t mode; /* File mode */ + uint32_t size; /* File size */ + /* NULL-terminated module name immediately follows */ +}; + +#endif diff --git a/rdoff/rdlib.c b/rdoff/rdlib.c new file mode 100644 index 0000000..31dbdb4 --- /dev/null +++ b/rdoff/rdlib.c @@ -0,0 +1,296 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * rdlib.c - routines for manipulating RDOFF libraries (.rdl) + */ + +#include "compiler.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define RDOFF_UTILS + +#include "rdoff.h" +#include "rdlib.h" +#include "rdlar.h" + +/* See Texinfo documentation about new RDOFF libraries format */ + +int rdl_error = 0; + +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; + int32_t 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; + + if (buf[0] == '.') { + /* + * A special module, eg a signature block or a directory. + * Format of such a module is defined to be: + * six char type identifier + * int32_t count bytes content + * content + * so we can handle it uniformaly with RDOFF2 modules. + */ + fread(buf, 6, 1, fp); + buf[6] = 0; + /* Currently, nothing useful to do with signature block.. */ + } else { + fread(buf, 6, 1, fp); + buf[6] = 0; + 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[512]; + int i, t; + void *hdr; + rdfheaderrec *r; + int32_t l; + + 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)) { + /* + * 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[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 = 16 * rdf_errno; + return 0; + } + /* + * read in the header, and scan for exported symbols + */ + 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->eof_offset; + rdfclose(f); + fseek(lib->fp, i, SEEK_SET); + } + + /* + * close the file if nobody else is using it + */ + lib->referenced--; + if (!lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return 0; +} + +int rdl_openmodule(struct librarynode *lib, int moduleno, rdffile * f) +{ + char buf[512]; + int i, cmod, t; + int32_t 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) +{ + 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 new file mode 100644 index 0000000..e1b3c5a --- /dev/null +++ b/rdoff/rdlib.h @@ -0,0 +1,62 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * rdlib.h Functions for manipulating libraries of RDOFF object files. + */ + +#ifndef RDOFF_RDLIB_H +#define RDOFF_RDLIB_H 1 + +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; + +#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); + +#endif diff --git a/rdoff/rdoff.c b/rdoff/rdoff.c new file mode 100644 index 0000000..3c7b336 --- /dev/null +++ b/rdoff/rdoff.c @@ -0,0 +1,611 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * rdoff.c library of routines for manipulating rdoff files + */ + +/* TODO: The functions in this module assume they are running + * on a little-endian machine. This should be fixed to + * make it portable. + */ + +#include "compiler.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <inttypes.h> + +#define RDOFF_UTILS + +#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) + +/* + * 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 int32_t it is). + * ======================================================================== */ + +memorybuffer *newmembuf() +{ + memorybuffer *t; + + t = malloc(sizeof(memorybuffer)); + if (!t) + return NULL; + + t->length = 0; + t->next = NULL; + return t; +} + +void membufwrite(memorybuffer * const b, void *data, int bytes) +{ + uint16_t w; + int32_t l; + char *c; + + 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); + return; + } + + switch (bytes) { + case -4: /* convert to little-endian */ + l = *(int32_t *)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 = *(uint16_t *) data; + b->buffer[b->length++] = w & 0xFF; + w >>= 8; + b->buffer[b->length++] = w & 0xFF; + break; + + default: + c = data; + while (bytes--) + b->buffer[b->length++] = *c++; + 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 + ========================================================================= */ + +/* + * translateint32_t() and translateint16_t() + * + * translate from little endian to local representation + */ +int32_t translateint32_t(int32_t in) +{ + int32_t r; + uint8_t *i; + + i = (uint8_t *)∈ + r = i[3]; + r = (r << 8) + i[2]; + r = (r << 8) + i[1]; + r = (r << 8) + *i; + + return r; +} + +uint16_t translateint16_t(uint16_t in) +{ + uint16_t r; + uint8_t *i; + + i = (uint8_t *)∈ + r = (i[1] << 8) + i[0]; + + return r; +} + +/* Segment types */ +static char *knownsegtypes[8] = { + "NULL", "text", "data", "object comment", + "linked comment", "loader comment", + "symbolic debug", "line number debug" +}; + +/* Get a textual string describing the segment type */ +char *translatesegmenttype(uint16_t type) +{ + if (type < 8) + return knownsegtypes[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"; +} + +/* This signature is written to the start of RDOFF files */ +const char *RDOFFId = RDOFF2_SIGNATURE; + +/* Error messages. Must correspond to the codes defined in rdoff.h */ +const char *rdf_errors[11] = { + /* 0 */ "no error occurred", + /* 1 */ "could not open file", + /* 2 */ "invalid file format", + /* 3 */ "error reading file", + /* 4 */ "unknown error", + /* 5 */ "header not read", + /* 6 */ "out of memory", + /* 7 */ "RDOFF v1 not supported", + /* 8 */ "unknown extended header record", + /* 9 */ "header record of known type but unknown length", + /* 10 */ "no such segment" +}; + +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 = RDF_ERR_OPEN; + + return rdfopenhere(f, fp, NULL, name); +} + +int rdfopenhere(rdffile * f, FILE * fp, int *refcount, const char *name) +{ + char buf[8]; + int32_t initpos; + int32_t l; + uint16_t s; + + if (translateint32_t(0x01020304) != 0x01020304) { + /* fix this to be portable! */ + fputs("*** this program requires a little endian machine\n", + stderr); + fprintf(stderr, "01020304h = %08"PRIx32"h\n", translateint32_t(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); + if (!strcmp(buf, "RDOFF1")) + return rdf_errno = RDF_ERR_VER; + return rdf_errno = RDF_ERR_FORMAT; + } + + if (fread(&l, 1, 4, f->fp) != 4 + || fread(&f->header_len, 1, 4, f->fp) != 4) { + fclose(f->fp); + return rdf_errno = RDF_ERR_READ; + } + + f->header_ofs = ftell(f->fp); + f->eof_offset = f->header_ofs + translateint32_t(l) - 4; + + if (fseek(f->fp, f->header_len, SEEK_CUR)) { + fclose(f->fp); + return rdf_errno = RDF_ERR_FORMAT; /* seek past end of file...? */ + } + + if (fread(&s, 1, 2, f->fp) != 2) { + fclose(f->fp); + return rdf_errno = RDF_ERR_READ; + } + + f->nsegs = 0; + + 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 = RDF_ERR_READ; + } + + 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 = RDF_ERR_FORMAT; + } + f->nsegs++; + + if (fread(&s, 1, 2, f->fp) != 2) { + fclose(f->fp); + return rdf_errno = RDF_ERR_READ; + } + } + + if (f->eof_offset != ftell(f->fp) + 8) { /* +8 = skip null segment header */ + fprintf(stderr, "warning: eof_offset [%"PRId32"] 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; + + f->name = newstr(name); + f->refcount = refcount; + if (refcount) + (*refcount)++; + return RDF_OK; +} + +int rdfclose(rdffile * f) +{ + if (!f->refcount || !--(*f->refcount)) { + fclose(f->fp); + f->fp = NULL; + } + free(f->name); + + return 0; +} + +/* + * Print the message for last error (from rdf_errno) + */ +void rdfperror(const char *app, const char *name) +{ + fprintf(stderr, "%s:%s: %s\n", app, name, rdf_errors[rdf_errno]); + if (rdf_errno == RDF_ERR_OPEN || rdf_errno == RDF_ERR_READ) { + perror(app); + } +} + +/* + * Find the segment by its number. + * Returns segment array index, or -1 if segment with such number was not found. + */ +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; +} + +/* + * Load the segment. Returns status. + */ +int rdfloadseg(rdffile * f, int segment, void *buffer) +{ + int32_t fpos; + size_t slen; + + switch (segment) { + case RDOFF_HEADER: + fpos = f->header_ofs; + slen = f->header_len; + f->header_loc = (uint8_t *) buffer; + f->header_fp = 0; + break; + default: + if (segment < f->nsegs) { + fpos = f->seg[segment].offset; + slen = f->seg[segment].length; + f->seg[segment].data = (uint8_t *) buffer; + } else { + return rdf_errno = RDF_ERR_SEGMENT; + } + } + + if (fseek(f->fp, fpos, SEEK_SET)) + return rdf_errno = RDF_ERR_UNKNOWN; + + if (fread(buffer, 1, slen, f->fp) != slen) + return rdf_errno = RDF_ERR_READ; + + return RDF_OK; +} + +/* 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; } + +/* + * Read a header record. + * Returns the address of record, or NULL in case of error. + */ +rdfheaderrec *rdfgetheaderrec(rdffile * f) +{ + static rdfheaderrec r; + int i; + + if (!f->header_loc) { + rdf_errno = RDF_ERR_HEADER; + return NULL; + } + + if (f->header_fp >= f->header_len) + return 0; + + RI8(r.type); + RI8(r.g.reclen); + + switch (r.type) { + case RDFREC_RELOC: /* Relocation record */ + case RDFREC_SEGRELOC: + if (r.r.reclen != 8) { + rdf_errno = RDF_ERR_RECLEN; + return NULL; + } + RI8(r.r.segment); + RI32(r.r.offset); + RI8(r.r.length); + RI16(r.r.refseg); + break; + + case RDFREC_IMPORT: /* Imported symbol record */ + case RDFREC_FARIMPORT: + RI8(r.i.flags); + RI16(r.i.segment); + RS(r.i.label, EXIM_LABEL_MAX); + break; + + case RDFREC_GLOBAL: /* Exported symbol record */ + RI8(r.e.flags); + RI8(r.e.segment); + RI32(r.e.offset); + RS(r.e.label, EXIM_LABEL_MAX); + break; + + case RDFREC_DLL: /* DLL record */ + RS(r.d.libname, MODLIB_NAME_MAX); + break; + + case RDFREC_BSS: /* BSS reservation record */ + if (r.r.reclen != 4) { + rdf_errno = RDF_ERR_RECLEN; + return NULL; + } + RI32(r.b.amount); + break; + + case RDFREC_MODNAME: /* Module name record */ + RS(r.m.modname, MODLIB_NAME_MAX); + break; + + case RDFREC_COMMON: /* Common variable */ + RI16(r.c.segment); + RI32(r.c.size); + RI16(r.c.align); + RS(r.c.label, EXIM_LABEL_MAX); + break; + + default: +#ifdef STRICT_ERRORS + rdf_errno = RDF_ERR_RECTYPE; /* unknown header record */ + return NULL; +#else + for (i = 0; i < r.g.reclen; i++) + RI8(r.g.data[i]); +#endif + } + return &r; +} + +/* + * Rewind to the beginning of the file + */ +void rdfheaderrewind(rdffile * f) +{ + f->header_fp = 0; +} + +rdf_headerbuf *rdfnewheader(void) +{ + rdf_headerbuf *hb = malloc(sizeof(rdf_headerbuf)); + 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 RDFREC_GENERIC: /* generic */ + membufwrite(h->buf, &r->g.data, r->g.reclen); + break; + case RDFREC_RELOC: + case RDFREC_SEGRELOC: + 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 RDFREC_IMPORT: /* import */ + case RDFREC_FARIMPORT: + membufwrite(h->buf, &r->i.flags, 1); + membufwrite(h->buf, &r->i.segment, -2); + membufwrite(h->buf, &r->i.label, strlen(r->i.label) + 1); + break; + + case RDFREC_GLOBAL: /* export */ + membufwrite(h->buf, &r->e.flags, 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 RDFREC_DLL: /* DLL */ + membufwrite(h->buf, &r->d.libname, strlen(r->d.libname) + 1); + break; + + case RDFREC_BSS: /* BSS */ + membufwrite(h->buf, &r->b.amount, -4); + break; + + case RDFREC_MODNAME: /* Module name */ + membufwrite(h->buf, &r->m.modname, strlen(r->m.modname) + 1); + break; + + default: +#ifdef STRICT_ERRORS + return rdf_errno = RDF_ERR_RECTYPE; +#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, int32_t seglength) +{ + h->nsegments++; + h->seglength += seglength; + return 0; +} + +int rdfwriteheader(FILE * fp, rdf_headerbuf * h) +{ + int32_t l, l2; + + fwrite(RDOFFId, 1, strlen(RDOFFId), fp); + + l = membuflength(h->buf); + l2 = l + 14 + 10 * h->nsegments + h->seglength; + l = translateint32_t(l); + l2 = translateint32_t(l2); + fwrite(&l2, 4, 1, fp); /* object length */ + fwrite(&l, 4, 1, fp); /* header length */ + + membufdump(h->buf, fp); + + return 0; /* no error handling in here... CHANGE THIS! */ +} + +void rdfdoneheader(rdf_headerbuf * h) +{ + freemembuf(h->buf); + free(h); +} diff --git a/rdoff/rdoff.h b/rdoff/rdoff.h new file mode 100644 index 0000000..a161733 --- /dev/null +++ b/rdoff/rdoff.h @@ -0,0 +1,293 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * rdoff.h RDOFF Object File manipulation routines header file + */ + +#ifndef RDOFF_RDOFF_H +#define RDOFF_RDOFF_H 1 + +#include <inttypes.h> + +/* + * RDOFF definitions. They are used by RDOFF utilities and by NASM's + * 'outrdf2.c' output module. + */ + +/* RDOFF format revision (currently used only when printing the version) */ +#define RDOFF2_REVISION "0.6.1" + +/* RDOFF2 file signature */ +#define RDOFF2_SIGNATURE "RDOFF2" + +/* Maximum size of an import/export label (including trailing zero) */ +#define EXIM_LABEL_MAX 64 + +/* Maximum size of library or module name (including trailing zero) */ +#define MODLIB_NAME_MAX 128 + +/* Maximum number of segments that we can handle in one file */ +#define RDF_MAXSEGS 64 + +/* Record types that may present the RDOFF header */ +#define RDFREC_GENERIC 0 +#define RDFREC_RELOC 1 +#define RDFREC_IMPORT 2 +#define RDFREC_GLOBAL 3 +#define RDFREC_DLL 4 +#define RDFREC_BSS 5 +#define RDFREC_SEGRELOC 6 +#define RDFREC_FARIMPORT 7 +#define RDFREC_MODNAME 8 +#define RDFREC_COMMON 10 + +/* + * Generic record - contains the type and length field, plus a 128 byte + * array 'data' + */ +struct GenericRec { + uint8_t type; + uint8_t reclen; + char data[128]; +}; + +/* + * Relocation record + */ +struct RelocRec { + uint8_t type; /* must be 1 */ + uint8_t reclen; /* content length */ + uint8_t segment; /* only 0 for code, or 1 for data supported, + but add 64 for relative refs (ie do not require + reloc @ loadtime, only linkage) */ + int32_t offset; /* from start of segment in which reference is loc'd */ + uint8_t length; /* 1 2 or 4 bytes */ + uint16_t refseg; /* segment to which reference refers to */ +}; + +/* + * Extern/import record + */ +struct ImportRec { + uint8_t type; /* must be 2 */ + uint8_t reclen; /* content length */ + uint8_t flags; /* SYM_* flags (see below) */ + uint16_t 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[EXIM_LABEL_MAX]; /* zero terminated, should be written to file + until the zero, but not after it */ +}; + +/* + * Public/export record + */ +struct ExportRec { + uint8_t type; /* must be 3 */ + uint8_t reclen; /* content length */ + uint8_t flags; /* SYM_* flags (see below) */ + uint8_t segment; /* segment referred to (0/1/2) */ + int32_t offset; /* offset within segment */ + char label[EXIM_LABEL_MAX]; /* zero terminated as in import */ +}; + +/* + * DLL record + */ +struct DLLRec { + uint8_t type; /* must be 4 */ + uint8_t reclen; /* content length */ + char libname[MODLIB_NAME_MAX]; /* name of library to link with at load time */ +}; + +/* + * BSS record + */ +struct BSSRec { + uint8_t type; /* must be 5 */ + uint8_t reclen; /* content length */ + int32_t amount; /* number of bytes BSS to reserve */ +}; + +/* + * Module name record + */ +struct ModRec { + uint8_t type; /* must be 8 */ + uint8_t reclen; /* content length */ + char modname[MODLIB_NAME_MAX]; /* module name */ +}; + +/* + * Common variable record + */ +struct CommonRec { + uint8_t type; /* must be 10 */ + uint8_t reclen; /* equals 7+label length */ + uint16_t segment; /* segment number */ + int32_t size; /* size of common variable */ + uint16_t align; /* alignment (power of two) */ + char label[EXIM_LABEL_MAX]; /* zero terminated as in import */ +}; + +/* Flags for ExportRec */ +#define SYM_DATA 1 +#define SYM_FUNCTION 2 +#define SYM_GLOBAL 4 +#define SYM_IMPORT 8 + +/*** The following part is used only by the utilities *************************/ + +#ifdef RDOFF_UTILS + +/* Some systems don't define this automatically */ +#if !defined(strdup) +extern char *strdup(const char *); +#endif + +typedef union RDFHeaderRec { + char type; /* invariant throughout all below */ + struct GenericRec g; /* type 0 */ + 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 */ + struct ModRec m; /* type == 8 */ + struct CommonRec c; /* type == 10 */ +} rdfheaderrec; + +struct SegmentHeaderRec { + /* information from file */ + uint16_t type; + uint16_t number; + uint16_t reserved; + int32_t length; + + /* information built up here */ + int32_t offset; + uint8_t *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 */ + int32_t header_len; + int32_t header_ofs; + + uint8_t *header_loc; /* keep location of header */ + int32_t header_fp; /* current location within header for reading */ + + struct SegmentHeaderRec seg[RDF_MAXSEGS]; + int nsegs; + + int32_t eof_offset; /* offset of the first uint8_t beyond the end of this + module */ + + 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; + uint8_t buffer[BUF_BLOCK_LEN]; + struct memorybuffer *next; +} memorybuffer; + +typedef struct { + memorybuffer *buf; /* buffer containing header records */ + int nsegments; /* number of segments to be written */ + int32_t seglength; /* total length of all the segments */ +} 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; + +/* rdf_errno can hold these error codes */ +enum { + /* 0 */ RDF_OK, + /* 1 */ RDF_ERR_OPEN, + /* 2 */ RDF_ERR_FORMAT, + /* 3 */ RDF_ERR_READ, + /* 4 */ RDF_ERR_UNKNOWN, + /* 5 */ RDF_ERR_HEADER, + /* 6 */ RDF_ERR_NOMEM, + /* 7 */ RDF_ERR_VER, + /* 8 */ RDF_ERR_RECTYPE, + /* 9 */ RDF_ERR_RECLEN, + /* 10 */ RDF_ERR_SEGMENT +}; + +/* utility functions */ +int32_t translateint32_t(int32_t in); +uint16_t translateint16_t(uint16_t in); +char *translatesegmenttype(uint16_t type); + +/* RDOFF file manipulation functions */ +int rdfopen(rdffile * f, const 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 */ +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, + rdfaddsegment to notify the header routines that a segment exists, and + to tell it how int32_t 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, int32_t seglength); +int rdfwriteheader(FILE * fp, rdf_headerbuf * h); +void rdfdoneheader(rdf_headerbuf * h); + +#endif /* RDOFF_UTILS */ + +#endif /* RDOFF_RDOFF_H */ diff --git a/rdoff/rdx.1 b/rdoff/rdx.1 new file mode 100644 index 0000000..a864056 --- /dev/null +++ b/rdoff/rdx.1 @@ -0,0 +1,21 @@ +.TH RDX 1 "September 6, 1999" "Debian Project" "Debian Manual" +.SH NAME +rdx \- load and execute an RDOFF object +.SH SYNOPSIS +.B rdx +.I object +.SH DESCRIPTION +.B rdx +loads an RDOFF +.IR object , +and then calls +.RB ` _main ', +which it expects to be a C-style function, accepting two parameters, +.I argc +and +.I argv +in normal C style. +.SH AUTHORS +Julian Hall <jules@earthcorp.com>. +.PP +This manual page was written by Matej Vela <vela@debian.org>. diff --git a/rdoff/rdx.c b/rdoff/rdx.c new file mode 100644 index 0000000..240ab59 --- /dev/null +++ b/rdoff/rdx.c @@ -0,0 +1,88 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * rdx.c RDOFF Object File loader program + */ + +/* 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 "compiler.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "rdfload.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: rdx <rdoff-executable> [params]\n"); + exit(255); + } + + m = rdfload(argv[1]); + + if (!m) { + rdfperror("rdx", 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)(size_t) s->offset; + + argv++, argc--; /* remove 'rdx' from command line */ + + return code(argc, argv); /* execute */ +} diff --git a/rdoff/segtab.c b/rdoff/segtab.c new file mode 100644 index 0000000..4a4c5b8 --- /dev/null +++ b/rdoff/segtab.c @@ -0,0 +1,175 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +#include "compiler.h" + +#include <stdio.h> +#include <stdlib.h> +#include "segtab.h" + +struct segtabnode { + int localseg; + int destseg; + int32_t 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, int32_t 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, int32_t offset) +{ + descend_tree_add((struct segtabnode **)root, localseg, destseg, + offset); +} + +int get_seglocation(segtab * root, int localseg, int *destseg, + int32_t *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..87ef017 --- /dev/null +++ b/rdoff/segtab.h @@ -0,0 +1,46 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +#ifndef RDOFF_SEGTAB_H +#define RDOFF_SEGTAB_H 1 + +#include <inttypes.h> + +typedef void *segtab; + +void init_seglocations(segtab * r); +void add_seglocation(segtab * r, int localseg, int destseg, int32_t offset); +int get_seglocation(segtab * r, int localseg, int *destseg, int32_t *offset); +void done_seglocations(segtab * r); + +#endif diff --git a/rdoff/symtab.c b/rdoff/symtab.c new file mode 100644 index 0000000..1dfee1a --- /dev/null +++ b/rdoff/symtab.c @@ -0,0 +1,159 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * symtab.c Routines to maintain and manipulate a symbol table + * + * These routines donated to the NASM effort by Graeme Defty. + */ + +#include "compiler.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "symtab.h" +#include "hash.h" + +#define SYMTABSIZE 64 +#define slotnum(x) (hash((x)) % SYMTABSIZE) + +/* ------------------------------------- */ +/* Private data types */ + +typedef struct tagSymtabNode { + struct tagSymtabNode *next; + symtabEnt ent; +} symtabNode; + +typedef symtabNode *(symtabTab[SYMTABSIZE]); + +typedef symtabTab *symtab; + +/* ------------------------------------- */ +void *symtabNew(void) +{ + symtab mytab; + + mytab = (symtabTab *) calloc(SYMTABSIZE, sizeof(symtabNode *)); + if (mytab == NULL) { + fprintf(stderr, "symtab: out of memory\n"); + exit(3); + } + + return mytab; +} + +/* ------------------------------------- */ +void symtabDone(void *stab) +{ + 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 *stab, symtabEnt * ent) +{ + symtab mytab = (symtab) stab; + symtabNode *node; + int slot; + + node = malloc(sizeof(symtabNode)); + if (node == NULL) { + fprintf(stderr, "symtab: out of memory\n"); + exit(3); + } + + slot = slotnum(ent->name); + + node->ent = *ent; + node->next = (*mytab)[slot]; + (*mytab)[slot] = node; +} + +/* ------------------------------------- */ +symtabEnt *symtabFind(void *stab, const char *name) +{ + 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 *stab, FILE * of) +{ + symtab mytab = (symtab) stab; + int i; + char *SegNames[3] = { "code", "data", "bss" }; + + 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) { + if ((l->ent.segment) == -1) { + fprintf(of, "%-32s Unresolved reference\n", l->ent.name); + } else { + fprintf(of, "%-32s %s:%08"PRIx32" (%"PRId32")\n", l->ent.name, + SegNames[l->ent.segment], + 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 new file mode 100644 index 0000000..0dc8c7b --- /dev/null +++ b/rdoff/symtab.h @@ -0,0 +1,56 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ----------------------------------------------------------------------- */ + +/* + * symtab.h Header file for symbol table manipulation routines + */ + +#ifndef RDOFF_SYMTAB_H +#define RDOFF_SYMTAB_H 1 + +#include <inttypes.h> + +typedef struct { + char *name; + int segment; + int32_t offset; + int32_t flags; +} symtabEnt; + +void *symtabNew(void); +void symtabDone(void *symtab); +void symtabInsert(void *symtab, symtabEnt * ent); +symtabEnt *symtabFind(void *symtab, const char *name); +void symtabDump(void *symtab, FILE * of); + +#endif diff --git a/rdoff/test/Makefile b/rdoff/test/Makefile new file mode 100644 index 0000000..658a6d4 --- /dev/null +++ b/rdoff/test/Makefile @@ -0,0 +1,10 @@ +RDT = $(patsubst %.asm,%.rdf,$(wildcard *.asm)) +NASM = ../../nasm + +all: $(RDT) + +%.rdf: %.asm + $(NASM) -f rdf -o $@ -l $*.lst $< + +clean: + rm -f *.rdf *.rdx *.lst diff --git a/rdoff/test/makelib.sh b/rdoff/test/makelib.sh new file mode 100644 index 0000000..520bb19 --- /dev/null +++ b/rdoff/test/makelib.sh @@ -0,0 +1,14 @@ +#! /bin/sh + +[ $1 ] || { + echo "Usage: $0 <library name> <module> [...]" + exit 1 +} + +libname=$1; shift + +rdflib c $libname + +for f in $*; do + rdflib a $libname $f $f +done 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/test/rdftest1.asm b/rdoff/test/rdftest1.asm new file mode 100644 index 0000000..76f1e43 --- /dev/null +++ b/rdoff/test/rdftest1.asm @@ -0,0 +1,54 @@ + ;; program to test RDOFF production and linkage + + ;; items to test include: + ;; [1] relocation within the same segment in each module + ;; [2] relocation to different segments in same module + ;; [3] relocation to same segment in different module + ;; [4] relocation to different segment in different module + ;; [5] relative relocation to same module + ;; [6] relative relocation to different module + ;; [7] correct generation of BSS addresses + +[SECTION .text] +[BITS 32] + +_main: + mov ax,localdata ; [2] (16 bit) => 66 b8 0000 + mov eax,localdata2 ; [2] (32 bit) => b8 0000000a + +[EXTERN _fardata] + + mov eax,[_fardata] ; [4] => a1 00000000 (+20) + mov cx,next ; [1] => 66 b9 0012 +next: + call localproc ; [5] => e8 00000019 + +[EXTERN _farproc] + mov eax,_farproc ; [3] => b8 00000000 (+40+0) + call _farproc ; [6] => e8 -$ (-0+40+0) (=1f) + + mov eax,localbss ; [7] => b8 00000000 + +[GLOBAL _term] +_term: xor ax,ax ; => 66 31 c0 + int 21h ; => cd 21 + jmp _term ; => e9 -0a (=fffffff6) + +localproc: + ret ; => c3 + +[GLOBAL _test1proc] +_test1proc: + call localproc ; [5] => e8 -$ (-0+0+?) (=-6=fffffffa) + ret ; => c3 + +[SECTION .data] +[GLOBAL localdata2] +localdata: db 'localdata',0 +localdata2: db 'localdata2',0 +farref: dd _fardata ; [3] => 0 (+20) +localref: dd _main ; [2] => 0 (+0) + +[SECTION .bss] +localbss: resw 4 ; reserve 8 bytes BSS +
\ No newline at end of file diff --git a/rdoff/test/rdftest2.asm b/rdoff/test/rdftest2.asm new file mode 100644 index 0000000..25b8c18 --- /dev/null +++ b/rdoff/test/rdftest2.asm @@ -0,0 +1,33 @@ + ;; rdftest2.asm - test linkage and generation of RDOFF files + +[SECTION .text] +[BITS 32] + +[GLOBAL _farproc] +[EXTERN _test1proc] +[EXTERN localdata2] +[EXTERN _term] +_farproc: + + mov bx,localdata2 ; [4] 0 => 66 bb 000a(+0) + mov eax,_term ; [3] 5 => b8 00000000(+26+0) + call _test1proc ; [6] A => e8 fffffff2(-40+0+31)(=ffffffe3) + + mov eax,_farproc ; [1] => b8 00000000(+40) + add eax,[_fardata] ; [2] => 03 05 00000000(+20) + + mov ebx,mybssdata ; [7] => bb 00000000(+08) + call myproc ; [5] => e8 00000001 + ret + +myproc: + add eax,ebx + ret + +[SECTION .data] +[GLOBAL _fardata] +_fardata: dw _term ; [4] +_localref: dd _farproc ; [2] + +[SECTION .bss] +mybssdata: resw 1 diff --git a/rdoff/test/rdtlib.asm b/rdoff/test/rdtlib.asm new file mode 100644 index 0000000..6c2b8ec --- /dev/null +++ b/rdoff/test/rdtlib.asm @@ -0,0 +1,48 @@ + ;; library functions for rdtmain - test of rdx linking and execution + + ;; library function = _strcmp, defined as in C + +[SECTION .text] +[BITS 32] + +[GLOBAL _strcmp] +_strcmp: + push ebp + mov ebp,esp + + ;; ebp+8 = first paramater, ebp+12 = second + + mov esi,[ebp+8] + mov edi,[ebp+12] + +.loop: + mov cl,byte [esi] + mov dl,byte [edi] + cmp cl,dl + jb .below + ja .above + or cl,cl + jz .match + inc esi + inc edi + jmp .loop + +.below: + mov eax,-1 + pop ebp + ret + +.above: + mov eax,1 + pop ebp + ret + +.match: + xor eax,eax + pop ebp + ret + +[SECTION .data] +[GLOBAL _message] + +_message: db 'hello',0
\ No newline at end of file diff --git a/rdoff/test/rdtmain.asm b/rdoff/test/rdtmain.asm new file mode 100644 index 0000000..626a2e2 --- /dev/null +++ b/rdoff/test/rdtmain.asm @@ -0,0 +1,47 @@ + ;; rdtmain - main part of test program for RDX execution. + ;; returns true (0) if its parameter equals the phrase "hello" + ;; "hello" is stored in the library part, to complicate the + ;; linkage. + + ;; assemble and link with the following commands: + ;; nasm -f rdf rdtmain.asm + ;; nasm -f rdf rdtlib.asm + ;; ldrdf rdtmain.rdf rdtlib.rdf -o rdxtest.rdx + + ;; run with 'rdx rdxtest.rdx [parameters]' on a Linux (or possibly + ;; other 32 bit OS) systems (x86 architectures only!) + ;; try using '&& echo Yes' afterwards to find out when it returns 0. + +[EXTERN _strcmp] ; strcmp is an imported function +[EXTERN _message] ; imported data +[SECTION .text] +[BITS 32] + + ;; main(int argc,char **argv) +[GLOBAL _main] +_main: + push ebp + mov ebp,esp + + ;; ebp+8 = argc, ebp+12 = argv + + cmp dword [ebp+8],2 + jb error ; cause error if < 1 parameters + + mov eax, [ebp+12] ; eax = argv + + mov ebx, [eax+4] ; ebx = argv[1] + mov ecx, _message ; ecx = "hello" + + push ecx + push ebx + call _strcmp ; compare strings + add esp,8 ; caller clears stack + + pop ebp + ret ; return return value of _strcmp + +error: + mov eax,2 ; return 2 on error + pop ebp + ret diff --git a/rdoff/test/testlib.asm b/rdoff/test/testlib.asm new file mode 100644 index 0000000..6ee3d89 --- /dev/null +++ b/rdoff/test/testlib.asm @@ -0,0 +1,18 @@ +; program to test retrieval of and linkage to modules in libraries by +; ldrdf + +[SECTION .text] +[GLOBAL _main] +[EXTERN _strcmp] + +_main: + push dword string1 + push dword string2 + call _strcmp + add esp,8 ; doh! clear up stack ;-) + ret + +[SECTION .data] + +string1: db 'abc',0 ; try changing these strings and see +string2: db 'abd',0 ; what happens! |