1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 1996-2014 The NASM Authors - All Rights Reserved
4  *   See the file AUTHORS included with the NASM distribution for
5  *   the specific copyright holders.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following
9  *   conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * ----------------------------------------------------------------------- */
33 
34 /*
35  * ldrdf.c - RDOFF Object File linker/loader main program.
36  */
37 
38 /*
39  * TODO:
40  * - enhance search of required export symbols in libraries (now depends
41  *   on modules order in library)
42  * - keep a cache of symbol names in each library module so
43  *   we don't have to constantly recheck the file
44  * - general performance improvements
45  *
46  * BUGS & LIMITATIONS: this program doesn't support multiple code, data
47  * or bss segments, therefore for 16 bit programs whose code, data or BSS
48  * segment exceeds 64K in size, it will not work. This program probably
49  * won't work if compiled by a 16 bit compiler. Try DJGPP if you're running
50  * under DOS. '#define STINGY_MEMORY' may help a little.
51  */
52 
53 #include "compiler.h"
54 
55 #include <stdio.h>
56 #include <stdlib.h>
57 
58 #include "rdfutils.h"
59 #include "symtab.h"
60 #include "collectn.h"
61 #include "rdlib.h"
62 #include "segtab.h"
63 #include "nasmlib.h"
64 
65 #define LDRDF_VERSION "1.08"
66 
67 /* #define STINGY_MEMORY */
68 
69 /* =======================================================================
70  * Types & macros that are private to this program
71  */
72 
73 struct segment_infonode {
74     int dest_seg;               /* output segment to be placed into, -1 to
75                                    skip linking this segment */
76     int32_t reloc;                 /* segment's relocation factor */
77 };
78 
79 struct modulenode {
80     rdffile f;                  /* the RDOFF file structure */
81     struct segment_infonode seginfo[RDF_MAXSEGS];       /* what are we doing
82                                                            with each segment? */
83     void *header;
84     char *name;
85     struct modulenode *next;
86     int32_t bss_reloc;
87 };
88 
89 #include "ldsegs.h"
90 
91 /* ==========================================================================
92  * Function prototypes of private utility functions
93  */
94 
95 void processmodule(const char *filename, struct modulenode *mod);
96 int allocnewseg(uint16_t type, uint16_t reserved);
97 int findsegment(uint16_t type, uint16_t reserved);
98 void symtab_add(const char *symbol, int segment, int32_t offset);
99 int symtab_get(const char *symbol, int *segment, int32_t *offset);
100 
101 /* =========================================================================
102  * Global data structures.
103  */
104 
105 /* a linked list of modules that will be included in the output */
106 struct modulenode *modules = NULL;
107 struct modulenode *lastmodule = NULL;
108 
109 /* a linked list of libraries to be searched for unresolved imported symbols */
110 struct librarynode *libraries = NULL;
111 struct librarynode *lastlib = NULL;
112 
113 /* the symbol table */
114 void *symtab = NULL;
115 
116 /* objects search path */
117 char *objpath = NULL;
118 
119 /* libraries search path */
120 char *libpath = NULL;
121 
122 /* file to embed as a generic record */
123 char *generic_rec_file = NULL;
124 
125 /* module name to be added at the beginning of output file */
126 char *modname_specified = NULL;
127 
128 /* the header of the output file, built up stage by stage */
129 rdf_headerbuf *newheader = NULL;
130 
131 /* The current state of segment allocation, including information about
132  * which output segment numbers have been allocated, and their types and
133  * amount of data which has already been allocated inside them.
134  */
135 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
136 int nsegs = 0;
137 int32_t bss_length;
138 
139 /* global options which affect how the program behaves */
140 struct ldrdfoptions {
141     int verbose;
142     int align;
143     int dynalink;
144     int strip;
145     int respfile;
146     int stderr_redir;
147     int objpath;
148     int libpath;
149 } options;
150 
151 int errorcount = 0;             /* determines main program exit status */
152 
153 /* =========================================================================
154  * Utility functions
155  */
156 
157 /*
158  * initsegments()
159  *
160  * sets up segments 0, 1, and 2, the initial code data and bss segments
161  */
initsegments(void)162 static void initsegments(void)
163 {
164     nsegs = 3;
165     outputseg[0].type = 1;
166     outputseg[0].number = 0;
167     outputseg[0].reserved = 0;
168     outputseg[0].length = 0;
169     outputseg[1].type = 2;
170     outputseg[1].number = 1;
171     outputseg[1].reserved = 0;
172     outputseg[1].length = 0;
173     outputseg[2].type = 0xFFFF; /* reserved segment type */
174     outputseg[2].number = 2;
175     outputseg[2].reserved = 0;
176     outputseg[2].length = 0;
177     bss_length = 0;
178 }
179 
180 /*
181  * loadmodule()
182  *
183  * Determine the characteristics of a module, and decide what to do with
184  * each segment it contains (including determining destination segments and
185  * relocation factors for segments that	are kept).
186  */
loadmodule(const char * filename)187 static void loadmodule(const char *filename)
188 {
189     if (options.verbose)
190         printf("loading `%s'\n", filename);
191 
192     /* allocate a new module entry on the end of the modules list */
193     if (!modules) {
194         modules = nasm_malloc(sizeof(*modules));
195         lastmodule = modules;
196     } else {
197         lastmodule->next = nasm_malloc(sizeof(*modules));
198         lastmodule = lastmodule->next;
199     }
200 
201     if (!lastmodule) {
202         fprintf(stderr, "ldrdf: out of memory\n");
203         exit(1);
204     }
205 
206     /* open the file using 'rdfopen', which returns nonzero on error */
207     if (rdfopen(&lastmodule->f, filename) != 0) {
208         rdfperror("ldrdf", filename);
209         exit(1);
210     }
211 
212     /*
213      * store information about the module, and determine what segments
214      * it contains, and what we should do with them (determine relocation
215      * factor if we decide to keep them)
216      */
217     lastmodule->header = NULL;
218     lastmodule->name = nasm_strdup(filename);
219     lastmodule->next = NULL;
220 
221     processmodule(filename, lastmodule);
222 }
223 
224 /*
225  * processmodule()
226  *
227  * step through each segment, determine what exactly we're doing with
228  * it, and if we intend to keep it, determine (a) which segment to
229  * put it in and (b) whereabouts in that segment it will end up.
230  * (b) is fairly easy, because we're now keeping track of how big each
231  * segment in our output file is...
232  */
processmodule(const char * filename,struct modulenode * mod)233 void processmodule(const char *filename, struct modulenode *mod)
234 {
235     struct segconfig sconf;
236     int seg, outseg;
237     void *header;
238     rdfheaderrec *hr;
239     int32_t bssamount = 0;
240     int bss_was_referenced = 0;
241 
242     memset(&sconf, 0, sizeof sconf);
243 
244     for (seg = 0; seg < mod->f.nsegs; seg++) {
245         /*
246          * get the segment configuration for this type from the segment
247          * table. getsegconfig() is a macro, defined in ldsegs.h.
248          */
249         getsegconfig(sconf, mod->f.seg[seg].type);
250 
251         if (options.verbose > 1) {
252             printf("%s %04x [%04x:%10s] ", filename,
253                    mod->f.seg[seg].number, mod->f.seg[seg].type,
254                    sconf.typedesc);
255         }
256         /*
257          * sconf->dowhat tells us what to do with a segment of this type.
258          */
259         switch (sconf.dowhat) {
260         case SEG_IGNORE:
261             /*
262              * Set destination segment to -1, to indicate that this segment
263              * should be ignored for the purpose of output, ie it is left
264              * out of the linked executable.
265              */
266             mod->seginfo[seg].dest_seg = -1;
267             if (options.verbose > 1)
268                 printf("IGNORED\n");
269             break;
270 
271         case SEG_NEWSEG:
272             /*
273              * The configuration tells us to create a new segment for
274              * each occurrence of this segment type.
275              */
276             outseg = allocnewseg(sconf.mergetype,
277                                  mod->f.seg[seg].reserved);
278             mod->seginfo[seg].dest_seg = outseg;
279             mod->seginfo[seg].reloc = 0;
280             outputseg[outseg].length = mod->f.seg[seg].length;
281             if (options.verbose > 1)
282                 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
283                        mod->seginfo[seg].reloc, mod->f.seg[seg].length);
284             break;
285 
286         case SEG_MERGE:
287             /*
288              * The configuration tells us to merge the segment with
289              * a previously existing segment of type 'sconf.mergetype',
290              * if one exists. Otherwise a new segment is created.
291              * This is handled transparently by 'findsegment()'.
292              */
293             outseg = findsegment(sconf.mergetype,
294                                  mod->f.seg[seg].reserved);
295             mod->seginfo[seg].dest_seg = outseg;
296 
297             /*
298              * We need to add alignment to these segments.
299              */
300             if (outputseg[outseg].length % options.align != 0)
301                 outputseg[outseg].length +=
302                     options.align -
303                     (outputseg[outseg].length % options.align);
304 
305             mod->seginfo[seg].reloc = outputseg[outseg].length;
306             outputseg[outseg].length += mod->f.seg[seg].length;
307 
308             if (options.verbose > 1)
309                 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
310                        mod->seginfo[seg].reloc, mod->f.seg[seg].length);
311         }
312 
313     }
314 
315     /*
316      * extract symbols from the header, and dump them into the
317      * symbol table
318      */
319     header = nasm_malloc(mod->f.header_len);
320     if (!header) {
321         fprintf(stderr, "ldrdf: not enough memory\n");
322         exit(1);
323     }
324     if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
325         rdfperror("ldrdf", filename);
326         exit(1);
327     }
328 
329     while ((hr = rdfgetheaderrec(&mod->f))) {
330         switch (hr->type) {
331         case RDFREC_IMPORT:    /* imported symbol */
332         case RDFREC_FARIMPORT:
333             /* Define with seg = -1 */
334             symtab_add(hr->i.label, -1, 0);
335             break;
336 
337         case RDFREC_GLOBAL:{   /* exported symbol */
338                 int destseg;
339                 int32_t destreloc;
340 
341                 if (hr->e.segment == 2) {
342                     bss_was_referenced = 1;
343                     destreloc = bss_length;
344                     if (destreloc % options.align != 0)
345                         destreloc +=
346                             options.align - (destreloc % options.align);
347                     destseg = 2;
348                 } else {
349                     if ((destseg =
350                          mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
351                         continue;
352                     destreloc = mod->seginfo[(int)hr->e.segment].reloc;
353                 }
354                 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
355                 break;
356             }
357 
358         case RDFREC_BSS:       /* BSS reservation */
359             /*
360              * first, amalgamate all BSS reservations in this module
361              * into one, because we allow this in the output format.
362              */
363             bssamount += hr->b.amount;
364             break;
365 
366         case RDFREC_COMMON:{   /* Common variable */
367                 symtabEnt *ste = symtabFind(symtab, hr->c.label);
368 
369                 /* Is the symbol already in the table? */
370                 if (ste)
371                     break;
372 
373                 /* Align the variable */
374                 if (bss_length % hr->c.align != 0)
375                     bss_length += hr->c.align - (bss_length % hr->c.align);
376                 if (options.verbose > 1) {
377                     printf("%s %04x common '%s' => 0002:%08"PRIx32" (+%04"PRIx32")\n",
378                            filename, hr->c.segment, hr->c.label,
379                            bss_length, hr->c.size);
380                 }
381 
382                 symtab_add(hr->c.label, 2, bss_length);
383                 mod->bss_reloc = bss_length;
384                 bss_length += hr->c.size;
385                 break;
386             }
387         }
388     }
389 
390     if (bssamount != 0 || bss_was_referenced) {
391         /*
392          * handle the BSS segment - first pad the existing bss length
393          * to the correct alignment, then store the length in bss_reloc
394          * for this module. Then add this module's BSS length onto
395          * bss_length.
396          */
397         if (bss_length % options.align != 0)
398             bss_length += options.align - (bss_length % options.align);
399 
400         mod->bss_reloc = bss_length;
401         if (options.verbose > 1) {
402             printf("%s 0002 [            BSS] => 0002:%08"PRIx32" (+%04"PRIx32")\n",
403                    filename, bss_length, bssamount);
404         }
405         bss_length += bssamount;
406     }
407 #ifdef STINGY_MEMORY
408     /*
409      * we free the header buffer here, to save memory later.
410      * this isn't efficient, but probably halves the memory usage
411      * of this program...
412      */
413     mod->f.header_loc = NULL;
414     nasm_free(header);
415 
416 #endif
417 
418 }
419 
420 /*
421  * Return 1 if a given module is in the list, 0 otherwise.
422  */
lookformodule(const char * name)423 static int lookformodule(const char *name)
424 {
425     struct modulenode *curr = modules;
426 
427     while (curr) {
428         if (!strcmp(name, curr->name))
429             return 1;
430         curr = curr->next;
431     }
432     return 0;
433 }
434 
435 /*
436  * allocnewseg()
437  * findsegment()
438  *
439  * These functions manipulate the array of output segments, and are used
440  * by processmodule(). allocnewseg() allocates a segment in the array,
441  * initialising it to be empty. findsegment() first scans the array for
442  * a segment of the type requested, and if one isn't found allocates a
443  * new one.
444  */
allocnewseg(uint16_t type,uint16_t reserved)445 int allocnewseg(uint16_t type, uint16_t reserved)
446 {
447     outputseg[nsegs].type = type;
448     outputseg[nsegs].number = nsegs;
449     outputseg[nsegs].reserved = reserved;
450     outputseg[nsegs].length = 0;
451     outputseg[nsegs].offset = 0;
452     outputseg[nsegs].data = NULL;
453 
454     return nsegs++;
455 }
456 
findsegment(uint16_t type,uint16_t reserved)457 int findsegment(uint16_t type, uint16_t reserved)
458 {
459     int i;
460 
461     for (i = 0; i < nsegs; i++)
462         if (outputseg[i].type == type)
463             return i;
464 
465     return allocnewseg(type, reserved);
466 }
467 
468 /*
469  * symtab_add()
470  *
471  * inserts a symbol into the global symbol table, which associates symbol
472  * names either with addresses, or a marker that the symbol hasn't been
473  * resolved yet, or possibly that the symbol has been defined as
474  * contained in a dynamic [load time/run time] linked library.
475  *
476  * segment = -1 => not yet defined
477  * segment = -2 => defined as dll symbol
478  *
479  * If the symbol is already defined, and the new segment >= 0, then
480  * if the original segment was < 0 the symbol is redefined, otherwise
481  * a duplicate symbol warning is issued. If new segment == -1, this
482  * routine won't change a previously existing symbol. It will change
483  * to segment = -2 only if the segment was previously < 0.
484  */
symtab_add(const char * symbol,int segment,int32_t offset)485 void symtab_add(const char *symbol, int segment, int32_t offset)
486 {
487     symtabEnt *ste;
488 
489     ste = symtabFind(symtab, symbol);
490     if (ste) {
491         if (ste->segment >= 0) {
492             /*
493              * symbol previously defined
494              */
495             if (segment < 0)
496                 return;
497             fprintf(error_file, "warning: `%s' redefined\n", symbol);
498             return;
499         }
500 
501         /*
502          * somebody wanted the symbol, and put an undefined symbol
503          * marker into the table
504          */
505         if (segment == -1)
506             return;
507         /*
508          * we have more information now - update the symbol's entry
509          */
510         ste->segment = segment;
511         ste->offset = offset;
512         ste->flags = 0;
513         return;
514     }
515     /*
516      * this is the first declaration of this symbol
517      */
518     ste = nasm_malloc(sizeof(symtabEnt));
519     if (!ste) {
520         fprintf(stderr, "ldrdf: out of memory\n");
521         exit(1);
522     }
523     ste->name = nasm_strdup(symbol);
524     ste->segment = segment;
525     ste->offset = offset;
526     ste->flags = 0;
527     symtabInsert(symtab, ste);
528 }
529 
530 /*
531  * symtab_get()
532  *
533  * Retrieves the values associated with a symbol. Undefined symbols
534  * are assumed to have -1:0 associated. Returns 1 if the symbol was
535  * successfully located.
536  */
symtab_get(const char * symbol,int * segment,int32_t * offset)537 int symtab_get(const char *symbol, int *segment, int32_t *offset)
538 {
539     symtabEnt *ste = symtabFind(symtab, symbol);
540     if (!ste) {
541         *segment = -1;
542         *offset = 0;
543         return 0;
544     } else {
545         *segment = ste->segment;
546         *offset = ste->offset;
547         return 1;
548     }
549 }
550 
551 /*
552  * add_library()
553  *
554  * checks that a library can be opened and is in the correct format,
555  * then adds it to the linked list of libraries.
556  */
add_library(const char * name)557 static void add_library(const char *name)
558 {
559     if (rdl_verify(name)) {
560         rdl_perror("ldrdf", name);
561         errorcount++;
562         return;
563     }
564     if (!libraries) {
565         lastlib = libraries = nasm_malloc(sizeof(*libraries));
566         if (!libraries) {
567             fprintf(stderr, "ldrdf: out of memory\n");
568             exit(1);
569         }
570     } else {
571         lastlib->next = nasm_malloc(sizeof(*libraries));
572         if (!lastlib->next) {
573             fprintf(stderr, "ldrdf: out of memory\n");
574             exit(1);
575         }
576         lastlib = lastlib->next;
577     }
578     lastlib->next = NULL;
579     if (rdl_open(lastlib, name)) {
580         rdl_perror("ldrdf", name);
581         errorcount++;
582         return;
583     }
584 }
585 
586 /*
587  * search_libraries()
588  *
589  * scans through the list of libraries, attempting to match symbols
590  * defined in library modules against symbols that are referenced but
591  * not defined (segment = -1 in the symbol table)
592  *
593  * returns 1 if any extra library modules are included, indicating that
594  * another pass through the library list should be made (possibly).
595  */
search_libraries(void)596 static int search_libraries(void)
597 {
598     struct librarynode *cur;
599     rdffile f;
600     int i;
601     void *header;
602     int segment;
603     int32_t offset;
604     int doneanything = 0, pass = 1, keepfile;
605     rdfheaderrec *hr;
606 
607     cur = libraries;
608 
609     while (cur) {
610         if (options.verbose > 2)
611             printf("scanning library `%s', pass %d...\n", cur->name, pass);
612 
613         for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
614             if (pass == 2 && lookformodule(f.name))
615                 continue;
616 
617             if (options.verbose > 3)
618                 printf("  looking in module `%s'\n", f.name);
619 
620             header = nasm_malloc(f.header_len);
621             if (!header) {
622                 fprintf(stderr, "ldrdf: not enough memory\n");
623                 exit(1);
624             }
625             if (rdfloadseg(&f, RDOFF_HEADER, header)) {
626                 rdfperror("ldrdf", f.name);
627                 errorcount++;
628                 return 0;
629             }
630 
631             keepfile = 0;
632 
633             while ((hr = rdfgetheaderrec(&f))) {
634                 /* We're only interested in exports, so skip others */
635                 if (hr->type != RDFREC_GLOBAL)
636                     continue;
637 
638                 /*
639                  * If the symbol is marked as SYM_GLOBAL, somebody will be
640                  * definitely interested in it..
641                  */
642                 if ((hr->e.flags & SYM_GLOBAL) == 0) {
643                     /*
644                      * otherwise the symbol is just public. Find it in
645                      * the symbol table. If the symbol isn't defined, we
646                      * aren't interested, so go on to the next.
647                      * If it is defined as anything but -1, we're also not
648                      * interested. But if it is defined as -1, insert this
649                      * module into the list of modules to use, and go
650                      * immediately on to the next module...
651                      */
652                     if (!symtab_get(hr->e.label, &segment, &offset)
653                         || segment != -1)
654                         continue;
655                 }
656 
657                 doneanything = 1;
658                 keepfile = 1;
659 
660                 /*
661                  * as there are undefined symbols, we can assume that
662                  * there are modules on the module list by the time
663                  * we get here.
664                  */
665                 lastmodule->next = nasm_malloc(sizeof(*lastmodule->next));
666                 if (!lastmodule->next) {
667                     fprintf(stderr, "ldrdf: not enough memory\n");
668                     exit(1);
669                 }
670                 lastmodule = lastmodule->next;
671                 memcpy(&lastmodule->f, &f, sizeof(f));
672                 lastmodule->name = nasm_strdup(f.name);
673                 lastmodule->next = NULL;
674                 processmodule(f.name, lastmodule);
675                 break;
676             }
677             if (!keepfile) {
678                 nasm_free(f.name);
679                 f.name = NULL;
680                 f.fp = NULL;
681             }
682         }
683         if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
684             rdl_perror("ldrdf", cur->name);
685 
686         cur = cur->next;
687         if (cur == NULL && pass == 1) {
688             cur = libraries;
689             pass++;
690         }
691     }
692 
693     return doneanything;
694 }
695 
696 /*
697  * write_output()
698  *
699  * this takes the linked list of modules, and walks through it, merging
700  * all the modules into a single output module, and then writes this to a
701  * file.
702  */
write_output(const char * filename)703 static void write_output(const char *filename)
704 {
705     FILE *f;
706     rdf_headerbuf *rdfheader;
707     struct modulenode *cur;
708     int i, n, availableseg, seg, localseg, isrelative;
709     void *header;
710     rdfheaderrec *hr, newrec;
711     symtabEnt *se;
712     segtab segs;
713     int32_t offset;
714     uint8_t *data;
715 
716     if ((f = fopen(filename, "wb")) == NULL) {
717         fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
718         exit(1);
719     }
720     if ((rdfheader = rdfnewheader()) == NULL) {
721         fprintf(stderr, "ldrdf: out of memory\n");
722         exit(1);
723     }
724 
725     /*
726      * If '-g' option was given, first record in output file will be a
727      * `generic' record, filled with a given file content.
728      * This can be useful, for example, when constructing multiboot
729      * compliant kernels.
730      */
731     if (generic_rec_file) {
732         FILE *ff;
733 
734         if (options.verbose)
735             printf("\nadding generic record from binary file %s\n",
736                    generic_rec_file);
737 
738         hr = (rdfheaderrec *) nasm_malloc(sizeof(struct GenericRec));
739         if ((ff = fopen(generic_rec_file, "r")) == NULL) {
740             fprintf(stderr, "ldrdf: couldn't open %s for input\n",
741                     generic_rec_file);
742             exit(1);
743         }
744         n = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
745         fseek(ff, 0, SEEK_END);
746         if (ftell(ff) > (long)sizeof(hr->g.data)) {
747             fprintf(error_file,
748                     "warning: maximum generic record size is %u, "
749 		    "rest of file ignored\n",
750                     (unsigned int)sizeof(hr->g.data));
751         }
752         fclose(ff);
753 
754         hr->g.type = RDFREC_GENERIC;
755         hr->g.reclen = n;
756         rdfaddheader(rdfheader, hr);
757         nasm_free(hr);
758     }
759 
760     /*
761      * Add module name record if `-mn' option was given
762      */
763     if (modname_specified) {
764 	n = strlen(modname_specified);
765 
766 	if ((n < 1) || (n >= MODLIB_NAME_MAX)) {
767             fprintf(stderr, "ldrdf: invalid length of module name `%s'\n",
768 		modname_specified);
769             exit(1);
770         }
771 
772         if (options.verbose)
773             printf("\nadding module name record %s\n", modname_specified);
774 
775         hr = (rdfheaderrec *) nasm_malloc(sizeof(struct ModRec));
776 	hr->m.type = RDFREC_MODNAME;
777         hr->m.reclen = n + 1;
778         strcpy(hr->m.modname, modname_specified);
779         rdfaddheader(rdfheader, hr);
780         nasm_free(hr);
781     }
782 
783 
784     if (options.verbose)
785         printf("\nbuilding output module (%d segments)\n", nsegs);
786 
787     /*
788      * Allocate the memory for the segments. We may be better off
789      * building the output module one segment at a time when running
790      * under 16 bit DOS, but that would be a slower way of doing this.
791      * And you could always use DJGPP...
792      */
793     for (i = 0; i < nsegs; i++) {
794         outputseg[i].data = NULL;
795         if (!outputseg[i].length)
796             continue;
797         outputseg[i].data = nasm_malloc(outputseg[i].length);
798         if (!outputseg[i].data) {
799             fprintf(stderr, "ldrdf: out of memory\n");
800             exit(1);
801         }
802     }
803 
804     /*
805      * initialise availableseg, used to allocate segment numbers for
806      * imported and exported labels...
807      */
808     availableseg = nsegs;
809 
810     /*
811      * Step through the modules, performing required actions on each one
812      */
813     for (cur = modules; cur; cur = cur->next) {
814         /*
815          * Read the actual segment contents into the correct places in
816          * the newly allocated segments
817          */
818 
819         for (i = 0; i < cur->f.nsegs; i++) {
820             int dest = cur->seginfo[i].dest_seg;
821 
822             if (dest == -1)
823                 continue;
824             if (rdfloadseg(&cur->f, i,
825                            outputseg[dest].data + cur->seginfo[i].reloc)) {
826                 rdfperror("ldrdf", cur->name);
827                 exit(1);
828             }
829         }
830 
831         /*
832          * Perform fixups, and add new header records where required
833          */
834 
835         header = nasm_malloc(cur->f.header_len);
836         if (!header) {
837             fprintf(stderr, "ldrdf: out of memory\n");
838             exit(1);
839         }
840 
841         if (cur->f.header_loc)
842             rdfheaderrewind(&cur->f);
843         else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
844             rdfperror("ldrdf", cur->name);
845             exit(1);
846         }
847 
848         /*
849          * we need to create a local segment number -> location
850          * table for the segments in this module.
851          */
852         init_seglocations(&segs);
853         for (i = 0; i < cur->f.nsegs; i++) {
854             add_seglocation(&segs, cur->f.seg[i].number,
855                             cur->seginfo[i].dest_seg,
856                             cur->seginfo[i].reloc);
857         }
858         /*
859          * and the BSS segment (doh!)
860          */
861         add_seglocation(&segs, 2, 2, cur->bss_reloc);
862 
863         while ((hr = rdfgetheaderrec(&cur->f))) {
864             switch (hr->type) {
865             case RDFREC_RELOC: /* relocation record - need to do a fixup */
866                 /*
867                  * First correct the offset stored in the segment from
868                  * the start of the segment (which may well have changed).
869                  *
870                  * To do this we add to the number stored the relocation
871                  * factor associated with the segment that contains the
872                  * target segment.
873                  *
874                  * The relocation could be a relative relocation, in which
875                  * case we have to first subtract the amount we've relocated
876                  * the containing segment by.
877                  */
878                 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
879                     fprintf(stderr,
880                             "%s: reloc to undefined segment %04x\n",
881                             cur->name, (int)hr->r.refseg);
882                     errorcount++;
883                     break;
884                 }
885 
886                 isrelative =
887                     (hr->r.segment & RDOFF_RELATIVEMASK) ==
888                     RDOFF_RELATIVEMASK;
889                 hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
890 
891                 if (hr->r.segment == 2 ||
892                     (localseg =
893                      rdffindsegment(&cur->f, hr->r.segment)) == -1) {
894                     fprintf(stderr, "%s: reloc from %s segment (%d)\n",
895                             cur->name,
896                             hr->r.segment == 2 ? "BSS" : "unknown",
897                             hr->r.segment);
898                     errorcount++;
899                     break;
900                 }
901 
902                 if (hr->r.length != 1 && hr->r.length != 2 &&
903                     hr->r.length != 4) {
904                     fprintf(stderr, "%s: nonstandard length reloc "
905                             "(%d bytes)\n", cur->name, hr->r.length);
906                     errorcount++;
907                     break;
908                 }
909 
910                 /*
911                  * okay, now the relocation is in the segment pointed to by
912                  * cur->seginfo[localseg], and we know everything else is
913                  * okay to go ahead and do the relocation
914                  */
915                 data = outputseg[cur->seginfo[localseg].dest_seg].data;
916                 data += cur->seginfo[localseg].reloc + hr->r.offset;
917 
918                 /*
919                  * data now points to the reference that needs
920                  * relocation. Calculate the relocation factor.
921                  * Factor is:
922                  *      offset of referred object in segment [in offset]
923                  *      (- relocation of localseg, if ref is relative)
924                  * For simplicity, the result is stored in 'offset'.
925                  * Then add 'offset' onto the value at data.
926                  */
927 
928                 if (isrelative)
929                     offset -= cur->seginfo[localseg].reloc;
930                 switch (hr->r.length) {
931                 case 1:
932                     offset += *data;
933                     if (offset < -127 || offset > 128)
934                         fprintf(error_file,
935                                 "warning: relocation out of range "
936                                 "at %s(%02x:%08"PRIx32")\n", cur->name,
937                                 (int)hr->r.segment, hr->r.offset);
938                     *data = (char)offset;
939                     break;
940                 case 2:
941                     offset += *(int16_t *)data;
942                     if (offset < -32767 || offset > 32768)
943                         fprintf(error_file,
944                                 "warning: relocation out of range "
945                                 "at %s(%02x:%08"PRIx32")\n", cur->name,
946                                 (int)hr->r.segment, hr->r.offset);
947                     *(int16_t *)data = (int16_t)offset;
948                     break;
949                 case 4:
950                     *(int32_t *)data += offset;
951                     /* we can't easily detect overflow on this one */
952                     break;
953                 }
954 
955                 /*
956                  * If the relocation was relative between two symbols in
957                  * the same segment, then we're done.
958                  *
959                  * Otherwise, we need to output a new relocation record
960                  * with the references updated segment and offset...
961                  */
962                 if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
963                     hr->r.segment = cur->seginfo[localseg].dest_seg;
964                     hr->r.offset += cur->seginfo[localseg].reloc;
965                     hr->r.refseg = seg;
966                     if (isrelative)
967                         hr->r.segment += RDOFF_RELATIVEMASK;
968                     rdfaddheader(rdfheader, hr);
969                 }
970                 break;
971 
972             case RDFREC_IMPORT:        /* import symbol */
973             case RDFREC_FARIMPORT:
974                 /*
975                  * scan the global symbol table for the symbol
976                  * and associate its location with the segment number
977                  * for this module
978                  */
979                 se = symtabFind(symtab, hr->i.label);
980                 if (!se || se->segment == -1) {
981                     if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
982                         fprintf(error_file,
983                                 "error: unresolved reference to `%s'"
984                                 " in module `%s'\n", hr->i.label,
985                                 cur->name);
986                         errorcount++;
987                     }
988                     /*
989                      * we need to allocate a segment number for this
990                      * symbol, and store it in the symbol table for
991                      * future reference
992                      */
993                     if (!se) {
994                         se = nasm_malloc(sizeof(*se));
995                         if (!se) {
996                             fprintf(stderr, "ldrdf: out of memory\n");
997                             exit(1);
998                         }
999                         se->name = nasm_strdup(hr->i.label);
1000                         se->flags = 0;
1001                         se->segment = availableseg++;
1002                         se->offset = 0;
1003                         symtabInsert(symtab, se);
1004                     } else {
1005                         se->segment = availableseg++;
1006                         se->offset = 0;
1007                     }
1008                     /*
1009                      * output a header record that imports it to the
1010                      * recently allocated segment number...
1011                      */
1012                     newrec = *hr;
1013                     newrec.i.segment = se->segment;
1014                     rdfaddheader(rdfheader, &newrec);
1015                 }
1016 
1017                 add_seglocation(&segs, hr->i.segment, se->segment,
1018                                 se->offset);
1019                 break;
1020 
1021             case RDFREC_GLOBAL:        /* export symbol */
1022                 /*
1023                  * need to insert an export for this symbol into the new
1024                  * header, unless we're stripping symbols. Even if we're
1025                  * stripping, put the symbol if it's marked as SYM_GLOBAL.
1026                  */
1027                 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
1028                     break;
1029 
1030                 if (hr->e.segment == 2) {
1031                     seg = 2;
1032                     offset = cur->bss_reloc;
1033                 } else {
1034                     localseg = rdffindsegment(&cur->f, hr->e.segment);
1035                     if (localseg == -1) {
1036                         fprintf(stderr, "%s: exported symbol `%s' from "
1037                                 "unrecognised segment\n", cur->name,
1038                                 hr->e.label);
1039                         errorcount++;
1040                         break;
1041                     }
1042                     offset = cur->seginfo[localseg].reloc;
1043                     seg = cur->seginfo[localseg].dest_seg;
1044                 }
1045 
1046                 hr->e.segment = seg;
1047                 hr->e.offset += offset;
1048                 rdfaddheader(rdfheader, hr);
1049                 break;
1050 
1051             case RDFREC_MODNAME:       /* module name */
1052                 /*
1053                  * Insert module name record if export symbols
1054                  * are not stripped.
1055                  * If module name begins with '$' - insert it anyway.
1056                  */
1057                 if (options.strip && hr->m.modname[0] != '$')
1058                     break;
1059                 rdfaddheader(rdfheader, hr);
1060                 break;
1061 
1062             case RDFREC_DLL:   /* DLL name */
1063                 /*
1064                  * Insert DLL name if it begins with '$'
1065                  */
1066                 if (hr->d.libname[0] != '$')
1067                     break;
1068                 rdfaddheader(rdfheader, hr);
1069                 break;
1070 
1071             case RDFREC_SEGRELOC:      /* segment fixup */
1072                 /*
1073                  * modify the segment numbers if necessary, and
1074                  * pass straight through to the output module header
1075                  *
1076                  * *** FIXME ***
1077                  */
1078                 if (hr->r.segment == 2) {
1079                     fprintf(stderr, "%s: segment fixup in BSS section\n",
1080                             cur->name);
1081                     errorcount++;
1082                     break;
1083                 }
1084                 localseg = rdffindsegment(&cur->f, hr->r.segment);
1085                 if (localseg == -1) {
1086                     fprintf(stderr, "%s: segment fixup in unrecognised"
1087                             " segment (%d)\n", cur->name, hr->r.segment);
1088                     errorcount++;
1089                     break;
1090                 }
1091                 hr->r.segment = cur->seginfo[localseg].dest_seg;
1092                 hr->r.offset += cur->seginfo[localseg].reloc;
1093 
1094                 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
1095                     fprintf(stderr, "%s: segment fixup to undefined "
1096                             "segment %04x\n", cur->name,
1097                             (int)hr->r.refseg);
1098                     errorcount++;
1099                     break;
1100                 }
1101                 hr->r.refseg = seg;
1102                 rdfaddheader(rdfheader, hr);
1103                 break;
1104 
1105             case RDFREC_COMMON:        /* Common variable */
1106                 /* Is this symbol already in the table? */
1107                 se = symtabFind(symtab, hr->c.label);
1108                 if (!se) {
1109                     printf("%s is not in symtab yet\n", hr->c.label);
1110                     break;
1111                 }
1112                 /* Add segment location */
1113                 add_seglocation(&segs, hr->c.segment, se->segment,
1114                                 se->offset);
1115                 break;
1116             }
1117         }
1118 
1119         nasm_free(header);
1120         done_seglocations(&segs);
1121 
1122     }
1123 
1124     /*
1125      * combined BSS reservation for the entire results
1126      */
1127     newrec.type = RDFREC_BSS;
1128     newrec.b.reclen = 4;
1129     newrec.b.amount = bss_length;
1130     rdfaddheader(rdfheader, &newrec);
1131 
1132     /*
1133      * Write the header
1134      */
1135     for (i = 0; i < nsegs; i++) {
1136         if (i == 2)
1137             continue;
1138         rdfaddsegment(rdfheader, outputseg[i].length);
1139     }
1140 
1141     rdfwriteheader(f, rdfheader);
1142     rdfdoneheader(rdfheader);
1143 
1144     /*
1145      * Step through the segments, one at a time, writing out into
1146      * the output file
1147      */
1148     for (i = 0; i < nsegs; i++) {
1149         if (i == 2)
1150             continue;
1151 
1152         fwriteint16_t(outputseg[i].type, f);
1153         fwriteint16_t(outputseg[i].number, f);
1154         fwriteint16_t(outputseg[i].reserved, f);
1155         fwriteint32_t(outputseg[i].length, f);
1156         nasm_write(outputseg[i].data, outputseg[i].length, f);
1157     }
1158 
1159     fwritezero(10, f);
1160 }
1161 
1162 /* =========================================================================
1163  * Main program
1164  */
1165 
usage(void)1166 static void usage(void)
1167 {
1168     printf("usage:\n"
1169            "   ldrdf [options] object modules ... [-llibrary ...]\n"
1170            "   ldrdf -r\n"
1171            "options:\n"
1172            "   -v[=n]          increase verbosity by 1, or set it to n\n"
1173            "   -a nn           set segment alignment value (default 16)\n"
1174            "   -s              strip public symbols\n"
1175            "   -dy             Unix-style dynamic linking\n"
1176            "   -o name         write output in file 'name'\n"
1177            "   -j path         specify objects search path\n"
1178            "   -L path         specify libraries search path\n"
1179            "   -g file         embed 'file' as a first header record with type 'generic'\n"
1180            "   -mn name        add module name record at the beginning of output file\n");
1181     exit(0);
1182 }
1183 
main(int argc,char ** argv)1184 int main(int argc, char **argv)
1185 {
1186     char *outname = "aout.rdf";
1187     int moduleloaded = 0;
1188     char *respstrings[128] = { 0, };
1189 
1190     rdoff_init();
1191 
1192     options.verbose = 0;
1193     options.align = 16;
1194     options.dynalink = 0;
1195     options.strip = 0;
1196 
1197     error_file = stderr;
1198 
1199     argc--, argv++;
1200     if (argc == 0)
1201         usage();
1202     while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
1203         switch (argv[0][1]) {
1204         case 'r':
1205             printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
1206                    "\n");
1207             printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
1208             exit(0);
1209         case 'v':
1210             if (argv[0][2] == '=') {
1211                 options.verbose = argv[0][3] - '0';
1212                 if (options.verbose < 0 || options.verbose > 9) {
1213                     fprintf(stderr,
1214                             "ldrdf: verbosity level must be a number"
1215                             " between 0 and 9\n");
1216                     exit(1);
1217                 }
1218             } else
1219                 options.verbose++;
1220             break;
1221         case 'a':
1222             options.align = atoi(argv[1]);
1223             if (options.align <= 0) {
1224                 fprintf(stderr,
1225                         "ldrdf: -a expects a positive number argument\n");
1226                 exit(1);
1227             }
1228             argv++, argc--;
1229             break;
1230         case 's':
1231             options.strip = 1;
1232             break;
1233         case 'd':
1234             if (argv[0][2] == 'y')
1235                 options.dynalink = 1;
1236             break;
1237         case 'm':
1238             if (argv[0][2] == 'n') {
1239                 modname_specified = argv[1];
1240 		argv++, argc--;
1241 		if (!argc) {
1242 		    fprintf(stderr, "ldrdf: -mn expects a module name\n");
1243 		    exit(1);
1244 		}
1245 	    }
1246             break;
1247         case 'o':
1248             outname = argv[1];
1249             argv++, argc--;
1250             break;
1251         case 'j':
1252             if (!objpath) {
1253                 options.objpath = 1;
1254                 objpath = argv[1];
1255                 argv++, argc--;
1256                 break;
1257             } else {
1258                 fprintf(stderr,
1259                         "ldrdf: more than one objects search path specified\n");
1260                 exit(1);
1261             }
1262         case 'L':
1263             if (!libpath) {
1264                 options.libpath = 1;
1265                 libpath = argv[1];
1266                 argv++, argc--;
1267                 break;
1268             } else {
1269                 fprintf(stderr,
1270                         "ldrdf: more than one libraries search path specified\n");
1271                 exit(1);
1272             }
1273         case '@':{
1274                 int i = 0;
1275                 char buf[256];
1276                 FILE *f;
1277 
1278                 options.respfile = 1;
1279                 if (argv[1] != NULL)
1280                     f = fopen(argv[1], "r");
1281                 else {
1282                     fprintf(stderr,
1283                             "ldrdf: no response file name specified\n");
1284                     exit(1);
1285                 }
1286 
1287                 if (f == NULL) {
1288                     fprintf(stderr,
1289                             "ldrdf: unable to open response file\n");
1290                     exit(1);
1291                 }
1292 
1293                 argv++, argc--;
1294                 while (fgets(buf, sizeof(buf), f) != NULL) {
1295                     char *p;
1296                     if (buf[0] == '\n')
1297                         continue;
1298                     if ((p = strchr(buf, '\n')) != NULL)
1299                         *p = '\0';
1300                     if (i >= 128) {
1301                         fclose(f);
1302                         fprintf(stderr, "ldrdf: too many input files\n");
1303                         exit(1);
1304                     }
1305                     *(respstrings + i) = nasm_strdup(buf);
1306                     argc++, i++;
1307                 }
1308                 fclose(f);
1309                 break;
1310             }
1311         case '2':
1312             options.stderr_redir = 1;
1313             error_file = stdout;
1314             break;
1315         case 'g':
1316             generic_rec_file = argv[1];
1317             argv++, argc--;
1318             if (!argc) {
1319 		fprintf(stderr, "ldrdf: -g expects a file name\n");
1320 		exit(1);
1321 	    }
1322             break;
1323         default:
1324             usage();
1325         }
1326         argv++, argc--;
1327     }
1328 
1329     if (options.verbose > 4) {
1330         printf("ldrdf invoked with options:\n");
1331         printf("    section alignment: %d bytes\n", options.align);
1332         printf("    output name: `%s'\n", outname);
1333         if (options.strip)
1334             printf("    strip symbols\n");
1335         if (options.dynalink)
1336             printf("    Unix-style dynamic linking\n");
1337         if (options.objpath)
1338             printf("    objects search path: %s\n", objpath);
1339         if (options.libpath)
1340             printf("    libraries search path: %s\n", libpath);
1341         printf("\n");
1342     }
1343 
1344     symtab = symtabNew();
1345     initsegments();
1346 
1347     if (!symtab) {
1348         fprintf(stderr, "ldrdf: out of memory\n");
1349         exit(1);
1350     }
1351 
1352     while (argc) {
1353         if (!*argv)
1354             argv = respstrings;
1355         if (!*argv)
1356             break;
1357         if (!strncmp(*argv, "-l", 2)) {
1358             if (libpath && (argv[0][2] != '/'))
1359                 add_library(nasm_strcat(libpath, *argv + 2));
1360             else
1361                 add_library(*argv + 2);
1362         } else {
1363             if (objpath && (argv[0][0] != '/'))
1364                 loadmodule(nasm_strcat(objpath, *argv));
1365             else
1366                 loadmodule(*argv);
1367             moduleloaded = 1;
1368         }
1369         argv++, argc--;
1370     }
1371 
1372     if (!moduleloaded) {
1373         printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1374         return 0;
1375     }
1376 
1377     search_libraries();
1378 
1379     if (options.verbose > 2) {
1380         printf("symbol table:\n");
1381         symtabDump(symtab, stdout);
1382     }
1383 
1384     write_output(outname);
1385 
1386     if (errorcount > 0) {
1387         remove(outname);
1388         exit(1);
1389     }
1390     return 0;
1391 }
1392