BR 2781900: handle common labels while optimizing
[nasm/avx512.git] / rdoff / ldrdf.c
blobd137f163fc8500dbad3d598945754be6c773870a
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"
40 #include "nasmlib.h"
42 #define LDRDF_VERSION "1.07"
44 /* #define STINGY_MEMORY */
46 /* =======================================================================
47 * Types & macros that are private to this program
50 struct segment_infonode {
51 int dest_seg; /* output segment to be placed into, -1 to
52 skip linking this segment */
53 int32_t reloc; /* segment's relocation factor */
56 struct modulenode {
57 rdffile f; /* the RDOFF file structure */
58 struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
59 with each segment? */
60 void *header;
61 char *name;
62 struct modulenode *next;
63 int32_t bss_reloc;
66 #include "ldsegs.h"
68 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
69 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
71 /* ==========================================================================
72 * Function prototypes of private utility functions
75 void processmodule(const char *filename, struct modulenode *mod);
76 int allocnewseg(uint16_t type, uint16_t reserved);
77 int findsegment(uint16_t type, uint16_t reserved);
78 void symtab_add(const char *symbol, int segment, int32_t offset);
79 int symtab_get(const char *symbol, int *segment, int32_t *offset);
81 /* =========================================================================
82 * Global data structures.
85 /* a linked list of modules that will be included in the output */
86 struct modulenode *modules = NULL;
87 struct modulenode *lastmodule = NULL;
89 /* a linked list of libraries to be searched for unresolved imported symbols */
90 struct librarynode *libraries = NULL;
91 struct librarynode *lastlib = NULL;
93 /* the symbol table */
94 void *symtab = NULL;
96 /* objects search path */
97 char *objpath = NULL;
99 /* libraries search path */
100 char *libpath = NULL;
102 /* file to embed as a generic record */
103 char *generic_rec_file = NULL;
105 /* error file */
106 static FILE *error_file;
108 /* the header of the output file, built up stage by stage */
109 rdf_headerbuf *newheader = NULL;
111 /* The current state of segment allocation, including information about
112 * which output segment numbers have been allocated, and their types and
113 * amount of data which has already been allocated inside them.
115 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
116 int nsegs = 0;
117 int32_t bss_length;
119 /* global options which affect how the program behaves */
120 struct ldrdfoptions {
121 int verbose;
122 int align;
123 int dynalink;
124 int strip;
125 int respfile;
126 int stderr_redir;
127 int objpath;
128 int libpath;
129 } options;
131 int errorcount = 0; /* determines main program exit status */
133 /* =========================================================================
134 * Utility functions
138 * initsegments()
140 * sets up segments 0, 1, and 2, the initial code data and bss segments
142 void initsegments()
144 nsegs = 3;
145 outputseg[0].type = 1;
146 outputseg[0].number = 0;
147 outputseg[0].reserved = 0;
148 outputseg[0].length = 0;
149 outputseg[1].type = 2;
150 outputseg[1].number = 1;
151 outputseg[1].reserved = 0;
152 outputseg[1].length = 0;
153 outputseg[2].type = 0xFFFF; /* reserved segment type */
154 outputseg[2].number = 2;
155 outputseg[2].reserved = 0;
156 outputseg[2].length = 0;
157 bss_length = 0;
161 * loadmodule
163 * Determine the characteristics of a module, and decide what to do with
164 * each segment it contains (including determining destination segments and
165 * relocation factors for segments that are kept).
167 void loadmodule(const char *filename)
169 if (options.verbose)
170 printf("loading `%s'\n", filename);
172 /* allocate a new module entry on the end of the modules list */
173 if (!modules) {
174 modules = malloc(sizeof(*modules));
175 lastmodule = modules;
176 } else {
177 lastmodule->next = malloc(sizeof(*modules));
178 lastmodule = lastmodule->next;
181 if (!lastmodule) {
182 fprintf(stderr, "ldrdf: out of memory\n");
183 exit(1);
186 /* open the file using 'rdfopen', which returns nonzero on error */
187 if (rdfopen(&lastmodule->f, filename) != 0) {
188 rdfperror("ldrdf", filename);
189 exit(1);
193 * store information about the module, and determine what segments
194 * it contains, and what we should do with them (determine relocation
195 * factor if we decide to keep them)
197 lastmodule->header = NULL;
198 lastmodule->name = strdup(filename);
199 lastmodule->next = NULL;
201 processmodule(filename, lastmodule);
205 * processmodule()
207 * step through each segment, determine what exactly we're doing with
208 * it, and if we intend to keep it, determine (a) which segment to
209 * put it in and (b) whereabouts in that segment it will end up.
210 * (b) is fairly easy, because we're now keeping track of how big each
211 * segment in our output file is...
213 void processmodule(const char *filename, struct modulenode *mod)
215 struct segconfig sconf;
216 int seg, outseg;
217 void *header;
218 rdfheaderrec *hr;
219 int32_t bssamount = 0;
220 int bss_was_referenced = 0;
222 memset(&sconf, 0, sizeof sconf);
224 for (seg = 0; seg < mod->f.nsegs; seg++) {
226 * get the segment configuration for this type from the segment
227 * table. getsegconfig() is a macro, defined in ldsegs.h.
229 getsegconfig(sconf, mod->f.seg[seg].type);
231 if (options.verbose > 1) {
232 printf("%s %04x [%04x:%10s] ", filename,
233 mod->f.seg[seg].number, mod->f.seg[seg].type,
234 sconf.typedesc);
237 * sconf->dowhat tells us what to do with a segment of this type.
239 switch (sconf.dowhat) {
240 case SEG_IGNORE:
242 * Set destination segment to -1, to indicate that this segment
243 * should be ignored for the purpose of output, ie it is left
244 * out of the linked executable.
246 mod->seginfo[seg].dest_seg = -1;
247 if (options.verbose > 1)
248 printf("IGNORED\n");
249 break;
251 case SEG_NEWSEG:
253 * The configuration tells us to create a new segment for
254 * each occurrence of this segment type.
256 outseg = allocnewseg(sconf.mergetype,
257 mod->f.seg[seg].reserved);
258 mod->seginfo[seg].dest_seg = outseg;
259 mod->seginfo[seg].reloc = 0;
260 outputseg[outseg].length = mod->f.seg[seg].length;
261 if (options.verbose > 1)
262 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
263 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
264 break;
266 case SEG_MERGE:
268 * The configuration tells us to merge the segment with
269 * a previously existing segment of type 'sconf.mergetype',
270 * if one exists. Otherwise a new segment is created.
271 * This is handled transparently by 'findsegment()'.
273 outseg = findsegment(sconf.mergetype,
274 mod->f.seg[seg].reserved);
275 mod->seginfo[seg].dest_seg = outseg;
278 * We need to add alignment to these segments.
280 if (outputseg[outseg].length % options.align != 0)
281 outputseg[outseg].length +=
282 options.align -
283 (outputseg[outseg].length % options.align);
285 mod->seginfo[seg].reloc = outputseg[outseg].length;
286 outputseg[outseg].length += mod->f.seg[seg].length;
288 if (options.verbose > 1)
289 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
290 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
296 * extract symbols from the header, and dump them into the
297 * symbol table
299 header = malloc(mod->f.header_len);
300 if (!header) {
301 fprintf(stderr, "ldrdf: not enough memory\n");
302 exit(1);
304 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
305 rdfperror("ldrdf", filename);
306 exit(1);
309 while ((hr = rdfgetheaderrec(&mod->f))) {
310 switch (hr->type) {
311 case RDFREC_IMPORT: /* imported symbol */
312 case RDFREC_FARIMPORT:
313 /* Define with seg = -1 */
314 symtab_add(hr->i.label, -1, 0);
315 break;
317 case RDFREC_GLOBAL:{ /* exported symbol */
318 int destseg;
319 int32_t destreloc;
321 if (hr->e.segment == 2) {
322 bss_was_referenced = 1;
323 destreloc = bss_length;
324 if (destreloc % options.align != 0)
325 destreloc +=
326 options.align - (destreloc % options.align);
327 destseg = 2;
328 } else {
329 if ((destseg =
330 mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
331 continue;
332 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
334 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
335 break;
338 case RDFREC_BSS: /* BSS reservation */
340 * first, amalgamate all BSS reservations in this module
341 * into one, because we allow this in the output format.
343 bssamount += hr->b.amount;
344 break;
346 case RDFREC_COMMON:{ /* Common variable */
347 symtabEnt *ste = symtabFind(symtab, hr->c.label);
349 /* Is the symbol already in the table? */
350 if (ste)
351 break;
353 /* Align the variable */
354 if (bss_length % hr->c.align != 0)
355 bss_length += hr->c.align - (bss_length % hr->c.align);
356 if (options.verbose > 1) {
357 printf("%s %04x common '%s' => 0002:%08"PRIx32" (+%04"PRIx32")\n",
358 filename, hr->c.segment, hr->c.label,
359 bss_length, hr->c.size);
362 symtab_add(hr->c.label, 2, bss_length);
363 mod->bss_reloc = bss_length;
364 bss_length += hr->c.size;
365 break;
370 if (bssamount != 0 || bss_was_referenced) {
372 * handle the BSS segment - first pad the existing bss length
373 * to the correct alignment, then store the length in bss_reloc
374 * for this module. Then add this module's BSS length onto
375 * bss_length.
377 if (bss_length % options.align != 0)
378 bss_length += options.align - (bss_length % options.align);
380 mod->bss_reloc = bss_length;
381 if (options.verbose > 1) {
382 printf("%s 0002 [ BSS] => 0002:%08"PRIx32" (+%04"PRIx32")\n",
383 filename, bss_length, bssamount);
385 bss_length += bssamount;
387 #ifdef STINGY_MEMORY
389 * we free the header buffer here, to save memory later.
390 * this isn't efficient, but probably halves the memory usage
391 * of this program...
393 mod->f.header_loc = NULL;
394 free(header);
396 #endif
401 * Return 1 if a given module is in the list, 0 otherwise.
403 int lookformodule(const char *name)
405 struct modulenode *curr = modules;
407 while (curr) {
408 if (!strcmp(name, curr->name))
409 return 1;
410 curr = curr->next;
412 return 0;
416 * allocnewseg()
417 * findsegment()
419 * These functions manipulate the array of output segments, and are used
420 * by processmodule(). allocnewseg() allocates a segment in the array,
421 * initialising it to be empty. findsegment() first scans the array for
422 * a segment of the type requested, and if one isn't found allocates a
423 * new one.
425 int allocnewseg(uint16_t type, uint16_t reserved)
427 outputseg[nsegs].type = type;
428 outputseg[nsegs].number = nsegs;
429 outputseg[nsegs].reserved = reserved;
430 outputseg[nsegs].length = 0;
431 outputseg[nsegs].offset = 0;
432 outputseg[nsegs].data = NULL;
434 return nsegs++;
437 int findsegment(uint16_t type, uint16_t reserved)
439 int i;
441 for (i = 0; i < nsegs; i++)
442 if (outputseg[i].type == type)
443 return i;
445 return allocnewseg(type, reserved);
449 * symtab_add()
451 * inserts a symbol into the global symbol table, which associates symbol
452 * names either with addresses, or a marker that the symbol hasn't been
453 * resolved yet, or possibly that the symbol has been defined as
454 * contained in a dynamic [load time/run time] linked library.
456 * segment = -1 => not yet defined
457 * segment = -2 => defined as dll symbol
459 * If the symbol is already defined, and the new segment >= 0, then
460 * if the original segment was < 0 the symbol is redefined, otherwise
461 * a duplicate symbol warning is issued. If new segment == -1, this
462 * routine won't change a previously existing symbol. It will change
463 * to segment = -2 only if the segment was previously < 0.
465 void symtab_add(const char *symbol, int segment, int32_t offset)
467 symtabEnt *ste;
469 ste = symtabFind(symtab, symbol);
470 if (ste) {
471 if (ste->segment >= 0) {
473 * symbol previously defined
475 if (segment < 0)
476 return;
477 fprintf(error_file, "warning: `%s' redefined\n", symbol);
478 return;
482 * somebody wanted the symbol, and put an undefined symbol
483 * marker into the table
485 if (segment == -1)
486 return;
488 * we have more information now - update the symbol's entry
490 ste->segment = segment;
491 ste->offset = offset;
492 ste->flags = 0;
493 return;
496 * this is the first declaration of this symbol
498 ste = malloc(sizeof(symtabEnt));
499 if (!ste) {
500 fprintf(stderr, "ldrdf: out of memory\n");
501 exit(1);
503 ste->name = strdup(symbol);
504 ste->segment = segment;
505 ste->offset = offset;
506 ste->flags = 0;
507 symtabInsert(symtab, ste);
511 * symtab_get()
513 * Retrieves the values associated with a symbol. Undefined symbols
514 * are assumed to have -1:0 associated. Returns 1 if the symbol was
515 * successfully located.
517 int symtab_get(const char *symbol, int *segment, int32_t *offset)
519 symtabEnt *ste = symtabFind(symtab, symbol);
520 if (!ste) {
521 *segment = -1;
522 *offset = 0;
523 return 0;
524 } else {
525 *segment = ste->segment;
526 *offset = ste->offset;
527 return 1;
532 * add_library()
534 * checks that a library can be opened and is in the correct format,
535 * then adds it to the linked list of libraries.
537 void add_library(const char *name)
539 if (rdl_verify(name)) {
540 rdl_perror("ldrdf", name);
541 errorcount++;
542 return;
544 if (!libraries) {
545 lastlib = libraries = malloc(sizeof(*libraries));
546 if (!libraries) {
547 fprintf(stderr, "ldrdf: out of memory\n");
548 exit(1);
550 } else {
551 lastlib->next = malloc(sizeof(*libraries));
552 if (!lastlib->next) {
553 fprintf(stderr, "ldrdf: out of memory\n");
554 exit(1);
556 lastlib = lastlib->next;
558 lastlib->next = NULL;
559 if (rdl_open(lastlib, name)) {
560 rdl_perror("ldrdf", name);
561 errorcount++;
562 return;
567 * search_libraries()
569 * scans through the list of libraries, attempting to match symbols
570 * defined in library modules against symbols that are referenced but
571 * not defined (segment = -1 in the symbol table)
573 * returns 1 if any extra library modules are included, indicating that
574 * another pass through the library list should be made (possibly).
576 int search_libraries()
578 struct librarynode *cur;
579 rdffile f;
580 int i;
581 void *header;
582 int segment;
583 int32_t offset;
584 int doneanything = 0, pass = 1, keepfile;
585 rdfheaderrec *hr;
587 cur = libraries;
589 while (cur) {
590 if (options.verbose > 2)
591 printf("scanning library `%s', pass %d...\n", cur->name, pass);
593 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
594 if (pass == 2 && lookformodule(f.name))
595 continue;
597 if (options.verbose > 3)
598 printf(" looking in module `%s'\n", f.name);
600 header = malloc(f.header_len);
601 if (!header) {
602 fprintf(stderr, "ldrdf: not enough memory\n");
603 exit(1);
605 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
606 rdfperror("ldrdf", f.name);
607 errorcount++;
608 return 0;
611 keepfile = 0;
613 while ((hr = rdfgetheaderrec(&f))) {
614 /* We're only interested in exports, so skip others */
615 if (hr->type != RDFREC_GLOBAL)
616 continue;
619 * If the symbol is marked as SYM_GLOBAL, somebody will be
620 * definitely interested in it..
622 if ((hr->e.flags & SYM_GLOBAL) == 0) {
624 * otherwise the symbol is just public. Find it in
625 * the symbol table. If the symbol isn't defined, we
626 * aren't interested, so go on to the next.
627 * If it is defined as anything but -1, we're also not
628 * interested. But if it is defined as -1, insert this
629 * module into the list of modules to use, and go
630 * immediately on to the next module...
632 if (!symtab_get(hr->e.label, &segment, &offset)
633 || segment != -1)
634 continue;
637 doneanything = 1;
638 keepfile = 1;
641 * as there are undefined symbols, we can assume that
642 * there are modules on the module list by the time
643 * we get here.
645 lastmodule->next = malloc(sizeof(*lastmodule->next));
646 if (!lastmodule->next) {
647 fprintf(stderr, "ldrdf: not enough memory\n");
648 exit(1);
650 lastmodule = lastmodule->next;
651 memcpy(&lastmodule->f, &f, sizeof(f));
652 lastmodule->name = strdup(f.name);
653 lastmodule->next = NULL;
654 processmodule(f.name, lastmodule);
655 break;
657 if (!keepfile) {
658 free(f.name);
659 f.name = NULL;
660 f.fp = NULL;
663 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
664 rdl_perror("ldrdf", cur->name);
666 cur = cur->next;
667 if (cur == NULL && pass == 1) {
668 cur = libraries;
669 pass++;
673 return doneanything;
677 * write_output()
679 * this takes the linked list of modules, and walks through it, merging
680 * all the modules into a single output module, and then writes this to a
681 * file.
683 void write_output(const char *filename)
685 FILE *f;
686 rdf_headerbuf *rdfheader;
687 struct modulenode *cur;
688 int i, availableseg, seg, localseg, isrelative;
689 void *header;
690 rdfheaderrec *hr, newrec;
691 symtabEnt *se;
692 segtab segs;
693 int32_t offset;
694 uint8_t *data;
696 if ((f = fopen(filename, "wb")) == NULL) {
697 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
698 exit(1);
700 if ((rdfheader = rdfnewheader()) == NULL) {
701 fprintf(stderr, "ldrdf: out of memory\n");
702 exit(1);
706 * If '-g' option was given, first record in output file will be a
707 * `generic' record, filled with a given file content.
708 * This can be useful, for example, when constructing multiboot
709 * compliant kernels.
711 if (generic_rec_file) {
712 FILE *ff;
714 if (options.verbose)
715 printf("\nadding generic record from binary file %s\n",
716 generic_rec_file);
718 hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec));
719 if ((ff = fopen(generic_rec_file, "r")) == NULL) {
720 fprintf(stderr, "ldrdf: couldn't open %s for input\n",
721 generic_rec_file);
722 exit(1);
724 i = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
725 fseek(ff, 0, SEEK_END);
726 if (ftell(ff) > (long)sizeof(hr->g.data)) {
727 fprintf(error_file,
728 "warning: maximum generic record size is %u, "
729 "rest of file ignored\n",
730 (unsigned int)sizeof(hr->g.data));
732 fclose(ff);
734 hr->g.type = 0;
735 hr->g.reclen = i;
736 rdfaddheader(rdfheader, hr);
737 free(hr);
740 if (options.verbose)
741 printf("\nbuilding output module (%d segments)\n", nsegs);
744 * Allocate the memory for the segments. We may be better off
745 * building the output module one segment at a time when running
746 * under 16 bit DOS, but that would be a slower way of doing this.
747 * And you could always use DJGPP...
749 for (i = 0; i < nsegs; i++) {
750 outputseg[i].data = NULL;
751 if (!outputseg[i].length)
752 continue;
753 outputseg[i].data = malloc(outputseg[i].length);
754 if (!outputseg[i].data) {
755 fprintf(stderr, "ldrdf: out of memory\n");
756 exit(1);
761 * initialise availableseg, used to allocate segment numbers for
762 * imported and exported labels...
764 availableseg = nsegs;
767 * Step through the modules, performing required actions on each one
769 for (cur = modules; cur; cur = cur->next) {
771 * Read the actual segment contents into the correct places in
772 * the newly allocated segments
775 for (i = 0; i < cur->f.nsegs; i++) {
776 int dest = cur->seginfo[i].dest_seg;
778 if (dest == -1)
779 continue;
780 if (rdfloadseg(&cur->f, i,
781 outputseg[dest].data + cur->seginfo[i].reloc)) {
782 rdfperror("ldrdf", cur->name);
783 exit(1);
788 * Perform fixups, and add new header records where required
791 header = malloc(cur->f.header_len);
792 if (!header) {
793 fprintf(stderr, "ldrdf: out of memory\n");
794 exit(1);
797 if (cur->f.header_loc)
798 rdfheaderrewind(&cur->f);
799 else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
800 rdfperror("ldrdf", cur->name);
801 exit(1);
805 * we need to create a local segment number -> location
806 * table for the segments in this module.
808 init_seglocations(&segs);
809 for (i = 0; i < cur->f.nsegs; i++) {
810 add_seglocation(&segs, cur->f.seg[i].number,
811 cur->seginfo[i].dest_seg,
812 cur->seginfo[i].reloc);
815 * and the BSS segment (doh!)
817 add_seglocation(&segs, 2, 2, cur->bss_reloc);
819 while ((hr = rdfgetheaderrec(&cur->f))) {
820 switch (hr->type) {
821 case RDFREC_RELOC: /* relocation record - need to do a fixup */
823 * First correct the offset stored in the segment from
824 * the start of the segment (which may well have changed).
826 * To do this we add to the number stored the relocation
827 * factor associated with the segment that contains the
828 * target segment.
830 * The relocation could be a relative relocation, in which
831 * case we have to first subtract the amount we've relocated
832 * the containing segment by.
834 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
835 fprintf(stderr,
836 "%s: reloc to undefined segment %04x\n",
837 cur->name, (int)hr->r.refseg);
838 errorcount++;
839 break;
842 isrelative =
843 (hr->r.segment & RDOFF_RELATIVEMASK) ==
844 RDOFF_RELATIVEMASK;
845 hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
847 if (hr->r.segment == 2 ||
848 (localseg =
849 rdffindsegment(&cur->f, hr->r.segment)) == -1) {
850 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
851 cur->name,
852 hr->r.segment == 2 ? "BSS" : "unknown",
853 hr->r.segment);
854 errorcount++;
855 break;
858 if (hr->r.length != 1 && hr->r.length != 2 &&
859 hr->r.length != 4) {
860 fprintf(stderr, "%s: nonstandard length reloc "
861 "(%d bytes)\n", cur->name, hr->r.length);
862 errorcount++;
863 break;
867 * okay, now the relocation is in the segment pointed to by
868 * cur->seginfo[localseg], and we know everything else is
869 * okay to go ahead and do the relocation
871 data = outputseg[cur->seginfo[localseg].dest_seg].data;
872 data += cur->seginfo[localseg].reloc + hr->r.offset;
875 * data now points to the reference that needs
876 * relocation. Calculate the relocation factor.
877 * Factor is:
878 * offset of referred object in segment [in offset]
879 * (- relocation of localseg, if ref is relative)
880 * For simplicity, the result is stored in 'offset'.
881 * Then add 'offset' onto the value at data.
884 if (isrelative)
885 offset -= cur->seginfo[localseg].reloc;
886 switch (hr->r.length) {
887 case 1:
888 offset += *data;
889 if (offset < -127 || offset > 128)
890 fprintf(error_file,
891 "warning: relocation out of range "
892 "at %s(%02x:%08"PRIx32")\n", cur->name,
893 (int)hr->r.segment, hr->r.offset);
894 *data = (char)offset;
895 break;
896 case 2:
897 offset += *(int16_t *)data;
898 if (offset < -32767 || offset > 32768)
899 fprintf(error_file,
900 "warning: relocation out of range "
901 "at %s(%02x:%08"PRIx32")\n", cur->name,
902 (int)hr->r.segment, hr->r.offset);
903 *(int16_t *)data = (int16_t)offset;
904 break;
905 case 4:
906 *(int32_t *)data += offset;
907 /* we can't easily detect overflow on this one */
908 break;
912 * If the relocation was relative between two symbols in
913 * the same segment, then we're done.
915 * Otherwise, we need to output a new relocation record
916 * with the references updated segment and offset...
918 if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
919 hr->r.segment = cur->seginfo[localseg].dest_seg;
920 hr->r.offset += cur->seginfo[localseg].reloc;
921 hr->r.refseg = seg;
922 if (isrelative)
923 hr->r.segment += RDOFF_RELATIVEMASK;
924 rdfaddheader(rdfheader, hr);
926 break;
928 case RDFREC_IMPORT: /* import symbol */
929 case RDFREC_FARIMPORT:
931 * scan the global symbol table for the symbol
932 * and associate its location with the segment number
933 * for this module
935 se = symtabFind(symtab, hr->i.label);
936 if (!se || se->segment == -1) {
937 if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
938 fprintf(error_file,
939 "error: unresolved reference to `%s'"
940 " in module `%s'\n", hr->i.label,
941 cur->name);
942 errorcount++;
945 * we need to allocate a segment number for this
946 * symbol, and store it in the symbol table for
947 * future reference
949 if (!se) {
950 se = malloc(sizeof(*se));
951 if (!se) {
952 fprintf(stderr, "ldrdf: out of memory\n");
953 exit(1);
955 se->name = strdup(hr->i.label);
956 se->flags = 0;
957 se->segment = availableseg++;
958 se->offset = 0;
959 symtabInsert(symtab, se);
960 } else {
961 se->segment = availableseg++;
962 se->offset = 0;
965 * output a header record that imports it to the
966 * recently allocated segment number...
968 newrec = *hr;
969 newrec.i.segment = se->segment;
970 rdfaddheader(rdfheader, &newrec);
973 add_seglocation(&segs, hr->i.segment, se->segment,
974 se->offset);
975 break;
977 case RDFREC_GLOBAL: /* export symbol */
979 * need to insert an export for this symbol into the new
980 * header, unless we're stripping symbols. Even if we're
981 * stripping, put the symbol if it's marked as SYM_GLOBAL.
983 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
984 break;
986 if (hr->e.segment == 2) {
987 seg = 2;
988 offset = cur->bss_reloc;
989 } else {
990 localseg = rdffindsegment(&cur->f, hr->e.segment);
991 if (localseg == -1) {
992 fprintf(stderr, "%s: exported symbol `%s' from "
993 "unrecognised segment\n", cur->name,
994 hr->e.label);
995 errorcount++;
996 break;
998 offset = cur->seginfo[localseg].reloc;
999 seg = cur->seginfo[localseg].dest_seg;
1002 hr->e.segment = seg;
1003 hr->e.offset += offset;
1004 rdfaddheader(rdfheader, hr);
1005 break;
1007 case RDFREC_MODNAME: /* module name */
1009 * Insert module name record if export symbols
1010 * are not stripped.
1011 * If module name begins with '$' - insert it anyway.
1013 if (options.strip && hr->m.modname[0] != '$')
1014 break;
1015 rdfaddheader(rdfheader, hr);
1016 break;
1018 case RDFREC_DLL: /* DLL name */
1020 * Insert DLL name if it begins with '$'
1022 if (hr->d.libname[0] != '$')
1023 break;
1024 rdfaddheader(rdfheader, hr);
1025 break;
1027 case RDFREC_SEGRELOC: /* segment fixup */
1029 * modify the segment numbers if necessary, and
1030 * pass straight through to the output module header
1032 * *** FIXME ***
1034 if (hr->r.segment == 2) {
1035 fprintf(stderr, "%s: segment fixup in BSS section\n",
1036 cur->name);
1037 errorcount++;
1038 break;
1040 localseg = rdffindsegment(&cur->f, hr->r.segment);
1041 if (localseg == -1) {
1042 fprintf(stderr, "%s: segment fixup in unrecognised"
1043 " segment (%d)\n", cur->name, hr->r.segment);
1044 errorcount++;
1045 break;
1047 hr->r.segment = cur->seginfo[localseg].dest_seg;
1048 hr->r.offset += cur->seginfo[localseg].reloc;
1050 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
1051 fprintf(stderr, "%s: segment fixup to undefined "
1052 "segment %04x\n", cur->name,
1053 (int)hr->r.refseg);
1054 errorcount++;
1055 break;
1057 hr->r.refseg = seg;
1058 rdfaddheader(rdfheader, hr);
1059 break;
1061 case RDFREC_COMMON: /* Common variable */
1062 /* Is this symbol already in the table? */
1063 se = symtabFind(symtab, hr->c.label);
1064 if (!se) {
1065 printf("%s is not in symtab yet\n", hr->c.label);
1066 break;
1068 /* Add segment location */
1069 add_seglocation(&segs, hr->c.segment, se->segment,
1070 se->offset);
1071 break;
1075 free(header);
1076 done_seglocations(&segs);
1081 * combined BSS reservation for the entire results
1083 newrec.type = RDFREC_BSS;
1084 newrec.b.reclen = 4;
1085 newrec.b.amount = bss_length;
1086 rdfaddheader(rdfheader, &newrec);
1089 * Write the header
1091 for (i = 0; i < nsegs; i++) {
1092 if (i == 2)
1093 continue;
1094 rdfaddsegment(rdfheader, outputseg[i].length);
1097 rdfwriteheader(f, rdfheader);
1098 rdfdoneheader(rdfheader);
1101 * Step through the segments, one at a time, writing out into
1102 * the output file
1104 for (i = 0; i < nsegs; i++) {
1105 uint16_t s;
1106 int32_t l;
1108 if (i == 2)
1109 continue;
1111 s = translateint16_t(outputseg[i].type);
1112 fwrite(&s, 2, 1, f);
1113 s = translateint16_t(outputseg[i].number);
1114 fwrite(&s, 2, 1, f);
1115 s = translateint16_t(outputseg[i].reserved);
1116 fwrite(&s, 2, 1, f);
1117 l = translateint32_t(outputseg[i].length);
1118 fwrite(&l, 4, 1, f);
1120 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1123 fwritezero(10, f);
1126 /* =========================================================================
1127 * Main program
1130 void usage()
1132 printf("usage:\n"
1133 " ldrdf [options] object modules ... [-llibrary ...]\n"
1134 " ldrdf -r\n"
1135 "options:\n"
1136 " -v[=n] increase verbosity by 1, or set it to n\n"
1137 " -a nn set segment alignment value (default 16)\n"
1138 " -s strip public symbols\n"
1139 " -dy Unix-style dynamic linking\n"
1140 " -o name write output in file 'name'\n"
1141 " -j path specify objects search path\n"
1142 " -L path specify libraries search path\n"
1143 " -g file embed 'file' as a first header record with type 'generic'\n");
1144 exit(0);
1147 int main(int argc, char **argv)
1149 char *outname = "aout.rdf";
1150 int moduleloaded = 0;
1151 char *respstrings[128] = { 0, };
1153 options.verbose = 0;
1154 options.align = 16;
1155 options.dynalink = 0;
1156 options.strip = 0;
1158 error_file = stderr;
1160 argc--, argv++;
1161 if (argc == 0)
1162 usage();
1163 while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
1164 switch (argv[0][1]) {
1165 case 'r':
1166 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
1167 "\n");
1168 printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
1169 exit(0);
1170 case 'v':
1171 if (argv[0][2] == '=') {
1172 options.verbose = argv[0][3] - '0';
1173 if (options.verbose < 0 || options.verbose > 9) {
1174 fprintf(stderr,
1175 "ldrdf: verbosity level must be a number"
1176 " between 0 and 9\n");
1177 exit(1);
1179 } else
1180 options.verbose++;
1181 break;
1182 case 'a':
1183 options.align = atoi(argv[1]);
1184 if (options.align <= 0) {
1185 fprintf(stderr,
1186 "ldrdf: -a expects a positive number argument\n");
1187 exit(1);
1189 argv++, argc--;
1190 break;
1191 case 's':
1192 options.strip = 1;
1193 break;
1194 case 'd':
1195 if (argv[0][2] == 'y')
1196 options.dynalink = 1;
1197 break;
1198 case 'o':
1199 outname = argv[1];
1200 argv++, argc--;
1201 break;
1202 case 'j':
1203 if (!objpath) {
1204 options.objpath = 1;
1205 objpath = argv[1];
1206 argv++, argc--;
1207 break;
1208 } else {
1209 fprintf(stderr,
1210 "ldrdf: more than one objects search path specified\n");
1211 exit(1);
1213 case 'L':
1214 if (!libpath) {
1215 options.libpath = 1;
1216 libpath = argv[1];
1217 argv++, argc--;
1218 break;
1219 } else {
1220 fprintf(stderr,
1221 "ldrdf: more than one libraries search path specified\n");
1222 exit(1);
1224 case '@':{
1225 int i = 0;
1226 char buf[256];
1227 FILE *f;
1229 options.respfile = 1;
1230 if (argv[1] != NULL)
1231 f = fopen(argv[1], "r");
1232 else {
1233 fprintf(stderr,
1234 "ldrdf: no response file name specified\n");
1235 exit(1);
1238 if (f == NULL) {
1239 fprintf(stderr,
1240 "ldrdf: unable to open response file\n");
1241 exit(1);
1244 argv++, argc--;
1245 while (fgets(buf, sizeof(buf), f) != NULL) {
1246 char *p;
1247 if (buf[0] == '\n')
1248 continue;
1249 if ((p = strchr(buf, '\n')) != NULL)
1250 *p = '\0';
1251 if (i >= 128) {
1252 fprintf(stderr, "ldrdf: too many input files\n");
1253 exit(1);
1255 *(respstrings + i) = newstr(buf);
1256 argc++, i++;
1258 break;
1260 case '2':
1261 options.stderr_redir = 1;
1262 error_file = stdout;
1263 break;
1264 case 'g':
1265 generic_rec_file = argv[1];
1266 argv++, argc--;
1267 break;
1268 default:
1269 usage();
1271 argv++, argc--;
1274 if (options.verbose > 4) {
1275 printf("ldrdf invoked with options:\n");
1276 printf(" section alignment: %d bytes\n", options.align);
1277 printf(" output name: `%s'\n", outname);
1278 if (options.strip)
1279 printf(" strip symbols\n");
1280 if (options.dynalink)
1281 printf(" Unix-style dynamic linking\n");
1282 if (options.objpath)
1283 printf(" objects search path: %s\n", objpath);
1284 if (options.libpath)
1285 printf(" libraries search path: %s\n", libpath);
1286 printf("\n");
1289 symtab = symtabNew();
1290 initsegments();
1292 if (!symtab) {
1293 fprintf(stderr, "ldrdf: out of memory\n");
1294 exit(1);
1297 while (argc) {
1298 if (!*argv)
1299 argv = respstrings;
1300 if (!*argv)
1301 break;
1302 if (!strncmp(*argv, "-l", 2)) {
1303 if (libpath && (argv[0][2] != '/'))
1304 add_library(newstrcat(libpath, *argv + 2));
1305 else
1306 add_library(*argv + 2);
1307 } else {
1308 if (objpath && (argv[0][0] != '/'))
1309 loadmodule(newstrcat(objpath, *argv));
1310 else
1311 loadmodule(*argv);
1312 moduleloaded = 1;
1314 argv++, argc--;
1317 if (!moduleloaded) {
1318 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1319 return 0;
1322 search_libraries();
1324 if (options.verbose > 2) {
1325 printf("symbol table:\n");
1326 symtabDump(symtab, stdout);
1329 write_output(outname);
1331 if (errorcount > 0)
1332 exit(1);
1333 return 0;