NASM 0.98.17
[nasm/avx512.git] / rdoff / ldrdf.c
blob3d9d749e5dbb2236cd74225910a4dbfcc8a381c6
1 /* ldrdf.c RDOFF Object File linker/loader main program
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
7 */
9 /*
10 * TODO: actually get this new version working!
11 * - finish off write_output() - appears to be done
12 * - implement library searching - appears to be done
13 * - maybe we only want to do one pass, for performance reasons?
14 * this makes things a little harder, but unix 'ld' copes...
15 * - implement command line options - appears to be done
16 * - improve symbol table implementation - done, thanks to Graeme Defty
17 * - keep a cache of symbol names in each library module so
18 * we don't have to constantly recheck the file
19 * - general performance improvements
21 * BUGS & LIMITATIONS: this program doesn't support multiple code, data
22 * or bss segments, therefore for 16 bit programs whose code, data or BSS
23 * segment exceeds 64K in size, it will not work. This program probably
24 * wont work if compiled by a 16 bit compiler. Try DJGPP if you're running
25 * under DOS. '#define STINGY_MEMORY' may help a little.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include "multboot.h"
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.02"
41 #define RDF_MAXSEGS 64
42 /* #define STINGY_MEMORY */
44 /* =======================================================================
45 * Types & macros that are private to this program
48 struct segment_infonode {
49 int dest_seg; /* output segment to be placed into, -1 to
50 skip linking this segment */
51 long reloc; /* segment's relocation factor */
55 struct modulenode {
56 rdffile f; /* the RDOFF file structure */
57 struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
58 with each segment? */
59 void * header;
60 char * name;
61 struct modulenode * next;
62 long bss_reloc;
65 #include "ldsegs.h"
67 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
68 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
70 /* ==========================================================================
71 * Function prototypes of private utility functions
74 void processmodule(const char * filename, struct modulenode * mod);
75 int allocnewseg(int16 type,int16 reserved);
76 int findsegment(int16 type,int16 reserved);
77 void symtab_add(const char * symbol, int segment, long offset);
78 int symtab_get(const char * symbol, int * segment, long * offset);
80 /* =========================================================================
81 * Global data structures.
84 /* a linked list of modules that will be included in the output */
85 struct modulenode * modules = NULL;
86 struct modulenode * lastmodule = NULL;
88 /* a linked list of libraries to be searched for unresolved imported symbols */
89 struct librarynode * libraries = NULL;
90 struct librarynode * lastlib = NULL;
92 /* the symbol table */
93 void * symtab = NULL;
95 /* objects search path */
96 char * objpath = NULL;
98 /* libraries search path */
99 char * libpath = NULL;
101 /* error file */
102 static FILE * error_file;
104 #ifdef _MULTBOOT_H
106 /* loading address for multiboot header */
107 unsigned MBHloadAddr;
110 * Tiny code that moves RDF loader to its working memory region:
111 * mov esi,SOURCE_ADDR ; BE xx xx xx xx
112 * mov edi,DEST_ADDR ; BF xx xx xx xx
113 * mov esp,edi ; 89 FC
114 * push edi ; 57
115 * mov ecx,RDFLDR_LENGTH/4 ; B9 xx xx xx xx
116 * cld ; FC
117 * rep movsd ; F3 A5
118 * ret ; C3
121 #define RDFLDR_LENGTH 4096 /* Loader will be moved to unused */
122 #define RDFLDR_DESTLOC 0xBF000 /* video page */
124 unsigned char RDFloaderMover[]={
125 0xBE, 0, 0, 0, 0, 0xBF, 0, 0xF0, 0xB, 0,
126 0x89, 0xFC, 0x57,
127 0xB9, 0, 4, 0, 0,
128 0xFC, 0xF3, 0xA5, 0xC3
131 #endif
133 /* the header of the output file, built up stage by stage */
134 rdf_headerbuf * newheader = NULL;
136 /* The current state of segment allocation, including information about
137 * which output segment numbers have been allocated, and their types and
138 * amount of data which has already been allocated inside them.
140 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
141 int nsegs = 0;
142 long bss_length;
144 /* global options which affect how the program behaves */
145 struct ldrdfoptions {
146 int verbose;
147 int align;
148 int warnUnresolved;
149 int errorUnresolved;
150 int strip;
151 int respfile;
152 int stderr_redir;
153 int objpath;
154 int libpath;
155 int addMBheader;
156 } options;
158 int errorcount = 0; /* determines main program exit status */
160 /* =========================================================================
161 * Utility functions
166 * initsegments()
168 * sets up segments 0, 1, and 2, the initial code data and bss segments
171 void initsegments()
173 nsegs = 3;
174 outputseg[0].type = 1;
175 outputseg[0].number = 0;
176 outputseg[0].reserved = 0;
177 outputseg[0].length = 0;
178 outputseg[1].type = 2;
179 outputseg[1].number = 1;
180 outputseg[1].reserved = 0;
181 outputseg[1].length = 0;
182 outputseg[2].type = 0xFFFF; /* reserved segment type */
183 outputseg[2].number = 2;
184 outputseg[2].reserved = 0;
185 outputseg[2].length = 0;
186 bss_length = 0;
190 * loadmodule
192 * Determine the characteristics of a module, and decide what to do with
193 * each segment it contains (including determining destination segments and
194 * relocation factors for segments that are kept).
197 void loadmodule(const char * filename)
199 if (options.verbose)
200 printf("loading `%s'\n", filename);
202 /* allocate a new module entry on the end of the modules list */
203 if (!modules)
205 modules = malloc (sizeof(*modules));
206 lastmodule = modules;
208 else
210 lastmodule->next = malloc (sizeof(*modules));
211 lastmodule = lastmodule->next;
214 if ( ! lastmodule)
216 fprintf(stderr, "ldrdf: out of memory\n");
217 exit(1);
220 /* open the file using 'rdfopen', which returns nonzero on error */
222 if (rdfopen(&lastmodule->f, filename) != 0)
224 rdfperror("ldrdf", filename);
225 exit(1);
229 * store information about the module, and determine what segments
230 * it contains, and what we should do with them (determine relocation
231 * factor if we decide to keep them)
234 lastmodule->header = NULL;
235 lastmodule->name = strdup(filename);
236 lastmodule->next = NULL;
238 processmodule(filename, lastmodule);
242 * processmodule()
244 * step through each segment, determine what exactly we're doing with
245 * it, and if we intend to keep it, determine (a) which segment to
246 * put it in and (b) whereabouts in that segment it will end up.
247 * (b) is fairly easy, cos we're now keeping track of how big each segment
248 * in our output file is...
251 void processmodule(const char * filename, struct modulenode * mod)
253 struct segconfig sconf;
254 int seg, outseg;
255 void * header;
256 rdfheaderrec * hr;
257 long bssamount = 0;
259 for (seg = 0; seg < mod->f.nsegs; seg++)
262 * get the segment configuration for this type from the segment
263 * table. getsegconfig() is a macro, defined in ldsegs.h.
265 getsegconfig(sconf, mod->f.seg[seg].type);
267 if (options.verbose > 1) {
268 printf ("%s %04x [%04x:%10s] ", filename, mod->f.seg[seg].number,
269 mod->f.seg[seg].type, sconf.typedesc);
272 * sconf->dowhat tells us what to do with a segment of this type.
274 switch (sconf.dowhat) {
275 case SEG_IGNORE:
277 * Set destination segment to -1, to indicate that this segment
278 * should be ignored for the purpose of output, ie it is left
279 * out of the linked executable.
281 mod->seginfo[seg].dest_seg = -1;
282 if (options.verbose > 1) printf("IGNORED\n");
283 break;
285 case SEG_NEWSEG:
287 * The configuration tells us to create a new segment for
288 * each occurrence of this segment type.
290 outseg = allocnewseg(sconf.mergetype,
291 mod->f.seg[seg].reserved);
292 mod->seginfo[seg].dest_seg = outseg;
293 mod->seginfo[seg].reloc = 0;
294 outputseg[outseg].length = mod->f.seg[seg].length;
295 if (options.verbose > 1)
296 printf ("=> %04x:%08lx (+%04lx)\n", outseg,
297 mod->seginfo[seg].reloc,
298 mod->f.seg[seg].length);
299 break;
301 case SEG_MERGE:
303 * The configuration tells us to merge the segment with
304 * a previously existing segment of type 'sconf.mergetype',
305 * if one exists. Otherwise a new segment is created.
306 * This is handled transparently by 'findsegment()'.
308 outseg = findsegment(sconf.mergetype,
309 mod->f.seg[seg].reserved);
310 mod->seginfo[seg].dest_seg = outseg;
313 * We need to add alignment to these segments.
315 if (outputseg[outseg].length % options.align != 0)
316 outputseg[outseg].length +=
317 options.align - (outputseg[outseg].length % options.align);
319 mod->seginfo[seg].reloc = outputseg[outseg].length;
320 outputseg[outseg].length += mod->f.seg[seg].length;
322 if (options.verbose > 1)
323 printf ("=> %04x:%08lx (+%04lx)\n", outseg,
324 mod->seginfo[seg].reloc,
325 mod->f.seg[seg].length);
331 * extract symbols from the header, and dump them into the
332 * symbol table
334 header = malloc(mod->f.header_len);
335 if (!header) {
336 fprintf(stderr, "ldrdf: not enough memory\n");
337 exit(1);
339 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
340 rdfperror("ldrdf", filename);
341 exit(1);
344 while ((hr = rdfgetheaderrec (&mod->f)))
346 switch(hr->type) {
347 case 2: /* imported symbol - define with seg = -1 */
348 case 7:
349 symtab_add(hr->i.label, -1, 0);
350 break;
352 case 3: /* exported symbol */
354 int destseg;
355 long destreloc;
357 if (hr->e.segment == 2)
359 destreloc = bss_length;
360 if (destreloc % options.align != 0)
361 destreloc += options.align - (destreloc % options.align);
362 destseg = 2;
364 else
366 if ((destseg = mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
367 continue;
368 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
370 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
371 break;
374 case 5: /* BSS reservation */
376 * first, amalgamate all BSS reservations in this module
377 * into one, because we allow this in the output format.
379 bssamount += hr->b.amount;
380 break;
384 if (bssamount != 0)
387 * handle the BSS segment - first pad the existing bss length
388 * to the correct alignment, then store the length in bss_reloc
389 * for this module. Then add this module's BSS length onto
390 * bss_length.
392 if (bss_length % options.align != 0)
393 bss_length += options.align - (bss_length % options.align);
395 mod->bss_reloc = bss_length;
396 if (options.verbose > 1) {
397 printf ("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n",
398 filename, bss_length, bssamount);
400 bss_length += bssamount;
403 #ifdef STINGY_MEMORY
405 * we free the header buffer here, to save memory later.
406 * this isn't efficient, but probably halves the memory usage
407 * of this program...
409 mod->f.header_loc = NULL;
410 free(header);
412 #endif
418 * Look in list for module by its name.
420 int lookformodule(const char *name)
422 struct modulenode *curr=modules;
424 while(curr) {
425 if (!strcmp(name,curr->name)) return 1;
426 curr = curr->next;
428 return 0;
433 * allocnewseg()
434 * findsegment()
436 * These functions manipulate the array of output segments, and are used
437 * by processmodule(). allocnewseg() allocates a segment in the array,
438 * initialising it to be empty. findsegment() first scans the array for
439 * a segment of the type requested, and if one isn't found allocates a
440 * new one.
442 int allocnewseg(int16 type,int16 reserved)
444 outputseg[nsegs].type = type;
445 outputseg[nsegs].number = nsegs;
446 outputseg[nsegs].reserved = reserved;
447 outputseg[nsegs].length = 0;
448 outputseg[nsegs].offset = 0;
449 outputseg[nsegs].data = NULL;
451 return nsegs++;
454 int findsegment(int16 type,int16 reserved)
456 int i;
458 for (i = 0; i < nsegs; i++)
459 if (outputseg[i].type == type) return i;
461 return allocnewseg(type,reserved);
465 * symtab_add()
467 * inserts a symbol into the global symbol table, which associates symbol
468 * names either with addresses, or a marker that the symbol hasn't been
469 * resolved yet, or possibly that the symbol has been defined as
470 * contained in a dynamic [load time/run time] linked library.
472 * segment = -1 => not yet defined
473 * segment = -2 => defined as dll symbol
475 * If the symbol is already defined, and the new segment >= 0, then
476 * if the original segment was < 0 the symbol is redefined, otherwise
477 * a duplicate symbol warning is issued. If new segment == -1, this
478 * routine won't change a previously existing symbol. It will change
479 * to segment = -2 only if the segment was previously < 0.
482 void symtab_add(const char * symbol, int segment, long offset)
484 symtabEnt * ste;
486 ste = symtabFind(symtab, symbol);
487 if (ste)
489 if (ste->segment >= 0) {
491 * symbol previously defined
493 if (segment < 0) return;
494 fprintf (error_file, "warning: `%s' redefined\n", symbol);
495 return;
499 * somebody wanted the symbol, and put an undefined symbol
500 * marker into the table
502 if (segment == -1) return;
504 * we have more information now - update the symbol's entry
506 ste->segment = segment;
507 ste->offset = offset;
508 ste->flags = 0;
509 return;
512 * this is the first declaration of this symbol
514 ste = malloc(sizeof(symtabEnt));
515 if (!ste) {
516 fprintf(stderr, "ldrdf: out of memory\n");
517 exit(1);
519 ste->name = strdup(symbol);
520 ste->segment = segment;
521 ste->offset = offset;
522 ste->flags = 0;
523 symtabInsert(symtab, ste);
527 * symtab_get()
529 * Retrieves the values associated with a symbol. Undefined symbols
530 * are assumed to have -1:0 associated. Returns 1 if the symbol was
531 * successfully located.
534 int symtab_get(const char * symbol, int * segment, long * offset)
536 symtabEnt * ste = symtabFind(symtab, symbol);
537 if (!ste) {
538 *segment = -1;
539 *offset = 0;
540 return 0;
542 else
544 *segment = ste->segment;
545 *offset = ste->offset;
546 return 1;
551 * add_library()
553 * checks that a library can be opened and is in the correct format,
554 * then adds it to the linked list of libraries.
557 void add_library(const char * name)
559 if (rdl_verify(name)) {
560 rdl_perror("ldrdf", name);
561 errorcount++;
562 return;
564 if (! libraries)
566 lastlib = libraries = malloc(sizeof(*libraries));
567 if (! libraries) {
568 fprintf(stderr, "ldrdf: out of memory\n");
569 exit(1);
572 else
574 lastlib->next = malloc(sizeof(*libraries));
575 if (!lastlib->next) {
576 fprintf(stderr, "ldrdf: out of memory\n");
577 exit(1);
579 lastlib = lastlib->next;
581 lastlib->next = NULL;
582 if (rdl_open(lastlib, name)) {
583 rdl_perror("ldrdf", name);
584 errorcount++;
585 return;
590 * search_libraries()
592 * scans through the list of libraries, attempting to match symbols
593 * defined in library modules against symbols that are referenced but
594 * not defined (segment = -1 in the symbol table)
596 * returns 1 if any extra library modules are included, indicating that
597 * another pass through the library list should be made (possibly).
600 int search_libraries()
602 struct librarynode * cur;
603 rdffile f;
604 int i;
605 void * header;
606 int segment;
607 long offset;
608 int doneanything = 0, pass = 1, keepfile;
609 rdfheaderrec * hr;
611 cur = libraries;
613 while (cur)
615 if (options.verbose > 2)
616 printf("scanning library `%s', pass %d...\n", cur->name, pass);
618 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++)
620 if (pass == 2 && lookformodule(f.name)) continue;
622 if (options.verbose > 3)
623 printf(" looking in module `%s'\n", f.name);
625 header = malloc(f.header_len);
626 if (!header) {
627 fprintf(stderr, "ldrdf: not enough memory\n");
628 exit(1);
630 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
631 rdfperror("ldrdf", f.name);
632 errorcount++;
633 return 0;
636 keepfile = 0;
638 while ((hr = rdfgetheaderrec (&f)))
640 /* we're only interested in exports, so skip others: */
641 if (hr->type != 3) continue;
644 * Find the symbol in the symbol table. If the symbol isn't
645 * defined, we aren't interested, so go on to the next.
646 * If it is defined as anything but -1, we're also not
647 * interested. But if it is defined as -1, insert this
648 * module into the list of modules to use, and go
649 * immediately on to the next module...
651 if (! symtab_get(hr->e.label, &segment, &offset)
652 || segment != -1)
654 continue;
657 doneanything = 1;
658 keepfile = 1;
661 * as there are undefined symbols, we can assume that
662 * there are modules on the module list by the time
663 * we get here.
665 lastmodule->next = malloc(sizeof(*lastmodule->next));
666 if (!lastmodule->next) {
667 fprintf(stderr, "ldrdf: not enough memory\n");
668 exit(1);
670 lastmodule = lastmodule->next;
671 memcpy(&lastmodule->f, &f, sizeof(f));
672 lastmodule->name = strdup(f.name);
673 lastmodule->next = NULL;
674 processmodule(f.name, lastmodule);
675 break;
677 if (!keepfile)
679 free(f.name);
680 f.name = NULL;
681 f.fp = NULL;
684 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
685 rdl_perror("ldrdf", cur->name);
687 cur = cur->next;
688 if (cur == NULL && pass == 1) {
689 cur = libraries;
690 pass++;
694 return doneanything;
698 * write_output()
700 * this takes the linked list of modules, and walks through it, merging
701 * all the modules into a single output module, and then writes this to a
702 * file.
704 void write_output(const char * filename)
706 FILE * f;
707 rdf_headerbuf * rdfheader;
708 struct modulenode * cur;
709 int i, availableseg, seg, localseg, isrelative;
710 void * header;
711 rdfheaderrec * hr, newrec;
712 symtabEnt * se;
713 segtab segs;
714 long offset;
715 byte * data;
717 if ((f = fopen(filename, "wb"))==NULL) {
718 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
719 exit(1);
721 if ((rdfheader=rdfnewheader())==NULL) {
722 fprintf(stderr, "ldrdf: out of memory\n");
723 exit(1);
727 * Add multiboot header if appropriate option is specified.
728 * Multiboot record *MUST* be the first record in output file.
730 if (options.addMBheader) {
731 if (options.verbose)
732 puts("\nadding multiboot header record");
734 hr = (rdfheaderrec *) malloc(sizeof(struct MultiBootHdrRec));
735 hr->mbh.type = 9;
736 hr->mbh.reclen = sizeof(struct tMultiBootHeader)+RDFLDRMOVER_SIZE;
738 hr->mbh.mb.Magic = MB_MAGIC;
739 hr->mbh.mb.Flags = MB_FL_KLUDGE;
740 hr->mbh.mb.Checksum = ~(MB_MAGIC+MB_FL_KLUDGE-1);
741 hr->mbh.mb.HeaderAddr = MBHloadAddr+16;
742 hr->mbh.mb.LoadAddr = MBHloadAddr;
743 hr->mbh.mb.Entry = MBHloadAddr+16+sizeof(struct tMultiBootHeader);
745 memcpy(hr->mbh.mover,RDFloaderMover,RDFLDRMOVER_SIZE);
747 rdfaddheader(rdfheader,hr);
748 free(hr);
751 if (options.verbose)
752 printf ("\nbuilding output module (%d segments)\n", nsegs);
755 * Allocate the memory for the segments. We may be better off
756 * building the output module one segment at a time when running
757 * under 16 bit DOS, but that would be a slower way of doing this.
758 * And you could always use DJGPP...
760 for (i = 0; i < nsegs; i++)
762 outputseg[i].data=NULL;
763 if(!outputseg[i].length) continue;
764 outputseg[i].data = malloc(outputseg[i].length);
765 if (!outputseg[i].data) {
766 fprintf(stderr, "ldrdf: out of memory\n");
767 exit(1);
772 * initialise availableseg, used to allocate segment numbers for
773 * imported and exported labels...
775 availableseg = nsegs;
778 * Step through the modules, performing required actions on each one
780 for (cur = modules; cur; cur=cur->next)
783 * Read the actual segment contents into the correct places in
784 * the newly allocated segments
787 for (i = 0; i < cur->f.nsegs; i++)
789 int dest = cur->seginfo[i].dest_seg;
791 if (dest == -1) continue;
792 if (rdfloadseg(&cur->f, i,
793 outputseg[dest].data + cur->seginfo[i].reloc))
795 rdfperror("ldrdf", cur->name);
796 exit(1);
801 * Perform fixups, and add new header records where required
804 header = malloc(cur->f.header_len);
805 if (!header) {
806 fprintf(stderr, "ldrdf: out of memory\n");
807 exit(1);
810 if (cur->f.header_loc)
811 rdfheaderrewind(&cur->f);
812 else
813 if (rdfloadseg(&cur->f, RDOFF_HEADER, header))
815 rdfperror("ldrdf", cur->name);
816 exit(1);
820 * we need to create a local segment number -> location
821 * table for the segments in this module.
823 init_seglocations(&segs);
824 for (i = 0; i < cur->f.nsegs; i++)
826 add_seglocation(&segs, cur->f.seg[i].number,
827 cur->seginfo[i].dest_seg, cur->seginfo[i].reloc);
830 * and the BSS segment (doh!)
832 add_seglocation (&segs, 2, 2, cur->bss_reloc);
834 while ((hr = rdfgetheaderrec(&cur->f)))
836 switch(hr->type) {
837 case 1: /* relocation record - need to do a fixup */
839 * First correct the offset stored in the segment from
840 * the start of the segment (which may well have changed).
842 * To do this we add to the number stored the relocation
843 * factor associated with the segment that contains the
844 * target segment.
846 * The relocation could be a relative relocation, in which
847 * case we have to first subtract the amount we've relocated
848 * the containing segment by.
851 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
853 fprintf(stderr, "%s: reloc to undefined segment %04x\n",
854 cur->name, (int) hr->r.refseg);
855 errorcount++;
856 break;
859 isrelative = (hr->r.segment & 64) == 64;
860 hr->r.segment &= 63;
862 if (hr->r.segment == 2 ||
863 (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1)
865 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
866 cur->name,
867 hr->r.segment == 2 ? "BSS" : "unknown",
868 hr->r.segment);
869 errorcount++;
870 break;
873 if (hr->r.length != 1 && hr->r.length != 2 && hr->r.length!=4)
875 fprintf(stderr, "%s: nonstandard length reloc "
876 "(%d bytes)\n", cur->name, hr->r.length);
877 errorcount++;
878 break;
882 * okay, now the relocation is in the segment pointed to by
883 * cur->seginfo[localseg], and we know everything else is
884 * okay to go ahead and do the relocation
886 data = outputseg[cur->seginfo[localseg].dest_seg].data;
887 data += cur->seginfo[localseg].reloc + hr->r.offset;
890 * data now points to the reference that needs
891 * relocation. Calculate the relocation factor.
892 * Factor is:
893 * offset of referred object in segment [in offset]
894 * (- relocation of localseg, if ref is relative)
895 * For simplicity, the result is stored in 'offset'.
896 * Then add 'offset' onto the value at data.
899 if (isrelative) offset -= cur->seginfo[localseg].reloc;
900 switch (hr->r.length)
902 case 1:
903 offset += *data;
904 if (offset < -127 || offset > 128)
905 fprintf(error_file, "warning: relocation out of range "
906 "at %s(%02x:%08lx)\n", cur->name,
907 (int)hr->r.segment, hr->r.offset);
908 *data = (char) offset;
909 break;
910 case 2:
911 offset += * (short *)data;
912 if (offset < -32767 || offset > 32768)
913 fprintf(error_file, "warning: relocation out of range "
914 "at %s(%02x:%08lx)\n", cur->name,
915 (int)hr->r.segment, hr->r.offset);
916 * (short *)data = (short) offset;
917 break;
918 case 4:
919 * (long *)data += offset;
920 /* we can't easily detect overflow on this one */
921 break;
925 * If the relocation was relative between two symbols in
926 * the same segment, then we're done.
928 * Otherwise, we need to output a new relocation record
929 * with the references updated segment and offset...
931 if (! isrelative
932 || cur->seginfo[localseg].dest_seg != seg)
934 hr->r.segment = cur->seginfo[localseg].dest_seg;
935 hr->r.offset += cur->seginfo[localseg].reloc;
936 hr->r.refseg = seg;
937 rdfaddheader(rdfheader, hr);
939 break;
941 case 2: /* import symbol */
942 case 7:
944 * scan the global symbol table for the symbol
945 * and associate its location with the segment number
946 * for this module
948 se = symtabFind(symtab, hr->i.label);
949 if (!se || se->segment == -1) {
950 if (options.warnUnresolved) {
951 fprintf(error_file, "warning: unresolved reference to `%s'"
952 " in module `%s'\n", hr->i.label, cur->name);
953 if (options.errorUnresolved==1) errorcount++;
956 * we need to allocate a segment number for this
957 * symbol, and store it in the symbol table for
958 * future reference
960 if (!se) {
961 se=malloc(sizeof(*se));
962 if (!se) {
963 fprintf(stderr, "ldrdf: out of memory\n");
964 exit(1);
966 se->name = strdup(hr->i.label);
967 se->flags = 0;
968 se->segment = availableseg++;
969 se->offset = 0;
970 symtabInsert(symtab, se);
972 else {
973 se->segment = availableseg++;
974 se->offset = 0;
977 * output a header record that imports it to the
978 * recently allocated segment number...
980 newrec = *hr;
981 newrec.i.segment = se->segment;
982 rdfaddheader(rdfheader, &newrec);
985 add_seglocation(&segs, hr->i.segment, se->segment, se->offset);
987 break;
989 case 3: /* export symbol */
991 * need to insert an export for this symbol into the new
992 * header, unless we're stripping symbols [unless this
993 * symbol is in an explicit keep list]. *** FIXME ***
995 if (options.strip)
996 break;
998 if (hr->e.segment == 2) {
999 seg = 2;
1000 offset = cur->bss_reloc;
1002 else {
1003 localseg = rdffindsegment(&cur->f, hr->e.segment);
1004 if (localseg == -1) {
1005 fprintf(stderr, "%s: exported symbol `%s' from "
1006 "unrecognised segment\n", cur->name,
1007 hr->e.label);
1008 errorcount++;
1009 break;
1011 offset = cur->seginfo[localseg].reloc;
1012 seg = cur->seginfo[localseg].dest_seg;
1015 hr->e.segment = seg;
1016 hr->e.offset += offset;
1017 rdfaddheader(rdfheader, hr);
1018 break;
1020 case 8: /* module name */
1022 * insert module name record if export symbols
1023 * are not stripped.
1025 if (options.strip) break;
1027 rdfaddheader(rdfheader, hr);
1028 break;
1030 case 6: /* segment fixup */
1032 * modify the segment numbers if necessary, and
1033 * pass straight through to the output module header
1035 * *** FIXME ***
1037 if (hr->r.segment == 2) {
1038 fprintf(stderr, "%s: segment fixup in BSS section\n",
1039 cur->name);
1040 errorcount++;
1041 break;
1043 localseg = rdffindsegment(&cur->f, hr->r.segment);
1044 if (localseg == -1) {
1045 fprintf(stderr, "%s: segment fixup in unrecognised"
1046 " segment (%d)\n", cur->name, hr->r.segment);
1047 errorcount++;
1048 break;
1050 hr->r.segment = cur->seginfo[localseg].dest_seg;
1051 hr->r.offset += cur->seginfo[localseg].reloc;
1053 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
1055 fprintf(stderr, "%s: segment fixup to undefined "
1056 "segment %04x\n", cur->name, (int)hr->r.refseg);
1057 errorcount++;
1058 break;
1060 hr->r.refseg = seg;
1061 rdfaddheader(rdfheader, hr);
1062 break;
1066 free(header);
1067 done_seglocations(&segs);
1072 * combined BSS reservation for the entire results
1074 newrec.type = 5;
1075 newrec.b.reclen = 4;
1076 newrec.b.amount = bss_length;
1077 rdfaddheader(rdfheader, &newrec);
1080 * Write the header
1082 for (i = 0; i < nsegs; i++)
1084 if (i == 2) continue;
1085 rdfaddsegment (rdfheader, outputseg[i].length);
1088 if (options.addMBheader) {
1089 struct MultiBootHdrRec *mbhrec = (struct MultiBootHdrRec *)(rdfheader->buf->buffer);
1090 unsigned l = membuflength(rdfheader->buf) + 14 +
1091 10*rdfheader->nsegments + rdfheader->seglength;
1092 unsigned *ldraddr = (unsigned *)(mbhrec->mover+1);
1094 mbhrec->mb.LoadEndAddr = MBHloadAddr+l+10+RDFLDR_LENGTH;
1095 mbhrec->mb.BSSendAddr = mbhrec->mb.LoadEndAddr;
1096 *ldraddr = MBHloadAddr+l+10;
1099 rdfwriteheader(f, rdfheader);
1100 rdfdoneheader(rdfheader);
1102 * Step through the segments, one at a time, writing out into
1103 * the output file
1106 for (i = 0; i < nsegs; i++)
1108 int16 s;
1109 long l;
1111 if (i == 2) continue;
1113 s = translateshort(outputseg[i].type);
1114 fwrite(&s, 2, 1, f);
1115 s = translateshort(outputseg[i].number);
1116 fwrite(&s, 2, 1, f);
1117 s = translateshort(outputseg[i].reserved);
1118 fwrite(&s, 2, 1, f);
1119 l = translatelong(outputseg[i].length);
1120 fwrite(&l, 4, 1, f);
1122 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1125 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f);
1128 /* =========================================================================
1129 * Main program
1132 void usage()
1134 printf("usage:\n");
1135 printf(" ldrdf [options] object modules ... [-llibrary ...]\n");
1136 printf(" ldrdf -r\n");
1137 printf("options:\n");
1138 printf(" -v[=n] increases verbosity by 1, or sets it to n\n");
1139 printf(" -a nn sets segment alignment value (default 16)\n");
1140 printf(" -s strips exported symbols\n");
1141 printf(" -x warn about unresolved symbols\n");
1142 printf(" -o name write output in file 'name'\n");
1143 printf(" -j path specify objects search path\n");
1144 printf(" -L path specify libraries search path\n");
1145 printf(" -mbh [address] add multiboot header to output file. Default\n");
1146 printf(" loading address is 0x110000\n");
1147 exit(0);
1150 int main(int argc, char ** argv)
1152 char * outname = "aout.rdf";
1153 int moduleloaded = 0;
1154 char *respstrings[128] = {0, };
1156 options.verbose = 0;
1157 options.align = 16;
1158 options.warnUnresolved = 0;
1159 options.strip = 0;
1161 error_file = stderr;
1163 argc --, argv ++;
1164 if (argc == 0) usage();
1165 while (argc && **argv == '-' && argv[0][1] != 'l')
1167 switch(argv[0][1]) {
1168 case 'r':
1169 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION "\n");
1170 printf( _RDOFF_H "\n");
1171 exit(0);
1172 case 'v':
1173 if (argv[0][2] == '=') {
1174 options.verbose = argv[0][3] - '0';
1175 if (options.verbose < 0 || options.verbose > 9) {
1176 fprintf(stderr, "ldrdf: verbosity level must be a number"
1177 " between 0 and 9\n");
1178 exit(1);
1181 else
1182 options.verbose++;
1183 break;
1184 case 'a':
1185 options.align = atoi(argv[1]);
1186 if (options.align <= 0) {
1187 fprintf(stderr,
1188 "ldrdf: -a expects a positive number argument\n");
1189 exit(1);
1191 argv++, argc--;
1192 break;
1193 case 's':
1194 options.strip = 1;
1195 break;
1196 case 'x':
1197 options.warnUnresolved = 1;
1198 if (argv[0][2]=='e')
1199 options.errorUnresolved = 1;
1200 break;
1201 case 'o':
1202 outname = argv[1];
1203 argv++, argc--;
1204 break;
1205 case 'j':
1206 if (!objpath)
1208 options.objpath = 1;
1209 objpath = argv[1];
1210 argv++, argc--;
1211 break;
1213 else
1215 fprintf(stderr,"ldrdf: more than one objects search path specified\n");
1216 exit(1);
1218 case 'L':
1219 if (!libpath)
1221 options.libpath = 1;
1222 libpath = argv[1];
1223 argv++, argc--;
1224 break;
1226 else
1228 fprintf(stderr,"ldrdf: more than one libraries search path specified\n");
1229 exit(1);
1231 case '@': {
1232 int i=0;
1233 char buf[256];
1234 FILE *f;
1236 options.respfile = 1;
1237 if (argv[1] != NULL) f = fopen(argv[1],"r");
1238 else
1240 fprintf(stderr,"ldrdf: no response file name specified\n");
1241 exit(1);
1244 if (f == NULL)
1246 fprintf(stderr,"ldrdf: unable to open response file\n");
1247 exit(1);
1249 argc-=2;
1250 while(fgets(buf,sizeof(buf)-1,f)!=NULL)
1252 char *p;
1253 if (buf[0]=='\n') continue;
1254 if ((p = strchr(buf,'\n')) != 0)
1255 *p=0;
1256 if (i >= 128)
1258 fprintf(stderr,"ldrdf: too many input files\n");
1259 exit(1);
1261 *(respstrings+i) = newstr(buf);
1262 argc++, i++;
1264 goto done;
1266 case '2':
1267 options.stderr_redir = 1;
1268 error_file = stdout;
1269 break;
1270 case 'm':
1271 if (argv[0][2] == 'b' && argv[0][3] == 'h') {
1272 if (argv[1][0] != '-') {
1273 MBHloadAddr = atoi(argv[1]);
1274 } else {
1275 MBHloadAddr = MB_DEFAULTLOADADDR;
1277 options.addMBheader = 1;
1278 break;
1280 default:
1281 usage();
1283 argv++, argc--;
1285 done:
1286 if (options.verbose > 4) {
1287 printf("ldrdf invoked with options:\n");
1288 printf(" section alignment: %d bytes\n", options.align);
1289 printf(" output name: `%s'\n", outname);
1290 if (options.strip)
1291 printf(" strip symbols\n");
1292 if (options.warnUnresolved)
1293 printf(" warn about unresolved symbols\n");
1294 if (options.errorUnresolved)
1295 printf(" error if unresolved symbols\n");
1296 if (options.objpath)
1297 printf(" objects search path: %s\n",objpath);
1298 if (options.libpath)
1299 printf(" libraries search path: %s\n",libpath);
1300 if (options.addMBheader)
1301 printf(" loading address for multiboot header: 0x%X\n",MBHloadAddr);
1302 printf("\n");
1305 symtab = symtabNew();
1306 initsegments();
1308 if (!symtab) {
1309 fprintf(stderr, "ldrdf: out of memory\n");
1310 exit(1);
1313 if (*respstrings) argv = respstrings;
1314 while (argc)
1316 if (!strncmp(*argv, "-l", 2)) /* library */
1318 if(libpath) add_library(newstrcat(libpath,*argv + 2));
1319 else add_library(*argv + 2);
1321 else {
1322 if(objpath) loadmodule(newstrcat(objpath,*argv));
1323 else loadmodule(*argv);
1324 moduleloaded = 1;
1326 argv++, argc--;
1329 if (! moduleloaded) {
1330 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1331 return 0;
1335 search_libraries();
1337 if (options.verbose > 2)
1339 printf ("symbol table:\n");
1340 symtabDump(symtab, stdout);
1343 write_output(outname);
1345 if (errorcount > 0) exit(1);
1346 return 0;