ldrdf.c
上传用户:yuppie_zhu
上传日期:2007-01-08
资源大小:535k
文件大小:29k
源码类别:

编译器/解释器

开发平台:

C/C++

  1. /* ldrdf.c      RDOFF Object File linker/loader main program
  2.  *
  3.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  4.  * Julian Hall. All rights reserved. The software is
  5.  * redistributable under the licence given in the file "Licence"
  6.  * distributed in the NASM archive.
  7.  */
  8. /*
  9.  * TODO: actually get this new version working!
  10.  * - finish off write_output()       - appears to be done
  11.  * - implement library searching     - appears to be done
  12.  *   - maybe we only want to do one pass, for performance reasons?
  13.  *     this makes things a little harder, but unix 'ld' copes...
  14.  * - implement command line options  - appears to be done
  15.  * - improve symbol table implementation  - done, thanks to Graeme Defty
  16.  * - keep a cache of symbol names in each library module so
  17.  *   we don't have to constantly recheck the file
  18.  * - general performance improvements
  19.  *
  20.  * BUGS & LIMITATIONS: this program doesn't support multiple code, data
  21.  * or bss segments, therefore for 16 bit programs whose code, data or BSS
  22.  * segment exceeds 64K in size, it will not work. This program probably
  23.  * wont work if compiled by a 16 bit compiler. Try DJGPP if you're running
  24.  * under DOS. '#define STINGY_MEMORY' may help a little.
  25.  */
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include "rdoff.h"
  30. #include "symtab.h"
  31. #include "collectn.h"
  32. #include "rdlib.h"
  33. #include "segtab.h"
  34. #define LDRDF_VERSION "1.00 alpha 1"
  35. #define RDF_MAXSEGS 64
  36. /* #define STINGY_MEMORY */
  37. /* =======================================================================
  38.  * Types & macros that are private to this program
  39.  */
  40. struct segment_infonode {
  41.     int dest_seg; /* output segment to be placed into, -1 to 
  42.    skip linking this segment */
  43.     long reloc; /* segment's relocation factor */
  44. };
  45. struct modulenode {
  46.     rdffile f; /* the RDOFF file structure */
  47.     struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
  48.      with each segment? */
  49.     void * header;
  50.     char * name;
  51.     struct modulenode * next;
  52.     long bss_reloc;
  53. };
  54. #include "ldsegs.h"
  55. #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
  56. #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
  57. /* ==========================================================================
  58.  * Function prototypes of private utility functions
  59.  */
  60. void processmodule(const char * filename, struct modulenode * mod);
  61. int allocnewseg(int16 type,int16 reserved);
  62. int findsegment(int16 type,int16 reserved);
  63. void symtab_add(const char * symbol, int segment, long offset);
  64. int symtab_get(const char * symbol, int * segment, long * offset);
  65. /* =========================================================================
  66.  * Global data structures.
  67.  */
  68. /* a linked list of modules that will be included in the output */
  69. struct modulenode  * modules = NULL;
  70. struct modulenode  * lastmodule = NULL;
  71. /* a linked list of libraries to be searched for unresolved imported symbols */
  72. struct librarynode  * libraries = NULL;
  73. struct librarynode * lastlib = NULL;
  74. /* the symbol table */
  75. void  * symtab = NULL;
  76. /* the header of the output file, built up stage by stage */
  77. rdf_headerbuf  * newheader = NULL;
  78. /* The current state of segment allocation, including information about
  79.  * which output segment numbers have been allocated, and their types and
  80.  * amount of data which has already been allocated inside them. 
  81.  */
  82. struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
  83. int nsegs = 0;
  84. long bss_length;
  85. /* global options which affect how the program behaves */
  86. struct ldrdfoptions {
  87.     int verbose;
  88.     int align;
  89.     int warnUnresolved;
  90.     int strip;
  91. } options;
  92. int errorcount = 0; /* determines main program exit status */
  93. /* =========================================================================
  94.  * Utility functions
  95.  */
  96. /*
  97.  * initsegments()
  98.  *
  99.  * sets up segments 0, 1, and 2, the initial code data and bss segments
  100.  */
  101. void initsegments()
  102. {
  103.     nsegs = 3;
  104.     outputseg[0].type = 1;
  105.     outputseg[0].number = 0;
  106.     outputseg[0].reserved = 0;
  107.     outputseg[0].length = 0;
  108.     outputseg[1].type = 2;
  109.     outputseg[1].number = 1;
  110.     outputseg[1].reserved = 0;
  111.     outputseg[1].length = 0;
  112.     outputseg[2].type = 0xFFFF; /* reserved segment type */
  113.     outputseg[2].number = 2;
  114.     outputseg[2].reserved = 0;
  115.     outputseg[2].length = 0;
  116.     bss_length = 0;
  117. }
  118. /*
  119.  * loadmodule
  120.  *
  121.  * Determine the characteristics of a module, and decide what to do with
  122.  * each segment it contains (including determining destination segments and
  123.  * relocation factors for segments that are kept).
  124.  */
  125. void loadmodule(const char * filename)
  126. {
  127.     if (options.verbose)
  128. printf("loading `%s'n", filename);
  129.     /* allocate a new module entry on the end of the modules list */
  130.     if (!modules)
  131.     {
  132. modules = malloc (sizeof(*modules));
  133. lastmodule = modules;
  134.     }
  135.     else
  136.     {
  137. lastmodule->next = malloc (sizeof(*modules));
  138. lastmodule = lastmodule->next;
  139.     }
  140.     if ( ! lastmodule)
  141.     {
  142. fprintf(stderr, "ldrdf: out of memoryn");
  143. exit(1);
  144.     }
  145.     /* open the file using 'rdfopen', which returns nonzero on error */
  146.     if (rdfopen(&lastmodule->f, filename) != 0)
  147.     {
  148. rdfperror("ldrdf", filename);
  149. exit(1);
  150.     }
  151.     /* 
  152.      * store information about the module, and determine what segments
  153.      * it contains, and what we should do with them (determine relocation
  154.      * factor if we decide to keep them)
  155.      */
  156.     lastmodule->header = NULL;
  157.     lastmodule->name = strdup(filename);
  158.     lastmodule->next = NULL;
  159.     processmodule(filename, lastmodule);
  160. }
  161. /*
  162.  * processmodule()
  163.  *
  164.  * step through each segment, determine what exactly we're doing with
  165.  * it, and if we intend to keep it, determine (a) which segment to
  166.  * put it in and (b) whereabouts in that segment it will end up.
  167.  * (b) is fairly easy, cos we're now keeping track of how big each segment
  168.  * in our output file is...
  169.  */
  170. void processmodule(const char * filename, struct modulenode * mod)
  171. {
  172.     struct segconfig sconf;
  173.     int seg, outseg;
  174.     void * header;
  175.     rdfheaderrec * hr;
  176.     long bssamount = 0;
  177.     for (seg = 0; seg < mod->f.nsegs; seg++)
  178.     {
  179. /*
  180.  * get the segment configuration for this type from the segment
  181.  * table. getsegconfig() is a macro, defined in ldsegs.h.
  182.  */
  183. getsegconfig(sconf, mod->f.seg[seg].type);
  184. if (options.verbose > 1) {
  185.     printf ("%s %04x [%04x:%10s] ", filename, mod->f.seg[seg].number, 
  186.     mod->f.seg[seg].type, sconf.typedesc);
  187. }
  188. /*
  189.  * sconf->dowhat tells us what to do with a segment of this type.
  190.  */
  191. switch (sconf.dowhat) {
  192. case SEG_IGNORE:
  193.     /*
  194.      * Set destination segment to -1, to indicate that this segment
  195.      * should be ignored for the purpose of output, ie it is left
  196.      * out of the linked executable.
  197.      */
  198.     mod->seginfo[seg].dest_seg = -1;
  199.     if (options.verbose > 1) printf("IGNOREDn");
  200.     break;
  201. case SEG_NEWSEG:
  202.     /*
  203.      * The configuration tells us to create a new segment for
  204.      * each occurrence of this segment type.
  205.      */
  206.     outseg = allocnewseg(sconf.mergetype,
  207.  mod->f.seg[seg].reserved);
  208.     mod->seginfo[seg].dest_seg = outseg;
  209.     mod->seginfo[seg].reloc = 0;
  210.     outputseg[outseg].length = mod->f.seg[seg].length;
  211.     if (options.verbose > 1) 
  212. printf ("=> %04x:%08lx (+%04lx)n", outseg,
  213. mod->seginfo[seg].reloc,
  214. mod->f.seg[seg].length);
  215.     break;
  216. case SEG_MERGE:
  217.     /*
  218.      * The configuration tells us to merge the segment with
  219.      * a previously existing segment of type 'sconf.mergetype',
  220.      * if one exists. Otherwise a new segment is created.
  221.      * This is handled transparently by 'findsegment()'.
  222.      */
  223.     outseg = findsegment(sconf.mergetype,
  224.  mod->f.seg[seg].reserved);
  225.     mod->seginfo[seg].dest_seg = outseg;
  226.     /*
  227.      * We need to add alignment to these segments.
  228.      */
  229.     if (outputseg[outseg].length % options.align != 0)
  230. outputseg[outseg].length += 
  231.     options.align - (outputseg[outseg].length % options.align);
  232.     
  233.     mod->seginfo[seg].reloc = outputseg[outseg].length;
  234.     outputseg[outseg].length  += mod->f.seg[seg].length;
  235.     if (options.verbose > 1) 
  236. printf ("=> %04x:%08lx (+%04lx)n", outseg,
  237. mod->seginfo[seg].reloc,
  238. mod->f.seg[seg].length);
  239. }
  240.     }
  241.     /*
  242.      * extract symbols from the header, and dump them into the
  243.      * symbol table
  244.      */
  245.     header = malloc(mod->f.header_len);
  246.     if (!header) {
  247. fprintf(stderr, "ldrdf: not enough memoryn");
  248. exit(1);
  249.     }
  250.     if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
  251. rdfperror("ldrdf", filename);
  252. exit(1);
  253.     }
  254.     while ((hr = rdfgetheaderrec (&mod->f)))
  255.     {
  256. switch(hr->type) {
  257. case 2: /* imported symbol - define with seg = -1 */
  258. case 7:
  259.     symtab_add(hr->i.label, -1, 0);
  260.     break;
  261. case 3: /* exported symbol */
  262.     if (mod->seginfo[(int)hr->e.segment].dest_seg == -1)
  263. continue;
  264.     symtab_add(hr->e.label, mod->seginfo[(int)hr->e.segment].dest_seg,
  265.        mod->seginfo[(int)hr->e.segment].reloc + hr->e.offset);
  266.     break;
  267. case 5: /* BSS reservation */
  268.     /*
  269.      * first, amalgamate all BSS reservations in this module
  270.      * into one, because we allow this in the output format.
  271.      */
  272.     bssamount += hr->b.amount;
  273.     break;
  274. }
  275.     }
  276.     if (bssamount != 0)
  277.     {
  278. /*
  279.  * handle the BSS segment - first pad the existing bss length
  280.  * to the correct alignment, then store the length in bss_reloc
  281.  * for this module. Then add this module's BSS length onto
  282.  * bss_length.
  283.  */
  284. if (bss_length % options.align != 0)
  285.     bss_length +=  options.align - (bss_length % options.align);
  286.     
  287. mod->bss_reloc = bss_length;
  288. if (options.verbose > 1) {
  289.     printf ("%s 0002 [            BSS] => 0002:%08lx (+%04lx)n",
  290.     filename, bss_length, bssamount);
  291. }
  292. bss_length += bssamount;
  293.     }
  294. #ifdef STINGY_MEMORY
  295.     /*
  296.      * we free the header buffer here, to save memory later.
  297.      * this isn't efficient, but probably halves the memory usage
  298.      * of this program...
  299.      */
  300.     mod->f.header_loc = NULL;
  301.     free(header);
  302. #endif
  303. }
  304. /*
  305.  * allocnewseg()
  306.  * findsegment()
  307.  *
  308.  * These functions manipulate the array of output segments, and are used
  309.  * by processmodule(). allocnewseg() allocates a segment in the array,
  310.  * initialising it to be empty. findsegment() first scans the array for
  311.  * a segment of the type requested, and if one isn't found allocates a
  312.  * new one.
  313.  */
  314. int allocnewseg(int16 type,int16 reserved)
  315. {
  316.     outputseg[nsegs].type = type;
  317.     outputseg[nsegs].number = nsegs;
  318.     outputseg[nsegs].reserved = reserved;
  319.     outputseg[nsegs].length = 0;
  320.     outputseg[nsegs].offset = 0;
  321.     outputseg[nsegs].data = NULL;
  322.     return nsegs++;
  323. }
  324. int findsegment(int16 type,int16 reserved)
  325. {
  326.     int i;
  327.     for (i = 0; i < nsegs; i++)
  328. if (outputseg[i].type == type) return i;
  329.     return allocnewseg(type,reserved);
  330. }
  331. /*
  332.  * symtab_add()
  333.  *
  334.  * inserts a symbol into the global symbol table, which associates symbol
  335.  * names either with addresses, or a marker that the symbol hasn't been
  336.  * resolved yet, or possibly that the symbol has been defined as
  337.  * contained in a dynamic [load time/run time] linked library.
  338.  *
  339.  * segment = -1 => not yet defined
  340.  * segment = -2 => defined as dll symbol
  341.  *
  342.  * If the symbol is already defined, and the new segment >= 0, then
  343.  * if the original segment was < 0 the symbol is redefined, otherwise
  344.  * a duplicate symbol warning is issued. If new segment == -1, this
  345.  * routine won't change a previously existing symbol. It will change
  346.  * to segment = -2 only if the segment was previously < 0.
  347.  */
  348. void symtab_add(const char * symbol, int segment, long offset)
  349. {
  350.     symtabEnt * ste;
  351.     ste = symtabFind(symtab, symbol);
  352.     if (ste)
  353.     {
  354. if (ste->segment >= 0) {
  355.     /*
  356.      * symbol previously defined
  357.      */
  358.     if (segment < 0) return;
  359.     fprintf (stderr, "warning: `%s' redefinedn", symbol);
  360.     return;
  361. }
  362. /*
  363.  * somebody wanted the symbol, and put an undefined symbol
  364.  * marker into the table
  365.  */
  366. if (segment == -1) return;
  367. /*
  368.  * we have more information now - update the symbol's entry
  369.  */
  370. ste->segment = segment;
  371. ste->offset = offset;
  372. ste->flags = 0;
  373. return;
  374.     }
  375.     /*
  376.      * this is the first declaration of this symbol
  377.      */
  378.     ste = malloc(sizeof(symtabEnt));
  379.     if (!ste) {
  380. fprintf(stderr, "ldrdf: out of memoryn");
  381. exit(1);
  382.     }
  383.     ste->name = strdup(symbol);
  384.     ste->segment = segment;
  385.     ste->offset = offset;
  386.     ste->flags = 0;
  387.     symtabInsert(symtab, ste);
  388. }
  389. /*
  390.  * symtab_get()
  391.  *
  392.  * Retrieves the values associated with a symbol. Undefined symbols
  393.  * are assumed to have -1:0 associated. Returns 1 if the symbol was
  394.  * successfully located.
  395.  */
  396. int symtab_get(const char * symbol, int * segment, long * offset)
  397. {
  398.     symtabEnt * ste = symtabFind(symtab, symbol);
  399.     if (!ste) {
  400. *segment = -1;
  401. *offset = 0;
  402. return 0;
  403.     }
  404.     else
  405.     {
  406. *segment = ste->segment;
  407. *offset = ste->offset;
  408. return 1;
  409.     }
  410. }
  411. /*
  412.  * add_library()
  413.  *
  414.  * checks that a library can be opened and is in the correct format,
  415.  * then adds it to the linked list of libraries.
  416.  */
  417. void add_library(const char * name)
  418. {
  419.     if (rdl_verify(name)) {
  420. rdl_perror("ldrdf", name);
  421. errorcount++;
  422. return;
  423.     }
  424.     if (! libraries)
  425.     {
  426. lastlib = libraries = malloc(sizeof(*libraries));
  427. if (! libraries) {
  428.     fprintf(stderr, "ldrdf: out of memoryn");
  429.     exit(1);
  430. }
  431.     }
  432.     else
  433.     {
  434. lastlib->next = malloc(sizeof(*libraries));
  435. if (!lastlib->next) {
  436.     fprintf(stderr, "ldrdf: out of memoryn");
  437.     exit(1);
  438. }
  439. lastlib = lastlib->next;
  440.     }
  441.     if (rdl_open(lastlib, name)) {
  442. rdl_perror("ldrdf", name);
  443. errorcount++;
  444. return;
  445.     }
  446. }
  447. /*
  448.  * search_libraries()
  449.  *
  450.  * scans through the list of libraries, attempting to match symbols
  451.  * defined in library modules against symbols that are referenced but
  452.  * not defined (segment = -1 in the symbol table)
  453.  *
  454.  * returns 1 if any extra library modules are included, indicating that
  455.  * another pass through the library list should be made (possibly).
  456.  */
  457. int search_libraries()
  458. {
  459.     struct librarynode * cur;
  460.     rdffile f;
  461.     int     i;
  462.     void    * header;
  463.     int     segment;
  464.     long    offset;
  465.     int     doneanything = 0, keepfile;
  466.     rdfheaderrec * hr;
  467.     cur = libraries;
  468.     while (cur)
  469.     {
  470. if (options.verbose > 2)
  471.     printf("scanning library `%s'...n", cur->name);
  472. for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++)
  473. {
  474.     if (options.verbose > 3)
  475. printf("  looking in module `%s'n", f.name);
  476.     header = malloc(f.header_len);
  477.     if (!header) {
  478. fprintf(stderr, "ldrdf: not enough memoryn");
  479. exit(1);
  480.     }
  481.     if (rdfloadseg(&f, RDOFF_HEADER, header)) {
  482. rdfperror("ldrdf", f.name);
  483. errorcount++;
  484. return 0;
  485.     }
  486.     
  487.     keepfile = 0;
  488.     while ((hr = rdfgetheaderrec (&f)))
  489.     {
  490.                 /* we're only interested in exports, so skip others: */
  491. if (hr->type != 3) continue; 
  492. /*
  493.  * Find the symbol in the symbol table. If the symbol isn't
  494.  * defined, we aren't interested, so go on to the next.
  495.  * If it is defined as anything but -1, we're also not
  496.  * interested. But if it is defined as -1, insert this
  497.  * module into the list of modules to use, and go
  498.  * immediately on to the next module...
  499.  */
  500. if (! symtab_get(hr->e.label, &segment, &offset) 
  501.     || segment != -1)
  502. {
  503.     continue;    
  504. }
  505. doneanything = 1;
  506. keepfile = 1;
  507. /*
  508.  * as there are undefined symbols, we can assume that
  509.  * there are modules on the module list by the time
  510.  * we get here.
  511.  */
  512. lastmodule->next = malloc(sizeof(*lastmodule->next));
  513. if (!lastmodule->next) {
  514.     fprintf(stderr, "ldrdf: not enough memoryn");
  515.     exit(1);
  516. }
  517. lastmodule = lastmodule->next;
  518. memcpy(&lastmodule->f, &f, sizeof(f));
  519. lastmodule->name = strdup(f.name);
  520. processmodule(f.name, lastmodule);
  521. break;
  522.     }
  523.     if (!keepfile)
  524. rdfclose(&f);     
  525. }
  526. if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
  527.     rdl_perror("ldrdf", cur->name);
  528. cur = cur->next;
  529.     }
  530.     return doneanything;
  531. }
  532. /*
  533.  * write_output()
  534.  *
  535.  * this takes the linked list of modules, and walks through it, merging
  536.  * all the modules into a single output module, and then writes this to a
  537.  * file.
  538.  */
  539. void write_output(const char * filename)
  540. {
  541.     FILE          * f = fopen(filename, "wb");
  542.     rdf_headerbuf * rdfheader = rdfnewheader();
  543.     struct modulenode * cur;
  544.     int   i, availableseg, seg, localseg, isrelative;
  545.     void   * header;
  546.     rdfheaderrec  * hr, newrec;
  547.     symtabEnt    * se;
  548.     segtab   segs;
  549.     long   offset;
  550.     byte    * data;
  551.     if (!f) {
  552. fprintf(stderr, "ldrdf: couldn't open %s for outputn", filename);
  553. exit(1);
  554.     }
  555.     if (!rdfheader) {
  556. fprintf(stderr, "ldrdf: out of memoryn");
  557. exit(1);
  558.     }
  559.     if (options.verbose)
  560. printf ("nbuilding output module (%d segments)n", nsegs);
  561.     
  562.     /*
  563.      * Allocate the memory for the segments. We may be better off
  564.      * building the output module one segment at a time when running
  565.      * under 16 bit DOS, but that would be a slower way of doing this.
  566.      * And you could always use DJGPP...
  567.      */
  568.     for (i = 0; i < nsegs; i++)
  569.     {
  570. outputseg[i].data = malloc(outputseg[i].length);
  571. if (!outputseg[i].data) {
  572.     fprintf(stderr, "ldrdf: out of memoryn");
  573.     exit(1);
  574. }
  575.     }
  576.     /*
  577.      * initialise availableseg, used to allocate segment numbers for
  578.      * imported and exported labels...
  579.      */
  580.     availableseg = nsegs;
  581.     /*
  582.      * Step through the modules, performing required actions on each one
  583.      */
  584.     for (cur = modules; cur; cur=cur->next)
  585.     {
  586. /*
  587.  * Read the actual segment contents into the correct places in
  588.  * the newly allocated segments
  589.  */
  590. for (i = 0; i < cur->f.nsegs; i++)
  591. {
  592.     int dest = cur->seginfo[i].dest_seg;
  593.     if (dest == -1) continue;
  594.     if (rdfloadseg(&cur->f, i, 
  595.    outputseg[dest].data + cur->seginfo[i].reloc))
  596.     {
  597. rdfperror("ldrdf", cur->name);
  598. exit(1);
  599.     }
  600. }
  601.  
  602. /*
  603.  * Perform fixups, and add new header records where required
  604.  */
  605. header = malloc(cur->f.header_len);
  606. if (!header) {
  607.     fprintf(stderr, "ldrdf: out of memoryn");
  608.     exit(1);
  609. }
  610. if (cur->f.header_loc)
  611.     rdfheaderrewind(&cur->f);
  612. else
  613.     if (rdfloadseg(&cur->f, RDOFF_HEADER, header))
  614.     {
  615. rdfperror("ldrdf", cur->name);
  616. exit(1);
  617.     }
  618. /*
  619.  * we need to create a local segment number -> location
  620.  * table for the segments in this module.
  621.  */
  622. init_seglocations(&segs);
  623. for (i = 0; i < cur->f.nsegs; i++)
  624. {
  625.     add_seglocation(&segs, cur->f.seg[i].number,
  626.     cur->seginfo[i].dest_seg, cur->seginfo[i].reloc);
  627. }
  628. /*
  629.  * and the BSS segment (doh!)
  630.  */
  631. add_seglocation (&segs, 2, 2, cur->bss_reloc);
  632. while ((hr = rdfgetheaderrec(&cur->f)))
  633. {
  634.     switch(hr->type) {
  635.     case 1: /* relocation record - need to do a fixup */
  636. /*
  637.  * First correct the offset stored in the segment from
  638.  * the start of the segment (which may well have changed).
  639.  *
  640.  * To do this we add to the number stored the relocation
  641.  * factor associated with the segment that contains the
  642.  * target segment.
  643.  *
  644.  * The relocation could be a relative relocation, in which
  645.  * case we have to first subtract the amount we've relocated
  646.  * the containing segment by.
  647.  */
  648. if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
  649. {
  650.     fprintf(stderr, "%s: reloc to undefined segment %04xn",
  651.     cur->name, (int) hr->r.refseg);
  652.     errorcount++;
  653.     break;
  654. }
  655. isrelative = (hr->r.segment & 64) == 64;
  656. hr->r.segment &= 63;
  657. if (hr->r.segment == 2 || 
  658.     (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1)
  659. {
  660.     fprintf(stderr, "%s: reloc from %s segment (%d)n", 
  661.     cur->name,
  662.     hr->r.segment == 2 ? "BSS" : "unknown",
  663.     hr->r.segment);
  664.     errorcount++;
  665.     break;
  666. }
  667. if (hr->r.length != 1 && hr->r.length != 2 && hr->r.length!=4)
  668. {
  669.     fprintf(stderr, "%s: nonstandard length reloc "
  670.     "(%d bytes)n", cur->name, hr->r.length);
  671.     errorcount++;
  672.     break;
  673. }
  674. /* 
  675.  * okay, now the relocation is in the segment pointed to by
  676.  * cur->seginfo[localseg], and we know everything else is
  677.  * okay to go ahead and do the relocation
  678.  */
  679. data = outputseg[cur->seginfo[localseg].dest_seg].data;
  680. data += cur->seginfo[localseg].reloc + hr->r.offset;
  681. /*
  682.  * data now points to the reference that needs
  683.  * relocation. Calculate the relocation factor.
  684.  * Factor is:
  685.  *      offset of referred object in segment [in offset]
  686.  * (- relocation of localseg, if ref is relative)
  687.  * For simplicity, the result is stored in 'offset'.
  688.  * Then add 'offset' onto the value at data.
  689.  */
  690. if (isrelative) offset -= cur->seginfo[localseg].reloc;
  691. switch (hr->r.length)
  692. {
  693. case 1:
  694.     offset += *data;
  695.     if (offset < -127 || offset > 128)
  696. fprintf(stderr, "warning: relocation out of range "
  697. "at %s(%02x:%08lx)n", cur->name,
  698. (int)hr->r.segment, hr->r.offset);
  699.     *data = (char) offset;
  700.     break;
  701. case 2:
  702.     offset += * (short *)data;
  703.     if (offset < -32767 || offset > 32768)
  704. fprintf(stderr, "warning: relocation out of range "
  705. "at %s(%02x:%08lx)n", cur->name,
  706. (int)hr->r.segment, hr->r.offset);
  707.     * (short *)data = (short) offset;
  708.     break;
  709. case 4:
  710.     * (long *)data += offset;
  711.     /* we can't easily detect overflow on this one */
  712.     break;
  713. }
  714. /*
  715.  * If the relocation was relative between two symbols in
  716.  * the same segment, then we're done.
  717.  *
  718.  * Otherwise, we need to output a new relocation record
  719.  * with the references updated segment and offset...
  720.  */
  721. if (! isrelative 
  722.     || cur->seginfo[localseg].dest_seg != seg)
  723. {
  724.     hr->r.segment = cur->seginfo[localseg].dest_seg;
  725.     hr->r.offset += cur->seginfo[localseg].reloc;
  726.     hr->r.refseg = seg;
  727.     rdfaddheader(rdfheader, hr);
  728. }
  729. break;
  730.     case 2: /* import symbol */
  731.     case 7:
  732. /*
  733.  * scan the global symbol table for the symbol
  734.  * and associate its location with the segment number 
  735.  * for this module
  736.  */
  737. se = symtabFind(symtab, hr->i.label);
  738. if (!se || se->segment == -1) {
  739.     if (options.warnUnresolved) {
  740. fprintf(stderr, "warning: unresolved reference to `%s'"
  741. " in module `%s'n", hr->i.label, cur->name);
  742.     }
  743.     /*
  744.      * we need to allocate a segment number for this
  745.      * symbol, and store it in the symbol table for
  746.      * future reference
  747.      */ 
  748.     if (!se) {
  749. se=malloc(sizeof(*se));
  750. if (!se) {
  751.     fprintf(stderr, "ldrdf: out of memoryn");
  752.     exit(1);
  753. }
  754. se->name = strdup(hr->i.label);
  755. se->flags = 0;
  756. se->segment = availableseg++;
  757. se->offset = 0;
  758. symtabInsert(symtab, se);
  759.     }
  760.     else {
  761. se->segment = availableseg++;
  762. se->offset = 0;
  763.     }
  764.     /*
  765.      * output a header record that imports it to the
  766.      * recently allocated segment number...
  767.      */
  768.     newrec = *hr;
  769.     newrec.i.segment = se->segment;
  770.     rdfaddheader(rdfheader, &newrec);
  771. }
  772. add_seglocation(&segs, hr->i.segment, se->segment, se->offset);
  773. break;
  774.     case 3: /* export symbol */
  775. /*
  776.  * need to insert an export for this symbol into the new
  777.  * header, unless we're stripping symbols [unless this
  778.  * symbol is in an explicit keep list]. *** FIXME ***
  779.  */
  780. if (options.strip)
  781.     break;
  782. if (hr->e.segment == 2) {
  783.     seg = 2;
  784.     offset = cur->bss_reloc;
  785. }
  786. else {
  787.     localseg = rdffindsegment(&cur->f, hr->e.segment);
  788.     if (localseg == -1) {
  789. fprintf(stderr, "%s: exported symbol `%s' from "
  790. "unrecognised segmentn", cur->name,
  791. hr->e.label);
  792. errorcount++;
  793. break;
  794.     }
  795.     offset = cur->seginfo[localseg].reloc;
  796.     seg = cur->seginfo[localseg].dest_seg;
  797. }
  798. hr->e.segment = seg;
  799. hr->e.offset += offset;
  800. rdfaddheader(rdfheader, hr);
  801. break;
  802.     case 6: /* segment fixup */
  803. /*
  804.  * modify the segment numbers if necessary, and
  805.  * pass straight through to the output module header
  806.  *
  807.  * *** FIXME ***
  808.  */
  809. if (hr->r.segment == 2) {
  810.     fprintf(stderr, "%s: segment fixup in BSS sectionn",
  811.     cur->name);
  812.     errorcount++;
  813.     break;
  814. }
  815. localseg = rdffindsegment(&cur->f, hr->r.segment);
  816. if (localseg == -1) {
  817.     fprintf(stderr, "%s: segment fixup in unrecognised"
  818.     " segment (%d)n", cur->name, hr->r.segment);
  819.     errorcount++;
  820.     break;
  821. }
  822. hr->r.segment = cur->seginfo[localseg].dest_seg;
  823. hr->r.offset += cur->seginfo[localseg].reloc;
  824. if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
  825. {
  826.     fprintf(stderr, "%s: segment fixup to undefined "
  827.     "segment %04xn", cur->name, (int)hr->r.refseg);
  828.     errorcount++;
  829.     break;
  830. }
  831. hr->r.refseg = seg;
  832. rdfaddheader(rdfheader, hr);
  833. break;
  834.     }
  835. }
  836. free(header);
  837. done_seglocations(&segs);
  838.    }
  839.     /*
  840.      * combined BSS reservation for the entire results
  841.      */
  842.     newrec.type = 5;
  843.     newrec.b.reclen = 4;
  844.     newrec.b.amount = bss_length;
  845.     rdfaddheader(rdfheader, &newrec);
  846.     /*
  847.      * Write the header
  848.      */
  849.     for (i = 0; i < nsegs; i++)
  850.     {
  851. if (i == 2) continue;
  852. rdfaddsegment (rdfheader, outputseg[i].length);
  853.     }
  854.     rdfwriteheader(f, rdfheader);
  855.     rdfdoneheader(rdfheader);
  856.     /*
  857.      * Step through the segments, one at a time, writing out into
  858.      * the output file
  859.      */
  860.     
  861.     for (i = 0; i < nsegs; i++)
  862.     {
  863. int16 s;
  864. long l;
  865. if (i == 2) continue;
  866. s = translateshort(outputseg[i].type);
  867. fwrite(&s, 2, 1, f);
  868. s = translateshort(outputseg[i].number);
  869. fwrite(&s, 2, 1, f);
  870. s = translateshort(outputseg[i].reserved);
  871. fwrite(&s, 2, 1, f);
  872. l = translatelong(outputseg[i].length);
  873. fwrite(&l, 4, 1, f);
  874. fwrite(outputseg[i].data, outputseg[i].length, 1, f);
  875.     }
  876.     fwrite("", 10, 1, f);
  877. }
  878. /* =========================================================================
  879.  * Main program
  880.  */
  881. void usage()
  882. {
  883.     printf("usage:n");
  884.     printf("   ldrdf [options] object modules ... [-llibrary ...]n");
  885.     printf("   ldrdf -rn");
  886.     printf("options:n");
  887.     printf("   -v[=n]    increases verbosity by 1, or sets it to nn");
  888.     printf("   -a nn     sets segment alignment value (default 16)n");
  889.     printf("   -s        strips exported symbolsn");
  890.     printf("   -x        warn about unresolved symbolsn");
  891.     printf("   -o name   write output in file 'name'n");
  892.     printf("n");
  893.     printf("Note: no library searching is performed. Please specify fulln");
  894.     printf("paths to all files referenced.n");
  895.     exit(0);
  896. }
  897. int main(int argc, char ** argv)
  898. {
  899.     char * outname = "aout.rdf";
  900.     int  moduleloaded = 0;
  901.     options.verbose = 0;
  902.     options.align = 16;
  903.     options.warnUnresolved = 0;
  904.     options.strip = 0;
  905.     
  906.     argc --, argv ++;
  907.     if (argc == 0) usage();
  908.     while (argc && **argv == '-' && argv[0][1] != 'l')
  909.     {
  910. switch(argv[0][1]) {
  911. case 'r':
  912.     printf("ldrdf (linker for RDF files) version " LDRDF_VERSION "n");
  913.     printf( _RDOFF_H "n");
  914.     exit(0);
  915. case 'v':
  916.     if (argv[0][2] == '=') {
  917. options.verbose = argv[0][3] - '0';
  918. if (options.verbose < 0 || options.verbose > 9) {
  919.     fprintf(stderr, "ldrdf: verbosity level must be a number"
  920.     " between 0 and 9n");
  921.     exit(1);
  922. }
  923.     }
  924.     else
  925. options.verbose++;
  926.     break;
  927. case 'a':
  928.     options.align = atoi(argv[1]);
  929.     if (options.align <= 0) {
  930. fprintf(stderr, 
  931. "ldrdf: -a expects a positive number argumentn");
  932. exit(1);
  933.     }
  934.     argv++, argc--;
  935.     break;
  936. case 's':
  937.     options.strip = 1;
  938.     break;
  939. case 'x':
  940.     options.warnUnresolved = 1;
  941.     break;
  942. case 'o':
  943.     outname = argv[1];
  944.     argv++, argc--;
  945.     break;
  946. default:
  947.     usage();
  948. }
  949. argv++, argc--;
  950.     }
  951.     if (options.verbose > 4) {
  952. printf("ldrdf invoked with options:n");
  953. printf("    section alignment: %d bytesn", options.align);
  954. printf("    output name: `%s'n", outname);
  955. if (options.strip)
  956.     printf("    strip symbolsn");
  957. if (options.warnUnresolved)
  958.     printf("    warn about unresolved symbolsn");
  959. printf("n");
  960.     }
  961.     symtab = symtabNew();
  962.     initsegments();
  963.     if (!symtab) {
  964. fprintf(stderr, "ldrdf: out of memoryn");
  965. exit(1);
  966.     }
  967.     while (argc)
  968.     {
  969. if (!strncmp(*argv, "-l", 2)) /* library */
  970.     add_library(*argv + 2);
  971. else {
  972.     loadmodule(*argv);
  973.     moduleloaded = 1;
  974. }
  975. argv++, argc--;
  976.     }
  977.     if (! moduleloaded) {
  978. printf("ldrdf: nothing to do. ldrdf -h for usagen");
  979. return 0;
  980.     }
  981.     
  982.     search_libraries();
  983.     if (options.verbose > 2)
  984.     {
  985. printf ("symbol table:n");
  986. symtabDump(symtab, stdout);
  987.     }
  988.     write_output(outname);
  989.     if (errorcount > 0)
  990. exit(1);
  991.     return 0;
  992. }