phash.ph: yet another attempt at getting Perl to behave, arithmetically
[nasm/avx512.git] / rdoff / ldrdf.c
blobe28f28428e5bb7fea248cd881f0cb55ce4bf3959
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 %u, "
724 "rest of file ignored\n",
725 (unsigned int)sizeof(hr->g.data));
727 fclose(ff);
729 hr->g.type = 0;
730 hr->g.reclen = i;
731 rdfaddheader(rdfheader, hr);
732 free(hr);
735 if (options.verbose)
736 printf("\nbuilding output module (%d segments)\n", nsegs);
739 * Allocate the memory for the segments. We may be better off
740 * building the output module one segment at a time when running
741 * under 16 bit DOS, but that would be a slower way of doing this.
742 * And you could always use DJGPP...
744 for (i = 0; i < nsegs; i++) {
745 outputseg[i].data = NULL;
746 if (!outputseg[i].length)
747 continue;
748 outputseg[i].data = malloc(outputseg[i].length);
749 if (!outputseg[i].data) {
750 fprintf(stderr, "ldrdf: out of memory\n");
751 exit(1);
756 * initialise availableseg, used to allocate segment numbers for
757 * imported and exported labels...
759 availableseg = nsegs;
762 * Step through the modules, performing required actions on each one
764 for (cur = modules; cur; cur = cur->next) {
766 * Read the actual segment contents into the correct places in
767 * the newly allocated segments
770 for (i = 0; i < cur->f.nsegs; i++) {
771 int dest = cur->seginfo[i].dest_seg;
773 if (dest == -1)
774 continue;
775 if (rdfloadseg(&cur->f, i,
776 outputseg[dest].data + cur->seginfo[i].reloc)) {
777 rdfperror("ldrdf", cur->name);
778 exit(1);
783 * Perform fixups, and add new header records where required
786 header = malloc(cur->f.header_len);
787 if (!header) {
788 fprintf(stderr, "ldrdf: out of memory\n");
789 exit(1);
792 if (cur->f.header_loc)
793 rdfheaderrewind(&cur->f);
794 else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
795 rdfperror("ldrdf", cur->name);
796 exit(1);
800 * we need to create a local segment number -> location
801 * table for the segments in this module.
803 init_seglocations(&segs);
804 for (i = 0; i < cur->f.nsegs; i++) {
805 add_seglocation(&segs, cur->f.seg[i].number,
806 cur->seginfo[i].dest_seg,
807 cur->seginfo[i].reloc);
810 * and the BSS segment (doh!)
812 add_seglocation(&segs, 2, 2, cur->bss_reloc);
814 while ((hr = rdfgetheaderrec(&cur->f))) {
815 switch (hr->type) {
816 case RDFREC_RELOC: /* relocation record - need to do a fixup */
818 * First correct the offset stored in the segment from
819 * the start of the segment (which may well have changed).
821 * To do this we add to the number stored the relocation
822 * factor associated with the segment that contains the
823 * target segment.
825 * The relocation could be a relative relocation, in which
826 * case we have to first subtract the amount we've relocated
827 * the containing segment by.
829 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
830 fprintf(stderr,
831 "%s: reloc to undefined segment %04x\n",
832 cur->name, (int)hr->r.refseg);
833 errorcount++;
834 break;
837 isrelative =
838 (hr->r.segment & RDOFF_RELATIVEMASK) ==
839 RDOFF_RELATIVEMASK;
840 hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
842 if (hr->r.segment == 2 ||
843 (localseg =
844 rdffindsegment(&cur->f, hr->r.segment)) == -1) {
845 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
846 cur->name,
847 hr->r.segment == 2 ? "BSS" : "unknown",
848 hr->r.segment);
849 errorcount++;
850 break;
853 if (hr->r.length != 1 && hr->r.length != 2 &&
854 hr->r.length != 4) {
855 fprintf(stderr, "%s: nonstandard length reloc "
856 "(%d bytes)\n", cur->name, hr->r.length);
857 errorcount++;
858 break;
862 * okay, now the relocation is in the segment pointed to by
863 * cur->seginfo[localseg], and we know everything else is
864 * okay to go ahead and do the relocation
866 data = outputseg[cur->seginfo[localseg].dest_seg].data;
867 data += cur->seginfo[localseg].reloc + hr->r.offset;
870 * data now points to the reference that needs
871 * relocation. Calculate the relocation factor.
872 * Factor is:
873 * offset of referred object in segment [in offset]
874 * (- relocation of localseg, if ref is relative)
875 * For simplicity, the result is stored in 'offset'.
876 * Then add 'offset' onto the value at data.
879 if (isrelative)
880 offset -= cur->seginfo[localseg].reloc;
881 switch (hr->r.length) {
882 case 1:
883 offset += *data;
884 if (offset < -127 || offset > 128)
885 fprintf(error_file,
886 "warning: relocation out of range "
887 "at %s(%02x:%08"PRIx32")\n", cur->name,
888 (int)hr->r.segment, hr->r.offset);
889 *data = (char)offset;
890 break;
891 case 2:
892 offset += *(int16_t *)data;
893 if (offset < -32767 || offset > 32768)
894 fprintf(error_file,
895 "warning: relocation out of range "
896 "at %s(%02x:%08"PRIx32")\n", cur->name,
897 (int)hr->r.segment, hr->r.offset);
898 *(int16_t *)data = (int16_t)offset;
899 break;
900 case 4:
901 *(int32_t *)data += offset;
902 /* we can't easily detect overflow on this one */
903 break;
907 * If the relocation was relative between two symbols in
908 * the same segment, then we're done.
910 * Otherwise, we need to output a new relocation record
911 * with the references updated segment and offset...
913 if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
914 hr->r.segment = cur->seginfo[localseg].dest_seg;
915 hr->r.offset += cur->seginfo[localseg].reloc;
916 hr->r.refseg = seg;
917 if (isrelative)
918 hr->r.segment += RDOFF_RELATIVEMASK;
919 rdfaddheader(rdfheader, hr);
921 break;
923 case RDFREC_IMPORT: /* import symbol */
924 case RDFREC_FARIMPORT:
926 * scan the global symbol table for the symbol
927 * and associate its location with the segment number
928 * for this module
930 se = symtabFind(symtab, hr->i.label);
931 if (!se || se->segment == -1) {
932 if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
933 fprintf(error_file,
934 "error: unresolved reference to `%s'"
935 " in module `%s'\n", hr->i.label,
936 cur->name);
937 errorcount++;
940 * we need to allocate a segment number for this
941 * symbol, and store it in the symbol table for
942 * future reference
944 if (!se) {
945 se = malloc(sizeof(*se));
946 if (!se) {
947 fprintf(stderr, "ldrdf: out of memory\n");
948 exit(1);
950 se->name = strdup(hr->i.label);
951 se->flags = 0;
952 se->segment = availableseg++;
953 se->offset = 0;
954 symtabInsert(symtab, se);
955 } else {
956 se->segment = availableseg++;
957 se->offset = 0;
960 * output a header record that imports it to the
961 * recently allocated segment number...
963 newrec = *hr;
964 newrec.i.segment = se->segment;
965 rdfaddheader(rdfheader, &newrec);
968 add_seglocation(&segs, hr->i.segment, se->segment,
969 se->offset);
970 break;
972 case RDFREC_GLOBAL: /* export symbol */
974 * need to insert an export for this symbol into the new
975 * header, unless we're stripping symbols. Even if we're
976 * stripping, put the symbol if it's marked as SYM_GLOBAL.
978 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
979 break;
981 if (hr->e.segment == 2) {
982 seg = 2;
983 offset = cur->bss_reloc;
984 } else {
985 localseg = rdffindsegment(&cur->f, hr->e.segment);
986 if (localseg == -1) {
987 fprintf(stderr, "%s: exported symbol `%s' from "
988 "unrecognised segment\n", cur->name,
989 hr->e.label);
990 errorcount++;
991 break;
993 offset = cur->seginfo[localseg].reloc;
994 seg = cur->seginfo[localseg].dest_seg;
997 hr->e.segment = seg;
998 hr->e.offset += offset;
999 rdfaddheader(rdfheader, hr);
1000 break;
1002 case RDFREC_MODNAME: /* module name */
1004 * Insert module name record if export symbols
1005 * are not stripped.
1006 * If module name begins with '$' - insert it anyway.
1008 if (options.strip && hr->m.modname[0] != '$')
1009 break;
1010 rdfaddheader(rdfheader, hr);
1011 break;
1013 case RDFREC_DLL: /* DLL name */
1015 * Insert DLL name if it begins with '$'
1017 if (hr->d.libname[0] != '$')
1018 break;
1019 rdfaddheader(rdfheader, hr);
1020 break;
1022 case RDFREC_SEGRELOC: /* segment fixup */
1024 * modify the segment numbers if necessary, and
1025 * pass straight through to the output module header
1027 * *** FIXME ***
1029 if (hr->r.segment == 2) {
1030 fprintf(stderr, "%s: segment fixup in BSS section\n",
1031 cur->name);
1032 errorcount++;
1033 break;
1035 localseg = rdffindsegment(&cur->f, hr->r.segment);
1036 if (localseg == -1) {
1037 fprintf(stderr, "%s: segment fixup in unrecognised"
1038 " segment (%d)\n", cur->name, hr->r.segment);
1039 errorcount++;
1040 break;
1042 hr->r.segment = cur->seginfo[localseg].dest_seg;
1043 hr->r.offset += cur->seginfo[localseg].reloc;
1045 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
1046 fprintf(stderr, "%s: segment fixup to undefined "
1047 "segment %04x\n", cur->name,
1048 (int)hr->r.refseg);
1049 errorcount++;
1050 break;
1052 hr->r.refseg = seg;
1053 rdfaddheader(rdfheader, hr);
1054 break;
1056 case RDFREC_COMMON: /* Common variable */
1057 /* Is this symbol already in the table? */
1058 se = symtabFind(symtab, hr->c.label);
1059 if (!se) {
1060 printf("%s is not in symtab yet\n", hr->c.label);
1061 break;
1063 /* Add segment location */
1064 add_seglocation(&segs, hr->c.segment, se->segment,
1065 se->offset);
1066 break;
1070 free(header);
1071 done_seglocations(&segs);
1076 * combined BSS reservation for the entire results
1078 newrec.type = RDFREC_BSS;
1079 newrec.b.reclen = 4;
1080 newrec.b.amount = bss_length;
1081 rdfaddheader(rdfheader, &newrec);
1084 * Write the header
1086 for (i = 0; i < nsegs; i++) {
1087 if (i == 2)
1088 continue;
1089 rdfaddsegment(rdfheader, outputseg[i].length);
1092 rdfwriteheader(f, rdfheader);
1093 rdfdoneheader(rdfheader);
1096 * Step through the segments, one at a time, writing out into
1097 * the output file
1099 for (i = 0; i < nsegs; i++) {
1100 uint16_t s;
1101 int32_t l;
1103 if (i == 2)
1104 continue;
1106 s = translateint16_t(outputseg[i].type);
1107 fwrite(&s, 2, 1, f);
1108 s = translateint16_t(outputseg[i].number);
1109 fwrite(&s, 2, 1, f);
1110 s = translateint16_t(outputseg[i].reserved);
1111 fwrite(&s, 2, 1, f);
1112 l = translateint32_t(outputseg[i].length);
1113 fwrite(&l, 4, 1, f);
1115 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1118 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f);
1121 /* =========================================================================
1122 * Main program
1125 void usage()
1127 printf("usage:\n"
1128 " ldrdf [options] object modules ... [-llibrary ...]\n"
1129 " ldrdf -r\n"
1130 "options:\n"
1131 " -v[=n] increase verbosity by 1, or set it to n\n"
1132 " -a nn set segment alignment value (default 16)\n"
1133 " -s strip public symbols\n"
1134 " -dy Unix-style dynamic linking\n"
1135 " -o name write output in file 'name'\n"
1136 " -j path specify objects search path\n"
1137 " -L path specify libraries search path\n"
1138 " -g file embed 'file' as a first header record with type 'generic'\n");
1139 exit(0);
1142 int main(int argc, char **argv)
1144 char *outname = "aout.rdf";
1145 int moduleloaded = 0;
1146 char *respstrings[128] = { 0, };
1148 options.verbose = 0;
1149 options.align = 16;
1150 options.dynalink = 0;
1151 options.strip = 0;
1153 error_file = stderr;
1155 argc--, argv++;
1156 if (argc == 0)
1157 usage();
1158 while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
1159 switch (argv[0][1]) {
1160 case 'r':
1161 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
1162 "\n");
1163 printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
1164 exit(0);
1165 case 'v':
1166 if (argv[0][2] == '=') {
1167 options.verbose = argv[0][3] - '0';
1168 if (options.verbose < 0 || options.verbose > 9) {
1169 fprintf(stderr,
1170 "ldrdf: verbosity level must be a number"
1171 " between 0 and 9\n");
1172 exit(1);
1174 } else
1175 options.verbose++;
1176 break;
1177 case 'a':
1178 options.align = atoi(argv[1]);
1179 if (options.align <= 0) {
1180 fprintf(stderr,
1181 "ldrdf: -a expects a positive number argument\n");
1182 exit(1);
1184 argv++, argc--;
1185 break;
1186 case 's':
1187 options.strip = 1;
1188 break;
1189 case 'd':
1190 if (argv[0][2] == 'y')
1191 options.dynalink = 1;
1192 break;
1193 case 'o':
1194 outname = argv[1];
1195 argv++, argc--;
1196 break;
1197 case 'j':
1198 if (!objpath) {
1199 options.objpath = 1;
1200 objpath = argv[1];
1201 argv++, argc--;
1202 break;
1203 } else {
1204 fprintf(stderr,
1205 "ldrdf: more than one objects search path specified\n");
1206 exit(1);
1208 case 'L':
1209 if (!libpath) {
1210 options.libpath = 1;
1211 libpath = argv[1];
1212 argv++, argc--;
1213 break;
1214 } else {
1215 fprintf(stderr,
1216 "ldrdf: more than one libraries search path specified\n");
1217 exit(1);
1219 case '@':{
1220 int i = 0;
1221 char buf[256];
1222 FILE *f;
1224 options.respfile = 1;
1225 if (argv[1] != NULL)
1226 f = fopen(argv[1], "r");
1227 else {
1228 fprintf(stderr,
1229 "ldrdf: no response file name specified\n");
1230 exit(1);
1233 if (f == NULL) {
1234 fprintf(stderr,
1235 "ldrdf: unable to open response file\n");
1236 exit(1);
1239 argv++, argc--;
1240 while (fgets(buf, sizeof(buf), f) != NULL) {
1241 char *p;
1242 if (buf[0] == '\n')
1243 continue;
1244 if ((p = strchr(buf, '\n')) != NULL)
1245 *p = '\0';
1246 if (i >= 128) {
1247 fprintf(stderr, "ldrdf: too many input files\n");
1248 exit(1);
1250 *(respstrings + i) = newstr(buf);
1251 argc++, i++;
1253 break;
1255 case '2':
1256 options.stderr_redir = 1;
1257 error_file = stdout;
1258 break;
1259 case 'g':
1260 generic_rec_file = argv[1];
1261 argv++, argc--;
1262 break;
1263 default:
1264 usage();
1266 argv++, argc--;
1269 if (options.verbose > 4) {
1270 printf("ldrdf invoked with options:\n");
1271 printf(" section alignment: %d bytes\n", options.align);
1272 printf(" output name: `%s'\n", outname);
1273 if (options.strip)
1274 printf(" strip symbols\n");
1275 if (options.dynalink)
1276 printf(" Unix-style dynamic linking\n");
1277 if (options.objpath)
1278 printf(" objects search path: %s\n", objpath);
1279 if (options.libpath)
1280 printf(" libraries search path: %s\n", libpath);
1281 printf("\n");
1284 symtab = symtabNew();
1285 initsegments();
1287 if (!symtab) {
1288 fprintf(stderr, "ldrdf: out of memory\n");
1289 exit(1);
1292 while (argc) {
1293 if (!*argv)
1294 argv = respstrings;
1295 if (!*argv)
1296 break;
1297 if (!strncmp(*argv, "-l", 2)) {
1298 if (libpath && (argv[0][2] != '/'))
1299 add_library(newstrcat(libpath, *argv + 2));
1300 else
1301 add_library(*argv + 2);
1302 } else {
1303 if (objpath && (argv[0][0] != '/'))
1304 loadmodule(newstrcat(objpath, *argv));
1305 else
1306 loadmodule(*argv);
1307 moduleloaded = 1;
1309 argv++, argc--;
1312 if (!moduleloaded) {
1313 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1314 return 0;
1317 search_libraries();
1319 if (options.verbose > 2) {
1320 printf("symbol table:\n");
1321 symtabDump(symtab, stdout);
1324 write_output(outname);
1326 if (errorcount > 0)
1327 exit(1);
1328 return 0;