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