output: outmac -- Fix few nits during merge
[nasm.git] / rdoff / ldrdf.c
blobff543f93f96a115b7611b1d01bbadb5b915c3f11
1 /* ----------------------------------------------------------------------- *
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.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
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.
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.
32 * ----------------------------------------------------------------------- */
35 * ldrdf.c - RDOFF Object File linker/loader main program.
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
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.
53 #include "compiler.h"
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
59 #define RDOFF_UTILS
61 #include "rdoff.h"
62 #include "symtab.h"
63 #include "collectn.h"
64 #include "rdlib.h"
65 #include "segtab.h"
66 #include "nasmlib.h"
68 #define LDRDF_VERSION "1.08"
70 /* #define STINGY_MEMORY */
72 /* =======================================================================
73 * Types & macros that are private to this program
76 struct segment_infonode {
77 int dest_seg; /* output segment to be placed into, -1 to
78 skip linking this segment */
79 int32_t reloc; /* segment's relocation factor */
82 struct modulenode {
83 rdffile f; /* the RDOFF file structure */
84 struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
85 with each segment? */
86 void *header;
87 char *name;
88 struct modulenode *next;
89 int32_t bss_reloc;
92 #include "ldsegs.h"
94 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
95 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
97 /* ==========================================================================
98 * Function prototypes of private utility functions
101 void processmodule(const char *filename, struct modulenode *mod);
102 int allocnewseg(uint16_t type, uint16_t reserved);
103 int findsegment(uint16_t type, uint16_t reserved);
104 void symtab_add(const char *symbol, int segment, int32_t offset);
105 int symtab_get(const char *symbol, int *segment, int32_t *offset);
107 /* =========================================================================
108 * Global data structures.
111 /* a linked list of modules that will be included in the output */
112 struct modulenode *modules = NULL;
113 struct modulenode *lastmodule = NULL;
115 /* a linked list of libraries to be searched for unresolved imported symbols */
116 struct librarynode *libraries = NULL;
117 struct librarynode *lastlib = NULL;
119 /* the symbol table */
120 void *symtab = NULL;
122 /* objects search path */
123 char *objpath = NULL;
125 /* libraries search path */
126 char *libpath = NULL;
128 /* file to embed as a generic record */
129 char *generic_rec_file = NULL;
131 /* module name to be added at the beginning of output file */
132 char *modname_specified = NULL;
134 /* error file */
135 static FILE *error_file;
137 /* the header of the output file, built up stage by stage */
138 rdf_headerbuf *newheader = NULL;
140 /* The current state of segment allocation, including information about
141 * which output segment numbers have been allocated, and their types and
142 * amount of data which has already been allocated inside them.
144 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
145 int nsegs = 0;
146 int32_t bss_length;
148 /* global options which affect how the program behaves */
149 struct ldrdfoptions {
150 int verbose;
151 int align;
152 int dynalink;
153 int strip;
154 int respfile;
155 int stderr_redir;
156 int objpath;
157 int libpath;
158 } options;
160 int errorcount = 0; /* determines main program exit status */
162 /* =========================================================================
163 * Utility functions
167 * initsegments()
169 * sets up segments 0, 1, and 2, the initial code data and bss segments
171 static void initsegments(void)
173 nsegs = 3;
174 outputseg[0].type = 1;
175 outputseg[0].number = 0;
176 outputseg[0].reserved = 0;
177 outputseg[0].length = 0;
178 outputseg[1].type = 2;
179 outputseg[1].number = 1;
180 outputseg[1].reserved = 0;
181 outputseg[1].length = 0;
182 outputseg[2].type = 0xFFFF; /* reserved segment type */
183 outputseg[2].number = 2;
184 outputseg[2].reserved = 0;
185 outputseg[2].length = 0;
186 bss_length = 0;
190 * loadmodule()
192 * Determine the characteristics of a module, and decide what to do with
193 * each segment it contains (including determining destination segments and
194 * relocation factors for segments that are kept).
196 static void loadmodule(const char *filename)
198 if (options.verbose)
199 printf("loading `%s'\n", filename);
201 /* allocate a new module entry on the end of the modules list */
202 if (!modules) {
203 modules = malloc(sizeof(*modules));
204 lastmodule = modules;
205 } else {
206 lastmodule->next = malloc(sizeof(*modules));
207 lastmodule = lastmodule->next;
210 if (!lastmodule) {
211 fprintf(stderr, "ldrdf: out of memory\n");
212 exit(1);
215 /* open the file using 'rdfopen', which returns nonzero on error */
216 if (rdfopen(&lastmodule->f, filename) != 0) {
217 rdfperror("ldrdf", filename);
218 exit(1);
222 * store information about the module, and determine what segments
223 * it contains, and what we should do with them (determine relocation
224 * factor if we decide to keep them)
226 lastmodule->header = NULL;
227 lastmodule->name = strdup(filename);
228 lastmodule->next = NULL;
230 processmodule(filename, lastmodule);
234 * processmodule()
236 * step through each segment, determine what exactly we're doing with
237 * it, and if we intend to keep it, determine (a) which segment to
238 * put it in and (b) whereabouts in that segment it will end up.
239 * (b) is fairly easy, because we're now keeping track of how big each
240 * segment in our output file is...
242 void processmodule(const char *filename, struct modulenode *mod)
244 struct segconfig sconf;
245 int seg, outseg;
246 void *header;
247 rdfheaderrec *hr;
248 int32_t bssamount = 0;
249 int bss_was_referenced = 0;
251 memset(&sconf, 0, sizeof sconf);
253 for (seg = 0; seg < mod->f.nsegs; seg++) {
255 * get the segment configuration for this type from the segment
256 * table. getsegconfig() is a macro, defined in ldsegs.h.
258 getsegconfig(sconf, mod->f.seg[seg].type);
260 if (options.verbose > 1) {
261 printf("%s %04x [%04x:%10s] ", filename,
262 mod->f.seg[seg].number, mod->f.seg[seg].type,
263 sconf.typedesc);
266 * sconf->dowhat tells us what to do with a segment of this type.
268 switch (sconf.dowhat) {
269 case SEG_IGNORE:
271 * Set destination segment to -1, to indicate that this segment
272 * should be ignored for the purpose of output, ie it is left
273 * out of the linked executable.
275 mod->seginfo[seg].dest_seg = -1;
276 if (options.verbose > 1)
277 printf("IGNORED\n");
278 break;
280 case SEG_NEWSEG:
282 * The configuration tells us to create a new segment for
283 * each occurrence of this segment type.
285 outseg = allocnewseg(sconf.mergetype,
286 mod->f.seg[seg].reserved);
287 mod->seginfo[seg].dest_seg = outseg;
288 mod->seginfo[seg].reloc = 0;
289 outputseg[outseg].length = mod->f.seg[seg].length;
290 if (options.verbose > 1)
291 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
292 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
293 break;
295 case SEG_MERGE:
297 * The configuration tells us to merge the segment with
298 * a previously existing segment of type 'sconf.mergetype',
299 * if one exists. Otherwise a new segment is created.
300 * This is handled transparently by 'findsegment()'.
302 outseg = findsegment(sconf.mergetype,
303 mod->f.seg[seg].reserved);
304 mod->seginfo[seg].dest_seg = outseg;
307 * We need to add alignment to these segments.
309 if (outputseg[outseg].length % options.align != 0)
310 outputseg[outseg].length +=
311 options.align -
312 (outputseg[outseg].length % options.align);
314 mod->seginfo[seg].reloc = outputseg[outseg].length;
315 outputseg[outseg].length += mod->f.seg[seg].length;
317 if (options.verbose > 1)
318 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
319 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
325 * extract symbols from the header, and dump them into the
326 * symbol table
328 header = malloc(mod->f.header_len);
329 if (!header) {
330 fprintf(stderr, "ldrdf: not enough memory\n");
331 exit(1);
333 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
334 rdfperror("ldrdf", filename);
335 exit(1);
338 while ((hr = rdfgetheaderrec(&mod->f))) {
339 switch (hr->type) {
340 case RDFREC_IMPORT: /* imported symbol */
341 case RDFREC_FARIMPORT:
342 /* Define with seg = -1 */
343 symtab_add(hr->i.label, -1, 0);
344 break;
346 case RDFREC_GLOBAL:{ /* exported symbol */
347 int destseg;
348 int32_t destreloc;
350 if (hr->e.segment == 2) {
351 bss_was_referenced = 1;
352 destreloc = bss_length;
353 if (destreloc % options.align != 0)
354 destreloc +=
355 options.align - (destreloc % options.align);
356 destseg = 2;
357 } else {
358 if ((destseg =
359 mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
360 continue;
361 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
363 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
364 break;
367 case RDFREC_BSS: /* BSS reservation */
369 * first, amalgamate all BSS reservations in this module
370 * into one, because we allow this in the output format.
372 bssamount += hr->b.amount;
373 break;
375 case RDFREC_COMMON:{ /* Common variable */
376 symtabEnt *ste = symtabFind(symtab, hr->c.label);
378 /* Is the symbol already in the table? */
379 if (ste)
380 break;
382 /* Align the variable */
383 if (bss_length % hr->c.align != 0)
384 bss_length += hr->c.align - (bss_length % hr->c.align);
385 if (options.verbose > 1) {
386 printf("%s %04x common '%s' => 0002:%08"PRIx32" (+%04"PRIx32")\n",
387 filename, hr->c.segment, hr->c.label,
388 bss_length, hr->c.size);
391 symtab_add(hr->c.label, 2, bss_length);
392 mod->bss_reloc = bss_length;
393 bss_length += hr->c.size;
394 break;
399 if (bssamount != 0 || bss_was_referenced) {
401 * handle the BSS segment - first pad the existing bss length
402 * to the correct alignment, then store the length in bss_reloc
403 * for this module. Then add this module's BSS length onto
404 * bss_length.
406 if (bss_length % options.align != 0)
407 bss_length += options.align - (bss_length % options.align);
409 mod->bss_reloc = bss_length;
410 if (options.verbose > 1) {
411 printf("%s 0002 [ BSS] => 0002:%08"PRIx32" (+%04"PRIx32")\n",
412 filename, bss_length, bssamount);
414 bss_length += bssamount;
416 #ifdef STINGY_MEMORY
418 * we free the header buffer here, to save memory later.
419 * this isn't efficient, but probably halves the memory usage
420 * of this program...
422 mod->f.header_loc = NULL;
423 free(header);
425 #endif
430 * Return 1 if a given module is in the list, 0 otherwise.
432 static int lookformodule(const char *name)
434 struct modulenode *curr = modules;
436 while (curr) {
437 if (!strcmp(name, curr->name))
438 return 1;
439 curr = curr->next;
441 return 0;
445 * allocnewseg()
446 * findsegment()
448 * These functions manipulate the array of output segments, and are used
449 * by processmodule(). allocnewseg() allocates a segment in the array,
450 * initialising it to be empty. findsegment() first scans the array for
451 * a segment of the type requested, and if one isn't found allocates a
452 * new one.
454 int allocnewseg(uint16_t type, uint16_t reserved)
456 outputseg[nsegs].type = type;
457 outputseg[nsegs].number = nsegs;
458 outputseg[nsegs].reserved = reserved;
459 outputseg[nsegs].length = 0;
460 outputseg[nsegs].offset = 0;
461 outputseg[nsegs].data = NULL;
463 return nsegs++;
466 int findsegment(uint16_t type, uint16_t reserved)
468 int i;
470 for (i = 0; i < nsegs; i++)
471 if (outputseg[i].type == type)
472 return i;
474 return allocnewseg(type, reserved);
478 * symtab_add()
480 * inserts a symbol into the global symbol table, which associates symbol
481 * names either with addresses, or a marker that the symbol hasn't been
482 * resolved yet, or possibly that the symbol has been defined as
483 * contained in a dynamic [load time/run time] linked library.
485 * segment = -1 => not yet defined
486 * segment = -2 => defined as dll symbol
488 * If the symbol is already defined, and the new segment >= 0, then
489 * if the original segment was < 0 the symbol is redefined, otherwise
490 * a duplicate symbol warning is issued. If new segment == -1, this
491 * routine won't change a previously existing symbol. It will change
492 * to segment = -2 only if the segment was previously < 0.
494 void symtab_add(const char *symbol, int segment, int32_t offset)
496 symtabEnt *ste;
498 ste = symtabFind(symtab, symbol);
499 if (ste) {
500 if (ste->segment >= 0) {
502 * symbol previously defined
504 if (segment < 0)
505 return;
506 fprintf(error_file, "warning: `%s' redefined\n", symbol);
507 return;
511 * somebody wanted the symbol, and put an undefined symbol
512 * marker into the table
514 if (segment == -1)
515 return;
517 * we have more information now - update the symbol's entry
519 ste->segment = segment;
520 ste->offset = offset;
521 ste->flags = 0;
522 return;
525 * this is the first declaration of this symbol
527 ste = malloc(sizeof(symtabEnt));
528 if (!ste) {
529 fprintf(stderr, "ldrdf: out of memory\n");
530 exit(1);
532 ste->name = strdup(symbol);
533 ste->segment = segment;
534 ste->offset = offset;
535 ste->flags = 0;
536 symtabInsert(symtab, ste);
540 * symtab_get()
542 * Retrieves the values associated with a symbol. Undefined symbols
543 * are assumed to have -1:0 associated. Returns 1 if the symbol was
544 * successfully located.
546 int symtab_get(const char *symbol, int *segment, int32_t *offset)
548 symtabEnt *ste = symtabFind(symtab, symbol);
549 if (!ste) {
550 *segment = -1;
551 *offset = 0;
552 return 0;
553 } else {
554 *segment = ste->segment;
555 *offset = ste->offset;
556 return 1;
561 * add_library()
563 * checks that a library can be opened and is in the correct format,
564 * then adds it to the linked list of libraries.
566 static void add_library(const char *name)
568 if (rdl_verify(name)) {
569 rdl_perror("ldrdf", name);
570 errorcount++;
571 return;
573 if (!libraries) {
574 lastlib = libraries = malloc(sizeof(*libraries));
575 if (!libraries) {
576 fprintf(stderr, "ldrdf: out of memory\n");
577 exit(1);
579 } else {
580 lastlib->next = malloc(sizeof(*libraries));
581 if (!lastlib->next) {
582 fprintf(stderr, "ldrdf: out of memory\n");
583 exit(1);
585 lastlib = lastlib->next;
587 lastlib->next = NULL;
588 if (rdl_open(lastlib, name)) {
589 rdl_perror("ldrdf", name);
590 errorcount++;
591 return;
596 * search_libraries()
598 * scans through the list of libraries, attempting to match symbols
599 * defined in library modules against symbols that are referenced but
600 * not defined (segment = -1 in the symbol table)
602 * returns 1 if any extra library modules are included, indicating that
603 * another pass through the library list should be made (possibly).
605 static int search_libraries(void)
607 struct librarynode *cur;
608 rdffile f;
609 int i;
610 void *header;
611 int segment;
612 int32_t offset;
613 int doneanything = 0, pass = 1, keepfile;
614 rdfheaderrec *hr;
616 cur = libraries;
618 while (cur) {
619 if (options.verbose > 2)
620 printf("scanning library `%s', pass %d...\n", cur->name, pass);
622 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
623 if (pass == 2 && lookformodule(f.name))
624 continue;
626 if (options.verbose > 3)
627 printf(" looking in module `%s'\n", f.name);
629 header = malloc(f.header_len);
630 if (!header) {
631 fprintf(stderr, "ldrdf: not enough memory\n");
632 exit(1);
634 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
635 rdfperror("ldrdf", f.name);
636 errorcount++;
637 return 0;
640 keepfile = 0;
642 while ((hr = rdfgetheaderrec(&f))) {
643 /* We're only interested in exports, so skip others */
644 if (hr->type != RDFREC_GLOBAL)
645 continue;
648 * If the symbol is marked as SYM_GLOBAL, somebody will be
649 * definitely interested in it..
651 if ((hr->e.flags & SYM_GLOBAL) == 0) {
653 * otherwise the symbol is just public. Find it in
654 * the symbol table. If the symbol isn't defined, we
655 * aren't interested, so go on to the next.
656 * If it is defined as anything but -1, we're also not
657 * interested. But if it is defined as -1, insert this
658 * module into the list of modules to use, and go
659 * immediately on to the next module...
661 if (!symtab_get(hr->e.label, &segment, &offset)
662 || segment != -1)
663 continue;
666 doneanything = 1;
667 keepfile = 1;
670 * as there are undefined symbols, we can assume that
671 * there are modules on the module list by the time
672 * we get here.
674 lastmodule->next = malloc(sizeof(*lastmodule->next));
675 if (!lastmodule->next) {
676 fprintf(stderr, "ldrdf: not enough memory\n");
677 exit(1);
679 lastmodule = lastmodule->next;
680 memcpy(&lastmodule->f, &f, sizeof(f));
681 lastmodule->name = strdup(f.name);
682 lastmodule->next = NULL;
683 processmodule(f.name, lastmodule);
684 break;
686 if (!keepfile) {
687 free(f.name);
688 f.name = NULL;
689 f.fp = NULL;
692 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
693 rdl_perror("ldrdf", cur->name);
695 cur = cur->next;
696 if (cur == NULL && pass == 1) {
697 cur = libraries;
698 pass++;
702 return doneanything;
706 * write_output()
708 * this takes the linked list of modules, and walks through it, merging
709 * all the modules into a single output module, and then writes this to a
710 * file.
712 static void write_output(const char *filename)
714 FILE *f;
715 rdf_headerbuf *rdfheader;
716 struct modulenode *cur;
717 int i, n, availableseg, seg, localseg, isrelative;
718 void *header;
719 rdfheaderrec *hr, newrec;
720 symtabEnt *se;
721 segtab segs;
722 int32_t offset;
723 uint8_t *data;
725 if ((f = fopen(filename, "wb")) == NULL) {
726 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
727 exit(1);
729 if ((rdfheader = rdfnewheader()) == NULL) {
730 fprintf(stderr, "ldrdf: out of memory\n");
731 exit(1);
735 * If '-g' option was given, first record in output file will be a
736 * `generic' record, filled with a given file content.
737 * This can be useful, for example, when constructing multiboot
738 * compliant kernels.
740 if (generic_rec_file) {
741 FILE *ff;
743 if (options.verbose)
744 printf("\nadding generic record from binary file %s\n",
745 generic_rec_file);
747 hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec));
748 if ((ff = fopen(generic_rec_file, "r")) == NULL) {
749 fprintf(stderr, "ldrdf: couldn't open %s for input\n",
750 generic_rec_file);
751 exit(1);
753 n = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
754 fseek(ff, 0, SEEK_END);
755 if (ftell(ff) > (long)sizeof(hr->g.data)) {
756 fprintf(error_file,
757 "warning: maximum generic record size is %u, "
758 "rest of file ignored\n",
759 (unsigned int)sizeof(hr->g.data));
761 fclose(ff);
763 hr->g.type = RDFREC_GENERIC;
764 hr->g.reclen = n;
765 rdfaddheader(rdfheader, hr);
766 free(hr);
770 * Add module name record if `-mn' option was given
772 if (modname_specified) {
773 n = strlen(modname_specified);
775 if ((n < 1) || (n >= MODLIB_NAME_MAX)) {
776 fprintf(stderr, "ldrdf: invalid length of module name `%s'\n",
777 modname_specified);
778 exit(1);
781 if (options.verbose)
782 printf("\nadding module name record %s\n", modname_specified);
784 hr = (rdfheaderrec *) malloc(sizeof(struct ModRec));
785 hr->m.type = RDFREC_MODNAME;
786 hr->m.reclen = n + 1;
787 strcpy(hr->m.modname, modname_specified);
788 rdfaddheader(rdfheader, hr);
789 free(hr);
793 if (options.verbose)
794 printf("\nbuilding output module (%d segments)\n", nsegs);
797 * Allocate the memory for the segments. We may be better off
798 * building the output module one segment at a time when running
799 * under 16 bit DOS, but that would be a slower way of doing this.
800 * And you could always use DJGPP...
802 for (i = 0; i < nsegs; i++) {
803 outputseg[i].data = NULL;
804 if (!outputseg[i].length)
805 continue;
806 outputseg[i].data = malloc(outputseg[i].length);
807 if (!outputseg[i].data) {
808 fprintf(stderr, "ldrdf: out of memory\n");
809 exit(1);
814 * initialise availableseg, used to allocate segment numbers for
815 * imported and exported labels...
817 availableseg = nsegs;
820 * Step through the modules, performing required actions on each one
822 for (cur = modules; cur; cur = cur->next) {
824 * Read the actual segment contents into the correct places in
825 * the newly allocated segments
828 for (i = 0; i < cur->f.nsegs; i++) {
829 int dest = cur->seginfo[i].dest_seg;
831 if (dest == -1)
832 continue;
833 if (rdfloadseg(&cur->f, i,
834 outputseg[dest].data + cur->seginfo[i].reloc)) {
835 rdfperror("ldrdf", cur->name);
836 exit(1);
841 * Perform fixups, and add new header records where required
844 header = malloc(cur->f.header_len);
845 if (!header) {
846 fprintf(stderr, "ldrdf: out of memory\n");
847 exit(1);
850 if (cur->f.header_loc)
851 rdfheaderrewind(&cur->f);
852 else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
853 rdfperror("ldrdf", cur->name);
854 exit(1);
858 * we need to create a local segment number -> location
859 * table for the segments in this module.
861 init_seglocations(&segs);
862 for (i = 0; i < cur->f.nsegs; i++) {
863 add_seglocation(&segs, cur->f.seg[i].number,
864 cur->seginfo[i].dest_seg,
865 cur->seginfo[i].reloc);
868 * and the BSS segment (doh!)
870 add_seglocation(&segs, 2, 2, cur->bss_reloc);
872 while ((hr = rdfgetheaderrec(&cur->f))) {
873 switch (hr->type) {
874 case RDFREC_RELOC: /* relocation record - need to do a fixup */
876 * First correct the offset stored in the segment from
877 * the start of the segment (which may well have changed).
879 * To do this we add to the number stored the relocation
880 * factor associated with the segment that contains the
881 * target segment.
883 * The relocation could be a relative relocation, in which
884 * case we have to first subtract the amount we've relocated
885 * the containing segment by.
887 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
888 fprintf(stderr,
889 "%s: reloc to undefined segment %04x\n",
890 cur->name, (int)hr->r.refseg);
891 errorcount++;
892 break;
895 isrelative =
896 (hr->r.segment & RDOFF_RELATIVEMASK) ==
897 RDOFF_RELATIVEMASK;
898 hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
900 if (hr->r.segment == 2 ||
901 (localseg =
902 rdffindsegment(&cur->f, hr->r.segment)) == -1) {
903 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
904 cur->name,
905 hr->r.segment == 2 ? "BSS" : "unknown",
906 hr->r.segment);
907 errorcount++;
908 break;
911 if (hr->r.length != 1 && hr->r.length != 2 &&
912 hr->r.length != 4) {
913 fprintf(stderr, "%s: nonstandard length reloc "
914 "(%d bytes)\n", cur->name, hr->r.length);
915 errorcount++;
916 break;
920 * okay, now the relocation is in the segment pointed to by
921 * cur->seginfo[localseg], and we know everything else is
922 * okay to go ahead and do the relocation
924 data = outputseg[cur->seginfo[localseg].dest_seg].data;
925 data += cur->seginfo[localseg].reloc + hr->r.offset;
928 * data now points to the reference that needs
929 * relocation. Calculate the relocation factor.
930 * Factor is:
931 * offset of referred object in segment [in offset]
932 * (- relocation of localseg, if ref is relative)
933 * For simplicity, the result is stored in 'offset'.
934 * Then add 'offset' onto the value at data.
937 if (isrelative)
938 offset -= cur->seginfo[localseg].reloc;
939 switch (hr->r.length) {
940 case 1:
941 offset += *data;
942 if (offset < -127 || offset > 128)
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 *data = (char)offset;
948 break;
949 case 2:
950 offset += *(int16_t *)data;
951 if (offset < -32767 || offset > 32768)
952 fprintf(error_file,
953 "warning: relocation out of range "
954 "at %s(%02x:%08"PRIx32")\n", cur->name,
955 (int)hr->r.segment, hr->r.offset);
956 *(int16_t *)data = (int16_t)offset;
957 break;
958 case 4:
959 *(int32_t *)data += offset;
960 /* we can't easily detect overflow on this one */
961 break;
965 * If the relocation was relative between two symbols in
966 * the same segment, then we're done.
968 * Otherwise, we need to output a new relocation record
969 * with the references updated segment and offset...
971 if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
972 hr->r.segment = cur->seginfo[localseg].dest_seg;
973 hr->r.offset += cur->seginfo[localseg].reloc;
974 hr->r.refseg = seg;
975 if (isrelative)
976 hr->r.segment += RDOFF_RELATIVEMASK;
977 rdfaddheader(rdfheader, hr);
979 break;
981 case RDFREC_IMPORT: /* import symbol */
982 case RDFREC_FARIMPORT:
984 * scan the global symbol table for the symbol
985 * and associate its location with the segment number
986 * for this module
988 se = symtabFind(symtab, hr->i.label);
989 if (!se || se->segment == -1) {
990 if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
991 fprintf(error_file,
992 "error: unresolved reference to `%s'"
993 " in module `%s'\n", hr->i.label,
994 cur->name);
995 errorcount++;
998 * we need to allocate a segment number for this
999 * symbol, and store it in the symbol table for
1000 * future reference
1002 if (!se) {
1003 se = malloc(sizeof(*se));
1004 if (!se) {
1005 fprintf(stderr, "ldrdf: out of memory\n");
1006 exit(1);
1008 se->name = strdup(hr->i.label);
1009 se->flags = 0;
1010 se->segment = availableseg++;
1011 se->offset = 0;
1012 symtabInsert(symtab, se);
1013 } else {
1014 se->segment = availableseg++;
1015 se->offset = 0;
1018 * output a header record that imports it to the
1019 * recently allocated segment number...
1021 newrec = *hr;
1022 newrec.i.segment = se->segment;
1023 rdfaddheader(rdfheader, &newrec);
1026 add_seglocation(&segs, hr->i.segment, se->segment,
1027 se->offset);
1028 break;
1030 case RDFREC_GLOBAL: /* export symbol */
1032 * need to insert an export for this symbol into the new
1033 * header, unless we're stripping symbols. Even if we're
1034 * stripping, put the symbol if it's marked as SYM_GLOBAL.
1036 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
1037 break;
1039 if (hr->e.segment == 2) {
1040 seg = 2;
1041 offset = cur->bss_reloc;
1042 } else {
1043 localseg = rdffindsegment(&cur->f, hr->e.segment);
1044 if (localseg == -1) {
1045 fprintf(stderr, "%s: exported symbol `%s' from "
1046 "unrecognised segment\n", cur->name,
1047 hr->e.label);
1048 errorcount++;
1049 break;
1051 offset = cur->seginfo[localseg].reloc;
1052 seg = cur->seginfo[localseg].dest_seg;
1055 hr->e.segment = seg;
1056 hr->e.offset += offset;
1057 rdfaddheader(rdfheader, hr);
1058 break;
1060 case RDFREC_MODNAME: /* module name */
1062 * Insert module name record if export symbols
1063 * are not stripped.
1064 * If module name begins with '$' - insert it anyway.
1066 if (options.strip && hr->m.modname[0] != '$')
1067 break;
1068 rdfaddheader(rdfheader, hr);
1069 break;
1071 case RDFREC_DLL: /* DLL name */
1073 * Insert DLL name if it begins with '$'
1075 if (hr->d.libname[0] != '$')
1076 break;
1077 rdfaddheader(rdfheader, hr);
1078 break;
1080 case RDFREC_SEGRELOC: /* segment fixup */
1082 * modify the segment numbers if necessary, and
1083 * pass straight through to the output module header
1085 * *** FIXME ***
1087 if (hr->r.segment == 2) {
1088 fprintf(stderr, "%s: segment fixup in BSS section\n",
1089 cur->name);
1090 errorcount++;
1091 break;
1093 localseg = rdffindsegment(&cur->f, hr->r.segment);
1094 if (localseg == -1) {
1095 fprintf(stderr, "%s: segment fixup in unrecognised"
1096 " segment (%d)\n", cur->name, hr->r.segment);
1097 errorcount++;
1098 break;
1100 hr->r.segment = cur->seginfo[localseg].dest_seg;
1101 hr->r.offset += cur->seginfo[localseg].reloc;
1103 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
1104 fprintf(stderr, "%s: segment fixup to undefined "
1105 "segment %04x\n", cur->name,
1106 (int)hr->r.refseg);
1107 errorcount++;
1108 break;
1110 hr->r.refseg = seg;
1111 rdfaddheader(rdfheader, hr);
1112 break;
1114 case RDFREC_COMMON: /* Common variable */
1115 /* Is this symbol already in the table? */
1116 se = symtabFind(symtab, hr->c.label);
1117 if (!se) {
1118 printf("%s is not in symtab yet\n", hr->c.label);
1119 break;
1121 /* Add segment location */
1122 add_seglocation(&segs, hr->c.segment, se->segment,
1123 se->offset);
1124 break;
1128 free(header);
1129 done_seglocations(&segs);
1134 * combined BSS reservation for the entire results
1136 newrec.type = RDFREC_BSS;
1137 newrec.b.reclen = 4;
1138 newrec.b.amount = bss_length;
1139 rdfaddheader(rdfheader, &newrec);
1142 * Write the header
1144 for (i = 0; i < nsegs; i++) {
1145 if (i == 2)
1146 continue;
1147 rdfaddsegment(rdfheader, outputseg[i].length);
1150 rdfwriteheader(f, rdfheader);
1151 rdfdoneheader(rdfheader);
1154 * Step through the segments, one at a time, writing out into
1155 * the output file
1157 for (i = 0; i < nsegs; i++) {
1158 uint16_t s;
1159 int32_t l;
1161 if (i == 2)
1162 continue;
1164 s = translateint16_t(outputseg[i].type);
1165 fwrite(&s, 2, 1, f);
1166 s = translateint16_t(outputseg[i].number);
1167 fwrite(&s, 2, 1, f);
1168 s = translateint16_t(outputseg[i].reserved);
1169 fwrite(&s, 2, 1, f);
1170 l = translateint32_t(outputseg[i].length);
1171 fwrite(&l, 4, 1, f);
1173 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1176 fwritezero(10, f);
1179 /* =========================================================================
1180 * Main program
1183 static void usage(void)
1185 printf("usage:\n"
1186 " ldrdf [options] object modules ... [-llibrary ...]\n"
1187 " ldrdf -r\n"
1188 "options:\n"
1189 " -v[=n] increase verbosity by 1, or set it to n\n"
1190 " -a nn set segment alignment value (default 16)\n"
1191 " -s strip public symbols\n"
1192 " -dy Unix-style dynamic linking\n"
1193 " -o name write output in file 'name'\n"
1194 " -j path specify objects search path\n"
1195 " -L path specify libraries search path\n"
1196 " -g file embed 'file' as a first header record with type 'generic'\n"
1197 " -mn name add module name record at the beginning of output file\n");
1198 exit(0);
1201 int main(int argc, char **argv)
1203 char *outname = "aout.rdf";
1204 int moduleloaded = 0;
1205 char *respstrings[128] = { 0, };
1207 options.verbose = 0;
1208 options.align = 16;
1209 options.dynalink = 0;
1210 options.strip = 0;
1212 error_file = stderr;
1214 argc--, argv++;
1215 if (argc == 0)
1216 usage();
1217 while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
1218 switch (argv[0][1]) {
1219 case 'r':
1220 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
1221 "\n");
1222 printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
1223 exit(0);
1224 case 'v':
1225 if (argv[0][2] == '=') {
1226 options.verbose = argv[0][3] - '0';
1227 if (options.verbose < 0 || options.verbose > 9) {
1228 fprintf(stderr,
1229 "ldrdf: verbosity level must be a number"
1230 " between 0 and 9\n");
1231 exit(1);
1233 } else
1234 options.verbose++;
1235 break;
1236 case 'a':
1237 options.align = atoi(argv[1]);
1238 if (options.align <= 0) {
1239 fprintf(stderr,
1240 "ldrdf: -a expects a positive number argument\n");
1241 exit(1);
1243 argv++, argc--;
1244 break;
1245 case 's':
1246 options.strip = 1;
1247 break;
1248 case 'd':
1249 if (argv[0][2] == 'y')
1250 options.dynalink = 1;
1251 break;
1252 case 'm':
1253 if (argv[0][2] == 'n') {
1254 modname_specified = argv[1];
1255 argv++, argc--;
1256 if (!argc) {
1257 fprintf(stderr, "ldrdf: -mn expects a module name\n");
1258 exit(1);
1261 break;
1262 case 'o':
1263 outname = argv[1];
1264 argv++, argc--;
1265 break;
1266 case 'j':
1267 if (!objpath) {
1268 options.objpath = 1;
1269 objpath = argv[1];
1270 argv++, argc--;
1271 break;
1272 } else {
1273 fprintf(stderr,
1274 "ldrdf: more than one objects search path specified\n");
1275 exit(1);
1277 case 'L':
1278 if (!libpath) {
1279 options.libpath = 1;
1280 libpath = argv[1];
1281 argv++, argc--;
1282 break;
1283 } else {
1284 fprintf(stderr,
1285 "ldrdf: more than one libraries search path specified\n");
1286 exit(1);
1288 case '@':{
1289 int i = 0;
1290 char buf[256];
1291 FILE *f;
1293 options.respfile = 1;
1294 if (argv[1] != NULL)
1295 f = fopen(argv[1], "r");
1296 else {
1297 fprintf(stderr,
1298 "ldrdf: no response file name specified\n");
1299 exit(1);
1302 if (f == NULL) {
1303 fprintf(stderr,
1304 "ldrdf: unable to open response file\n");
1305 exit(1);
1308 argv++, argc--;
1309 while (fgets(buf, sizeof(buf), f) != NULL) {
1310 char *p;
1311 if (buf[0] == '\n')
1312 continue;
1313 if ((p = strchr(buf, '\n')) != NULL)
1314 *p = '\0';
1315 if (i >= 128) {
1316 fclose(f);
1317 fprintf(stderr, "ldrdf: too many input files\n");
1318 exit(1);
1320 *(respstrings + i) = newstr(buf);
1321 argc++, i++;
1323 fclose(f);
1324 break;
1326 case '2':
1327 options.stderr_redir = 1;
1328 error_file = stdout;
1329 break;
1330 case 'g':
1331 generic_rec_file = argv[1];
1332 argv++, argc--;
1333 if (!argc) {
1334 fprintf(stderr, "ldrdf: -g expects a file name\n");
1335 exit(1);
1337 break;
1338 default:
1339 usage();
1341 argv++, argc--;
1344 if (options.verbose > 4) {
1345 printf("ldrdf invoked with options:\n");
1346 printf(" section alignment: %d bytes\n", options.align);
1347 printf(" output name: `%s'\n", outname);
1348 if (options.strip)
1349 printf(" strip symbols\n");
1350 if (options.dynalink)
1351 printf(" Unix-style dynamic linking\n");
1352 if (options.objpath)
1353 printf(" objects search path: %s\n", objpath);
1354 if (options.libpath)
1355 printf(" libraries search path: %s\n", libpath);
1356 printf("\n");
1359 symtab = symtabNew();
1360 initsegments();
1362 if (!symtab) {
1363 fprintf(stderr, "ldrdf: out of memory\n");
1364 exit(1);
1367 while (argc) {
1368 if (!*argv)
1369 argv = respstrings;
1370 if (!*argv)
1371 break;
1372 if (!strncmp(*argv, "-l", 2)) {
1373 if (libpath && (argv[0][2] != '/'))
1374 add_library(newstrcat(libpath, *argv + 2));
1375 else
1376 add_library(*argv + 2);
1377 } else {
1378 if (objpath && (argv[0][0] != '/'))
1379 loadmodule(newstrcat(objpath, *argv));
1380 else
1381 loadmodule(*argv);
1382 moduleloaded = 1;
1384 argv++, argc--;
1387 if (!moduleloaded) {
1388 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1389 return 0;
1392 search_libraries();
1394 if (options.verbose > 2) {
1395 printf("symbol table:\n");
1396 symtabDump(symtab, stdout);
1399 write_output(outname);
1401 if (errorcount > 0)
1402 exit(1);
1403 return 0;