Get rid of magic open-coded "register numbers"
[nasm.git] / rdoff / ldrdf.c
blob2ea1af8ff89da8b139e1961049b12e51c41854e0
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 <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
31 #define RDOFF_UTILS
33 #include "rdoff.h"
34 #include "symtab.h"
35 #include "collectn.h"
36 #include "rdlib.h"
37 #include "segtab.h"
39 #define LDRDF_VERSION "1.07"
41 /* #define STINGY_MEMORY */
43 /* =======================================================================
44 * Types & macros that are private to this program
47 struct segment_infonode {
48 int dest_seg; /* output segment to be placed into, -1 to
49 skip linking this segment */
50 int32_t reloc; /* segment's relocation factor */
53 struct modulenode {
54 rdffile f; /* the RDOFF file structure */
55 struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
56 with each segment? */
57 void *header;
58 char *name;
59 struct modulenode *next;
60 int32_t bss_reloc;
63 #include "ldsegs.h"
65 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
66 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
68 /* ==========================================================================
69 * Function prototypes of private utility functions
72 void processmodule(const char *filename, struct modulenode *mod);
73 int allocnewseg(uint16_t type, uint16_t reserved);
74 int findsegment(uint16_t type, uint16_t reserved);
75 void symtab_add(const char *symbol, int segment, int32_t offset);
76 int symtab_get(const char *symbol, int *segment, int32_t *offset);
78 /* =========================================================================
79 * Global data structures.
82 /* a linked list of modules that will be included in the output */
83 struct modulenode *modules = NULL;
84 struct modulenode *lastmodule = NULL;
86 /* a linked list of libraries to be searched for unresolved imported symbols */
87 struct librarynode *libraries = NULL;
88 struct librarynode *lastlib = NULL;
90 /* the symbol table */
91 void *symtab = NULL;
93 /* objects search path */
94 char *objpath = NULL;
96 /* libraries search path */
97 char *libpath = NULL;
99 /* file to embed as a generic record */
100 char *generic_rec_file = NULL;
102 /* error file */
103 static FILE *error_file;
105 /* the header of the output file, built up stage by stage */
106 rdf_headerbuf *newheader = NULL;
108 /* The current state of segment allocation, including information about
109 * which output segment numbers have been allocated, and their types and
110 * amount of data which has already been allocated inside them.
112 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
113 int nsegs = 0;
114 int32_t bss_length;
116 /* global options which affect how the program behaves */
117 struct ldrdfoptions {
118 int verbose;
119 int align;
120 int dynalink;
121 int strip;
122 int respfile;
123 int stderr_redir;
124 int objpath;
125 int libpath;
126 } options;
128 int errorcount = 0; /* determines main program exit status */
130 /* =========================================================================
131 * Utility functions
135 * initsegments()
137 * sets up segments 0, 1, and 2, the initial code data and bss segments
139 void initsegments()
141 nsegs = 3;
142 outputseg[0].type = 1;
143 outputseg[0].number = 0;
144 outputseg[0].reserved = 0;
145 outputseg[0].length = 0;
146 outputseg[1].type = 2;
147 outputseg[1].number = 1;
148 outputseg[1].reserved = 0;
149 outputseg[1].length = 0;
150 outputseg[2].type = 0xFFFF; /* reserved segment type */
151 outputseg[2].number = 2;
152 outputseg[2].reserved = 0;
153 outputseg[2].length = 0;
154 bss_length = 0;
158 * loadmodule
160 * Determine the characteristics of a module, and decide what to do with
161 * each segment it contains (including determining destination segments and
162 * relocation factors for segments that are kept).
164 void loadmodule(const char *filename)
166 if (options.verbose)
167 printf("loading `%s'\n", filename);
169 /* allocate a new module entry on the end of the modules list */
170 if (!modules) {
171 modules = malloc(sizeof(*modules));
172 lastmodule = modules;
173 } else {
174 lastmodule->next = malloc(sizeof(*modules));
175 lastmodule = lastmodule->next;
178 if (!lastmodule) {
179 fprintf(stderr, "ldrdf: out of memory\n");
180 exit(1);
183 /* open the file using 'rdfopen', which returns nonzero on error */
184 if (rdfopen(&lastmodule->f, filename) != 0) {
185 rdfperror("ldrdf", filename);
186 exit(1);
190 * store information about the module, and determine what segments
191 * it contains, and what we should do with them (determine relocation
192 * factor if we decide to keep them)
194 lastmodule->header = NULL;
195 lastmodule->name = strdup(filename);
196 lastmodule->next = NULL;
198 processmodule(filename, lastmodule);
202 * processmodule()
204 * step through each segment, determine what exactly we're doing with
205 * it, and if we intend to keep it, determine (a) which segment to
206 * put it in and (b) whereabouts in that segment it will end up.
207 * (b) is fairly easy, because we're now keeping track of how big each
208 * segment in our output file is...
210 void processmodule(const char *filename, struct modulenode *mod)
212 struct segconfig sconf;
213 int seg, outseg;
214 void *header;
215 rdfheaderrec *hr;
216 int32_t bssamount = 0;
217 int bss_was_referenced = 0;
219 for (seg = 0; seg < mod->f.nsegs; seg++) {
221 * get the segment configuration for this type from the segment
222 * table. getsegconfig() is a macro, defined in ldsegs.h.
224 getsegconfig(sconf, mod->f.seg[seg].type);
226 if (options.verbose > 1) {
227 printf("%s %04x [%04x:%10s] ", filename,
228 mod->f.seg[seg].number, mod->f.seg[seg].type,
229 sconf.typedesc);
232 * sconf->dowhat tells us what to do with a segment of this type.
234 switch (sconf.dowhat) {
235 case SEG_IGNORE:
237 * Set destination segment to -1, to indicate that this segment
238 * should be ignored for the purpose of output, ie it is left
239 * out of the linked executable.
241 mod->seginfo[seg].dest_seg = -1;
242 if (options.verbose > 1)
243 printf("IGNORED\n");
244 break;
246 case SEG_NEWSEG:
248 * The configuration tells us to create a new segment for
249 * each occurrence of this segment type.
251 outseg = allocnewseg(sconf.mergetype,
252 mod->f.seg[seg].reserved);
253 mod->seginfo[seg].dest_seg = outseg;
254 mod->seginfo[seg].reloc = 0;
255 outputseg[outseg].length = mod->f.seg[seg].length;
256 if (options.verbose > 1)
257 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
258 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
259 break;
261 case SEG_MERGE:
263 * The configuration tells us to merge the segment with
264 * a previously existing segment of type 'sconf.mergetype',
265 * if one exists. Otherwise a new segment is created.
266 * This is handled transparently by 'findsegment()'.
268 outseg = findsegment(sconf.mergetype,
269 mod->f.seg[seg].reserved);
270 mod->seginfo[seg].dest_seg = outseg;
273 * We need to add alignment to these segments.
275 if (outputseg[outseg].length % options.align != 0)
276 outputseg[outseg].length +=
277 options.align -
278 (outputseg[outseg].length % options.align);
280 mod->seginfo[seg].reloc = outputseg[outseg].length;
281 outputseg[outseg].length += mod->f.seg[seg].length;
283 if (options.verbose > 1)
284 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
285 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
291 * extract symbols from the header, and dump them into the
292 * symbol table
294 header = malloc(mod->f.header_len);
295 if (!header) {
296 fprintf(stderr, "ldrdf: not enough memory\n");
297 exit(1);
299 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
300 rdfperror("ldrdf", filename);
301 exit(1);
304 while ((hr = rdfgetheaderrec(&mod->f))) {
305 switch (hr->type) {
306 case RDFREC_IMPORT: /* imported symbol */
307 case RDFREC_FARIMPORT:
308 /* Define with seg = -1 */
309 symtab_add(hr->i.label, -1, 0);
310 break;
312 case RDFREC_GLOBAL:{ /* exported symbol */
313 int destseg;
314 int32_t destreloc;
316 if (hr->e.segment == 2) {
317 bss_was_referenced = 1;
318 destreloc = bss_length;
319 if (destreloc % options.align != 0)
320 destreloc +=
321 options.align - (destreloc % options.align);
322 destseg = 2;
323 } else {
324 if ((destseg =
325 mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
326 continue;
327 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
329 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
330 break;
333 case RDFREC_BSS: /* BSS reservation */
335 * first, amalgamate all BSS reservations in this module
336 * into one, because we allow this in the output format.
338 bssamount += hr->b.amount;
339 break;
341 case RDFREC_COMMON:{ /* Common variable */
342 symtabEnt *ste = symtabFind(symtab, hr->c.label);
344 /* Is the symbol already in the table? */
345 if (ste)
346 break;
348 /* Align the variable */
349 if (bss_length % hr->c.align != 0)
350 bss_length += hr->c.align - (bss_length % hr->c.align);
351 if (options.verbose > 1) {
352 printf("%s %04x common '%s' => 0002:%08"PRIx32" (+%04"PRIx32")\n",
353 filename, hr->c.segment, hr->c.label,
354 bss_length, hr->c.size);
357 symtab_add(hr->c.label, 2, bss_length);
358 mod->bss_reloc = bss_length;
359 bss_length += hr->c.size;
360 break;
365 if (bssamount != 0 || bss_was_referenced) {
367 * handle the BSS segment - first pad the existing bss length
368 * to the correct alignment, then store the length in bss_reloc
369 * for this module. Then add this module's BSS length onto
370 * bss_length.
372 if (bss_length % options.align != 0)
373 bss_length += options.align - (bss_length % options.align);
375 mod->bss_reloc = bss_length;
376 if (options.verbose > 1) {
377 printf("%s 0002 [ BSS] => 0002:%08"PRIx32" (+%04"PRIx32")\n",
378 filename, bss_length, bssamount);
380 bss_length += bssamount;
382 #ifdef STINGY_MEMORY
384 * we free the header buffer here, to save memory later.
385 * this isn't efficient, but probably halves the memory usage
386 * of this program...
388 mod->f.header_loc = NULL;
389 free(header);
391 #endif
396 * Return 1 if a given module is in the list, 0 otherwise.
398 int lookformodule(const char *name)
400 struct modulenode *curr = modules;
402 while (curr) {
403 if (!strcmp(name, curr->name))
404 return 1;
405 curr = curr->next;
407 return 0;
411 * allocnewseg()
412 * findsegment()
414 * These functions manipulate the array of output segments, and are used
415 * by processmodule(). allocnewseg() allocates a segment in the array,
416 * initialising it to be empty. findsegment() first scans the array for
417 * a segment of the type requested, and if one isn't found allocates a
418 * new one.
420 int allocnewseg(uint16_t type, uint16_t reserved)
422 outputseg[nsegs].type = type;
423 outputseg[nsegs].number = nsegs;
424 outputseg[nsegs].reserved = reserved;
425 outputseg[nsegs].length = 0;
426 outputseg[nsegs].offset = 0;
427 outputseg[nsegs].data = NULL;
429 return nsegs++;
432 int findsegment(uint16_t type, uint16_t reserved)
434 int i;
436 for (i = 0; i < nsegs; i++)
437 if (outputseg[i].type == type)
438 return i;
440 return allocnewseg(type, reserved);
444 * symtab_add()
446 * inserts a symbol into the global symbol table, which associates symbol
447 * names either with addresses, or a marker that the symbol hasn't been
448 * resolved yet, or possibly that the symbol has been defined as
449 * contained in a dynamic [load time/run time] linked library.
451 * segment = -1 => not yet defined
452 * segment = -2 => defined as dll symbol
454 * If the symbol is already defined, and the new segment >= 0, then
455 * if the original segment was < 0 the symbol is redefined, otherwise
456 * a duplicate symbol warning is issued. If new segment == -1, this
457 * routine won't change a previously existing symbol. It will change
458 * to segment = -2 only if the segment was previously < 0.
460 void symtab_add(const char *symbol, int segment, int32_t offset)
462 symtabEnt *ste;
464 ste = symtabFind(symtab, symbol);
465 if (ste) {
466 if (ste->segment >= 0) {
468 * symbol previously defined
470 if (segment < 0)
471 return;
472 fprintf(error_file, "warning: `%s' redefined\n", symbol);
473 return;
477 * somebody wanted the symbol, and put an undefined symbol
478 * marker into the table
480 if (segment == -1)
481 return;
483 * we have more information now - update the symbol's entry
485 ste->segment = segment;
486 ste->offset = offset;
487 ste->flags = 0;
488 return;
491 * this is the first declaration of this symbol
493 ste = malloc(sizeof(symtabEnt));
494 if (!ste) {
495 fprintf(stderr, "ldrdf: out of memory\n");
496 exit(1);
498 ste->name = strdup(symbol);
499 ste->segment = segment;
500 ste->offset = offset;
501 ste->flags = 0;
502 symtabInsert(symtab, ste);
506 * symtab_get()
508 * Retrieves the values associated with a symbol. Undefined symbols
509 * are assumed to have -1:0 associated. Returns 1 if the symbol was
510 * successfully located.
512 int symtab_get(const char *symbol, int *segment, int32_t *offset)
514 symtabEnt *ste = symtabFind(symtab, symbol);
515 if (!ste) {
516 *segment = -1;
517 *offset = 0;
518 return 0;
519 } else {
520 *segment = ste->segment;
521 *offset = ste->offset;
522 return 1;
527 * add_library()
529 * checks that a library can be opened and is in the correct format,
530 * then adds it to the linked list of libraries.
532 void add_library(const char *name)
534 if (rdl_verify(name)) {
535 rdl_perror("ldrdf", name);
536 errorcount++;
537 return;
539 if (!libraries) {
540 lastlib = libraries = malloc(sizeof(*libraries));
541 if (!libraries) {
542 fprintf(stderr, "ldrdf: out of memory\n");
543 exit(1);
545 } else {
546 lastlib->next = malloc(sizeof(*libraries));
547 if (!lastlib->next) {
548 fprintf(stderr, "ldrdf: out of memory\n");
549 exit(1);
551 lastlib = lastlib->next;
553 lastlib->next = NULL;
554 if (rdl_open(lastlib, name)) {
555 rdl_perror("ldrdf", name);
556 errorcount++;
557 return;
562 * search_libraries()
564 * scans through the list of libraries, attempting to match symbols
565 * defined in library modules against symbols that are referenced but
566 * not defined (segment = -1 in the symbol table)
568 * returns 1 if any extra library modules are included, indicating that
569 * another pass through the library list should be made (possibly).
571 int search_libraries()
573 struct librarynode *cur;
574 rdffile f;
575 int i;
576 void *header;
577 int segment;
578 int32_t offset;
579 int doneanything = 0, pass = 1, keepfile;
580 rdfheaderrec *hr;
582 cur = libraries;
584 while (cur) {
585 if (options.verbose > 2)
586 printf("scanning library `%s', pass %d...\n", cur->name, pass);
588 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
589 if (pass == 2 && lookformodule(f.name))
590 continue;
592 if (options.verbose > 3)
593 printf(" looking in module `%s'\n", f.name);
595 header = malloc(f.header_len);
596 if (!header) {
597 fprintf(stderr, "ldrdf: not enough memory\n");
598 exit(1);
600 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
601 rdfperror("ldrdf", f.name);
602 errorcount++;
603 return 0;
606 keepfile = 0;
608 while ((hr = rdfgetheaderrec(&f))) {
609 /* We're only interested in exports, so skip others */
610 if (hr->type != RDFREC_GLOBAL)
611 continue;
614 * If the symbol is marked as SYM_GLOBAL, somebody will be
615 * definitely interested in it..
617 if ((hr->e.flags & SYM_GLOBAL) == 0) {
619 * otherwise the symbol is just public. Find it in
620 * the symbol table. If the symbol isn't defined, we
621 * aren't interested, so go on to the next.
622 * If it is defined as anything but -1, we're also not
623 * interested. But if it is defined as -1, insert this
624 * module into the list of modules to use, and go
625 * immediately on to the next module...
627 if (!symtab_get(hr->e.label, &segment, &offset)
628 || segment != -1)
629 continue;
632 doneanything = 1;
633 keepfile = 1;
636 * as there are undefined symbols, we can assume that
637 * there are modules on the module list by the time
638 * we get here.
640 lastmodule->next = malloc(sizeof(*lastmodule->next));
641 if (!lastmodule->next) {
642 fprintf(stderr, "ldrdf: not enough memory\n");
643 exit(1);
645 lastmodule = lastmodule->next;
646 memcpy(&lastmodule->f, &f, sizeof(f));
647 lastmodule->name = strdup(f.name);
648 lastmodule->next = NULL;
649 processmodule(f.name, lastmodule);
650 break;
652 if (!keepfile) {
653 free(f.name);
654 f.name = NULL;
655 f.fp = NULL;
658 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
659 rdl_perror("ldrdf", cur->name);
661 cur = cur->next;
662 if (cur == NULL && pass == 1) {
663 cur = libraries;
664 pass++;
668 return doneanything;
672 * write_output()
674 * this takes the linked list of modules, and walks through it, merging
675 * all the modules into a single output module, and then writes this to a
676 * file.
678 void write_output(const char *filename)
680 FILE *f;
681 rdf_headerbuf *rdfheader;
682 struct modulenode *cur;
683 int i, availableseg, seg, localseg, isrelative;
684 void *header;
685 rdfheaderrec *hr, newrec;
686 symtabEnt *se;
687 segtab segs;
688 int32_t offset;
689 uint8_t *data;
691 if ((f = fopen(filename, "wb")) == NULL) {
692 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
693 exit(1);
695 if ((rdfheader = rdfnewheader()) == NULL) {
696 fprintf(stderr, "ldrdf: out of memory\n");
697 exit(1);
701 * If '-g' option was given, first record in output file will be a
702 * `generic' record, filled with a given file content.
703 * This can be useful, for example, when constructing multiboot
704 * compliant kernels.
706 if (generic_rec_file) {
707 FILE *ff;
709 if (options.verbose)
710 printf("\nadding generic record from binary file %s\n",
711 generic_rec_file);
713 hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec));
714 if ((ff = fopen(generic_rec_file, "r")) == NULL) {
715 fprintf(stderr, "ldrdf: couldn't open %s for input\n",
716 generic_rec_file);
717 exit(1);
719 i = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
720 fseek(ff, 0, SEEK_END);
721 if (ftell(ff) > sizeof(hr->g.data)) {
722 fprintf(error_file,
723 "warning: maximum generic record size is %d, rest of file ignored\n",
724 sizeof(hr->g.data));
726 fclose(ff);
728 hr->g.type = 0;
729 hr->g.reclen = i;
730 rdfaddheader(rdfheader, hr);
731 free(hr);
734 if (options.verbose)
735 printf("\nbuilding output module (%d segments)\n", nsegs);
738 * Allocate the memory for the segments. We may be better off
739 * building the output module one segment at a time when running
740 * under 16 bit DOS, but that would be a slower way of doing this.
741 * And you could always use DJGPP...
743 for (i = 0; i < nsegs; i++) {
744 outputseg[i].data = NULL;
745 if (!outputseg[i].length)
746 continue;
747 outputseg[i].data = malloc(outputseg[i].length);
748 if (!outputseg[i].data) {
749 fprintf(stderr, "ldrdf: out of memory\n");
750 exit(1);
755 * initialise availableseg, used to allocate segment numbers for
756 * imported and exported labels...
758 availableseg = nsegs;
761 * Step through the modules, performing required actions on each one
763 for (cur = modules; cur; cur = cur->next) {
765 * Read the actual segment contents into the correct places in
766 * the newly allocated segments
769 for (i = 0; i < cur->f.nsegs; i++) {
770 int dest = cur->seginfo[i].dest_seg;
772 if (dest == -1)
773 continue;
774 if (rdfloadseg(&cur->f, i,
775 outputseg[dest].data + cur->seginfo[i].reloc)) {
776 rdfperror("ldrdf", cur->name);
777 exit(1);
782 * Perform fixups, and add new header records where required
785 header = malloc(cur->f.header_len);
786 if (!header) {
787 fprintf(stderr, "ldrdf: out of memory\n");
788 exit(1);
791 if (cur->f.header_loc)
792 rdfheaderrewind(&cur->f);
793 else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
794 rdfperror("ldrdf", cur->name);
795 exit(1);
799 * we need to create a local segment number -> location
800 * table for the segments in this module.
802 init_seglocations(&segs);
803 for (i = 0; i < cur->f.nsegs; i++) {
804 add_seglocation(&segs, cur->f.seg[i].number,
805 cur->seginfo[i].dest_seg,
806 cur->seginfo[i].reloc);
809 * and the BSS segment (doh!)
811 add_seglocation(&segs, 2, 2, cur->bss_reloc);
813 while ((hr = rdfgetheaderrec(&cur->f))) {
814 switch (hr->type) {
815 case RDFREC_RELOC: /* relocation record - need to do a fixup */
817 * First correct the offset stored in the segment from
818 * the start of the segment (which may well have changed).
820 * To do this we add to the number stored the relocation
821 * factor associated with the segment that contains the
822 * target segment.
824 * The relocation could be a relative relocation, in which
825 * case we have to first subtract the amount we've relocated
826 * the containing segment by.
828 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
829 fprintf(stderr,
830 "%s: reloc to undefined segment %04x\n",
831 cur->name, (int)hr->r.refseg);
832 errorcount++;
833 break;
836 isrelative =
837 (hr->r.segment & RDOFF_RELATIVEMASK) ==
838 RDOFF_RELATIVEMASK;
839 hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
841 if (hr->r.segment == 2 ||
842 (localseg =
843 rdffindsegment(&cur->f, hr->r.segment)) == -1) {
844 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
845 cur->name,
846 hr->r.segment == 2 ? "BSS" : "unknown",
847 hr->r.segment);
848 errorcount++;
849 break;
852 if (hr->r.length != 1 && hr->r.length != 2 &&
853 hr->r.length != 4) {
854 fprintf(stderr, "%s: nonstandard length reloc "
855 "(%d bytes)\n", cur->name, hr->r.length);
856 errorcount++;
857 break;
861 * okay, now the relocation is in the segment pointed to by
862 * cur->seginfo[localseg], and we know everything else is
863 * okay to go ahead and do the relocation
865 data = outputseg[cur->seginfo[localseg].dest_seg].data;
866 data += cur->seginfo[localseg].reloc + hr->r.offset;
869 * data now points to the reference that needs
870 * relocation. Calculate the relocation factor.
871 * Factor is:
872 * offset of referred object in segment [in offset]
873 * (- relocation of localseg, if ref is relative)
874 * For simplicity, the result is stored in 'offset'.
875 * Then add 'offset' onto the value at data.
878 if (isrelative)
879 offset -= cur->seginfo[localseg].reloc;
880 switch (hr->r.length) {
881 case 1:
882 offset += *data;
883 if (offset < -127 || offset > 128)
884 fprintf(error_file,
885 "warning: relocation out of range "
886 "at %s(%02x:%08"PRIx32")\n", cur->name,
887 (int)hr->r.segment, hr->r.offset);
888 *data = (char)offset;
889 break;
890 case 2:
891 offset += *(int16_t *)data;
892 if (offset < -32767 || offset > 32768)
893 fprintf(error_file,
894 "warning: relocation out of range "
895 "at %s(%02x:%08"PRIx32")\n", cur->name,
896 (int)hr->r.segment, hr->r.offset);
897 *(int16_t *)data = (int16_t)offset;
898 break;
899 case 4:
900 *(int32_t *)data += offset;
901 /* we can't easily detect overflow on this one */
902 break;
906 * If the relocation was relative between two symbols in
907 * the same segment, then we're done.
909 * Otherwise, we need to output a new relocation record
910 * with the references updated segment and offset...
912 if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
913 hr->r.segment = cur->seginfo[localseg].dest_seg;
914 hr->r.offset += cur->seginfo[localseg].reloc;
915 hr->r.refseg = seg;
916 if (isrelative)
917 hr->r.segment += RDOFF_RELATIVEMASK;
918 rdfaddheader(rdfheader, hr);
920 break;
922 case RDFREC_IMPORT: /* import symbol */
923 case RDFREC_FARIMPORT:
925 * scan the global symbol table for the symbol
926 * and associate its location with the segment number
927 * for this module
929 se = symtabFind(symtab, hr->i.label);
930 if (!se || se->segment == -1) {
931 if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
932 fprintf(error_file,
933 "error: unresolved reference to `%s'"
934 " in module `%s'\n", hr->i.label,
935 cur->name);
936 errorcount++;
939 * we need to allocate a segment number for this
940 * symbol, and store it in the symbol table for
941 * future reference
943 if (!se) {
944 se = malloc(sizeof(*se));
945 if (!se) {
946 fprintf(stderr, "ldrdf: out of memory\n");
947 exit(1);
949 se->name = strdup(hr->i.label);
950 se->flags = 0;
951 se->segment = availableseg++;
952 se->offset = 0;
953 symtabInsert(symtab, se);
954 } else {
955 se->segment = availableseg++;
956 se->offset = 0;
959 * output a header record that imports it to the
960 * recently allocated segment number...
962 newrec = *hr;
963 newrec.i.segment = se->segment;
964 rdfaddheader(rdfheader, &newrec);
967 add_seglocation(&segs, hr->i.segment, se->segment,
968 se->offset);
969 break;
971 case RDFREC_GLOBAL: /* export symbol */
973 * need to insert an export for this symbol into the new
974 * header, unless we're stripping symbols. Even if we're
975 * stripping, put the symbol if it's marked as SYM_GLOBAL.
977 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
978 break;
980 if (hr->e.segment == 2) {
981 seg = 2;
982 offset = cur->bss_reloc;
983 } else {
984 localseg = rdffindsegment(&cur->f, hr->e.segment);
985 if (localseg == -1) {
986 fprintf(stderr, "%s: exported symbol `%s' from "
987 "unrecognised segment\n", cur->name,
988 hr->e.label);
989 errorcount++;
990 break;
992 offset = cur->seginfo[localseg].reloc;
993 seg = cur->seginfo[localseg].dest_seg;
996 hr->e.segment = seg;
997 hr->e.offset += offset;
998 rdfaddheader(rdfheader, hr);
999 break;
1001 case RDFREC_MODNAME: /* module name */
1003 * Insert module name record if export symbols
1004 * are not stripped.
1005 * If module name begins with '$' - insert it anyway.
1007 if (options.strip && hr->m.modname[0] != '$')
1008 break;
1009 rdfaddheader(rdfheader, hr);
1010 break;
1012 case RDFREC_DLL: /* DLL name */
1014 * Insert DLL name if it begins with '$'
1016 if (hr->d.libname[0] != '$')
1017 break;
1018 rdfaddheader(rdfheader, hr);
1019 break;
1021 case RDFREC_SEGRELOC: /* segment fixup */
1023 * modify the segment numbers if necessary, and
1024 * pass straight through to the output module header
1026 * *** FIXME ***
1028 if (hr->r.segment == 2) {
1029 fprintf(stderr, "%s: segment fixup in BSS section\n",
1030 cur->name);
1031 errorcount++;
1032 break;
1034 localseg = rdffindsegment(&cur->f, hr->r.segment);
1035 if (localseg == -1) {
1036 fprintf(stderr, "%s: segment fixup in unrecognised"
1037 " segment (%d)\n", cur->name, hr->r.segment);
1038 errorcount++;
1039 break;
1041 hr->r.segment = cur->seginfo[localseg].dest_seg;
1042 hr->r.offset += cur->seginfo[localseg].reloc;
1044 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
1045 fprintf(stderr, "%s: segment fixup to undefined "
1046 "segment %04x\n", cur->name,
1047 (int)hr->r.refseg);
1048 errorcount++;
1049 break;
1051 hr->r.refseg = seg;
1052 rdfaddheader(rdfheader, hr);
1053 break;
1055 case RDFREC_COMMON: /* Common variable */
1056 /* Is this symbol already in the table? */
1057 se = symtabFind(symtab, hr->c.label);
1058 if (!se) {
1059 printf("%s is not in symtab yet\n", hr->c.label);
1060 break;
1062 /* Add segment location */
1063 add_seglocation(&segs, hr->c.segment, se->segment,
1064 se->offset);
1065 break;
1069 free(header);
1070 done_seglocations(&segs);
1075 * combined BSS reservation for the entire results
1077 newrec.type = RDFREC_BSS;
1078 newrec.b.reclen = 4;
1079 newrec.b.amount = bss_length;
1080 rdfaddheader(rdfheader, &newrec);
1083 * Write the header
1085 for (i = 0; i < nsegs; i++) {
1086 if (i == 2)
1087 continue;
1088 rdfaddsegment(rdfheader, outputseg[i].length);
1091 rdfwriteheader(f, rdfheader);
1092 rdfdoneheader(rdfheader);
1095 * Step through the segments, one at a time, writing out into
1096 * the output file
1098 for (i = 0; i < nsegs; i++) {
1099 uint16_t s;
1100 int32_t l;
1102 if (i == 2)
1103 continue;
1105 s = translateint16_t(outputseg[i].type);
1106 fwrite(&s, 2, 1, f);
1107 s = translateint16_t(outputseg[i].number);
1108 fwrite(&s, 2, 1, f);
1109 s = translateint16_t(outputseg[i].reserved);
1110 fwrite(&s, 2, 1, f);
1111 l = translateint32_t(outputseg[i].length);
1112 fwrite(&l, 4, 1, f);
1114 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1117 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f);
1120 /* =========================================================================
1121 * Main program
1124 void usage()
1126 printf("usage:\n"
1127 " ldrdf [options] object modules ... [-llibrary ...]\n"
1128 " ldrdf -r\n"
1129 "options:\n"
1130 " -v[=n] increase verbosity by 1, or set it to n\n"
1131 " -a nn set segment alignment value (default 16)\n"
1132 " -s strip public symbols\n"
1133 " -dy Unix-style dynamic linking\n"
1134 " -o name write output in file 'name'\n"
1135 " -j path specify objects search path\n"
1136 " -L path specify libraries search path\n"
1137 " -g file embed 'file' as a first header record with type 'generic'\n");
1138 exit(0);
1141 int main(int argc, char **argv)
1143 char *outname = "aout.rdf";
1144 int moduleloaded = 0;
1145 char *respstrings[128] = { 0, };
1147 options.verbose = 0;
1148 options.align = 16;
1149 options.dynalink = 0;
1150 options.strip = 0;
1152 error_file = stderr;
1154 argc--, argv++;
1155 if (argc == 0)
1156 usage();
1157 while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
1158 switch (argv[0][1]) {
1159 case 'r':
1160 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
1161 "\n");
1162 printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
1163 exit(0);
1164 case 'v':
1165 if (argv[0][2] == '=') {
1166 options.verbose = argv[0][3] - '0';
1167 if (options.verbose < 0 || options.verbose > 9) {
1168 fprintf(stderr,
1169 "ldrdf: verbosity level must be a number"
1170 " between 0 and 9\n");
1171 exit(1);
1173 } else
1174 options.verbose++;
1175 break;
1176 case 'a':
1177 options.align = atoi(argv[1]);
1178 if (options.align <= 0) {
1179 fprintf(stderr,
1180 "ldrdf: -a expects a positive number argument\n");
1181 exit(1);
1183 argv++, argc--;
1184 break;
1185 case 's':
1186 options.strip = 1;
1187 break;
1188 case 'd':
1189 if (argv[0][2] == 'y')
1190 options.dynalink = 1;
1191 break;
1192 case 'o':
1193 outname = argv[1];
1194 argv++, argc--;
1195 break;
1196 case 'j':
1197 if (!objpath) {
1198 options.objpath = 1;
1199 objpath = argv[1];
1200 argv++, argc--;
1201 break;
1202 } else {
1203 fprintf(stderr,
1204 "ldrdf: more than one objects search path specified\n");
1205 exit(1);
1207 case 'L':
1208 if (!libpath) {
1209 options.libpath = 1;
1210 libpath = argv[1];
1211 argv++, argc--;
1212 break;
1213 } else {
1214 fprintf(stderr,
1215 "ldrdf: more than one libraries search path specified\n");
1216 exit(1);
1218 case '@':{
1219 int i = 0;
1220 char buf[256];
1221 FILE *f;
1223 options.respfile = 1;
1224 if (argv[1] != NULL)
1225 f = fopen(argv[1], "r");
1226 else {
1227 fprintf(stderr,
1228 "ldrdf: no response file name specified\n");
1229 exit(1);
1232 if (f == NULL) {
1233 fprintf(stderr,
1234 "ldrdf: unable to open response file\n");
1235 exit(1);
1238 argv++, argc--;
1239 while (fgets(buf, sizeof(buf), f) != NULL) {
1240 char *p;
1241 if (buf[0] == '\n')
1242 continue;
1243 if ((p = strchr(buf, '\n')) != NULL)
1244 *p = '\0';
1245 if (i >= 128) {
1246 fprintf(stderr, "ldrdf: too many input files\n");
1247 exit(1);
1249 *(respstrings + i) = newstr(buf);
1250 argc++, i++;
1252 break;
1254 case '2':
1255 options.stderr_redir = 1;
1256 error_file = stdout;
1257 break;
1258 case 'g':
1259 generic_rec_file = argv[1];
1260 argv++, argc--;
1261 break;
1262 default:
1263 usage();
1265 argv++, argc--;
1268 if (options.verbose > 4) {
1269 printf("ldrdf invoked with options:\n");
1270 printf(" section alignment: %d bytes\n", options.align);
1271 printf(" output name: `%s'\n", outname);
1272 if (options.strip)
1273 printf(" strip symbols\n");
1274 if (options.dynalink)
1275 printf(" Unix-style dynamic linking\n");
1276 if (options.objpath)
1277 printf(" objects search path: %s\n", objpath);
1278 if (options.libpath)
1279 printf(" libraries search path: %s\n", libpath);
1280 printf("\n");
1283 symtab = symtabNew();
1284 initsegments();
1286 if (!symtab) {
1287 fprintf(stderr, "ldrdf: out of memory\n");
1288 exit(1);
1291 while (argc) {
1292 if (!*argv)
1293 argv = respstrings;
1294 if (!*argv)
1295 break;
1296 if (!strncmp(*argv, "-l", 2)) {
1297 if (libpath && (argv[0][2] != '/'))
1298 add_library(newstrcat(libpath, *argv + 2));
1299 else
1300 add_library(*argv + 2);
1301 } else {
1302 if (objpath && (argv[0][0] != '/'))
1303 loadmodule(newstrcat(objpath, *argv));
1304 else
1305 loadmodule(*argv);
1306 moduleloaded = 1;
1308 argv++, argc--;
1311 if (!moduleloaded) {
1312 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1313 return 0;
1316 search_libraries();
1318 if (options.verbose > 2) {
1319 printf("symbol table:\n");
1320 symtabDump(symtab, stdout);
1323 write_output(outname);
1325 if (errorcount > 0)
1326 exit(1);
1327 return 0;