Update dependencies
[nasm/avx512.git] / rdoff / ldrdf.c
blob22e077e62cf1b93563b1297c3acc5d5a82b28197
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 long reloc; /* segment's relocation factor */
54 struct modulenode {
55 rdffile f; /* the RDOFF file structure */
56 struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
57 with each segment? */
58 void * header;
59 char * name;
60 struct modulenode * next;
61 long bss_reloc;
64 #include "ldsegs.h"
66 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
67 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
69 /* ==========================================================================
70 * Function prototypes of private utility functions
73 void processmodule(const char * filename, struct modulenode * mod);
74 int allocnewseg(uint16 type,uint16 reserved);
75 int findsegment(uint16 type,uint16 reserved);
76 void symtab_add(const char * symbol, int segment, long offset);
77 int symtab_get(const char * symbol, int * segment, long * offset);
79 /* =========================================================================
80 * Global data structures.
83 /* a linked list of modules that will be included in the output */
84 struct modulenode * modules = NULL;
85 struct modulenode * lastmodule = NULL;
87 /* a linked list of libraries to be searched for unresolved imported symbols */
88 struct librarynode * libraries = NULL;
89 struct librarynode * lastlib = NULL;
91 /* the symbol table */
92 void * symtab = NULL;
94 /* objects search path */
95 char * objpath = NULL;
97 /* libraries search path */
98 char * libpath = NULL;
100 /* file to embed as a generic record */
101 char * generic_rec_file = NULL;
103 /* error file */
104 static FILE * error_file;
106 /* the header of the output file, built up stage by stage */
107 rdf_headerbuf * newheader = NULL;
109 /* The current state of segment allocation, including information about
110 * which output segment numbers have been allocated, and their types and
111 * amount of data which has already been allocated inside them.
113 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
114 int nsegs = 0;
115 long bss_length;
117 /* global options which affect how the program behaves */
118 struct ldrdfoptions {
119 int verbose;
120 int align;
121 int dynalink;
122 int strip;
123 int respfile;
124 int stderr_redir;
125 int objpath;
126 int libpath;
127 } options;
129 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;
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);
206 * processmodule()
208 * step through each segment, determine what exactly we're doing with
209 * it, and if we intend to keep it, determine (a) which segment to
210 * put it in and (b) whereabouts in that segment it will end up.
211 * (b) is fairly easy, because we're now keeping track of how big each
212 * segment in our output file is...
214 void processmodule(const char * filename, struct modulenode * mod)
216 struct segconfig sconf;
217 int seg, outseg;
218 void * header;
219 rdfheaderrec * hr;
220 long bssamount = 0;
221 int bss_was_referenced = 0;
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, mod->f.seg[seg].number,
232 mod->f.seg[seg].type, sconf.typedesc);
235 * sconf->dowhat tells us what to do with a segment of this type.
237 switch (sconf.dowhat) {
238 case SEG_IGNORE:
240 * Set destination segment to -1, to indicate that this segment
241 * should be ignored for the purpose of output, ie it is left
242 * out of the linked executable.
244 mod->seginfo[seg].dest_seg = -1;
245 if (options.verbose > 1) printf("IGNORED\n");
246 break;
248 case SEG_NEWSEG:
250 * The configuration tells us to create a new segment for
251 * each occurrence of this segment type.
253 outseg = allocnewseg(sconf.mergetype,
254 mod->f.seg[seg].reserved);
255 mod->seginfo[seg].dest_seg = outseg;
256 mod->seginfo[seg].reloc = 0;
257 outputseg[outseg].length = mod->f.seg[seg].length;
258 if (options.verbose > 1)
259 printf ("=> %04x:%08lx (+%04lx)\n", outseg,
260 mod->seginfo[seg].reloc,
261 mod->f.seg[seg].length);
262 break;
264 case SEG_MERGE:
266 * The configuration tells us to merge the segment with
267 * a previously existing segment of type 'sconf.mergetype',
268 * if one exists. Otherwise a new segment is created.
269 * This is handled transparently by 'findsegment()'.
271 outseg = findsegment(sconf.mergetype,
272 mod->f.seg[seg].reserved);
273 mod->seginfo[seg].dest_seg = outseg;
276 * We need to add alignment to these segments.
278 if (outputseg[outseg].length % options.align != 0)
279 outputseg[outseg].length +=
280 options.align - (outputseg[outseg].length % options.align);
282 mod->seginfo[seg].reloc = outputseg[outseg].length;
283 outputseg[outseg].length += mod->f.seg[seg].length;
285 if (options.verbose > 1)
286 printf ("=> %04x:%08lx (+%04lx)\n", outseg,
287 mod->seginfo[seg].reloc,
288 mod->f.seg[seg].length);
294 * extract symbols from the header, and dump them into the
295 * symbol table
297 header = malloc(mod->f.header_len);
298 if (!header) {
299 fprintf(stderr, "ldrdf: not enough memory\n");
300 exit(1);
302 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
303 rdfperror("ldrdf", filename);
304 exit(1);
307 while ((hr = rdfgetheaderrec (&mod->f))) {
308 switch(hr->type) {
309 case RDFREC_IMPORT: /* imported symbol */
310 case RDFREC_FARIMPORT:
311 /* Define with seg = -1 */
312 symtab_add(hr->i.label, -1, 0);
313 break;
315 case RDFREC_GLOBAL: { /* exported symbol */
316 int destseg;
317 long destreloc;
319 if (hr->e.segment == 2) {
320 bss_was_referenced = 1;
321 destreloc = bss_length;
322 if (destreloc % options.align != 0)
323 destreloc += options.align - (destreloc % options.align);
324 destseg = 2;
325 } else {
326 if ((destseg = mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
327 continue;
328 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
330 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
331 break;
334 case RDFREC_BSS: /* BSS reservation */
336 * first, amalgamate all BSS reservations in this module
337 * into one, because we allow this in the output format.
339 bssamount += hr->b.amount;
340 break;
342 case RDFREC_COMMON: { /* Common variable */
343 symtabEnt *ste = symtabFind(symtab, hr->c.label);
345 /* Is the symbol already in the table? */
346 if (ste) 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:%08lx (+%04lx)\n",
353 filename, hr->c.segment, hr->c.label, bss_length, hr->c.size);
356 symtab_add(hr->c.label, 2, bss_length);
357 mod->bss_reloc = bss_length;
358 bss_length += hr->c.size;
359 break;
364 if (bssamount != 0 || bss_was_referenced) {
366 * handle the BSS segment - first pad the existing bss length
367 * to the correct alignment, then store the length in bss_reloc
368 * for this module. Then add this module's BSS length onto
369 * bss_length.
371 if (bss_length % options.align != 0)
372 bss_length += options.align - (bss_length % options.align);
374 mod->bss_reloc = bss_length;
375 if (options.verbose > 1) {
376 printf ("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n",
377 filename, bss_length, bssamount);
379 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
397 * Return 1 if a given module is in the list, 0 otherwise.
399 int lookformodule(const char *name)
401 struct modulenode *curr = modules;
403 while(curr) {
404 if (!strcmp(name, curr->name)) return 1;
405 curr = curr->next;
407 return 0;
412 * allocnewseg()
413 * findsegment()
415 * These functions manipulate the array of output segments, and are used
416 * by processmodule(). allocnewseg() allocates a segment in the array,
417 * initialising it to be empty. findsegment() first scans the array for
418 * a segment of the type requested, and if one isn't found allocates a
419 * new one.
421 int allocnewseg(uint16 type,uint16 reserved)
423 outputseg[nsegs].type = type;
424 outputseg[nsegs].number = nsegs;
425 outputseg[nsegs].reserved = reserved;
426 outputseg[nsegs].length = 0;
427 outputseg[nsegs].offset = 0;
428 outputseg[nsegs].data = NULL;
430 return nsegs++;
433 int findsegment(uint16 type,uint16 reserved)
435 int i;
437 for (i = 0; i < nsegs; i++)
438 if (outputseg[i].type == type) return i;
440 return allocnewseg(type,reserved);
445 * symtab_add()
447 * inserts a symbol into the global symbol table, which associates symbol
448 * names either with addresses, or a marker that the symbol hasn't been
449 * resolved yet, or possibly that the symbol has been defined as
450 * contained in a dynamic [load time/run time] linked library.
452 * segment = -1 => not yet defined
453 * segment = -2 => defined as dll symbol
455 * If the symbol is already defined, and the new segment >= 0, then
456 * if the original segment was < 0 the symbol is redefined, otherwise
457 * a duplicate symbol warning is issued. If new segment == -1, this
458 * routine won't change a previously existing symbol. It will change
459 * to segment = -2 only if the segment was previously < 0.
461 void symtab_add(const char * symbol, int segment, long offset)
463 symtabEnt * ste;
465 ste = symtabFind(symtab, symbol);
466 if (ste) {
467 if (ste->segment >= 0) {
469 * symbol previously defined
471 if (segment < 0) 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) return;
482 * we have more information now - update the symbol's entry
484 ste->segment = segment;
485 ste->offset = offset;
486 ste->flags = 0;
487 return;
490 * this is the first declaration of this symbol
492 ste = malloc(sizeof(symtabEnt));
493 if (!ste) {
494 fprintf(stderr, "ldrdf: out of memory\n");
495 exit(1);
497 ste->name = strdup(symbol);
498 ste->segment = segment;
499 ste->offset = offset;
500 ste->flags = 0;
501 symtabInsert(symtab, ste);
505 * symtab_get()
507 * Retrieves the values associated with a symbol. Undefined symbols
508 * are assumed to have -1:0 associated. Returns 1 if the symbol was
509 * successfully located.
511 int symtab_get(const char * symbol, int * segment, long * offset)
513 symtabEnt * ste = symtabFind(symtab, symbol);
514 if (!ste) {
515 *segment = -1;
516 *offset = 0;
517 return 0;
518 } else {
519 *segment = ste->segment;
520 *offset = ste->offset;
521 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;
563 * search_libraries()
565 * scans through the list of libraries, attempting to match symbols
566 * defined in library modules against symbols that are referenced but
567 * not defined (segment = -1 in the symbol table)
569 * returns 1 if any extra library modules are included, indicating that
570 * another pass through the library list should be made (possibly).
572 int search_libraries()
574 struct librarynode * cur;
575 rdffile f;
576 int i;
577 void * header;
578 int segment;
579 long offset;
580 int doneanything = 0, pass = 1, keepfile;
581 rdfheaderrec * hr;
583 cur = libraries;
585 while (cur) {
586 if (options.verbose > 2)
587 printf("scanning library `%s', pass %d...\n", cur->name, pass);
589 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
590 if (pass == 2 && lookformodule(f.name)) 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) continue;
613 * If the symbol is marked as SYM_GLOBAL, somebody will be
614 * definitely interested in it..
616 if ((hr->e.flags & SYM_GLOBAL) == 0) {
618 * otherwise the symbol is just public. Find it in
619 * the symbol table. If the symbol isn't defined, we
620 * aren't interested, so go on to the next.
621 * If it is defined as anything but -1, we're also not
622 * interested. But if it is defined as -1, insert this
623 * module into the list of modules to use, and go
624 * immediately on to the next module...
626 if (!symtab_get(hr->e.label, &segment, &offset) || segment != -1)
627 continue;
630 doneanything = 1;
631 keepfile = 1;
634 * as there are undefined symbols, we can assume that
635 * there are modules on the module list by the time
636 * we get here.
638 lastmodule->next = malloc(sizeof(*lastmodule->next));
639 if (!lastmodule->next) {
640 fprintf(stderr, "ldrdf: not enough memory\n");
641 exit(1);
643 lastmodule = lastmodule->next;
644 memcpy(&lastmodule->f, &f, sizeof(f));
645 lastmodule->name = strdup(f.name);
646 lastmodule->next = NULL;
647 processmodule(f.name, lastmodule);
648 break;
650 if (!keepfile) {
651 free(f.name);
652 f.name = NULL;
653 f.fp = NULL;
656 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
657 rdl_perror("ldrdf", cur->name);
659 cur = cur->next;
660 if (cur == NULL && pass == 1) {
661 cur = libraries;
662 pass++;
666 return doneanything;
671 * write_output()
673 * this takes the linked list of modules, and walks through it, merging
674 * all the modules into a single output module, and then writes this to a
675 * file.
677 void write_output(const char * filename)
679 FILE * f;
680 rdf_headerbuf * rdfheader;
681 struct modulenode * cur;
682 int i, availableseg, seg, localseg, isrelative;
683 void * header;
684 rdfheaderrec * hr, newrec;
685 symtabEnt * se;
686 segtab segs;
687 long offset;
688 byte * data;
690 if ((f = fopen(filename, "wb"))==NULL) {
691 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
692 exit(1);
694 if ((rdfheader=rdfnewheader())==NULL) {
695 fprintf(stderr, "ldrdf: out of memory\n");
696 exit(1);
700 * If '-g' option was given, first record in output file will be a
701 * `generic' record, filled with a given file content.
702 * This can be useful, for example, when constructing multiboot
703 * compliant kernels.
705 if (generic_rec_file) {
706 FILE *ff;
708 if (options.verbose)
709 printf("\nadding generic record from binary file %s\n", generic_rec_file);
711 hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec));
712 if ((ff = fopen(generic_rec_file, "r")) == NULL) {
713 fprintf(stderr, "ldrdf: couldn't open %s for input\n", generic_rec_file);
714 exit(1);
716 i = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
717 fseek(ff, 0, SEEK_END);
718 if (ftell(ff) > sizeof(hr->g.data)) {
719 fprintf (error_file, "warning: maximum generic record size is %d, rest of file ignored\n", sizeof(hr->g.data));
721 fclose(ff);
723 hr->g.type = 0;
724 hr->g.reclen = i;
725 rdfaddheader(rdfheader, hr);
726 free(hr);
729 if (options.verbose)
730 printf ("\nbuilding output module (%d segments)\n", nsegs);
733 * Allocate the memory for the segments. We may be better off
734 * building the output module one segment at a time when running
735 * under 16 bit DOS, but that would be a slower way of doing this.
736 * And you could always use DJGPP...
738 for (i = 0; i < nsegs; i++) {
739 outputseg[i].data=NULL;
740 if(!outputseg[i].length) continue;
741 outputseg[i].data = malloc(outputseg[i].length);
742 if (!outputseg[i].data) {
743 fprintf(stderr, "ldrdf: out of memory\n");
744 exit(1);
749 * initialise availableseg, used to allocate segment numbers for
750 * imported and exported labels...
752 availableseg = nsegs;
755 * Step through the modules, performing required actions on each one
757 for (cur = modules; cur; cur=cur->next) {
759 * Read the actual segment contents into the correct places in
760 * the newly allocated segments
763 for (i = 0; i < cur->f.nsegs; i++) {
764 int dest = cur->seginfo[i].dest_seg;
766 if (dest == -1) continue;
767 if (rdfloadseg(&cur->f, i,
768 outputseg[dest].data + cur->seginfo[i].reloc)) {
769 rdfperror("ldrdf", cur->name);
770 exit(1);
775 * Perform fixups, and add new header records where required
778 header = malloc(cur->f.header_len);
779 if (!header) {
780 fprintf(stderr, "ldrdf: out of memory\n");
781 exit(1);
784 if (cur->f.header_loc)
785 rdfheaderrewind(&cur->f);
786 else
787 if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
788 rdfperror("ldrdf", cur->name);
789 exit(1);
793 * we need to create a local segment number -> location
794 * table for the segments in this module.
796 init_seglocations(&segs);
797 for (i = 0; i < cur->f.nsegs; i++) {
798 add_seglocation(&segs, cur->f.seg[i].number,
799 cur->seginfo[i].dest_seg, cur->seginfo[i].reloc);
802 * and the BSS segment (doh!)
804 add_seglocation(&segs, 2, 2, cur->bss_reloc);
806 while ((hr = rdfgetheaderrec(&cur->f))) {
807 switch(hr->type) {
808 case RDFREC_RELOC: /* relocation record - need to do a fixup */
810 * First correct the offset stored in the segment from
811 * the start of the segment (which may well have changed).
813 * To do this we add to the number stored the relocation
814 * factor associated with the segment that contains the
815 * target segment.
817 * The relocation could be a relative relocation, in which
818 * case we have to first subtract the amount we've relocated
819 * the containing segment by.
821 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
822 fprintf(stderr, "%s: reloc to undefined segment %04x\n",
823 cur->name, (int) hr->r.refseg);
824 errorcount++;
825 break;
828 isrelative = (hr->r.segment & RDOFF_RELATIVEMASK) == RDOFF_RELATIVEMASK;
829 hr->r.segment &= (RDOFF_RELATIVEMASK-1);
831 if (hr->r.segment == 2 ||
832 (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1) {
833 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
834 cur->name,
835 hr->r.segment == 2 ? "BSS" : "unknown",
836 hr->r.segment);
837 errorcount++;
838 break;
841 if (hr->r.length != 1 && hr->r.length != 2 &&
842 hr->r.length != 4 ) {
843 fprintf(stderr, "%s: nonstandard length reloc "
844 "(%d bytes)\n", cur->name, hr->r.length);
845 errorcount++;
846 break;
850 * okay, now the relocation is in the segment pointed to by
851 * cur->seginfo[localseg], and we know everything else is
852 * okay to go ahead and do the relocation
854 data = outputseg[cur->seginfo[localseg].dest_seg].data;
855 data += cur->seginfo[localseg].reloc + hr->r.offset;
858 * data now points to the reference that needs
859 * relocation. Calculate the relocation factor.
860 * Factor is:
861 * offset of referred object in segment [in offset]
862 * (- relocation of localseg, if ref is relative)
863 * For simplicity, the result is stored in 'offset'.
864 * Then add 'offset' onto the value at data.
867 if (isrelative)
868 offset -= cur->seginfo[localseg].reloc;
869 switch (hr->r.length) {
870 case 1:
871 offset += *data;
872 if (offset < -127 || offset > 128)
873 fprintf(error_file, "warning: relocation out of range "
874 "at %s(%02x:%08lx)\n", cur->name,
875 (int)hr->r.segment, hr->r.offset);
876 *data = (char) offset;
877 break;
878 case 2:
879 offset += * (short *)data;
880 if (offset < -32767 || offset > 32768)
881 fprintf(error_file, "warning: relocation out of range "
882 "at %s(%02x:%08lx)\n", cur->name,
883 (int)hr->r.segment, hr->r.offset);
884 * (short *)data = (short) offset;
885 break;
886 case 4:
887 * (long *)data += offset;
888 /* we can't easily detect overflow on this one */
889 break;
893 * If the relocation was relative between two symbols in
894 * the same segment, then we're done.
896 * Otherwise, we need to output a new relocation record
897 * with the references updated segment and offset...
899 if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
900 hr->r.segment = cur->seginfo[localseg].dest_seg;
901 hr->r.offset += cur->seginfo[localseg].reloc;
902 hr->r.refseg = seg;
903 if (isrelative)
904 hr->r.segment += RDOFF_RELATIVEMASK;
905 rdfaddheader(rdfheader, hr);
907 break;
909 case RDFREC_IMPORT: /* import symbol */
910 case RDFREC_FARIMPORT:
912 * scan the global symbol table for the symbol
913 * and associate its location with the segment number
914 * for this module
916 se = symtabFind(symtab, hr->i.label);
917 if (!se || se->segment == -1) {
918 if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
919 fprintf(error_file, "error: unresolved reference to `%s'"
920 " in module `%s'\n", hr->i.label, cur->name);
921 errorcount++;
924 * we need to allocate a segment number for this
925 * symbol, and store it in the symbol table for
926 * future reference
928 if (!se) {
929 se=malloc(sizeof(*se));
930 if (!se) {
931 fprintf(stderr, "ldrdf: out of memory\n");
932 exit(1);
934 se->name = strdup(hr->i.label);
935 se->flags = 0;
936 se->segment = availableseg++;
937 se->offset = 0;
938 symtabInsert(symtab, se);
940 else {
941 se->segment = availableseg++;
942 se->offset = 0;
945 * output a header record that imports it to the
946 * recently allocated segment number...
948 newrec = *hr;
949 newrec.i.segment = se->segment;
950 rdfaddheader(rdfheader, &newrec);
953 add_seglocation(&segs, hr->i.segment, se->segment, se->offset);
954 break;
956 case RDFREC_GLOBAL: /* export symbol */
958 * need to insert an export for this symbol into the new
959 * header, unless we're stripping symbols. Even if we're
960 * stripping, put the symbol if it's marked as SYM_GLOBAL.
962 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
963 break;
965 if (hr->e.segment == 2) {
966 seg = 2;
967 offset = cur->bss_reloc;
969 else {
970 localseg = rdffindsegment(&cur->f, hr->e.segment);
971 if (localseg == -1) {
972 fprintf(stderr, "%s: exported symbol `%s' from "
973 "unrecognised segment\n", cur->name,
974 hr->e.label);
975 errorcount++;
976 break;
978 offset = cur->seginfo[localseg].reloc;
979 seg = cur->seginfo[localseg].dest_seg;
982 hr->e.segment = seg;
983 hr->e.offset += offset;
984 rdfaddheader(rdfheader, hr);
985 break;
987 case RDFREC_MODNAME: /* module name */
989 * Insert module name record if export symbols
990 * are not stripped.
991 * If module name begins with '$' - insert it anyway.
993 if (options.strip && hr->m.modname[0] != '$') break;
994 rdfaddheader(rdfheader, hr);
995 break;
997 case RDFREC_DLL: /* DLL name */
999 * Insert DLL name if it begins with '$'
1001 if (hr->d.libname[0] != '$') break;
1002 rdfaddheader(rdfheader, hr);
1003 break;
1005 case RDFREC_SEGRELOC: /* segment fixup */
1007 * modify the segment numbers if necessary, and
1008 * pass straight through to the output module header
1010 * *** FIXME ***
1012 if (hr->r.segment == 2) {
1013 fprintf(stderr, "%s: segment fixup in BSS section\n",
1014 cur->name);
1015 errorcount++;
1016 break;
1018 localseg = rdffindsegment(&cur->f, hr->r.segment);
1019 if (localseg == -1) {
1020 fprintf(stderr, "%s: segment fixup in unrecognised"
1021 " segment (%d)\n", cur->name, hr->r.segment);
1022 errorcount++;
1023 break;
1025 hr->r.segment = cur->seginfo[localseg].dest_seg;
1026 hr->r.offset += cur->seginfo[localseg].reloc;
1028 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
1029 fprintf(stderr, "%s: segment fixup to undefined "
1030 "segment %04x\n", cur->name, (int)hr->r.refseg);
1031 errorcount++;
1032 break;
1034 hr->r.refseg = seg;
1035 rdfaddheader(rdfheader, hr);
1036 break;
1038 case RDFREC_COMMON: /* Common variable */
1039 /* Is this symbol already in the table? */
1040 se = symtabFind(symtab, hr->c.label);
1041 if (!se) {
1042 printf("%s is not in symtab yet\n", hr->c.label);
1043 break;
1045 /* Add segment location */
1046 add_seglocation(&segs, hr->c.segment, se->segment, se->offset);
1047 break;
1051 free(header);
1052 done_seglocations(&segs);
1057 * combined BSS reservation for the entire results
1059 newrec.type = RDFREC_BSS;
1060 newrec.b.reclen = 4;
1061 newrec.b.amount = bss_length;
1062 rdfaddheader(rdfheader, &newrec);
1065 * Write the header
1067 for (i = 0; i < nsegs; i++) {
1068 if (i == 2) continue;
1069 rdfaddsegment (rdfheader, outputseg[i].length);
1072 rdfwriteheader(f, rdfheader);
1073 rdfdoneheader(rdfheader);
1076 * Step through the segments, one at a time, writing out into
1077 * the output file
1079 for (i = 0; i < nsegs; i++) {
1080 uint16 s;
1081 long l;
1083 if (i == 2) continue;
1085 s = translateshort(outputseg[i].type);
1086 fwrite(&s, 2, 1, f);
1087 s = translateshort(outputseg[i].number);
1088 fwrite(&s, 2, 1, f);
1089 s = translateshort(outputseg[i].reserved);
1090 fwrite(&s, 2, 1, f);
1091 l = translatelong(outputseg[i].length);
1092 fwrite(&l, 4, 1, f);
1094 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1097 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f);
1100 /* =========================================================================
1101 * Main program
1104 void usage()
1106 printf("usage:\n"
1107 " ldrdf [options] object modules ... [-llibrary ...]\n"
1108 " ldrdf -r\n"
1109 "options:\n"
1110 " -v[=n] increase verbosity by 1, or set it to n\n"
1111 " -a nn set segment alignment value (default 16)\n"
1112 " -s strip public symbols\n"
1113 " -dy Unix-style dynamic linking\n"
1114 " -o name write output in file 'name'\n"
1115 " -j path specify objects search path\n"
1116 " -L path specify libraries search path\n"
1117 " -g file embed 'file' as a first header record with type 'generic'\n");
1118 exit(0);
1121 int main(int argc, char ** argv)
1123 char * outname = "aout.rdf";
1124 int moduleloaded = 0;
1125 char *respstrings[128] = {0, };
1127 options.verbose = 0;
1128 options.align = 16;
1129 options.dynalink = 0;
1130 options.strip = 0;
1132 error_file = stderr;
1134 argc--, argv++;
1135 if (argc == 0) usage();
1136 while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
1137 switch(argv[0][1]) {
1138 case 'r':
1139 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION "\n");
1140 printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
1141 exit(0);
1142 case 'v':
1143 if (argv[0][2] == '=') {
1144 options.verbose = argv[0][3] - '0';
1145 if (options.verbose < 0 || options.verbose > 9) {
1146 fprintf(stderr, "ldrdf: verbosity level must be a number"
1147 " between 0 and 9\n");
1148 exit(1);
1151 else
1152 options.verbose++;
1153 break;
1154 case 'a':
1155 options.align = atoi(argv[1]);
1156 if (options.align <= 0) {
1157 fprintf(stderr,
1158 "ldrdf: -a expects a positive number argument\n");
1159 exit(1);
1161 argv++, argc--;
1162 break;
1163 case 's':
1164 options.strip = 1;
1165 break;
1166 case 'd':
1167 if (argv[0][2] == 'y') options.dynalink = 1;
1168 break;
1169 case 'o':
1170 outname = argv[1];
1171 argv++, argc--;
1172 break;
1173 case 'j':
1174 if (!objpath) {
1175 options.objpath = 1;
1176 objpath = argv[1];
1177 argv++, argc--;
1178 break;
1179 } else {
1180 fprintf(stderr,"ldrdf: more than one objects search path specified\n");
1181 exit(1);
1183 case 'L':
1184 if (!libpath) {
1185 options.libpath = 1;
1186 libpath = argv[1];
1187 argv++, argc--;
1188 break;
1189 } else {
1190 fprintf(stderr,"ldrdf: more than one libraries search path specified\n");
1191 exit(1);
1193 case '@': {
1194 int i=0;
1195 char buf[256];
1196 FILE *f;
1198 options.respfile = 1;
1199 if (argv[1] != NULL) f = fopen(argv[1],"r");
1200 else {
1201 fprintf(stderr,"ldrdf: no response file name specified\n");
1202 exit(1);
1205 if (f == NULL) {
1206 fprintf(stderr,"ldrdf: unable to open response file\n");
1207 exit(1);
1210 argv++, argc--;
1211 while (fgets(buf, sizeof(buf), f) != NULL) {
1212 char *p;
1213 if (buf[0]=='\n') continue;
1214 if ((p = strchr(buf,'\n')) != NULL) *p = '\0';
1215 if (i >= 128) {
1216 fprintf(stderr,"ldrdf: too many input files\n");
1217 exit(1);
1219 *(respstrings + i) = newstr(buf);
1220 argc++, i++;
1222 break;
1224 case '2':
1225 options.stderr_redir = 1;
1226 error_file = stdout;
1227 break;
1228 case 'g':
1229 generic_rec_file = argv[1];
1230 argv++, argc--;
1231 break;
1232 default:
1233 usage();
1235 argv++, argc--;
1238 if (options.verbose > 4) {
1239 printf("ldrdf invoked with options:\n");
1240 printf(" section alignment: %d bytes\n", options.align);
1241 printf(" output name: `%s'\n", outname);
1242 if (options.strip)
1243 printf(" strip symbols\n");
1244 if (options.dynalink)
1245 printf(" Unix-style dynamic linking\n");
1246 if (options.objpath)
1247 printf(" objects search path: %s\n", objpath);
1248 if (options.libpath)
1249 printf(" libraries search path: %s\n", libpath);
1250 printf("\n");
1253 symtab = symtabNew();
1254 initsegments();
1256 if (!symtab) {
1257 fprintf(stderr, "ldrdf: out of memory\n");
1258 exit(1);
1261 while (argc) {
1262 if (!*argv) argv = respstrings;
1263 if (!*argv) break;
1264 if (!strncmp(*argv, "-l", 2)) {
1265 if(libpath && (argv[0][2] != '/'))
1266 add_library(newstrcat(libpath,*argv + 2));
1267 else
1268 add_library(*argv + 2);
1269 } else {
1270 if(objpath && (argv[0][0] != '/'))
1271 loadmodule(newstrcat(objpath, *argv));
1272 else
1273 loadmodule(*argv);
1274 moduleloaded = 1;
1276 argv++, argc--;
1279 if (! moduleloaded) {
1280 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1281 return 0;
1284 search_libraries();
1286 if (options.verbose > 2)
1288 printf ("symbol table:\n");
1289 symtabDump(symtab, stdout);
1292 write_output(outname);
1294 if (errorcount > 0) exit(1);
1295 return 0;