doc: ps/pdf: set page numbers in normal-sized italic
[nasm/autotest.git] / rdoff / ldrdf.c
blob046139b3744a80be4aef693ba9f70e0ab1caf7da
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 memset(&sconf, 0, sizeof sconf);
223 for (seg = 0; seg < mod->f.nsegs; seg++) {
225 * get the segment configuration for this type from the segment
226 * table. getsegconfig() is a macro, defined in ldsegs.h.
228 getsegconfig(sconf, mod->f.seg[seg].type);
230 if (options.verbose > 1) {
231 printf("%s %04x [%04x:%10s] ", filename,
232 mod->f.seg[seg].number, mod->f.seg[seg].type,
233 sconf.typedesc);
236 * sconf->dowhat tells us what to do with a segment of this type.
238 switch (sconf.dowhat) {
239 case SEG_IGNORE:
241 * Set destination segment to -1, to indicate that this segment
242 * should be ignored for the purpose of output, ie it is left
243 * out of the linked executable.
245 mod->seginfo[seg].dest_seg = -1;
246 if (options.verbose > 1)
247 printf("IGNORED\n");
248 break;
250 case SEG_NEWSEG:
252 * The configuration tells us to create a new segment for
253 * each occurrence of this segment type.
255 outseg = allocnewseg(sconf.mergetype,
256 mod->f.seg[seg].reserved);
257 mod->seginfo[seg].dest_seg = outseg;
258 mod->seginfo[seg].reloc = 0;
259 outputseg[outseg].length = mod->f.seg[seg].length;
260 if (options.verbose > 1)
261 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
262 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
263 break;
265 case SEG_MERGE:
267 * The configuration tells us to merge the segment with
268 * a previously existing segment of type 'sconf.mergetype',
269 * if one exists. Otherwise a new segment is created.
270 * This is handled transparently by 'findsegment()'.
272 outseg = findsegment(sconf.mergetype,
273 mod->f.seg[seg].reserved);
274 mod->seginfo[seg].dest_seg = outseg;
277 * We need to add alignment to these segments.
279 if (outputseg[outseg].length % options.align != 0)
280 outputseg[outseg].length +=
281 options.align -
282 (outputseg[outseg].length % options.align);
284 mod->seginfo[seg].reloc = outputseg[outseg].length;
285 outputseg[outseg].length += mod->f.seg[seg].length;
287 if (options.verbose > 1)
288 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
289 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
295 * extract symbols from the header, and dump them into the
296 * symbol table
298 header = malloc(mod->f.header_len);
299 if (!header) {
300 fprintf(stderr, "ldrdf: not enough memory\n");
301 exit(1);
303 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
304 rdfperror("ldrdf", filename);
305 exit(1);
308 while ((hr = rdfgetheaderrec(&mod->f))) {
309 switch (hr->type) {
310 case RDFREC_IMPORT: /* imported symbol */
311 case RDFREC_FARIMPORT:
312 /* Define with seg = -1 */
313 symtab_add(hr->i.label, -1, 0);
314 break;
316 case RDFREC_GLOBAL:{ /* exported symbol */
317 int destseg;
318 int32_t destreloc;
320 if (hr->e.segment == 2) {
321 bss_was_referenced = 1;
322 destreloc = bss_length;
323 if (destreloc % options.align != 0)
324 destreloc +=
325 options.align - (destreloc % options.align);
326 destseg = 2;
327 } else {
328 if ((destseg =
329 mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
330 continue;
331 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
333 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
334 break;
337 case RDFREC_BSS: /* BSS reservation */
339 * first, amalgamate all BSS reservations in this module
340 * into one, because we allow this in the output format.
342 bssamount += hr->b.amount;
343 break;
345 case RDFREC_COMMON:{ /* Common variable */
346 symtabEnt *ste = symtabFind(symtab, hr->c.label);
348 /* Is the symbol already in the table? */
349 if (ste)
350 break;
352 /* Align the variable */
353 if (bss_length % hr->c.align != 0)
354 bss_length += hr->c.align - (bss_length % hr->c.align);
355 if (options.verbose > 1) {
356 printf("%s %04x common '%s' => 0002:%08"PRIx32" (+%04"PRIx32")\n",
357 filename, hr->c.segment, hr->c.label,
358 bss_length, hr->c.size);
361 symtab_add(hr->c.label, 2, bss_length);
362 mod->bss_reloc = bss_length;
363 bss_length += hr->c.size;
364 break;
369 if (bssamount != 0 || bss_was_referenced) {
371 * handle the BSS segment - first pad the existing bss length
372 * to the correct alignment, then store the length in bss_reloc
373 * for this module. Then add this module's BSS length onto
374 * bss_length.
376 if (bss_length % options.align != 0)
377 bss_length += options.align - (bss_length % options.align);
379 mod->bss_reloc = bss_length;
380 if (options.verbose > 1) {
381 printf("%s 0002 [ BSS] => 0002:%08"PRIx32" (+%04"PRIx32")\n",
382 filename, bss_length, bssamount);
384 bss_length += bssamount;
386 #ifdef STINGY_MEMORY
388 * we free the header buffer here, to save memory later.
389 * this isn't efficient, but probably halves the memory usage
390 * of this program...
392 mod->f.header_loc = NULL;
393 free(header);
395 #endif
400 * Return 1 if a given module is in the list, 0 otherwise.
402 int lookformodule(const char *name)
404 struct modulenode *curr = modules;
406 while (curr) {
407 if (!strcmp(name, curr->name))
408 return 1;
409 curr = curr->next;
411 return 0;
415 * allocnewseg()
416 * findsegment()
418 * These functions manipulate the array of output segments, and are used
419 * by processmodule(). allocnewseg() allocates a segment in the array,
420 * initialising it to be empty. findsegment() first scans the array for
421 * a segment of the type requested, and if one isn't found allocates a
422 * new one.
424 int allocnewseg(uint16_t type, uint16_t reserved)
426 outputseg[nsegs].type = type;
427 outputseg[nsegs].number = nsegs;
428 outputseg[nsegs].reserved = reserved;
429 outputseg[nsegs].length = 0;
430 outputseg[nsegs].offset = 0;
431 outputseg[nsegs].data = NULL;
433 return nsegs++;
436 int findsegment(uint16_t type, uint16_t reserved)
438 int i;
440 for (i = 0; i < nsegs; i++)
441 if (outputseg[i].type == type)
442 return i;
444 return allocnewseg(type, reserved);
448 * symtab_add()
450 * inserts a symbol into the global symbol table, which associates symbol
451 * names either with addresses, or a marker that the symbol hasn't been
452 * resolved yet, or possibly that the symbol has been defined as
453 * contained in a dynamic [load time/run time] linked library.
455 * segment = -1 => not yet defined
456 * segment = -2 => defined as dll symbol
458 * If the symbol is already defined, and the new segment >= 0, then
459 * if the original segment was < 0 the symbol is redefined, otherwise
460 * a duplicate symbol warning is issued. If new segment == -1, this
461 * routine won't change a previously existing symbol. It will change
462 * to segment = -2 only if the segment was previously < 0.
464 void symtab_add(const char *symbol, int segment, int32_t offset)
466 symtabEnt *ste;
468 ste = symtabFind(symtab, symbol);
469 if (ste) {
470 if (ste->segment >= 0) {
472 * symbol previously defined
474 if (segment < 0)
475 return;
476 fprintf(error_file, "warning: `%s' redefined\n", symbol);
477 return;
481 * somebody wanted the symbol, and put an undefined symbol
482 * marker into the table
484 if (segment == -1)
485 return;
487 * we have more information now - update the symbol's entry
489 ste->segment = segment;
490 ste->offset = offset;
491 ste->flags = 0;
492 return;
495 * this is the first declaration of this symbol
497 ste = malloc(sizeof(symtabEnt));
498 if (!ste) {
499 fprintf(stderr, "ldrdf: out of memory\n");
500 exit(1);
502 ste->name = strdup(symbol);
503 ste->segment = segment;
504 ste->offset = offset;
505 ste->flags = 0;
506 symtabInsert(symtab, ste);
510 * symtab_get()
512 * Retrieves the values associated with a symbol. Undefined symbols
513 * are assumed to have -1:0 associated. Returns 1 if the symbol was
514 * successfully located.
516 int symtab_get(const char *symbol, int *segment, int32_t *offset)
518 symtabEnt *ste = symtabFind(symtab, symbol);
519 if (!ste) {
520 *segment = -1;
521 *offset = 0;
522 return 0;
523 } else {
524 *segment = ste->segment;
525 *offset = ste->offset;
526 return 1;
531 * add_library()
533 * checks that a library can be opened and is in the correct format,
534 * then adds it to the linked list of libraries.
536 void add_library(const char *name)
538 if (rdl_verify(name)) {
539 rdl_perror("ldrdf", name);
540 errorcount++;
541 return;
543 if (!libraries) {
544 lastlib = libraries = malloc(sizeof(*libraries));
545 if (!libraries) {
546 fprintf(stderr, "ldrdf: out of memory\n");
547 exit(1);
549 } else {
550 lastlib->next = malloc(sizeof(*libraries));
551 if (!lastlib->next) {
552 fprintf(stderr, "ldrdf: out of memory\n");
553 exit(1);
555 lastlib = lastlib->next;
557 lastlib->next = NULL;
558 if (rdl_open(lastlib, name)) {
559 rdl_perror("ldrdf", name);
560 errorcount++;
561 return;
566 * search_libraries()
568 * scans through the list of libraries, attempting to match symbols
569 * defined in library modules against symbols that are referenced but
570 * not defined (segment = -1 in the symbol table)
572 * returns 1 if any extra library modules are included, indicating that
573 * another pass through the library list should be made (possibly).
575 int search_libraries()
577 struct librarynode *cur;
578 rdffile f;
579 int i;
580 void *header;
581 int segment;
582 int32_t offset;
583 int doneanything = 0, pass = 1, keepfile;
584 rdfheaderrec *hr;
586 cur = libraries;
588 while (cur) {
589 if (options.verbose > 2)
590 printf("scanning library `%s', pass %d...\n", cur->name, pass);
592 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
593 if (pass == 2 && lookformodule(f.name))
594 continue;
596 if (options.verbose > 3)
597 printf(" looking in module `%s'\n", f.name);
599 header = malloc(f.header_len);
600 if (!header) {
601 fprintf(stderr, "ldrdf: not enough memory\n");
602 exit(1);
604 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
605 rdfperror("ldrdf", f.name);
606 errorcount++;
607 return 0;
610 keepfile = 0;
612 while ((hr = rdfgetheaderrec(&f))) {
613 /* We're only interested in exports, so skip others */
614 if (hr->type != RDFREC_GLOBAL)
615 continue;
618 * If the symbol is marked as SYM_GLOBAL, somebody will be
619 * definitely interested in it..
621 if ((hr->e.flags & SYM_GLOBAL) == 0) {
623 * otherwise the symbol is just public. Find it in
624 * the symbol table. If the symbol isn't defined, we
625 * aren't interested, so go on to the next.
626 * If it is defined as anything but -1, we're also not
627 * interested. But if it is defined as -1, insert this
628 * module into the list of modules to use, and go
629 * immediately on to the next module...
631 if (!symtab_get(hr->e.label, &segment, &offset)
632 || segment != -1)
633 continue;
636 doneanything = 1;
637 keepfile = 1;
640 * as there are undefined symbols, we can assume that
641 * there are modules on the module list by the time
642 * we get here.
644 lastmodule->next = malloc(sizeof(*lastmodule->next));
645 if (!lastmodule->next) {
646 fprintf(stderr, "ldrdf: not enough memory\n");
647 exit(1);
649 lastmodule = lastmodule->next;
650 memcpy(&lastmodule->f, &f, sizeof(f));
651 lastmodule->name = strdup(f.name);
652 lastmodule->next = NULL;
653 processmodule(f.name, lastmodule);
654 break;
656 if (!keepfile) {
657 free(f.name);
658 f.name = NULL;
659 f.fp = NULL;
662 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
663 rdl_perror("ldrdf", cur->name);
665 cur = cur->next;
666 if (cur == NULL && pass == 1) {
667 cur = libraries;
668 pass++;
672 return doneanything;
676 * write_output()
678 * this takes the linked list of modules, and walks through it, merging
679 * all the modules into a single output module, and then writes this to a
680 * file.
682 void write_output(const char *filename)
684 FILE *f;
685 rdf_headerbuf *rdfheader;
686 struct modulenode *cur;
687 int i, availableseg, seg, localseg, isrelative;
688 void *header;
689 rdfheaderrec *hr, newrec;
690 symtabEnt *se;
691 segtab segs;
692 int32_t offset;
693 uint8_t *data;
695 if ((f = fopen(filename, "wb")) == NULL) {
696 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
697 exit(1);
699 if ((rdfheader = rdfnewheader()) == NULL) {
700 fprintf(stderr, "ldrdf: out of memory\n");
701 exit(1);
705 * If '-g' option was given, first record in output file will be a
706 * `generic' record, filled with a given file content.
707 * This can be useful, for example, when constructing multiboot
708 * compliant kernels.
710 if (generic_rec_file) {
711 FILE *ff;
713 if (options.verbose)
714 printf("\nadding generic record from binary file %s\n",
715 generic_rec_file);
717 hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec));
718 if ((ff = fopen(generic_rec_file, "r")) == NULL) {
719 fprintf(stderr, "ldrdf: couldn't open %s for input\n",
720 generic_rec_file);
721 exit(1);
723 i = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
724 fseek(ff, 0, SEEK_END);
725 if (ftell(ff) > (long)sizeof(hr->g.data)) {
726 fprintf(error_file,
727 "warning: maximum generic record size is %u, "
728 "rest of file ignored\n",
729 (unsigned int)sizeof(hr->g.data));
731 fclose(ff);
733 hr->g.type = 0;
734 hr->g.reclen = i;
735 rdfaddheader(rdfheader, hr);
736 free(hr);
739 if (options.verbose)
740 printf("\nbuilding output module (%d segments)\n", nsegs);
743 * Allocate the memory for the segments. We may be better off
744 * building the output module one segment at a time when running
745 * under 16 bit DOS, but that would be a slower way of doing this.
746 * And you could always use DJGPP...
748 for (i = 0; i < nsegs; i++) {
749 outputseg[i].data = NULL;
750 if (!outputseg[i].length)
751 continue;
752 outputseg[i].data = malloc(outputseg[i].length);
753 if (!outputseg[i].data) {
754 fprintf(stderr, "ldrdf: out of memory\n");
755 exit(1);
760 * initialise availableseg, used to allocate segment numbers for
761 * imported and exported labels...
763 availableseg = nsegs;
766 * Step through the modules, performing required actions on each one
768 for (cur = modules; cur; cur = cur->next) {
770 * Read the actual segment contents into the correct places in
771 * the newly allocated segments
774 for (i = 0; i < cur->f.nsegs; i++) {
775 int dest = cur->seginfo[i].dest_seg;
777 if (dest == -1)
778 continue;
779 if (rdfloadseg(&cur->f, i,
780 outputseg[dest].data + cur->seginfo[i].reloc)) {
781 rdfperror("ldrdf", cur->name);
782 exit(1);
787 * Perform fixups, and add new header records where required
790 header = malloc(cur->f.header_len);
791 if (!header) {
792 fprintf(stderr, "ldrdf: out of memory\n");
793 exit(1);
796 if (cur->f.header_loc)
797 rdfheaderrewind(&cur->f);
798 else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
799 rdfperror("ldrdf", cur->name);
800 exit(1);
804 * we need to create a local segment number -> location
805 * table for the segments in this module.
807 init_seglocations(&segs);
808 for (i = 0; i < cur->f.nsegs; i++) {
809 add_seglocation(&segs, cur->f.seg[i].number,
810 cur->seginfo[i].dest_seg,
811 cur->seginfo[i].reloc);
814 * and the BSS segment (doh!)
816 add_seglocation(&segs, 2, 2, cur->bss_reloc);
818 while ((hr = rdfgetheaderrec(&cur->f))) {
819 switch (hr->type) {
820 case RDFREC_RELOC: /* relocation record - need to do a fixup */
822 * First correct the offset stored in the segment from
823 * the start of the segment (which may well have changed).
825 * To do this we add to the number stored the relocation
826 * factor associated with the segment that contains the
827 * target segment.
829 * The relocation could be a relative relocation, in which
830 * case we have to first subtract the amount we've relocated
831 * the containing segment by.
833 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
834 fprintf(stderr,
835 "%s: reloc to undefined segment %04x\n",
836 cur->name, (int)hr->r.refseg);
837 errorcount++;
838 break;
841 isrelative =
842 (hr->r.segment & RDOFF_RELATIVEMASK) ==
843 RDOFF_RELATIVEMASK;
844 hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
846 if (hr->r.segment == 2 ||
847 (localseg =
848 rdffindsegment(&cur->f, hr->r.segment)) == -1) {
849 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
850 cur->name,
851 hr->r.segment == 2 ? "BSS" : "unknown",
852 hr->r.segment);
853 errorcount++;
854 break;
857 if (hr->r.length != 1 && hr->r.length != 2 &&
858 hr->r.length != 4) {
859 fprintf(stderr, "%s: nonstandard length reloc "
860 "(%d bytes)\n", cur->name, hr->r.length);
861 errorcount++;
862 break;
866 * okay, now the relocation is in the segment pointed to by
867 * cur->seginfo[localseg], and we know everything else is
868 * okay to go ahead and do the relocation
870 data = outputseg[cur->seginfo[localseg].dest_seg].data;
871 data += cur->seginfo[localseg].reloc + hr->r.offset;
874 * data now points to the reference that needs
875 * relocation. Calculate the relocation factor.
876 * Factor is:
877 * offset of referred object in segment [in offset]
878 * (- relocation of localseg, if ref is relative)
879 * For simplicity, the result is stored in 'offset'.
880 * Then add 'offset' onto the value at data.
883 if (isrelative)
884 offset -= cur->seginfo[localseg].reloc;
885 switch (hr->r.length) {
886 case 1:
887 offset += *data;
888 if (offset < -127 || offset > 128)
889 fprintf(error_file,
890 "warning: relocation out of range "
891 "at %s(%02x:%08"PRIx32")\n", cur->name,
892 (int)hr->r.segment, hr->r.offset);
893 *data = (char)offset;
894 break;
895 case 2:
896 offset += *(int16_t *)data;
897 if (offset < -32767 || offset > 32768)
898 fprintf(error_file,
899 "warning: relocation out of range "
900 "at %s(%02x:%08"PRIx32")\n", cur->name,
901 (int)hr->r.segment, hr->r.offset);
902 *(int16_t *)data = (int16_t)offset;
903 break;
904 case 4:
905 *(int32_t *)data += offset;
906 /* we can't easily detect overflow on this one */
907 break;
911 * If the relocation was relative between two symbols in
912 * the same segment, then we're done.
914 * Otherwise, we need to output a new relocation record
915 * with the references updated segment and offset...
917 if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
918 hr->r.segment = cur->seginfo[localseg].dest_seg;
919 hr->r.offset += cur->seginfo[localseg].reloc;
920 hr->r.refseg = seg;
921 if (isrelative)
922 hr->r.segment += RDOFF_RELATIVEMASK;
923 rdfaddheader(rdfheader, hr);
925 break;
927 case RDFREC_IMPORT: /* import symbol */
928 case RDFREC_FARIMPORT:
930 * scan the global symbol table for the symbol
931 * and associate its location with the segment number
932 * for this module
934 se = symtabFind(symtab, hr->i.label);
935 if (!se || se->segment == -1) {
936 if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
937 fprintf(error_file,
938 "error: unresolved reference to `%s'"
939 " in module `%s'\n", hr->i.label,
940 cur->name);
941 errorcount++;
944 * we need to allocate a segment number for this
945 * symbol, and store it in the symbol table for
946 * future reference
948 if (!se) {
949 se = malloc(sizeof(*se));
950 if (!se) {
951 fprintf(stderr, "ldrdf: out of memory\n");
952 exit(1);
954 se->name = strdup(hr->i.label);
955 se->flags = 0;
956 se->segment = availableseg++;
957 se->offset = 0;
958 symtabInsert(symtab, se);
959 } else {
960 se->segment = availableseg++;
961 se->offset = 0;
964 * output a header record that imports it to the
965 * recently allocated segment number...
967 newrec = *hr;
968 newrec.i.segment = se->segment;
969 rdfaddheader(rdfheader, &newrec);
972 add_seglocation(&segs, hr->i.segment, se->segment,
973 se->offset);
974 break;
976 case RDFREC_GLOBAL: /* export symbol */
978 * need to insert an export for this symbol into the new
979 * header, unless we're stripping symbols. Even if we're
980 * stripping, put the symbol if it's marked as SYM_GLOBAL.
982 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
983 break;
985 if (hr->e.segment == 2) {
986 seg = 2;
987 offset = cur->bss_reloc;
988 } else {
989 localseg = rdffindsegment(&cur->f, hr->e.segment);
990 if (localseg == -1) {
991 fprintf(stderr, "%s: exported symbol `%s' from "
992 "unrecognised segment\n", cur->name,
993 hr->e.label);
994 errorcount++;
995 break;
997 offset = cur->seginfo[localseg].reloc;
998 seg = cur->seginfo[localseg].dest_seg;
1001 hr->e.segment = seg;
1002 hr->e.offset += offset;
1003 rdfaddheader(rdfheader, hr);
1004 break;
1006 case RDFREC_MODNAME: /* module name */
1008 * Insert module name record if export symbols
1009 * are not stripped.
1010 * If module name begins with '$' - insert it anyway.
1012 if (options.strip && hr->m.modname[0] != '$')
1013 break;
1014 rdfaddheader(rdfheader, hr);
1015 break;
1017 case RDFREC_DLL: /* DLL name */
1019 * Insert DLL name if it begins with '$'
1021 if (hr->d.libname[0] != '$')
1022 break;
1023 rdfaddheader(rdfheader, hr);
1024 break;
1026 case RDFREC_SEGRELOC: /* segment fixup */
1028 * modify the segment numbers if necessary, and
1029 * pass straight through to the output module header
1031 * *** FIXME ***
1033 if (hr->r.segment == 2) {
1034 fprintf(stderr, "%s: segment fixup in BSS section\n",
1035 cur->name);
1036 errorcount++;
1037 break;
1039 localseg = rdffindsegment(&cur->f, hr->r.segment);
1040 if (localseg == -1) {
1041 fprintf(stderr, "%s: segment fixup in unrecognised"
1042 " segment (%d)\n", cur->name, hr->r.segment);
1043 errorcount++;
1044 break;
1046 hr->r.segment = cur->seginfo[localseg].dest_seg;
1047 hr->r.offset += cur->seginfo[localseg].reloc;
1049 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
1050 fprintf(stderr, "%s: segment fixup to undefined "
1051 "segment %04x\n", cur->name,
1052 (int)hr->r.refseg);
1053 errorcount++;
1054 break;
1056 hr->r.refseg = seg;
1057 rdfaddheader(rdfheader, hr);
1058 break;
1060 case RDFREC_COMMON: /* Common variable */
1061 /* Is this symbol already in the table? */
1062 se = symtabFind(symtab, hr->c.label);
1063 if (!se) {
1064 printf("%s is not in symtab yet\n", hr->c.label);
1065 break;
1067 /* Add segment location */
1068 add_seglocation(&segs, hr->c.segment, se->segment,
1069 se->offset);
1070 break;
1074 free(header);
1075 done_seglocations(&segs);
1080 * combined BSS reservation for the entire results
1082 newrec.type = RDFREC_BSS;
1083 newrec.b.reclen = 4;
1084 newrec.b.amount = bss_length;
1085 rdfaddheader(rdfheader, &newrec);
1088 * Write the header
1090 for (i = 0; i < nsegs; i++) {
1091 if (i == 2)
1092 continue;
1093 rdfaddsegment(rdfheader, outputseg[i].length);
1096 rdfwriteheader(f, rdfheader);
1097 rdfdoneheader(rdfheader);
1100 * Step through the segments, one at a time, writing out into
1101 * the output file
1103 for (i = 0; i < nsegs; i++) {
1104 uint16_t s;
1105 int32_t l;
1107 if (i == 2)
1108 continue;
1110 s = translateint16_t(outputseg[i].type);
1111 fwrite(&s, 2, 1, f);
1112 s = translateint16_t(outputseg[i].number);
1113 fwrite(&s, 2, 1, f);
1114 s = translateint16_t(outputseg[i].reserved);
1115 fwrite(&s, 2, 1, f);
1116 l = translateint32_t(outputseg[i].length);
1117 fwrite(&l, 4, 1, f);
1119 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1122 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f);
1125 /* =========================================================================
1126 * Main program
1129 void usage()
1131 printf("usage:\n"
1132 " ldrdf [options] object modules ... [-llibrary ...]\n"
1133 " ldrdf -r\n"
1134 "options:\n"
1135 " -v[=n] increase verbosity by 1, or set it to n\n"
1136 " -a nn set segment alignment value (default 16)\n"
1137 " -s strip public symbols\n"
1138 " -dy Unix-style dynamic linking\n"
1139 " -o name write output in file 'name'\n"
1140 " -j path specify objects search path\n"
1141 " -L path specify libraries search path\n"
1142 " -g file embed 'file' as a first header record with type 'generic'\n");
1143 exit(0);
1146 int main(int argc, char **argv)
1148 char *outname = "aout.rdf";
1149 int moduleloaded = 0;
1150 char *respstrings[128] = { 0, };
1152 options.verbose = 0;
1153 options.align = 16;
1154 options.dynalink = 0;
1155 options.strip = 0;
1157 error_file = stderr;
1159 argc--, argv++;
1160 if (argc == 0)
1161 usage();
1162 while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
1163 switch (argv[0][1]) {
1164 case 'r':
1165 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
1166 "\n");
1167 printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
1168 exit(0);
1169 case 'v':
1170 if (argv[0][2] == '=') {
1171 options.verbose = argv[0][3] - '0';
1172 if (options.verbose < 0 || options.verbose > 9) {
1173 fprintf(stderr,
1174 "ldrdf: verbosity level must be a number"
1175 " between 0 and 9\n");
1176 exit(1);
1178 } else
1179 options.verbose++;
1180 break;
1181 case 'a':
1182 options.align = atoi(argv[1]);
1183 if (options.align <= 0) {
1184 fprintf(stderr,
1185 "ldrdf: -a expects a positive number argument\n");
1186 exit(1);
1188 argv++, argc--;
1189 break;
1190 case 's':
1191 options.strip = 1;
1192 break;
1193 case 'd':
1194 if (argv[0][2] == 'y')
1195 options.dynalink = 1;
1196 break;
1197 case 'o':
1198 outname = argv[1];
1199 argv++, argc--;
1200 break;
1201 case 'j':
1202 if (!objpath) {
1203 options.objpath = 1;
1204 objpath = argv[1];
1205 argv++, argc--;
1206 break;
1207 } else {
1208 fprintf(stderr,
1209 "ldrdf: more than one objects search path specified\n");
1210 exit(1);
1212 case 'L':
1213 if (!libpath) {
1214 options.libpath = 1;
1215 libpath = argv[1];
1216 argv++, argc--;
1217 break;
1218 } else {
1219 fprintf(stderr,
1220 "ldrdf: more than one libraries search path specified\n");
1221 exit(1);
1223 case '@':{
1224 int i = 0;
1225 char buf[256];
1226 FILE *f;
1228 options.respfile = 1;
1229 if (argv[1] != NULL)
1230 f = fopen(argv[1], "r");
1231 else {
1232 fprintf(stderr,
1233 "ldrdf: no response file name specified\n");
1234 exit(1);
1237 if (f == NULL) {
1238 fprintf(stderr,
1239 "ldrdf: unable to open response file\n");
1240 exit(1);
1243 argv++, argc--;
1244 while (fgets(buf, sizeof(buf), f) != NULL) {
1245 char *p;
1246 if (buf[0] == '\n')
1247 continue;
1248 if ((p = strchr(buf, '\n')) != NULL)
1249 *p = '\0';
1250 if (i >= 128) {
1251 fprintf(stderr, "ldrdf: too many input files\n");
1252 exit(1);
1254 *(respstrings + i) = newstr(buf);
1255 argc++, i++;
1257 break;
1259 case '2':
1260 options.stderr_redir = 1;
1261 error_file = stdout;
1262 break;
1263 case 'g':
1264 generic_rec_file = argv[1];
1265 argv++, argc--;
1266 break;
1267 default:
1268 usage();
1270 argv++, argc--;
1273 if (options.verbose > 4) {
1274 printf("ldrdf invoked with options:\n");
1275 printf(" section alignment: %d bytes\n", options.align);
1276 printf(" output name: `%s'\n", outname);
1277 if (options.strip)
1278 printf(" strip symbols\n");
1279 if (options.dynalink)
1280 printf(" Unix-style dynamic linking\n");
1281 if (options.objpath)
1282 printf(" objects search path: %s\n", objpath);
1283 if (options.libpath)
1284 printf(" libraries search path: %s\n", libpath);
1285 printf("\n");
1288 symtab = symtabNew();
1289 initsegments();
1291 if (!symtab) {
1292 fprintf(stderr, "ldrdf: out of memory\n");
1293 exit(1);
1296 while (argc) {
1297 if (!*argv)
1298 argv = respstrings;
1299 if (!*argv)
1300 break;
1301 if (!strncmp(*argv, "-l", 2)) {
1302 if (libpath && (argv[0][2] != '/'))
1303 add_library(newstrcat(libpath, *argv + 2));
1304 else
1305 add_library(*argv + 2);
1306 } else {
1307 if (objpath && (argv[0][0] != '/'))
1308 loadmodule(newstrcat(objpath, *argv));
1309 else
1310 loadmodule(*argv);
1311 moduleloaded = 1;
1313 argv++, argc--;
1316 if (!moduleloaded) {
1317 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1318 return 0;
1321 search_libraries();
1323 if (options.verbose > 2) {
1324 printf("symbol table:\n");
1325 symtabDump(symtab, stdout);
1328 write_output(outname);
1330 if (errorcount > 0)
1331 exit(1);
1332 return 0;