Formatting: kill off "stealth whitespace"
[nasm.git] / rdoff / ldrdf.c
blobece8c3f1dbd7ccade40e9cfd6114e2c0c213be09
1 /*
2 * ldrdf.c - RDOFF Object File linker/loader main program.
4 * Copyright (c) 1996,99 Julian Hall. All rights reserved.
5 * Improvements and fixes (c) 1999-2004 RET & COM Research.
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.
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
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.
27 #include "compiler.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
33 #define RDOFF_UTILS
35 #include "rdoff.h"
36 #include "symtab.h"
37 #include "collectn.h"
38 #include "rdlib.h"
39 #include "segtab.h"
41 #define LDRDF_VERSION "1.07"
43 /* #define STINGY_MEMORY */
45 /* =======================================================================
46 * Types & macros that are private to this program
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 */
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;
65 #include "ldsegs.h"
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)
70 /* ==========================================================================
71 * Function prototypes of private utility functions
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);
80 /* =========================================================================
81 * Global data structures.
84 /* a linked list of modules that will be included in the output */
85 struct modulenode *modules = NULL;
86 struct modulenode *lastmodule = NULL;
88 /* a linked list of libraries to be searched for unresolved imported symbols */
89 struct librarynode *libraries = NULL;
90 struct librarynode *lastlib = NULL;
92 /* the symbol table */
93 void *symtab = NULL;
95 /* objects search path */
96 char *objpath = NULL;
98 /* libraries search path */
99 char *libpath = NULL;
101 /* file to embed as a generic record */
102 char *generic_rec_file = NULL;
104 /* error file */
105 static FILE *error_file;
107 /* the header of the output file, built up stage by stage */
108 rdf_headerbuf *newheader = NULL;
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.
114 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
115 int nsegs = 0;
116 int32_t bss_length;
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;
130 int errorcount = 0; /* determines main program exit status */
132 /* =========================================================================
133 * Utility functions
137 * initsegments()
139 * sets up segments 0, 1, and 2, the initial code data and bss segments
141 void initsegments()
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;
160 * loadmodule
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).
166 void loadmodule(const char *filename)
168 if (options.verbose)
169 printf("loading `%s'\n", filename);
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;
180 if (!lastmodule) {
181 fprintf(stderr, "ldrdf: out of memory\n");
182 exit(1);
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);
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)
196 lastmodule->header = NULL;
197 lastmodule->name = strdup(filename);
198 lastmodule->next = NULL;
200 processmodule(filename, lastmodule);
204 * processmodule()
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...
212 void processmodule(const char *filename, struct modulenode *mod)
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;
221 for (seg = 0; seg < mod->f.nsegs; seg++) {
223 * get the segment configuration for this type from the segment
224 * table. getsegconfig() is a macro, defined in ldsegs.h.
226 getsegconfig(sconf, mod->f.seg[seg].type);
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);
234 * sconf->dowhat tells us what to do with a segment of this type.
236 switch (sconf.dowhat) {
237 case SEG_IGNORE:
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.
243 mod->seginfo[seg].dest_seg = -1;
244 if (options.verbose > 1)
245 printf("IGNORED\n");
246 break;
248 case SEG_NEWSEG:
250 * The configuration tells us to create a new segment for
251 * each occurrence of this segment type.
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;
263 case SEG_MERGE:
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()'.
270 outseg = findsegment(sconf.mergetype,
271 mod->f.seg[seg].reserved);
272 mod->seginfo[seg].dest_seg = outseg;
275 * We need to add alignment to these segments.
277 if (outputseg[outseg].length % options.align != 0)
278 outputseg[outseg].length +=
279 options.align -
280 (outputseg[outseg].length % options.align);
282 mod->seginfo[seg].reloc = outputseg[outseg].length;
283 outputseg[outseg].length += mod->f.seg[seg].length;
285 if (options.verbose > 1)
286 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
287 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
293 * extract symbols from the header, and dump them into the
294 * symbol table
296 header = malloc(mod->f.header_len);
297 if (!header) {
298 fprintf(stderr, "ldrdf: not enough memory\n");
299 exit(1);
301 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
302 rdfperror("ldrdf", filename);
303 exit(1);
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;
314 case RDFREC_GLOBAL:{ /* exported symbol */
315 int destseg;
316 int32_t destreloc;
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;
331 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
332 break;
335 case RDFREC_BSS: /* BSS reservation */
337 * first, amalgamate all BSS reservations in this module
338 * into one, because we allow this in the output format.
340 bssamount += hr->b.amount;
341 break;
343 case RDFREC_COMMON:{ /* Common variable */
344 symtabEnt *ste = symtabFind(symtab, hr->c.label);
346 /* Is the symbol already in the table? */
347 if (ste)
348 break;
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);
359 symtab_add(hr->c.label, 2, bss_length);
360 mod->bss_reloc = bss_length;
361 bss_length += hr->c.size;
362 break;
367 if (bssamount != 0 || bss_was_referenced) {
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.
374 if (bss_length % options.align != 0)
375 bss_length += options.align - (bss_length % options.align);
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);
382 bss_length += bssamount;
384 #ifdef STINGY_MEMORY
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...
390 mod->f.header_loc = NULL;
391 free(header);
393 #endif
398 * Return 1 if a given module is in the list, 0 otherwise.
400 int lookformodule(const char *name)
402 struct modulenode *curr = modules;
404 while (curr) {
405 if (!strcmp(name, curr->name))
406 return 1;
407 curr = curr->next;
409 return 0;
413 * allocnewseg()
414 * findsegment()
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.
422 int allocnewseg(uint16_t type, uint16_t reserved)
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;
431 return nsegs++;
434 int findsegment(uint16_t type, uint16_t reserved)
436 int i;
438 for (i = 0; i < nsegs; i++)
439 if (outputseg[i].type == type)
440 return i;
442 return allocnewseg(type, reserved);
446 * symtab_add()
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.
453 * segment = -1 => not yet defined
454 * segment = -2 => defined as dll symbol
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.
462 void symtab_add(const char *symbol, int segment, int32_t offset)
464 symtabEnt *ste;
466 ste = symtabFind(symtab, symbol);
467 if (ste) {
468 if (ste->segment >= 0) {
470 * symbol previously defined
472 if (segment < 0)
473 return;
474 fprintf(error_file, "warning: `%s' redefined\n", symbol);
475 return;
479 * somebody wanted the symbol, and put an undefined symbol
480 * marker into the table
482 if (segment == -1)
483 return;
485 * we have more information now - update the symbol's entry
487 ste->segment = segment;
488 ste->offset = offset;
489 ste->flags = 0;
490 return;
493 * this is the first declaration of this symbol
495 ste = malloc(sizeof(symtabEnt));
496 if (!ste) {
497 fprintf(stderr, "ldrdf: out of memory\n");
498 exit(1);
500 ste->name = strdup(symbol);
501 ste->segment = segment;
502 ste->offset = offset;
503 ste->flags = 0;
504 symtabInsert(symtab, ste);
508 * symtab_get()
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.
514 int symtab_get(const char *symbol, int *segment, int32_t *offset)
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;
529 * add_library()
531 * checks that a library can be opened and is in the correct format,
532 * then adds it to the linked list of libraries.
534 void add_library(const char *name)
536 if (rdl_verify(name)) {
537 rdl_perror("ldrdf", name);
538 errorcount++;
539 return;
541 if (!libraries) {
542 lastlib = libraries = malloc(sizeof(*libraries));
543 if (!libraries) {
544 fprintf(stderr, "ldrdf: out of memory\n");
545 exit(1);
547 } else {
548 lastlib->next = malloc(sizeof(*libraries));
549 if (!lastlib->next) {
550 fprintf(stderr, "ldrdf: out of memory\n");
551 exit(1);
553 lastlib = lastlib->next;
555 lastlib->next = NULL;
556 if (rdl_open(lastlib, name)) {
557 rdl_perror("ldrdf", name);
558 errorcount++;
559 return;
564 * search_libraries()
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)
570 * returns 1 if any extra library modules are included, indicating that
571 * another pass through the library list should be made (possibly).
573 int search_libraries()
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;
584 cur = libraries;
586 while (cur) {
587 if (options.verbose > 2)
588 printf("scanning library `%s', pass %d...\n", cur->name, pass);
590 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
591 if (pass == 2 && lookformodule(f.name))
592 continue;
594 if (options.verbose > 3)
595 printf(" looking in module `%s'\n", f.name);
597 header = malloc(f.header_len);
598 if (!header) {
599 fprintf(stderr, "ldrdf: not enough memory\n");
600 exit(1);
602 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
603 rdfperror("ldrdf", f.name);
604 errorcount++;
605 return 0;
608 keepfile = 0;
610 while ((hr = rdfgetheaderrec(&f))) {
611 /* We're only interested in exports, so skip others */
612 if (hr->type != RDFREC_GLOBAL)
613 continue;
616 * If the symbol is marked as SYM_GLOBAL, somebody will be
617 * definitely interested in it..
619 if ((hr->e.flags & SYM_GLOBAL) == 0) {
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...
629 if (!symtab_get(hr->e.label, &segment, &offset)
630 || segment != -1)
631 continue;
634 doneanything = 1;
635 keepfile = 1;
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.
642 lastmodule->next = malloc(sizeof(*lastmodule->next));
643 if (!lastmodule->next) {
644 fprintf(stderr, "ldrdf: not enough memory\n");
645 exit(1);
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;
654 if (!keepfile) {
655 free(f.name);
656 f.name = NULL;
657 f.fp = NULL;
660 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
661 rdl_perror("ldrdf", cur->name);
663 cur = cur->next;
664 if (cur == NULL && pass == 1) {
665 cur = libraries;
666 pass++;
670 return doneanything;
674 * write_output()
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.
680 void write_output(const char *filename)
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;
693 if ((f = fopen(filename, "wb")) == NULL) {
694 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
695 exit(1);
697 if ((rdfheader = rdfnewheader()) == NULL) {
698 fprintf(stderr, "ldrdf: out of memory\n");
699 exit(1);
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.
708 if (generic_rec_file) {
709 FILE *ff;
711 if (options.verbose)
712 printf("\nadding generic record from binary file %s\n",
713 generic_rec_file);
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);
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));
729 fclose(ff);
731 hr->g.type = 0;
732 hr->g.reclen = i;
733 rdfaddheader(rdfheader, hr);
734 free(hr);
737 if (options.verbose)
738 printf("\nbuilding output module (%d segments)\n", nsegs);
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...
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);
758 * initialise availableseg, used to allocate segment numbers for
759 * imported and exported labels...
761 availableseg = nsegs;
764 * Step through the modules, performing required actions on each one
766 for (cur = modules; cur; cur = cur->next) {
768 * Read the actual segment contents into the correct places in
769 * the newly allocated segments
772 for (i = 0; i < cur->f.nsegs; i++) {
773 int dest = cur->seginfo[i].dest_seg;
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);
785 * Perform fixups, and add new header records where required
788 header = malloc(cur->f.header_len);
789 if (!header) {
790 fprintf(stderr, "ldrdf: out of memory\n");
791 exit(1);
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);
802 * we need to create a local segment number -> location
803 * table for the segments in this module.
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);
812 * and the BSS segment (doh!)
814 add_seglocation(&segs, 2, 2, cur->bss_reloc);
816 while ((hr = rdfgetheaderrec(&cur->f))) {
817 switch (hr->type) {
818 case RDFREC_RELOC: /* relocation record - need to do a fixup */
820 * First correct the offset stored in the segment from
821 * the start of the segment (which may well have changed).
823 * To do this we add to the number stored the relocation
824 * factor associated with the segment that contains the
825 * target segment.
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.
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;
839 isrelative =
840 (hr->r.segment & RDOFF_RELATIVEMASK) ==
841 RDOFF_RELATIVEMASK;
842 hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
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;
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;
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
868 data = outputseg[cur->seginfo[localseg].dest_seg].data;
869 data += cur->seginfo[localseg].reloc + hr->r.offset;
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.
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;
909 * If the relocation was relative between two symbols in
910 * the same segment, then we're done.
912 * Otherwise, we need to output a new relocation record
913 * with the references updated segment and offset...
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);
923 break;
925 case RDFREC_IMPORT: /* import symbol */
926 case RDFREC_FARIMPORT:
928 * scan the global symbol table for the symbol
929 * and associate its location with the segment number
930 * for this module
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++;
942 * we need to allocate a segment number for this
943 * symbol, and store it in the symbol table for
944 * future reference
946 if (!se) {
947 se = malloc(sizeof(*se));
948 if (!se) {
949 fprintf(stderr, "ldrdf: out of memory\n");
950 exit(1);
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;
962 * output a header record that imports it to the
963 * recently allocated segment number...
965 newrec = *hr;
966 newrec.i.segment = se->segment;
967 rdfaddheader(rdfheader, &newrec);
970 add_seglocation(&segs, hr->i.segment, se->segment,
971 se->offset);
972 break;
974 case RDFREC_GLOBAL: /* export symbol */
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.
980 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
981 break;
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;
995 offset = cur->seginfo[localseg].reloc;
996 seg = cur->seginfo[localseg].dest_seg;
999 hr->e.segment = seg;
1000 hr->e.offset += offset;
1001 rdfaddheader(rdfheader, hr);
1002 break;
1004 case RDFREC_MODNAME: /* module name */
1006 * Insert module name record if export symbols
1007 * are not stripped.
1008 * If module name begins with '$' - insert it anyway.
1010 if (options.strip && hr->m.modname[0] != '$')
1011 break;
1012 rdfaddheader(rdfheader, hr);
1013 break;
1015 case RDFREC_DLL: /* DLL name */
1017 * Insert DLL name if it begins with '$'
1019 if (hr->d.libname[0] != '$')
1020 break;
1021 rdfaddheader(rdfheader, hr);
1022 break;
1024 case RDFREC_SEGRELOC: /* segment fixup */
1026 * modify the segment numbers if necessary, and
1027 * pass straight through to the output module header
1029 * *** FIXME ***
1031 if (hr->r.segment == 2) {
1032 fprintf(stderr, "%s: segment fixup in BSS section\n",
1033 cur->name);
1034 errorcount++;
1035 break;
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;
1044 hr->r.segment = cur->seginfo[localseg].dest_seg;
1045 hr->r.offset += cur->seginfo[localseg].reloc;
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;
1054 hr->r.refseg = seg;
1055 rdfaddheader(rdfheader, hr);
1056 break;
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;
1065 /* Add segment location */
1066 add_seglocation(&segs, hr->c.segment, se->segment,
1067 se->offset);
1068 break;
1072 free(header);
1073 done_seglocations(&segs);
1078 * combined BSS reservation for the entire results
1080 newrec.type = RDFREC_BSS;
1081 newrec.b.reclen = 4;
1082 newrec.b.amount = bss_length;
1083 rdfaddheader(rdfheader, &newrec);
1086 * Write the header
1088 for (i = 0; i < nsegs; i++) {
1089 if (i == 2)
1090 continue;
1091 rdfaddsegment(rdfheader, outputseg[i].length);
1094 rdfwriteheader(f, rdfheader);
1095 rdfdoneheader(rdfheader);
1098 * Step through the segments, one at a time, writing out into
1099 * the output file
1101 for (i = 0; i < nsegs; i++) {
1102 uint16_t s;
1103 int32_t l;
1105 if (i == 2)
1106 continue;
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);
1117 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1120 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f);
1123 /* =========================================================================
1124 * Main program
1127 void usage()
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);
1144 int main(int argc, char **argv)
1146 char *outname = "aout.rdf";
1147 int moduleloaded = 0;
1148 char *respstrings[128] = { 0, };
1150 options.verbose = 0;
1151 options.align = 16;
1152 options.dynalink = 0;
1153 options.strip = 0;
1155 error_file = stderr;
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);
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);
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);
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);
1221 case '@':{
1222 int i = 0;
1223 char buf[256];
1224 FILE *f;
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);
1235 if (f == NULL) {
1236 fprintf(stderr,
1237 "ldrdf: unable to open response file\n");
1238 exit(1);
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);
1252 *(respstrings + i) = newstr(buf);
1253 argc++, i++;
1255 break;
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();
1268 argv++, argc--;
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");
1286 symtab = symtabNew();
1287 initsegments();
1289 if (!symtab) {
1290 fprintf(stderr, "ldrdf: out of memory\n");
1291 exit(1);
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;
1311 argv++, argc--;
1314 if (!moduleloaded) {
1315 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1316 return 0;
1319 search_libraries();
1321 if (options.verbose > 2) {
1322 printf("symbol table:\n");
1323 symtabDump(symtab, stdout);
1326 write_output(outname);
1328 if (errorcount > 0)
1329 exit(1);
1330 return 0;