summaryrefslogtreecommitdiff
path: root/rdoff/ldrdf.c
diff options
context:
space:
mode:
Diffstat (limited to 'rdoff/ldrdf.c')
-rw-r--r--rdoff/ldrdf.c1571
1 files changed, 980 insertions, 591 deletions
diff --git a/rdoff/ldrdf.c b/rdoff/ldrdf.c
index 9e4a215d..72f87255 100644
--- a/rdoff/ldrdf.c
+++ b/rdoff/ldrdf.c
@@ -1,4 +1,4 @@
-/* ldrdf.c RDOFF Object File linker/loader main program
+/* ldrdf.c RDOFF Object File linker/loader main program
*
* The Netwide Assembler is copyright (C) 1996 Simon Tatham and
* Julian Hall. All rights reserved. The software is
@@ -6,18 +6,23 @@
* distributed in the NASM archive.
*/
-/* TODO: Make the system skip a module (other than the first) if none
- * of the other specified modules contain a reference to it.
- * May require the system to make an extra pass of the modules to be
- * loaded eliminating those that aren't required.
+/*
+ * TODO: actually get this new version working!
+ * - finish off write_output() - appears to be done
+ * - implement library searching - appears to be done
+ * - maybe we only want to do one pass, for performance reasons?
+ * this makes things a little harder, but unix 'ld' copes...
+ * - implement command line options - appears to be done
+ * - improve symbol table implementation - done, thanks to Graeme Defty
+ * - keep a cache of symbol names in each library module so
+ * we don't have to constantly recheck the file
+ * - general performance improvements
*
- * Support all the existing documented options...
- *
- * Support libaries (.a files - requires a 'ranlib' type utility)
- * (I think I've got this working, so I've upped the version)
- *
- * -s option to strip resolved symbols from exports. (Could make this an
- * external utility)
+ * BUGS & LIMITATIONS: this program doesn't support multiple code, data
+ * or bss segments, therefore for 16 bit programs whose code, data or BSS
+ * segment exceeds 64K in size, it will not work. This program probably
+ * wont work if compiled by a 16 bit compiler. Try DJGPP if you're running
+ * under DOS. '#define STINGY_MEMORY' may help a little.
*/
#include <stdio.h>
@@ -25,704 +30,1088 @@
#include <string.h>
#include "rdoff.h"
-#include "nasmlib.h"
#include "symtab.h"
#include "collectn.h"
#include "rdlib.h"
+#include "segtab.h"
-#define LDRDF_VERSION "0.30"
+#define LDRDF_VERSION "1.00 alpha 1"
-/* global variables - those to set options: */
+#define RDF_MAXSEGS 64
+/* #define STINGY_MEMORY */
-int verbose = 0; /* reflects setting of command line switch */
-int align = 16;
-int errors = 0; /* set by functions to cause halt after current
- stage of processing */
+/* =======================================================================
+ * Types & macros that are private to this program
+ */
+
+struct segment_infonode {
+ int dest_seg; /* output segment to be placed into, -1 to
+ skip linking this segment */
+ long reloc; /* segment's relocation factor */
+};
-/* the linked list of modules that must be loaded & linked */
struct modulenode {
- rdffile f; /* the file */
- long coderel; /* module's code relocation factor */
- long datarel; /* module's data relocation factor */
- long bssrel; /* module's bss data reloc. factor */
- void * header; /* header location, if loaded */
- char * name; /* filename */
- struct modulenode *next;
+ rdffile f; /* the RDOFF file structure */
+ struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
+ with each segment? */
+ void * header;
+ char * name;
+ struct modulenode * next;
+ long bss_reloc;
};
+#include "ldsegs.h"
+
#define newstr(str) strcpy(malloc(strlen(str) + 1),str)
#define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
+/* ==========================================================================
+ * Function prototypes of private utility functions
+ */
-struct modulenode *modules = NULL,*lastmodule = NULL;
+void processmodule(const char * filename, struct modulenode * mod);
+int allocnewseg(int16 type,int16 reserved);
+int findsegment(int16 type,int16 reserved);
+void symtab_add(const char * symbol, int segment, long offset);
+int symtab_get(const char * symbol, int * segment, long * offset);
-/* the linked list of libraries to be searched for missing imported
- symbols */
+/* =========================================================================
+ * Global data structures.
+ */
-struct librarynode * libraries = NULL, * lastlib = NULL;
+/* a linked list of modules that will be included in the output */
+struct modulenode * modules = NULL;
+struct modulenode * lastmodule = NULL;
-void *symtab; /* The symbol table */
+/* a linked list of libraries to be searched for unresolved imported symbols */
+struct librarynode * libraries = NULL;
+struct librarynode * lastlib = NULL;
-rdf_headerbuf * newheader ; /* New header to be written to output */
+/* the symbol table */
+void * symtab = NULL;
-/* loadmodule - find the characteristics of a module and add it to the
- * list of those being linked together */
+/* the header of the output file, built up stage by stage */
+rdf_headerbuf * newheader = NULL;
-void loadmodule(char *filename)
+/* The current state of segment allocation, including information about
+ * which output segment numbers have been allocated, and their types and
+ * amount of data which has already been allocated inside them.
+ */
+struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
+int nsegs = 0;
+long bss_length;
+
+/* global options which affect how the program behaves */
+struct ldrdfoptions {
+ int verbose;
+ int align;
+ int warnUnresolved;
+ int strip;
+} options;
+
+int errorcount = 0; /* determines main program exit status */
+
+/* =========================================================================
+ * Utility functions
+ */
+
+
+/*
+ * initsegments()
+ *
+ * sets up segments 0, 1, and 2, the initial code data and bss segments
+ */
+
+void initsegments()
{
- struct modulenode *prev;
- if (! modules) {
- modules = malloc(sizeof(struct modulenode));
- lastmodule = modules;
- prev = NULL;
- }
- else {
- lastmodule->next = malloc(sizeof(struct modulenode));
- prev = lastmodule;
- lastmodule = lastmodule->next;
- }
-
- if (! lastmodule) {
- fputs("ldrdf: not enough memory\n",stderr);
- exit(1);
- }
-
- if (rdfopen(&lastmodule->f,filename)) {
- rdfperror("ldrdf",filename);
- exit(1);
- }
-
- lastmodule->header = NULL; /* header hasn't been loaded */
- lastmodule->name = filename;
- lastmodule->next = NULL;
-
- if (prev) {
- lastmodule->coderel = prev->coderel + prev->f.code_len;
- if (lastmodule->coderel % align != 0)
- lastmodule->coderel += align - (lastmodule->coderel % align);
- lastmodule->datarel = prev->datarel + prev->f.data_len;
- if (lastmodule->datarel % align != 0)
- lastmodule->datarel += align - (lastmodule->datarel % align);
- }
- else {
- lastmodule->coderel = 0;
- lastmodule->datarel = 0;
- }
-
- if (verbose)
- printf("%s code = %08lx (+%04lx), data = %08lx (+%04lx)\n",filename,
- lastmodule->coderel,lastmodule->f.code_len,
- lastmodule->datarel,lastmodule->f.data_len);
-
- lastmodule->header = malloc(lastmodule->f.header_len);
- if (!lastmodule->header) {
- fprintf(stderr,"ldrdf: out of memory\n");
- exit(1);
- }
-
- if (rdfloadseg(&lastmodule->f,RDOFF_HEADER,lastmodule->header))
- {
- rdfperror("ldrdf",filename);
- exit(1);
- }
+ nsegs = 3;
+ outputseg[0].type = 1;
+ outputseg[0].number = 0;
+ outputseg[0].reserved = 0;
+ outputseg[0].length = 0;
+ outputseg[1].type = 2;
+ outputseg[1].number = 1;
+ outputseg[1].reserved = 0;
+ outputseg[1].length = 0;
+ outputseg[2].type = 0xFFFF; /* reserved segment type */
+ outputseg[2].number = 2;
+ outputseg[2].reserved = 0;
+ outputseg[2].length = 0;
+ bss_length = 0;
}
-/* load_library add a library to list of libraries to search
- * for undefined symbols
+/*
+ * loadmodule
+ *
+ * Determine the characteristics of a module, and decide what to do with
+ * each segment it contains (including determining destination segments and
+ * relocation factors for segments that are kept).
*/
-void load_library(char * name)
+void loadmodule(const char * filename)
{
- if (verbose)
- printf("adding library %s to search path\n",name);
-
- if (! lastlib) {
- lastlib = libraries = malloc(sizeof(struct librarynode));
+ if (options.verbose)
+ printf("loading `%s'\n", filename);
+
+ /* allocate a new module entry on the end of the modules list */
+ if (!modules)
+ {
+ modules = malloc (sizeof(*modules));
+ lastmodule = modules;
}
else
{
- lastlib->next = malloc(sizeof(struct librarynode));
- lastlib = lastlib->next;
+ lastmodule->next = malloc (sizeof(*modules));
+ lastmodule = lastmodule->next;
}
- if (! lastlib) {
+ if ( ! lastmodule)
+ {
fprintf(stderr, "ldrdf: out of memory\n");
exit(1);
}
- strcpy (lastlib->name = malloc (1+strlen(name)), name);
- lastlib->fp = NULL;
- lastlib->referenced = 0;
- lastlib->next = NULL;
-}
+ /* open the file using 'rdfopen', which returns nonzero on error */
-/* build_symbols() step through each module's header, and locate
- * exported symbols, placing them in a global table
- */
+ if (rdfopen(&lastmodule->f, filename) != 0)
+ {
+ rdfperror("ldrdf", filename);
+ exit(1);
+ }
-long bsslength;
+ /*
+ * store information about the module, and determine what segments
+ * it contains, and what we should do with them (determine relocation
+ * factor if we decide to keep them)
+ */
-void mod_addsymbols(struct modulenode * mod)
+ lastmodule->header = NULL;
+ lastmodule->name = strdup(filename);
+ lastmodule->next = NULL;
+
+ processmodule(filename, lastmodule);
+}
+
+/*
+ * processmodule()
+ *
+ * step through each segment, determine what exactly we're doing with
+ * it, and if we intend to keep it, determine (a) which segment to
+ * put it in and (b) whereabouts in that segment it will end up.
+ * (b) is fairly easy, cos we're now keeping track of how big each segment
+ * in our output file is...
+ */
+
+void processmodule(const char * filename, struct modulenode * mod)
{
- rdfheaderrec *r;
- symtabEnt e;
- long cbBss;
-
- mod->bssrel = bsslength;
- cbBss = 0;
- rdfheaderrewind(&mod->f);
- while ((r = rdfgetheaderrec(&mod->f)))
+ struct segconfig sconf;
+ int seg, outseg;
+ void * header;
+ rdfheaderrec * hr;
+ long bssamount = 0;
+
+ for (seg = 0; seg < mod->f.nsegs; seg++)
{
+ /*
+ * get the segment configuration for this type from the segment
+ * table. getsegconfig() is a macro, defined in ldsegs.h.
+ */
+ getsegconfig(sconf, mod->f.seg[seg].type);
+
+ if (options.verbose > 1) {
+ printf ("%s %04x [%04x:%10s] ", filename, mod->f.seg[seg].number,
+ mod->f.seg[seg].type, sconf.typedesc);
+ }
+ /*
+ * sconf->dowhat tells us what to do with a segment of this type.
+ */
+ switch (sconf.dowhat) {
+ case SEG_IGNORE:
+ /*
+ * Set destination segment to -1, to indicate that this segment
+ * should be ignored for the purpose of output, ie it is left
+ * out of the linked executable.
+ */
+ mod->seginfo[seg].dest_seg = -1;
+ if (options.verbose > 1) printf("IGNORED\n");
+ break;
- if (r->type == 5) /* Allocate BSS */
- cbBss += r->b.amount;
+ case SEG_NEWSEG:
+ /*
+ * The configuration tells us to create a new segment for
+ * each occurrence of this segment type.
+ */
+ outseg = allocnewseg(sconf.mergetype,
+ mod->f.seg[seg].reserved);
+ mod->seginfo[seg].dest_seg = outseg;
+ mod->seginfo[seg].reloc = 0;
+ outputseg[outseg].length = mod->f.seg[seg].length;
+ if (options.verbose > 1)
+ printf ("=> %04x:%08lx (+%04lx)\n", outseg,
+ mod->seginfo[seg].reloc,
+ mod->f.seg[seg].length);
+ break;
- if (r->type != 3) continue; /* ignore all but export recs */
+ case SEG_MERGE:
+ /*
+ * The configuration tells us to merge the segment with
+ * a previously existing segment of type 'sconf.mergetype',
+ * if one exists. Otherwise a new segment is created.
+ * This is handled transparently by 'findsegment()'.
+ */
+ outseg = findsegment(sconf.mergetype,
+ mod->f.seg[seg].reserved);
+ mod->seginfo[seg].dest_seg = outseg;
+
+ /*
+ * We need to add alignment to these segments.
+ */
+ if (outputseg[outseg].length % options.align != 0)
+ outputseg[outseg].length +=
+ options.align - (outputseg[outseg].length % options.align);
+
+ mod->seginfo[seg].reloc = outputseg[outseg].length;
+ outputseg[outseg].length += mod->f.seg[seg].length;
- e.segment = r->e.segment;
- e.offset = r->e.offset +
- (e.segment == 0 ? mod->coderel : /* 0 -> code */
- e.segment == 1 ? mod->datarel : /* 1 -> data */
- mod->bssrel) ; /* 2 -> bss */
-
- e.flags = 0;
- e.name = malloc(strlen(r->e.label) + 1);
- if (! e.name)
- {
- fprintf(stderr,"ldrdf: out of memory\n");
- exit(1);
+ if (options.verbose > 1)
+ printf ("=> %04x:%08lx (+%04lx)\n", outseg,
+ mod->seginfo[seg].reloc,
+ mod->f.seg[seg].length);
}
- strcpy(e.name,r->e.label);
- symtabInsert(symtab,&e);
+
}
- bsslength += cbBss;
-}
-void build_symbols()
-{
- struct modulenode *mod;
-
- if (verbose) printf("building global symbol table:\n");
- newheader = rdfnewheader();
-
- symtab = symtabNew();
- bsslength = 0; /* keep track of location of BSS symbols */
-
- for (mod = modules; mod; mod = mod->next)
- {
- mod_addsymbols( mod );
- }
- if (verbose)
- {
- symtabDump(symtab,stdout);
- printf("BSS length = %ld bytes\n\n",bsslength);
- }
-}
+ /*
+ * extract symbols from the header, and dump them into the
+ * symbol table
+ */
+ header = malloc(mod->f.header_len);
+ if (!header) {
+ fprintf(stderr, "ldrdf: not enough memory\n");
+ exit(1);
+ }
+ if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
+ rdfperror("ldrdf", filename);
+ exit(1);
+ }
+ while ((hr = rdfgetheaderrec (&mod->f)))
+ {
+ switch(hr->type) {
+ case 2: /* imported symbol - define with seg = -1 */
+ case 7:
+ symtab_add(hr->i.label, -1, 0);
+ break;
-/* scan_libraries() search through headers of modules for undefined
- * symbols, and scan libraries for those symbols,
- * adding library modules found to list of modules
- * to load. */
+ case 3: /* exported symbol */
+ if (mod->seginfo[(int)hr->e.segment].dest_seg == -1)
+ continue;
+ symtab_add(hr->e.label, mod->seginfo[(int)hr->e.segment].dest_seg,
+ mod->seginfo[(int)hr->e.segment].reloc + hr->e.offset);
+ break;
-void scan_libraries(void)
-{
- struct modulenode * mod, * nm;
- struct librarynode * lib;
- rdfheaderrec * r;
- int found;
- char * tmp;
+ case 5: /* BSS reservation */
+ /*
+ * first, amalgamate all BSS reservations in this module
+ * into one, because we allow this in the output format.
+ */
+ bssamount += hr->b.amount;
+ break;
+ }
+ }
- if (verbose) printf("Scanning libraries for unresolved symbols...\n");
+ if (bssamount != 0)
+ {
+ /*
+ * handle the BSS segment - first pad the existing bss length
+ * to the correct alignment, then store the length in bss_reloc
+ * for this module. Then add this module's BSS length onto
+ * bss_length.
+ */
+ if (bss_length % options.align != 0)
+ bss_length += options.align - (bss_length % options.align);
+
+ mod->bss_reloc = bss_length;
+ if (options.verbose > 1) {
+ printf ("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n",
+ filename, bss_length, bssamount);
+ }
+ bss_length += bssamount;
+ }
- mod = modules;
+#ifdef STINGY_MEMORY
+ /*
+ * we free the header buffer here, to save memory later.
+ * this isn't efficient, but probably halves the memory usage
+ * of this program...
+ */
+ mod->f.header_loc = NULL;
+ free(header);
- while (mod)
- {
- rdfheaderrewind(&mod->f);
+#endif
- while ((r = rdfgetheaderrec(&mod->f)))
- {
- if (r->type != 2) continue; /* not an import record */
- if ( symtabFind (symtab,r->i.label) )
- continue; /* symbol already defined */
-
- /* okay, we have an undefined symbol... step through
- the libraries now */
- if (verbose >= 2) {
- printf("undefined symbol '%s'...",r->i.label);
- fflush(stdout);
- }
+}
- lib = libraries;
- found = 0;
+/*
+ * allocnewseg()
+ * findsegment()
+ *
+ * These functions manipulate the array of output segments, and are used
+ * by processmodule(). allocnewseg() allocates a segment in the array,
+ * initialising it to be empty. findsegment() first scans the array for
+ * a segment of the type requested, and if one isn't found allocates a
+ * new one.
+ */
+int allocnewseg(int16 type,int16 reserved)
+{
+ outputseg[nsegs].type = type;
+ outputseg[nsegs].number = nsegs;
+ outputseg[nsegs].reserved = reserved;
+ outputseg[nsegs].length = 0;
+ outputseg[nsegs].offset = 0;
+ outputseg[nsegs].data = NULL;
+
+ return nsegs++;
+}
- tmp = newstr(r->i.label);
- while (! found && lib)
- {
- /* move this to an outer loop...! */
- nm = malloc(sizeof(struct modulenode));
+int findsegment(int16 type,int16 reserved)
+{
+ int i;
- if (rdl_searchlib(lib,tmp,&nm->f))
- { /* found a module in the library */
+ for (i = 0; i < nsegs; i++)
+ if (outputseg[i].type == type) return i;
- /* create a modulenode for it */
+ return allocnewseg(type,reserved);
+}
- if (! nm) {
- fprintf(stderr,"ldrdf: out of memory\n");
- exit(1);
- }
+/*
+ * symtab_add()
+ *
+ * inserts a symbol into the global symbol table, which associates symbol
+ * names either with addresses, or a marker that the symbol hasn't been
+ * resolved yet, or possibly that the symbol has been defined as
+ * contained in a dynamic [load time/run time] linked library.
+ *
+ * segment = -1 => not yet defined
+ * segment = -2 => defined as dll symbol
+ *
+ * If the symbol is already defined, and the new segment >= 0, then
+ * if the original segment was < 0 the symbol is redefined, otherwise
+ * a duplicate symbol warning is issued. If new segment == -1, this
+ * routine won't change a previously existing symbol. It will change
+ * to segment = -2 only if the segment was previously < 0.
+ */
- nm->name = newstrcat(lib->name,nm->f.name);
- if (verbose >= 2) printf("found in '%s'\n",nm->name);
+void symtab_add(const char * symbol, int segment, long offset)
+{
+ symtabEnt * ste;
- nm->coderel = lastmodule->coderel + lastmodule->f.code_len;
- if (nm->coderel % align != 0)
- nm->coderel += align - (nm->coderel % align);
+ ste = symtabFind(symtab, symbol);
+ if (ste)
+ {
+ if (ste->segment >= 0) {
+ /*
+ * symbol previously defined
+ */
+ if (segment < 0) return;
+ fprintf (stderr, "warning: `%s' redefined\n", symbol);
+ return;
+ }
- nm->datarel = lastmodule->datarel + lastmodule->f.data_len;
- if (nm->datarel % align != 0)
- nm->datarel += align - (nm->datarel % align);
+ /*
+ * somebody wanted the symbol, and put an undefined symbol
+ * marker into the table
+ */
+ if (segment == -1) return;
+ /*
+ * we have more information now - update the symbol's entry
+ */
+ ste->segment = segment;
+ ste->offset = offset;
+ ste->flags = 0;
+ return;
+ }
+ /*
+ * this is the first declaration of this symbol
+ */
+ ste = malloc(sizeof(symtabEnt));
+ if (!ste) {
+ fprintf(stderr, "ldrdf: out of memory\n");
+ exit(1);
+ }
+ ste->name = strdup(symbol);
+ ste->segment = segment;
+ ste->offset = offset;
+ ste->flags = 0;
+ symtabInsert(symtab, ste);
+}
- nm->header = malloc(nm->f.header_len);
- if (! nm->header)
- {
- fprintf(stderr,"ldrdf: out of memory\n");
- exit(1);
- }
+/*
+ * symtab_get()
+ *
+ * Retrieves the values associated with a symbol. Undefined symbols
+ * are assumed to have -1:0 associated. Returns 1 if the symbol was
+ * successfully located.
+ */
- if (rdfloadseg(&nm->f,RDOFF_HEADER,nm->header))
- {
- rdfperror("ldrdf",nm->name);
- exit(1);
- }
+int symtab_get(const char * symbol, int * segment, long * offset)
+{
+ symtabEnt * ste = symtabFind(symtab, symbol);
+ if (!ste) {
+ *segment = -1;
+ *offset = 0;
+ return 0;
+ }
+ else
+ {
+ *segment = ste->segment;
+ *offset = ste->offset;
+ return 1;
+ }
+}
- nm->next = NULL;
- found = 1;
- lastmodule->next = nm;
- lastmodule = nm;
+/*
+ * add_library()
+ *
+ * checks that a library can be opened and is in the correct format,
+ * then adds it to the linked list of libraries.
+ */
- if (verbose)
- printf("%s code = %08lx (+%04lx), data = %08lx "
- "(+%04lx)\n",lastmodule->name,
- lastmodule->coderel,lastmodule->f.code_len,
- lastmodule->datarel,lastmodule->f.data_len);
+void add_library(const char * name)
+{
+ if (rdl_verify(name)) {
+ rdl_perror("ldrdf", name);
+ errorcount++;
+ return;
+ }
+ if (! libraries)
+ {
+ lastlib = libraries = malloc(sizeof(*libraries));
+ if (! libraries) {
+ fprintf(stderr, "ldrdf: out of memory\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ lastlib->next = malloc(sizeof(*libraries));
+ if (!lastlib->next) {
+ fprintf(stderr, "ldrdf: out of memory\n");
+ exit(1);
+ }
+ lastlib = lastlib->next;
+ }
+ if (rdl_open(lastlib, name)) {
+ rdl_perror("ldrdf", name);
+ errorcount++;
+ return;
+ }
+}
- /* add the module's info to the symbol table */
- mod_addsymbols(nm);
- }
- else
+/*
+ * search_libraries()
+ *
+ * scans through the list of libraries, attempting to match symbols
+ * defined in library modules against symbols that are referenced but
+ * not defined (segment = -1 in the symbol table)
+ *
+ * returns 1 if any extra library modules are included, indicating that
+ * another pass through the library list should be made (possibly).
+ */
+
+int search_libraries()
+{
+ struct librarynode * cur;
+ rdffile f;
+ int i;
+ void * header;
+ int segment;
+ long offset;
+ int doneanything = 0, keepfile;
+ rdfheaderrec * hr;
+
+ cur = libraries;
+
+ while (cur)
+ {
+ if (options.verbose > 2)
+ printf("scanning library `%s'...\n", cur->name);
+
+ for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++)
+ {
+ if (options.verbose > 3)
+ printf(" looking in module `%s'\n", f.name);
+
+ header = malloc(f.header_len);
+ if (!header) {
+ fprintf(stderr, "ldrdf: not enough memory\n");
+ exit(1);
+ }
+ if (rdfloadseg(&f, RDOFF_HEADER, header)) {
+ rdfperror("ldrdf", f.name);
+ errorcount++;
+ return 0;
+ }
+
+ keepfile = 0;
+
+ while ((hr = rdfgetheaderrec (&f)))
+ {
+ /* we're only interested in exports, so skip others: */
+ if (hr->type != 3) continue;
+
+ /*
+ * Find the symbol in the symbol table. If the symbol isn't
+ * defined, we aren't interested, so go on to the next.
+ * If it is defined as anything but -1, we're also not
+ * interested. But if it is defined as -1, insert this
+ * module into the list of modules to use, and go
+ * immediately on to the next module...
+ */
+ if (! symtab_get(hr->e.label, &segment, &offset)
+ || segment != -1)
{
- if (rdl_error) {
- rdl_perror("ldrdf",lib->name);
- exit(1);
- }
- free(nm);
+ continue;
}
- lib = lib->next;
+
+ doneanything = 1;
+ keepfile = 1;
+
+ /*
+ * as there are undefined symbols, we can assume that
+ * there are modules on the module list by the time
+ * we get here.
+ */
+ lastmodule->next = malloc(sizeof(*lastmodule->next));
+ if (!lastmodule->next) {
+ fprintf(stderr, "ldrdf: not enough memory\n");
+ exit(1);
+ }
+ lastmodule = lastmodule->next;
+ memcpy(&lastmodule->f, &f, sizeof(f));
+ lastmodule->name = strdup(f.name);
+ processmodule(f.name, lastmodule);
+ break;
}
- free(tmp);
- if (!found && verbose >= 2) printf("not found\n");
+ if (!keepfile)
+ rdfclose(&f);
}
- mod = mod->next;
+ if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
+ rdl_perror("ldrdf", cur->name);
+ cur = cur->next;
}
+
+ return doneanything;
}
-/* load_segments() allocates memory for & loads the code & data segs
- * from the RDF modules
+/*
+ * write_output()
+ *
+ * this takes the linked list of modules, and walks through it, merging
+ * all the modules into a single output module, and then writes this to a
+ * file.
*/
-
-char *text,*data;
-long textlength,datalength;
-
-void load_segments(void)
+void write_output(const char * filename)
{
- struct modulenode *mod;
-
- if (!modules) {
- fprintf(stderr,"ldrdf: nothing to do\n");
- exit(0);
- }
- if (!lastmodule) {
- fprintf(stderr,"ldrdf: panic: module list exists, but lastmodule=NULL\n");
- exit(3);
- }
-
- if (verbose)
- printf("loading modules into memory\n");
-
- /* The following stops 16 bit DOS from crashing whilst attempting to
- work using segments > 64K */
- if (sizeof(int) == 2) { /* expect a 'code has no effect' warning on 32 bit
- platforms... */
- if (lastmodule->coderel + lastmodule->f.code_len > 65535 ||
- lastmodule->datarel + lastmodule->f.data_len > 65535) {
- fprintf(stderr,"ldrdf: segment length has exceeded 64K; use a 32 bit "
- "version.\nldrdf: code size = %05lx, data size = %05lx\n",
- lastmodule->coderel + lastmodule->f.code_len,
- lastmodule->datarel + lastmodule->f.data_len);
- exit(1);
+ FILE * f = fopen(filename, "wb");
+ rdf_headerbuf * rdfheader = rdfnewheader();
+ struct modulenode * cur;
+ int i, availableseg, seg, localseg, isrelative;
+ void * header;
+ rdfheaderrec * hr, newrec;
+ symtabEnt * se;
+ segtab segs;
+ long offset;
+ byte * data;
+
+ if (!f) {
+ fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
+ exit(1);
}
- }
-
- text = malloc(textlength = lastmodule->coderel + lastmodule->f.code_len);
- data = malloc(datalength = lastmodule->datarel + lastmodule->f.data_len);
-
- if (!text || !data) {
- fprintf(stderr,"ldrdf: out of memory\n");
- exit(1);
- }
-
- mod = modules;
- while (mod) { /* load the segments for each module */
- if (verbose >= 2) printf(" loading %s\n",mod->name);
- if (rdfloadseg(&mod->f,RDOFF_CODE,&text[mod->coderel]) ||
- rdfloadseg(&mod->f,RDOFF_DATA,&data[mod->datarel])) {
- rdfperror("ldrdf",mod->name);
- exit(1);
- }
- rdfclose(&mod->f); /* close file; segments remain */
- mod = mod->next;
- }
-}
+ if (!rdfheader) {
+ fprintf(stderr, "ldrdf: out of memory\n");
+ exit(1);
+ }
+
+ if (options.verbose)
+ printf ("\nbuilding output module (%d segments)\n", nsegs);
-/* link_segments() step through relocation records in each module's
- * header, fixing up references.
- */
+ /*
+ * Allocate the memory for the segments. We may be better off
+ * building the output module one segment at a time when running
+ * under 16 bit DOS, but that would be a slower way of doing this.
+ * And you could always use DJGPP...
+ */
+ for (i = 0; i < nsegs; i++)
+ {
+ outputseg[i].data = malloc(outputseg[i].length);
+ if (!outputseg[i].data) {
+ fprintf(stderr, "ldrdf: out of memory\n");
+ exit(1);
+ }
+ }
-void link_segments(void)
-{
- struct modulenode *mod;
- Collection imports;
- symtabEnt *s;
- long rel,relto;
- char *seg;
- rdfheaderrec *r;
- int bRelative;
-
- if (verbose) printf("linking segments\n");
-
- collection_init(&imports);
-
- for (mod = modules; mod; mod = mod->next) {
- if (verbose >= 2) printf("* processing %s\n",mod->name);
- rdfheaderrewind(&mod->f);
- while((r = rdfgetheaderrec(&mod->f))) {
- if (verbose >= 3) printf("record type: %d\n",r->type);
- switch(r->type) {
- case 1: /* relocation record */
- if (r->r.segment >= 64) { /* Relative relocation; */
- bRelative = 1; /* need to find location relative */
- r->r.segment -= 64; /* to start of this segment */
- relto = r->r.segment == 0 ? mod->coderel : mod->datarel;
+ /*
+ * initialise availableseg, used to allocate segment numbers for
+ * imported and exported labels...
+ */
+ availableseg = nsegs;
+
+ /*
+ * Step through the modules, performing required actions on each one
+ */
+ for (cur = modules; cur; cur=cur->next)
+ {
+ /*
+ * Read the actual segment contents into the correct places in
+ * the newly allocated segments
+ */
+
+ for (i = 0; i < cur->f.nsegs; i++)
+ {
+ int dest = cur->seginfo[i].dest_seg;
+
+ if (dest == -1) continue;
+ if (rdfloadseg(&cur->f, i,
+ outputseg[dest].data + cur->seginfo[i].reloc))
+ {
+ rdfperror("ldrdf", cur->name);
+ exit(1);
}
- else
+ }
+
+ /*
+ * Perform fixups, and add new header records where required
+ */
+
+ header = malloc(cur->f.header_len);
+ if (!header) {
+ fprintf(stderr, "ldrdf: out of memory\n");
+ exit(1);
+ }
+
+ if (cur->f.header_loc)
+ rdfheaderrewind(&cur->f);
+ else
+ if (rdfloadseg(&cur->f, RDOFF_HEADER, header))
{
- bRelative = 0; /* non-relative - need to relocate
- * at load time */
- relto = 0; /* placate optimiser warnings */
+ rdfperror("ldrdf", cur->name);
+ exit(1);
}
+
+ /*
+ * we need to create a local segment number -> location
+ * table for the segments in this module.
+ */
+ init_seglocations(&segs);
+ for (i = 0; i < cur->f.nsegs; i++)
+ {
+ add_seglocation(&segs, cur->f.seg[i].number,
+ cur->seginfo[i].dest_seg, cur->seginfo[i].reloc);
+ }
+ /*
+ * and the BSS segment (doh!)
+ */
+ add_seglocation (&segs, 2, 2, cur->bss_reloc);
- /* calculate absolute offset of reference, not rel to beginning of
- segment */
- r->r.offset += r->r.segment == 0 ? mod->coderel : mod->datarel;
-
- /* calculate the relocation factor to apply to the operand -
- the base address of one of this modules segments if referred
- segment is 0 - 2, or the address of an imported symbol
- otherwise. */
-
- if (r->r.refseg == 0) rel = mod->coderel;
- else if (r->r.refseg == 1) rel = mod->datarel;
- else if (r->r.refseg == 2) rel = mod->bssrel;
- else { /* cross module link - find reference */
- s = *colln(&imports,r->r.refseg - 2);
- if (!s) {
- fprintf(stderr,"ldrdf: link to undefined segment %04x in"
- " %s:%d\n", r->r.refseg,mod->name,r->r.segment);
- errors = 1;
+ while ((hr = rdfgetheaderrec(&cur->f)))
+ {
+ switch(hr->type) {
+ case 1: /* relocation record - need to do a fixup */
+ /*
+ * First correct the offset stored in the segment from
+ * the start of the segment (which may well have changed).
+ *
+ * To do this we add to the number stored the relocation
+ * factor associated with the segment that contains the
+ * target segment.
+ *
+ * The relocation could be a relative relocation, in which
+ * case we have to first subtract the amount we've relocated
+ * the containing segment by.
+ */
+
+ if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
+ {
+ fprintf(stderr, "%s: reloc to undefined segment %04x\n",
+ cur->name, (int) hr->r.refseg);
+ errorcount++;
break;
}
- rel = s->offset;
-
- r->r.refseg = s->segment; /* change referred segment,
- so that new header is
- correct */
- }
- if (bRelative) /* Relative - subtract current segment start */
- rel -= relto;
- else
- { /* Add new relocation header */
- rdfaddheader(newheader,r);
- }
-
- /* Work out which segment we're making changes to ... */
- if (r->r.segment == 0) seg = text;
- else if (r->r.segment == 1) seg = data;
- else {
- fprintf(stderr,"ldrdf: relocation in unknown segment %d in "
- "%s\n", r->r.segment,mod->name);
- errors = 1;
- break;
- }
+ isrelative = (hr->r.segment & 64) == 64;
+ hr->r.segment &= 63;
+
+ if (hr->r.segment == 2 ||
+ (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1)
+ {
+ fprintf(stderr, "%s: reloc from %s segment (%d)\n",
+ cur->name,
+ hr->r.segment == 2 ? "BSS" : "unknown",
+ hr->r.segment);
+ errorcount++;
+ break;
+ }
- /* Add the relocation factor to the datum specified: */
+ if (hr->r.length != 1 && hr->r.length != 2 && hr->r.length!=4)
+ {
+ fprintf(stderr, "%s: nonstandard length reloc "
+ "(%d bytes)\n", cur->name, hr->r.length);
+ errorcount++;
+ break;
+ }
- if (verbose >= 3)
- printf(" - relocating %d:%08lx by %08lx\n",r->r.segment,
- r->r.offset,rel);
+ /*
+ * okay, now the relocation is in the segment pointed to by
+ * cur->seginfo[localseg], and we know everything else is
+ * okay to go ahead and do the relocation
+ */
+ data = outputseg[cur->seginfo[localseg].dest_seg].data;
+ data += cur->seginfo[localseg].reloc + hr->r.offset;
+
+ /*
+ * data now points to the reference that needs
+ * relocation. Calculate the relocation factor.
+ * Factor is:
+ * offset of referred object in segment [in offset]
+ * (- relocation of localseg, if ref is relative)
+ * For simplicity, the result is stored in 'offset'.
+ * Then add 'offset' onto the value at data.
+ */
+
+ if (isrelative) offset -= cur->seginfo[localseg].reloc;
+ switch (hr->r.length)
+ {
+ case 1:
+ offset += *data;
+ if (offset < -127 || offset > 128)
+ fprintf(stderr, "warning: relocation out of range "
+ "at %s(%02x:%08lx)\n", cur->name,
+ (int)hr->r.segment, hr->r.offset);
+ *data = (char) offset;
+ break;
+ case 2:
+ offset += * (short *)data;
+ if (offset < -32767 || offset > 32768)
+ fprintf(stderr, "warning: relocation out of range "
+ "at %s(%02x:%08lx)\n", cur->name,
+ (int)hr->r.segment, hr->r.offset);
+ * (short *)data = (short) offset;
+ break;
+ case 4:
+ * (long *)data += offset;
+ /* we can't easily detect overflow on this one */
+ break;
+ }
- /**** The following code is non-portable. Rewrite it... ****/
- switch(r->r.length) {
- case 1:
- seg[r->r.offset] += (char) rel;
+ /*
+ * If the relocation was relative between two symbols in
+ * the same segment, then we're done.
+ *
+ * Otherwise, we need to output a new relocation record
+ * with the references updated segment and offset...
+ */
+ if (! isrelative
+ || cur->seginfo[localseg].dest_seg != seg)
+ {
+ hr->r.segment = cur->seginfo[localseg].dest_seg;
+ hr->r.offset += cur->seginfo[localseg].reloc;
+ hr->r.refseg = seg;
+ rdfaddheader(rdfheader, hr);
+ }
break;
- case 2:
- *(int16 *)(seg + r->r.offset) += (int16) rel;
+
+ case 2: /* import symbol */
+ case 7:
+ /*
+ * scan the global symbol table for the symbol
+ * and associate its location with the segment number
+ * for this module
+ */
+ se = symtabFind(symtab, hr->i.label);
+ if (!se || se->segment == -1) {
+ if (options.warnUnresolved) {
+ fprintf(stderr, "warning: unresolved reference to `%s'"
+ " in module `%s'\n", hr->i.label, cur->name);
+ }
+ /*
+ * we need to allocate a segment number for this
+ * symbol, and store it in the symbol table for
+ * future reference
+ */
+ if (!se) {
+ se=malloc(sizeof(*se));
+ if (!se) {
+ fprintf(stderr, "ldrdf: out of memory\n");
+ exit(1);
+ }
+ se->name = strdup(hr->i.label);
+ se->flags = 0;
+ se->segment = availableseg++;
+ se->offset = 0;
+ symtabInsert(symtab, se);
+ }
+ else {
+ se->segment = availableseg++;
+ se->offset = 0;
+ }
+ /*
+ * output a header record that imports it to the
+ * recently allocated segment number...
+ */
+ newrec = *hr;
+ newrec.i.segment = se->segment;
+ rdfaddheader(rdfheader, &newrec);
+ }
+
+ add_seglocation(&segs, hr->i.segment, se->segment, se->offset);
+
break;
- case 4:
- *(long *)(seg + r->r.offset) += rel;
+
+ case 3: /* export symbol */
+ /*
+ * need to insert an export for this symbol into the new
+ * header, unless we're stripping symbols [unless this
+ * symbol is in an explicit keep list]. *** FIXME ***
+ */
+ if (options.strip)
+ break;
+
+ if (hr->e.segment == 2) {
+ seg = 2;
+ offset = cur->bss_reloc;
+ }
+ else {
+ localseg = rdffindsegment(&cur->f, hr->e.segment);
+ if (localseg == -1) {
+ fprintf(stderr, "%s: exported symbol `%s' from "
+ "unrecognised segment\n", cur->name,
+ hr->e.label);
+ errorcount++;
+ break;
+ }
+ offset = cur->seginfo[localseg].reloc;
+ seg = cur->seginfo[localseg].dest_seg;
+ }
+
+ hr->e.segment = seg;
+ hr->e.offset += offset;
+ rdfaddheader(rdfheader, hr);
break;
- }
- break;
- case 2: /* import record */
- s = symtabFind(symtab, r->i.label);
- if (s == NULL) {
- /* Need to add support for dynamic linkage */
- fprintf(stderr,"ldrdf: undefined symbol %s in module %s\n",
- r->i.label,mod->name);
- errors = 1;
- }
- else
- {
- *colln(&imports,r->i.segment - 2) = s;
- if (verbose >= 2)
- printf("imported %s as %04x\n", r->i.label, r->i.segment);
- }
- break;
+ case 6: /* segment fixup */
+ /*
+ * modify the segment numbers if necessary, and
+ * pass straight through to the output module header
+ *
+ * *** FIXME ***
+ */
+ if (hr->r.segment == 2) {
+ fprintf(stderr, "%s: segment fixup in BSS section\n",
+ cur->name);
+ errorcount++;
+ break;
+ }
+ localseg = rdffindsegment(&cur->f, hr->r.segment);
+ if (localseg == -1) {
+ fprintf(stderr, "%s: segment fixup in unrecognised"
+ " segment (%d)\n", cur->name, hr->r.segment);
+ errorcount++;
+ break;
+ }
+ hr->r.segment = cur->seginfo[localseg].dest_seg;
+ hr->r.offset += cur->seginfo[localseg].reloc;
- case 3: /* export; dump to output new version */
- s = symtabFind(symtab, r->e.label);
- if (! s) {
- fprintf(stderr,"ldrdf: internal error - undefined symbol %s "
- "exported in header of '%s'\n",r->e.label,mod->name);
- continue;
+ if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
+ {
+ fprintf(stderr, "%s: segment fixup to undefined "
+ "segment %04x\n", cur->name, (int)hr->r.refseg);
+ errorcount++;
+ break;
+ }
+ hr->r.refseg = seg;
+ rdfaddheader(rdfheader, hr);
+ break;
}
- r->e.offset = s->offset;
- rdfaddheader(newheader,r);
- break;
-
- case 4: /* DLL record */
- rdfaddheader(newheader,r); /* copy straight to output */
- break;
}
- }
- if (rdf_errno != 0) {
- rdfperror("ldrdf",mod->name);
- exit(1);
- }
- collection_reset(&imports);
- }
-}
-
-/* write_output() write linked program out to a file */
-void write_output(char *filename)
-{
- FILE * fp;
- rdfheaderrec r;
+ free(header);
+ done_seglocations(&segs);
+
+ }
- if (verbose) printf("writing output to '%s'\n",filename);
+ /*
+ * combined BSS reservation for the entire results
+ */
+ newrec.type = 5;
+ newrec.b.reclen = 4;
+ newrec.b.amount = bss_length;
+ rdfaddheader(rdfheader, &newrec);
- fp = fopen(filename,"wb");
- if (! fp)
+ /*
+ * Write the header
+ */
+ for (i = 0; i < nsegs; i++)
{
- fprintf(stderr,"ldrdf: could not open '%s' for writing\n",filename);
- exit(1);
+ if (i == 2) continue;
+ rdfaddsegment (rdfheader, outputseg[i].length);
}
-
+ rdfwriteheader(f, rdfheader);
+ rdfdoneheader(rdfheader);
+ /*
+ * Step through the segments, one at a time, writing out into
+ * the output file
+ */
- /* add BSS length count to header... */
- if (bsslength)
- {
- r.type = 5;
- r.b.amount = bsslength;
- rdfaddheader(newheader,&r);
- }
-
- /* Write header */
- rdfwriteheader(fp,newheader);
- rdfdoneheader(newheader);
- newheader = NULL;
-
- /* Write text */
- if (fwrite(&textlength,1,4,fp) != 4
- || fwrite(text,1,textlength,fp) !=textlength)
+ for (i = 0; i < nsegs; i++)
{
- fprintf(stderr,"ldrdf: error writing %s\n",filename);
- exit(1);
+ int16 s;
+ long l;
+
+ if (i == 2) continue;
+
+ s = translateshort(outputseg[i].type);
+ fwrite(&s, 2, 1, f);
+ s = translateshort(outputseg[i].number);
+ fwrite(&s, 2, 1, f);
+ s = translateshort(outputseg[i].reserved);
+ fwrite(&s, 2, 1, f);
+ l = translatelong(outputseg[i].length);
+ fwrite(&l, 4, 1, f);
+
+ fwrite(outputseg[i].data, outputseg[i].length, 1, f);
}
- /* Write data */
- if (fwrite(&datalength,1,4,fp) != 4 ||
- fwrite(data,1,datalength,fp) != datalength)
- {
- fprintf (stderr,"ldrdf: error writing %s\n", filename);
- exit(1);
- }
- fclose(fp);
+ fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f);
}
-
-/* main program: interpret command line, and pass parameters on to
- * individual module loaders & the linker
- *
- * Command line format:
- * ldrdf [-o outfile | -x] [-r xxxx] [-v] [--] infile [infile ...]
- *
- * Default action is to output a file named 'aout.rdx'. -x specifies
- * that the linked object program should be executed, rather than
- * written to a file. -r specifies that the object program should
- * be prelocated at address 'xxxx'. This option cannot be used
- * in conjunction with -x.
+/* =========================================================================
+ * Main program
*/
-const char *usagemsg = "usage:\n"
-" ldrdf [-o outfile | -x] [-a x] [-v] [-p x] [--] infile [infile ...]\n"
-" [-l<libname> ...]\n\n"
-" ldrdf -h displays this message\n"
-" ldrdf -r displays version information\n\n"
-" -o selects output filename (default is aout.rdx)\n"
-" -x causes ldrdx to link & execute rather than write to file\n"
-" -a x causes object program to be statically relocated to address 'x'\n"
-" -v turns on verbose mode\n"
-" -p x causes segments to be aligned (padded) to x byte boundaries\n"
-" (default is 16 bytes)\n"
-" -l<name> causes 'name' to be linked in as a library. Note no search is\n"
-" performed - the entire pathname MUST be specified.\n";
-
-void usage(void)
+void usage()
{
- fputs(usagemsg,stderr);
+ printf("usage:\n");
+ printf(" ldrdf [options] object modules ... [-llibrary ...]\n");
+ printf(" ldrdf -r\n");
+ printf("options:\n");
+ printf(" -v[=n] increases verbosity by 1, or sets it to n\n");
+ printf(" -a nn sets segment alignment value (default 16)\n");
+ printf(" -s strips exported symbols\n");
+ printf(" -x warn about unresolved symbols\n");
+ printf(" -o name write output in file 'name'\n");
+ printf("\n");
+ printf("Note: no library searching is performed. Please specify full\n");
+ printf("paths to all files referenced.\n");
+ exit(0);
}
-int main(int argc,char **argv)
+int main(int argc, char ** argv)
{
- char *ofilename = "aout.rdx";
- long relocateaddr = -1; /* -1 if no relocation is to occur */
- int execute = 0; /* 1 to execute after linking, 0 otherwise */
- int procsw = 1; /* set to 0 by '--' */
- int tmp;
-
- if (argc == 1) {
- usage();
- exit(1);
- }
-
- /* process command line switches, and add modules specified to linked list
- of modules, keeping track of total memory required to load them */
-
- while(argv++,--argc) {
- if (procsw && !strcmp(*argv,"-h")) { /* Help command */
- usage(); exit(1);
+ char * outname = "aout.rdf";
+ int moduleloaded = 0;
+
+ options.verbose = 0;
+ options.align = 16;
+ options.warnUnresolved = 0;
+ options.strip = 0;
+
+ argc --, argv ++;
+ if (argc == 0) usage();
+ while (argc && **argv == '-' && argv[0][1] != 'l')
+ {
+ switch(argv[0][1]) {
+ case 'r':
+ printf("ldrdf (linker for RDF files) version " LDRDF_VERSION "\n");
+ printf( _RDOFF_H "\n");
+ exit(0);
+ case 'v':
+ if (argv[0][2] == '=') {
+ options.verbose = argv[0][3] - '0';
+ if (options.verbose < 0 || options.verbose > 9) {
+ fprintf(stderr, "ldrdf: verbosity level must be a number"
+ " between 0 and 9\n");
+ exit(1);
+ }
+ }
+ else
+ options.verbose++;
+ break;
+ case 'a':
+ options.align = atoi(argv[1]);
+ if (options.align <= 0) {
+ fprintf(stderr,
+ "ldrdf: -a expects a positive number argument\n");
+ exit(1);
+ }
+ argv++, argc--;
+ break;
+ case 's':
+ options.strip = 1;
+ break;
+ case 'x':
+ options.warnUnresolved = 1;
+ break;
+ case 'o':
+ outname = argv[1];
+ argv++, argc--;
+ break;
+ default:
+ usage();
+ }
+ argv++, argc--;
}
- else if (procsw && !strcmp(*argv,"-r")) {
- printf("ldrdf version %s (%s) (%s)\n",LDRDF_VERSION,_RDOFF_H,
- sizeof(int) == 2 ? "16 bit" : "32 bit");
- exit(1);
+
+ if (options.verbose > 4) {
+ printf("ldrdf invoked with options:\n");
+ printf(" section alignment: %d bytes\n", options.align);
+ printf(" output name: `%s'\n", outname);
+ if (options.strip)
+ printf(" strip symbols\n");
+ if (options.warnUnresolved)
+ printf(" warn about unresolved symbols\n");
+ printf("\n");
}
- else if (procsw && !strcmp(*argv,"-o")) {
- ofilename = *++argv;
- --argc;
- if (execute) {
- fprintf(stderr,"ldrdf: -o and -x switches incompatible\n");
+
+ symtab = symtabNew();
+ initsegments();
+
+ if (!symtab) {
+ fprintf(stderr, "ldrdf: out of memory\n");
exit(1);
- }
- if (verbose > 1) printf("output filename set to '%s'\n",ofilename);
}
- else if (procsw && !strcmp(*argv,"-x")) {
- execute++;
- if (verbose > 1) printf("will execute linked object\n");
+
+ while (argc)
+ {
+ if (!strncmp(*argv, "-l", 2)) /* library */
+ add_library(*argv + 2);
+ else {
+ loadmodule(*argv);
+ moduleloaded = 1;
+ }
+ argv++, argc--;
}
- else if (procsw && !strcmp(*argv,"-a")) {
- relocateaddr = readnum(*++argv,&tmp);
- --argc;
- if (tmp) {
- fprintf(stderr,"ldrdf: error in parameter to '-a' switch: '%s'\n",
- *argv);
- exit(1);
- }
- if (execute) {
- fprintf(stderr,"ldrdf: -a and -x switches incompatible\n");
- exit(1);
- }
- if (verbose) printf("will relocate to %08lx\n",relocateaddr);
+
+ if (! moduleloaded) {
+ printf("ldrdf: nothing to do. ldrdf -h for usage\n");
+ return 0;
}
- else if (procsw && !strcmp(*argv,"-v")) {
- verbose++;
- if (verbose == 1) printf("verbose mode selected\n");
+
+
+ search_libraries();
+
+ if (options.verbose > 2)
+ {
+ printf ("symbol table:\n");
+ symtabDump(symtab, stdout);
}
- else if (procsw && !strcmp(*argv,"-p")) {
- align = readnum(*++argv,&tmp);
- --argc;
- if (tmp) {
- fprintf(stderr,"ldrdf: error in parameter to '-p' switch: '%s'\n",
- *argv);
- exit(1);
- }
- if (align != 1 && align != 2 && align != 4 && align != 8 && align != 16
- && align != 32 && align != 256) {
- fprintf(stderr,"ldrdf: %d is an invalid alignment factor - must be"
- "1,2,4,8,16 or 256\n",align);
+
+ write_output(outname);
+
+ if (errorcount > 0)
exit(1);
- }
- if (verbose > 1) printf("alignment %d selected\n",align);
- }
- else if (procsw && !strncmp(*argv,"-l",2)) {
- load_library(*argv + 2);
- }
- else if (procsw && !strcmp(*argv,"--")) {
- procsw = 0;
- }
- else { /* is a filename */
- if (verbose > 1) printf("processing module %s\n",*argv);
- loadmodule(*argv);
- }
- }
-
- /* we should be scanning for unresolved references, and removing
- unreferenced modules from the list of modules here, so that
- we know about the final size once libraries have been linked in */
-
- build_symbols(); /* build a global symbol table... */
-
- scan_libraries(); /* check for imported symbols not in table,
- and ensure the relevant library modules
- are loaded */
-
- load_segments(); /* having calculated size of reqd segments, load
- each rdoff module's segments into memory */
-
- link_segments(); /* step through each module's header, and resolve
- references to the global symbol table.
- This also does local address fixups. */
-
- if (errors) {
- fprintf(stderr,"ldrdf: there were errors - aborted\n");
- exit(errors);
- }
- if (execute) {
- fprintf(stderr,"ldrdf: module execution not yet supported\n");
- exit(1);
- }
- if (relocateaddr != -1) {
- fprintf(stderr,"ldrdf: static relocation not yet supported\n");
- exit(1);
- }
-
- write_output(ofilename);
- return 0;
+
+ return 0;
}
+