diff options
author | H. Peter Anvin <hpa@zytor.com> | 2002-04-30 21:02:47 +0000 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2002-04-30 21:02:47 +0000 |
commit | 9eb185bfdb10f1dfccbb9a702d2801a32cd1b13d (patch) | |
tree | 8fb0cb3aafd0b78da681ca24c0d25562f394c47d /rdoff | |
parent | ce61607e1125f1fc1f7c74dfa486031bb7c898fa (diff) | |
download | nasm-9eb185bfdb10f1dfccbb9a702d2801a32cd1b13d.tar.gz nasm-9eb185bfdb10f1dfccbb9a702d2801a32cd1b13d.tar.bz2 nasm-9eb185bfdb10f1dfccbb9a702d2801a32cd1b13d.zip |
NASM 0.98.15
Diffstat (limited to 'rdoff')
-rw-r--r-- | rdoff/ldrdf.c | 1378 |
1 files changed, 31 insertions, 1347 deletions
diff --git a/rdoff/ldrdf.c b/rdoff/ldrdf.c index 3d9d749..d9aac2f 100644 --- a/rdoff/ldrdf.c +++ b/rdoff/ldrdf.c @@ -1,1347 +1,31 @@ -/* ldrdf.c RDOFF Object File linker/loader main program - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -/* - * TODO: 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 - * - * 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> -#include <stdlib.h> -#include <string.h> - -#include "multboot.h" -#include "rdoff.h" -#include "symtab.h" -#include "collectn.h" -#include "rdlib.h" -#include "segtab.h" - -#define LDRDF_VERSION "1.02" - -#define RDF_MAXSEGS 64 -/* #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 */ - long 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; - 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 - */ - -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); - -/* ========================================================================= - * 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; - -/* error file */ -static FILE * error_file; - -#ifdef _MULTBOOT_H - -/* loading address for multiboot header */ -unsigned MBHloadAddr; - -/* - * Tiny code that moves RDF loader to its working memory region: - * mov esi,SOURCE_ADDR ; BE xx xx xx xx - * mov edi,DEST_ADDR ; BF xx xx xx xx - * mov esp,edi ; 89 FC - * push edi ; 57 - * mov ecx,RDFLDR_LENGTH/4 ; B9 xx xx xx xx - * cld ; FC - * rep movsd ; F3 A5 - * ret ; C3 - */ - -#define RDFLDR_LENGTH 4096 /* Loader will be moved to unused */ -#define RDFLDR_DESTLOC 0xBF000 /* video page */ - -unsigned char RDFloaderMover[]={ - 0xBE, 0, 0, 0, 0, 0xBF, 0, 0xF0, 0xB, 0, - 0x89, 0xFC, 0x57, - 0xB9, 0, 4, 0, 0, - 0xFC, 0xF3, 0xA5, 0xC3 -}; - -#endif - -/* 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; -long bss_length; - -/* global options which affect how the program behaves */ -struct ldrdfoptions { - int verbose; - int align; - int warnUnresolved; - int errorUnresolved; - int strip; - int respfile; - int stderr_redir; - int objpath; - int libpath; - int addMBheader; -} 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, cos 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; - 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; - - 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; - - 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:%08lx (+%04lx)\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 2: /* imported symbol - define with seg = -1 */ - case 7: - symtab_add(hr->i.label, -1, 0); - break; - - case 3: /* exported symbol */ - { - int destseg; - long destreloc; - - if (hr->e.segment == 2) - { - 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 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 (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; - } - -#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 - -} - - -/* - * Look in list for module by its name. - */ -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(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++; -} - -int findsegment(int16 type,int16 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, long 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, long * 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; - long 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 != 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) - { - 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; - long offset; - byte * 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); - } - - /* - * Add multiboot header if appropriate option is specified. - * Multiboot record *MUST* be the first record in output file. - */ - if (options.addMBheader) { - if (options.verbose) - puts("\nadding multiboot header record"); - - hr = (rdfheaderrec *) malloc(sizeof(struct MultiBootHdrRec)); - hr->mbh.type = 9; - hr->mbh.reclen = sizeof(struct tMultiBootHeader)+RDFLDRMOVER_SIZE; - - hr->mbh.mb.Magic = MB_MAGIC; - hr->mbh.mb.Flags = MB_FL_KLUDGE; - hr->mbh.mb.Checksum = ~(MB_MAGIC+MB_FL_KLUDGE-1); - hr->mbh.mb.HeaderAddr = MBHloadAddr+16; - hr->mbh.mb.LoadAddr = MBHloadAddr; - hr->mbh.mb.Entry = MBHloadAddr+16+sizeof(struct tMultiBootHeader); - - memcpy(hr->mbh.mover,RDFloaderMover,RDFLDRMOVER_SIZE); - - 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 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; - } - - 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; - } - - 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:%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(error_file, "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; - } - - /* - * 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: /* 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(error_file, "warning: unresolved reference to `%s'" - " in module `%s'\n", hr->i.label, cur->name); - if (options.errorUnresolved==1) 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 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; - - case 8: /* module name */ - /* - * insert module name record if export symbols - * are not stripped. - */ - if (options.strip) break; - - rdfaddheader(rdfheader, hr); - 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; - - 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; - } - } - - free(header); - done_seglocations(&segs); - - } - - /* - * combined BSS reservation for the entire results - */ - newrec.type = 5; - 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); - } - - if (options.addMBheader) { - struct MultiBootHdrRec *mbhrec = (struct MultiBootHdrRec *)(rdfheader->buf->buffer); - unsigned l = membuflength(rdfheader->buf) + 14 + - 10*rdfheader->nsegments + rdfheader->seglength; - unsigned *ldraddr = (unsigned *)(mbhrec->mover+1); - - mbhrec->mb.LoadEndAddr = MBHloadAddr+l+10+RDFLDR_LENGTH; - mbhrec->mb.BSSendAddr = mbhrec->mb.LoadEndAddr; - *ldraddr = MBHloadAddr+l+10; - } - - 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++) - { - 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); - } - - fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f); -} - -/* ========================================================================= - * Main program - */ - -void usage() -{ - 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(" -j path specify objects search path\n"); - printf(" -L path specify libraries search path\n"); - printf(" -mbh [address] add multiboot header to output file. Default\n"); - printf(" loading address is 0x110000\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.warnUnresolved = 0; - options.strip = 0; - - error_file = stderr; - - 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; - if (argv[0][2]=='e') - options.errorUnresolved = 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); - } - argc-=2; - while(fgets(buf,sizeof(buf)-1,f)!=NULL) - { - char *p; - if (buf[0]=='\n') continue; - if ((p = strchr(buf,'\n')) != 0) - *p=0; - if (i >= 128) - { - fprintf(stderr,"ldrdf: too many input files\n"); - exit(1); - } - *(respstrings+i) = newstr(buf); - argc++, i++; - } - goto done; - } - case '2': - options.stderr_redir = 1; - error_file = stdout; - break; - case 'm': - if (argv[0][2] == 'b' && argv[0][3] == 'h') { - if (argv[1][0] != '-') { - MBHloadAddr = atoi(argv[1]); - } else { - MBHloadAddr = MB_DEFAULTLOADADDR; - } - options.addMBheader = 1; - break; - } - default: - usage(); - } - argv++, argc--; - } -done: - 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"); - if (options.errorUnresolved) - printf(" error if unresolved symbols\n"); - if (options.objpath) - printf(" objects search path: %s\n",objpath); - if (options.libpath) - printf(" libraries search path: %s\n",libpath); - if (options.addMBheader) - printf(" loading address for multiboot header: 0x%X\n",MBHloadAddr); - printf("\n"); - } - - symtab = symtabNew(); - initsegments(); - - if (!symtab) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - - if (*respstrings) argv = respstrings; - while (argc) - { - if (!strncmp(*argv, "-l", 2)) /* library */ - { - if(libpath) add_library(newstrcat(libpath,*argv + 2)); - else add_library(*argv + 2); - } - else { - if(objpath) 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; -} +*************** +*** 29,42 **** + #include <stdlib.h> + #include <string.h> + + #include "rdoff.h" + #include "symtab.h" + #include "collectn.h" + #include "rdlib.h" + #include "segtab.h" +- #include "multboot.h" + +- #define LDRDF_VERSION "1.01 alpha 2" + + #define RDF_MAXSEGS 64 + /* #define STINGY_MEMORY */ +--- 29,42 ---- + #include <stdlib.h> + #include <string.h> + ++ #include "multboot.h" + #include "rdoff.h" + #include "symtab.h" + #include "collectn.h" + #include "rdlib.h" + #include "segtab.h" + ++ #define LDRDF_VERSION "1.02" + + #define RDF_MAXSEGS 64 + /* #define STINGY_MEMORY */ |