Strip the anchor tags from the table of contents
[nasm.git] / rdoff / ldrdf.c
blob2226fef177a62397c8ee0c19c0ccd55e234f8145
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:
11 * enhance search of required export symbols in libraries (now depends
12 * on modules order in library)
13 * - keep a cache of symbol names in each library module so
14 * we don't have to constantly recheck the file
15 * - general performance improvements
17 * BUGS & LIMITATIONS: this program doesn't support multiple code, data
18 * or bss segments, therefore for 16 bit programs whose code, data or BSS
19 * segment exceeds 64K in size, it will not work. This program probably
20 * won't work if compiled by a 16 bit compiler. Try DJGPP if you're running
21 * under DOS. '#define STINGY_MEMORY' may help a little.
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #include "multboot.h"
29 #include "rdoff.h"
30 #include "symtab.h"
31 #include "collectn.h"
32 #include "rdlib.h"
33 #include "segtab.h"
35 #define LDRDF_VERSION "1.04"
37 #define RDF_MAXSEGS 64
38 /* #define STINGY_MEMORY */
40 /* =======================================================================
41 * Types & macros that are private to this program
44 struct segment_infonode {
45 int dest_seg; /* output segment to be placed into, -1 to
46 skip linking this segment */
47 long reloc; /* segment's relocation factor */
51 struct modulenode {
52 rdffile f; /* the RDOFF file structure */
53 struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
54 with each segment? */
55 void * header;
56 char * name;
57 struct modulenode * next;
58 long bss_reloc;
61 #include "ldsegs.h"
63 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
64 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
66 /* ==========================================================================
67 * Function prototypes of private utility functions
70 void processmodule(const char * filename, struct modulenode * mod);
71 int allocnewseg(int16 type,int16 reserved);
72 int findsegment(int16 type,int16 reserved);
73 void symtab_add(const char * symbol, int segment, long offset);
74 int symtab_get(const char * symbol, int * segment, long * offset);
76 /* =========================================================================
77 * Global data structures.
80 /* a linked list of modules that will be included in the output */
81 struct modulenode * modules = NULL;
82 struct modulenode * lastmodule = NULL;
84 /* a linked list of libraries to be searched for unresolved imported symbols */
85 struct librarynode * libraries = NULL;
86 struct librarynode * lastlib = NULL;
88 /* the symbol table */
89 void * symtab = NULL;
91 /* objects search path */
92 char * objpath = NULL;
94 /* libraries search path */
95 char * libpath = NULL;
97 /* error file */
98 static FILE * error_file;
100 /* the header of the output file, built up stage by stage */
101 rdf_headerbuf * newheader = NULL;
103 /* The current state of segment allocation, including information about
104 * which output segment numbers have been allocated, and their types and
105 * amount of data which has already been allocated inside them.
107 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
108 int nsegs = 0;
109 long bss_length;
111 /* global options which affect how the program behaves */
112 struct ldrdfoptions {
113 int verbose;
114 int align;
115 int warnUnresolved;
116 int errorUnresolved;
117 int strip;
118 int respfile;
119 int stderr_redir;
120 int objpath;
121 int libpath;
122 int addMBheader;
123 } options;
125 int errorcount = 0; /* determines main program exit status */
128 * Multiboot header support.
131 /* loading address for multiboot header */
132 unsigned MBHloadAddr;
134 #define RDFLDR_LENGTH 4096 /* Loader size is 4K */
135 #define RDFLDR_DESTLOC 0x100000 /* and its absolute address */
138 * Tiny code that moves RDF setup code to its working memory region
140 unsigned char trampoline_code[] = {
141 0xBE, 0, 0, 0, 0, /* mov esi,SOURCE_ADDR */
142 0xBF, 0, 0, 0, 0, /* mov edi,DEST_ADDR */
143 0x89, 0xFA, /* mov edx,edi */
144 0xB9, 0, 4, 0, 0, /* mov ecx,RDFLDR_LENGTH/4 */
145 0xFC, /* cld */
146 0xF3, 0xA5, /* rep movsd */
147 0xFF, 0xE2 /* jmp edx */
150 /* =========================================================================
151 * Utility functions
156 * initsegments()
158 * sets up segments 0, 1, and 2, the initial code data and bss segments
161 void initsegments()
163 nsegs = 3;
164 outputseg[0].type = 1;
165 outputseg[0].number = 0;
166 outputseg[0].reserved = 0;
167 outputseg[0].length = 0;
168 outputseg[1].type = 2;
169 outputseg[1].number = 1;
170 outputseg[1].reserved = 0;
171 outputseg[1].length = 0;
172 outputseg[2].type = 0xFFFF; /* reserved segment type */
173 outputseg[2].number = 2;
174 outputseg[2].reserved = 0;
175 outputseg[2].length = 0;
176 bss_length = 0;
180 * loadmodule
182 * Determine the characteristics of a module, and decide what to do with
183 * each segment it contains (including determining destination segments and
184 * relocation factors for segments that are kept).
187 void loadmodule(const char * filename)
189 if (options.verbose)
190 printf("loading `%s'\n", filename);
192 /* allocate a new module entry on the end of the modules list */
193 if (!modules)
195 modules = malloc (sizeof(*modules));
196 lastmodule = modules;
198 else
200 lastmodule->next = malloc (sizeof(*modules));
201 lastmodule = lastmodule->next;
204 if ( ! lastmodule)
206 fprintf(stderr, "ldrdf: out of memory\n");
207 exit(1);
210 /* open the file using 'rdfopen', which returns nonzero on error */
212 if (rdfopen(&lastmodule->f, filename) != 0)
214 rdfperror("ldrdf", filename);
215 exit(1);
219 * store information about the module, and determine what segments
220 * it contains, and what we should do with them (determine relocation
221 * factor if we decide to keep them)
224 lastmodule->header = NULL;
225 lastmodule->name = strdup(filename);
226 lastmodule->next = NULL;
228 processmodule(filename, lastmodule);
232 * processmodule()
234 * step through each segment, determine what exactly we're doing with
235 * it, and if we intend to keep it, determine (a) which segment to
236 * put it in and (b) whereabouts in that segment it will end up.
237 * (b) is fairly easy, cos we're now keeping track of how big each segment
238 * in our output file is...
241 void processmodule(const char * filename, struct modulenode * mod)
243 struct segconfig sconf;
244 int seg, outseg;
245 void * header;
246 rdfheaderrec * hr;
247 long bssamount = 0;
249 for (seg = 0; seg < mod->f.nsegs; seg++)
252 * get the segment configuration for this type from the segment
253 * table. getsegconfig() is a macro, defined in ldsegs.h.
255 getsegconfig(sconf, mod->f.seg[seg].type);
257 if (options.verbose > 1) {
258 printf ("%s %04x [%04x:%10s] ", filename, mod->f.seg[seg].number,
259 mod->f.seg[seg].type, sconf.typedesc);
262 * sconf->dowhat tells us what to do with a segment of this type.
264 switch (sconf.dowhat) {
265 case SEG_IGNORE:
267 * Set destination segment to -1, to indicate that this segment
268 * should be ignored for the purpose of output, ie it is left
269 * out of the linked executable.
271 mod->seginfo[seg].dest_seg = -1;
272 if (options.verbose > 1) printf("IGNORED\n");
273 break;
275 case SEG_NEWSEG:
277 * The configuration tells us to create a new segment for
278 * each occurrence of this segment type.
280 outseg = allocnewseg(sconf.mergetype,
281 mod->f.seg[seg].reserved);
282 mod->seginfo[seg].dest_seg = outseg;
283 mod->seginfo[seg].reloc = 0;
284 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);
289 break;
291 case SEG_MERGE:
293 * The configuration tells us to merge the segment with
294 * a previously existing segment of type 'sconf.mergetype',
295 * if one exists. Otherwise a new segment is created.
296 * This is handled transparently by 'findsegment()'.
298 outseg = findsegment(sconf.mergetype,
299 mod->f.seg[seg].reserved);
300 mod->seginfo[seg].dest_seg = outseg;
303 * We need to add alignment to these segments.
305 if (outputseg[outseg].length % options.align != 0)
306 outputseg[outseg].length +=
307 options.align - (outputseg[outseg].length % options.align);
309 mod->seginfo[seg].reloc = outputseg[outseg].length;
310 outputseg[outseg].length += mod->f.seg[seg].length;
312 if (options.verbose > 1)
313 printf ("=> %04x:%08lx (+%04lx)\n", outseg,
314 mod->seginfo[seg].reloc,
315 mod->f.seg[seg].length);
321 * extract symbols from the header, and dump them into the
322 * symbol table
324 header = malloc(mod->f.header_len);
325 if (!header) {
326 fprintf(stderr, "ldrdf: not enough memory\n");
327 exit(1);
329 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
330 rdfperror("ldrdf", filename);
331 exit(1);
334 while ((hr = rdfgetheaderrec (&mod->f)))
336 switch(hr->type) {
337 case 2: /* imported symbol - define with seg = -1 */
338 case 7:
339 symtab_add(hr->i.label, -1, 0);
340 break;
342 case 3: /* exported symbol */
344 int destseg;
345 long destreloc;
347 if (hr->e.segment == 2)
349 destreloc = bss_length;
350 if (destreloc % options.align != 0)
351 destreloc += options.align - (destreloc % options.align);
352 destseg = 2;
354 else
356 if ((destseg = mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
357 continue;
358 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
360 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
361 break;
364 case 5: /* BSS reservation */
366 * first, amalgamate all BSS reservations in this module
367 * into one, because we allow this in the output format.
369 bssamount += hr->b.amount;
370 break;
374 if (bssamount != 0)
377 * handle the BSS segment - first pad the existing bss length
378 * to the correct alignment, then store the length in bss_reloc
379 * for this module. Then add this module's BSS length onto
380 * bss_length.
382 if (bss_length % options.align != 0)
383 bss_length += options.align - (bss_length % options.align);
385 mod->bss_reloc = bss_length;
386 if (options.verbose > 1) {
387 printf ("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n",
388 filename, bss_length, bssamount);
390 bss_length += bssamount;
393 #ifdef STINGY_MEMORY
395 * we free the header buffer here, to save memory later.
396 * this isn't efficient, but probably halves the memory usage
397 * of this program...
399 mod->f.header_loc = NULL;
400 free(header);
402 #endif
408 * Look in list for module by its name.
410 int lookformodule(const char *name)
412 struct modulenode *curr=modules;
414 while(curr) {
415 if (!strcmp(name,curr->name)) return 1;
416 curr = curr->next;
418 return 0;
423 * allocnewseg()
424 * findsegment()
426 * These functions manipulate the array of output segments, and are used
427 * by processmodule(). allocnewseg() allocates a segment in the array,
428 * initialising it to be empty. findsegment() first scans the array for
429 * a segment of the type requested, and if one isn't found allocates a
430 * new one.
432 int allocnewseg(int16 type,int16 reserved)
434 outputseg[nsegs].type = type;
435 outputseg[nsegs].number = nsegs;
436 outputseg[nsegs].reserved = reserved;
437 outputseg[nsegs].length = 0;
438 outputseg[nsegs].offset = 0;
439 outputseg[nsegs].data = NULL;
441 return nsegs++;
444 int findsegment(int16 type,int16 reserved)
446 int i;
448 for (i = 0; i < nsegs; i++)
449 if (outputseg[i].type == type) return i;
451 return allocnewseg(type,reserved);
455 * symtab_add()
457 * inserts a symbol into the global symbol table, which associates symbol
458 * names either with addresses, or a marker that the symbol hasn't been
459 * resolved yet, or possibly that the symbol has been defined as
460 * contained in a dynamic [load time/run time] linked library.
462 * segment = -1 => not yet defined
463 * segment = -2 => defined as dll symbol
465 * If the symbol is already defined, and the new segment >= 0, then
466 * if the original segment was < 0 the symbol is redefined, otherwise
467 * a duplicate symbol warning is issued. If new segment == -1, this
468 * routine won't change a previously existing symbol. It will change
469 * to segment = -2 only if the segment was previously < 0.
472 void symtab_add(const char * symbol, int segment, long offset)
474 symtabEnt * ste;
476 ste = symtabFind(symtab, symbol);
477 if (ste)
479 if (ste->segment >= 0) {
481 * symbol previously defined
483 if (segment < 0) return;
484 fprintf (error_file, "warning: `%s' redefined\n", symbol);
485 return;
489 * somebody wanted the symbol, and put an undefined symbol
490 * marker into the table
492 if (segment == -1) return;
494 * we have more information now - update the symbol's entry
496 ste->segment = segment;
497 ste->offset = offset;
498 ste->flags = 0;
499 return;
502 * this is the first declaration of this symbol
504 ste = malloc(sizeof(symtabEnt));
505 if (!ste) {
506 fprintf(stderr, "ldrdf: out of memory\n");
507 exit(1);
509 ste->name = strdup(symbol);
510 ste->segment = segment;
511 ste->offset = offset;
512 ste->flags = 0;
513 symtabInsert(symtab, ste);
517 * symtab_get()
519 * Retrieves the values associated with a symbol. Undefined symbols
520 * are assumed to have -1:0 associated. Returns 1 if the symbol was
521 * successfully located.
524 int symtab_get(const char * symbol, int * segment, long * offset)
526 symtabEnt * ste = symtabFind(symtab, symbol);
527 if (!ste) {
528 *segment = -1;
529 *offset = 0;
530 return 0;
532 else
534 *segment = ste->segment;
535 *offset = ste->offset;
536 return 1;
541 * add_library()
543 * checks that a library can be opened and is in the correct format,
544 * then adds it to the linked list of libraries.
547 void add_library(const char * name)
549 if (rdl_verify(name)) {
550 rdl_perror("ldrdf", name);
551 errorcount++;
552 return;
554 if (! libraries)
556 lastlib = libraries = malloc(sizeof(*libraries));
557 if (! libraries) {
558 fprintf(stderr, "ldrdf: out of memory\n");
559 exit(1);
562 else
564 lastlib->next = malloc(sizeof(*libraries));
565 if (!lastlib->next) {
566 fprintf(stderr, "ldrdf: out of memory\n");
567 exit(1);
569 lastlib = lastlib->next;
571 lastlib->next = NULL;
572 if (rdl_open(lastlib, name)) {
573 rdl_perror("ldrdf", name);
574 errorcount++;
575 return;
580 * search_libraries()
582 * scans through the list of libraries, attempting to match symbols
583 * defined in library modules against symbols that are referenced but
584 * not defined (segment = -1 in the symbol table)
586 * returns 1 if any extra library modules are included, indicating that
587 * another pass through the library list should be made (possibly).
590 int search_libraries()
592 struct librarynode * cur;
593 rdffile f;
594 int i;
595 void * header;
596 int segment;
597 long offset;
598 int doneanything = 0, pass = 1, keepfile;
599 rdfheaderrec * hr;
601 cur = libraries;
603 while (cur)
605 if (options.verbose > 2)
606 printf("scanning library `%s', pass %d...\n", cur->name, pass);
608 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++)
610 if (pass == 2 && lookformodule(f.name)) continue;
612 if (options.verbose > 3)
613 printf(" looking in module `%s'\n", f.name);
615 header = malloc(f.header_len);
616 if (!header) {
617 fprintf(stderr, "ldrdf: not enough memory\n");
618 exit(1);
620 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
621 rdfperror("ldrdf", f.name);
622 errorcount++;
623 return 0;
626 keepfile = 0;
628 while ((hr = rdfgetheaderrec (&f)))
630 /* we're only interested in exports, so skip others: */
631 if (hr->type != 3) continue;
634 * Find the symbol in the symbol table. If the symbol isn't
635 * defined, we aren't interested, so go on to the next.
636 * If it is defined as anything but -1, we're also not
637 * interested. But if it is defined as -1, insert this
638 * module into the list of modules to use, and go
639 * immediately on to the next module...
641 if (! symtab_get(hr->e.label, &segment, &offset)
642 || segment != -1)
644 continue;
647 doneanything = 1;
648 keepfile = 1;
651 * as there are undefined symbols, we can assume that
652 * there are modules on the module list by the time
653 * we get here.
655 lastmodule->next = malloc(sizeof(*lastmodule->next));
656 if (!lastmodule->next) {
657 fprintf(stderr, "ldrdf: not enough memory\n");
658 exit(1);
660 lastmodule = lastmodule->next;
661 memcpy(&lastmodule->f, &f, sizeof(f));
662 lastmodule->name = strdup(f.name);
663 lastmodule->next = NULL;
664 processmodule(f.name, lastmodule);
665 break;
667 if (!keepfile)
669 free(f.name);
670 f.name = NULL;
671 f.fp = NULL;
674 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
675 rdl_perror("ldrdf", cur->name);
677 cur = cur->next;
678 if (cur == NULL && pass == 1) {
679 cur = libraries;
680 pass++;
684 return doneanything;
688 * write_output()
690 * this takes the linked list of modules, and walks through it, merging
691 * all the modules into a single output module, and then writes this to a
692 * file.
694 void write_output(const char * filename)
696 FILE * f;
697 rdf_headerbuf * rdfheader;
698 struct modulenode * cur;
699 int i, availableseg, seg, localseg, isrelative;
700 void * header;
701 rdfheaderrec * hr, newrec;
702 symtabEnt * se;
703 segtab segs;
704 long offset;
705 byte * data;
707 if ((f = fopen(filename, "wb"))==NULL) {
708 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
709 exit(1);
711 if ((rdfheader=rdfnewheader())==NULL) {
712 fprintf(stderr, "ldrdf: out of memory\n");
713 exit(1);
717 * Add multiboot header if appropriate option is specified.
718 * Multiboot record *MUST* be the first record in output file.
720 if (options.addMBheader) {
721 if (options.verbose)
722 puts("\nadding multiboot header record");
724 hr = (rdfheaderrec *) malloc(sizeof(struct MultiBootHdrRec));
725 hr->mbh.type = 9;
726 hr->mbh.reclen = sizeof(struct tMultiBootHeader)+TRAMPOLINESIZE;
728 hr->mbh.mb.Magic = MB_MAGIC;
729 hr->mbh.mb.Flags = MB_FL_KLUDGE;
730 hr->mbh.mb.Checksum = ~(MB_MAGIC+MB_FL_KLUDGE-1);
731 hr->mbh.mb.HeaderAddr = MBHloadAddr+16;
732 hr->mbh.mb.LoadAddr = MBHloadAddr;
733 hr->mbh.mb.Entry = MBHloadAddr+16+sizeof(struct tMultiBootHeader);
735 memcpy(hr->mbh.trampoline,trampoline_code,TRAMPOLINESIZE);
737 rdfaddheader(rdfheader,hr);
738 free(hr);
741 if (options.verbose)
742 printf ("\nbuilding output module (%d segments)\n", nsegs);
745 * Allocate the memory for the segments. We may be better off
746 * building the output module one segment at a time when running
747 * under 16 bit DOS, but that would be a slower way of doing this.
748 * And you could always use DJGPP...
750 for (i = 0; i < nsegs; i++)
752 outputseg[i].data=NULL;
753 if(!outputseg[i].length) continue;
754 outputseg[i].data = malloc(outputseg[i].length);
755 if (!outputseg[i].data) {
756 fprintf(stderr, "ldrdf: out of memory\n");
757 exit(1);
762 * initialise availableseg, used to allocate segment numbers for
763 * imported and exported labels...
765 availableseg = nsegs;
768 * Step through the modules, performing required actions on each one
770 for (cur = modules; cur; cur=cur->next)
773 * Read the actual segment contents into the correct places in
774 * the newly allocated segments
777 for (i = 0; i < cur->f.nsegs; i++)
779 int dest = cur->seginfo[i].dest_seg;
781 if (dest == -1) continue;
782 if (rdfloadseg(&cur->f, i,
783 outputseg[dest].data + cur->seginfo[i].reloc))
785 rdfperror("ldrdf", cur->name);
786 exit(1);
791 * Perform fixups, and add new header records where required
794 header = malloc(cur->f.header_len);
795 if (!header) {
796 fprintf(stderr, "ldrdf: out of memory\n");
797 exit(1);
800 if (cur->f.header_loc)
801 rdfheaderrewind(&cur->f);
802 else
803 if (rdfloadseg(&cur->f, RDOFF_HEADER, header))
805 rdfperror("ldrdf", cur->name);
806 exit(1);
810 * we need to create a local segment number -> location
811 * table for the segments in this module.
813 init_seglocations(&segs);
814 for (i = 0; i < cur->f.nsegs; i++)
816 add_seglocation(&segs, cur->f.seg[i].number,
817 cur->seginfo[i].dest_seg, cur->seginfo[i].reloc);
820 * and the BSS segment (doh!)
822 add_seglocation (&segs, 2, 2, cur->bss_reloc);
824 while ((hr = rdfgetheaderrec(&cur->f)))
826 switch(hr->type) {
827 case 1: /* relocation record - need to do a fixup */
829 * First correct the offset stored in the segment from
830 * the start of the segment (which may well have changed).
832 * To do this we add to the number stored the relocation
833 * factor associated with the segment that contains the
834 * target segment.
836 * The relocation could be a relative relocation, in which
837 * case we have to first subtract the amount we've relocated
838 * the containing segment by.
841 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
843 fprintf(stderr, "%s: reloc to undefined segment %04x\n",
844 cur->name, (int) hr->r.refseg);
845 errorcount++;
846 break;
849 isrelative = (hr->r.segment & 64) == 64;
850 hr->r.segment &= 63;
852 if (hr->r.segment == 2 ||
853 (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1)
855 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
856 cur->name,
857 hr->r.segment == 2 ? "BSS" : "unknown",
858 hr->r.segment);
859 errorcount++;
860 break;
863 if (hr->r.length != 1 && hr->r.length != 2 && hr->r.length!=4)
865 fprintf(stderr, "%s: nonstandard length reloc "
866 "(%d bytes)\n", cur->name, hr->r.length);
867 errorcount++;
868 break;
872 * okay, now the relocation is in the segment pointed to by
873 * cur->seginfo[localseg], and we know everything else is
874 * okay to go ahead and do the relocation
876 data = outputseg[cur->seginfo[localseg].dest_seg].data;
877 data += cur->seginfo[localseg].reloc + hr->r.offset;
880 * data now points to the reference that needs
881 * relocation. Calculate the relocation factor.
882 * Factor is:
883 * offset of referred object in segment [in offset]
884 * (- relocation of localseg, if ref is relative)
885 * For simplicity, the result is stored in 'offset'.
886 * Then add 'offset' onto the value at data.
889 if (isrelative) offset -= cur->seginfo[localseg].reloc;
890 switch (hr->r.length)
892 case 1:
893 offset += *data;
894 if (offset < -127 || offset > 128)
895 fprintf(error_file, "warning: relocation out of range "
896 "at %s(%02x:%08lx)\n", cur->name,
897 (int)hr->r.segment, hr->r.offset);
898 *data = (char) offset;
899 break;
900 case 2:
901 offset += * (short *)data;
902 if (offset < -32767 || offset > 32768)
903 fprintf(error_file, "warning: relocation out of range "
904 "at %s(%02x:%08lx)\n", cur->name,
905 (int)hr->r.segment, hr->r.offset);
906 * (short *)data = (short) offset;
907 break;
908 case 4:
909 * (long *)data += offset;
910 /* we can't easily detect overflow on this one */
911 break;
915 * If the relocation was relative between two symbols in
916 * the same segment, then we're done.
918 * Otherwise, we need to output a new relocation record
919 * with the references updated segment and offset...
922 if (isrelative && cur->seginfo[localseg].dest_seg != seg)
924 hr->r.segment = cur->seginfo[localseg].dest_seg+64;
925 hr->r.offset += cur->seginfo[localseg].reloc;
926 hr->r.refseg = seg;
927 rdfaddheader(rdfheader, hr);
928 break;
931 if (! isrelative || cur->seginfo[localseg].dest_seg != seg)
933 hr->r.segment = cur->seginfo[localseg].dest_seg;
934 hr->r.offset += cur->seginfo[localseg].reloc;
935 hr->r.refseg = seg;
936 rdfaddheader(rdfheader, hr);
938 break;
940 case 2: /* import symbol */
941 case 7:
943 * scan the global symbol table for the symbol
944 * and associate its location with the segment number
945 * for this module
947 se = symtabFind(symtab, hr->i.label);
948 if (!se || se->segment == -1) {
949 if (options.warnUnresolved) {
950 fprintf(error_file, "warning: unresolved reference to `%s'"
951 " in module `%s'\n", hr->i.label, cur->name);
952 if (options.errorUnresolved==1) errorcount++;
955 * we need to allocate a segment number for this
956 * symbol, and store it in the symbol table for
957 * future reference
959 if (!se) {
960 se=malloc(sizeof(*se));
961 if (!se) {
962 fprintf(stderr, "ldrdf: out of memory\n");
963 exit(1);
965 se->name = strdup(hr->i.label);
966 se->flags = 0;
967 se->segment = availableseg++;
968 se->offset = 0;
969 symtabInsert(symtab, se);
971 else {
972 se->segment = availableseg++;
973 se->offset = 0;
976 * output a header record that imports it to the
977 * recently allocated segment number...
979 newrec = *hr;
980 newrec.i.segment = se->segment;
981 rdfaddheader(rdfheader, &newrec);
984 add_seglocation(&segs, hr->i.segment, se->segment, se->offset);
986 break;
988 case 3: /* export symbol */
990 * need to insert an export for this symbol into the new
991 * header, unless we're stripping symbols. Even if we're
992 * stripping, put the symbol if it's marked as SYM_GLOBAL.
994 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
995 break;
997 if (hr->e.segment == 2) {
998 seg = 2;
999 offset = cur->bss_reloc;
1001 else {
1002 localseg = rdffindsegment(&cur->f, hr->e.segment);
1003 if (localseg == -1) {
1004 fprintf(stderr, "%s: exported symbol `%s' from "
1005 "unrecognised segment\n", cur->name,
1006 hr->e.label);
1007 errorcount++;
1008 break;
1010 offset = cur->seginfo[localseg].reloc;
1011 seg = cur->seginfo[localseg].dest_seg;
1014 hr->e.segment = seg;
1015 hr->e.offset += offset;
1016 rdfaddheader(rdfheader, hr);
1017 break;
1019 case 8: /* module name */
1021 * Insert module name record if export symbols
1022 * are not stripped.
1023 * If module name begins with '$' - insert it anyway.
1026 if (options.strip && hr->m.modname[0] != '$') break;
1028 rdfaddheader(rdfheader, hr);
1029 break;
1031 case 6: /* segment fixup */
1033 * modify the segment numbers if necessary, and
1034 * pass straight through to the output module header
1036 * *** FIXME ***
1038 if (hr->r.segment == 2) {
1039 fprintf(stderr, "%s: segment fixup in BSS section\n",
1040 cur->name);
1041 errorcount++;
1042 break;
1044 localseg = rdffindsegment(&cur->f, hr->r.segment);
1045 if (localseg == -1) {
1046 fprintf(stderr, "%s: segment fixup in unrecognised"
1047 " segment (%d)\n", cur->name, hr->r.segment);
1048 errorcount++;
1049 break;
1051 hr->r.segment = cur->seginfo[localseg].dest_seg;
1052 hr->r.offset += cur->seginfo[localseg].reloc;
1054 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
1056 fprintf(stderr, "%s: segment fixup to undefined "
1057 "segment %04x\n", cur->name, (int)hr->r.refseg);
1058 errorcount++;
1059 break;
1061 hr->r.refseg = seg;
1062 rdfaddheader(rdfheader, hr);
1063 break;
1067 free(header);
1068 done_seglocations(&segs);
1073 * combined BSS reservation for the entire results
1075 newrec.type = 5;
1076 newrec.b.reclen = 4;
1077 newrec.b.amount = bss_length;
1078 rdfaddheader(rdfheader, &newrec);
1081 * Write the header
1083 for (i = 0; i < nsegs; i++)
1085 if (i == 2) continue;
1086 rdfaddsegment (rdfheader, outputseg[i].length);
1089 if (options.addMBheader) {
1090 struct MultiBootHdrRec *mbhrec = (struct MultiBootHdrRec *)(rdfheader->buf->buffer);
1091 unsigned l = membuflength(rdfheader->buf) + 14 +
1092 10*rdfheader->nsegments + rdfheader->seglength;
1093 unsigned *ldraddr = (unsigned *)(mbhrec->trampoline+1);
1094 unsigned *ldrdest = (unsigned *)(mbhrec->trampoline+6);
1096 mbhrec->mb.LoadEndAddr = MBHloadAddr+l+10+RDFLDR_LENGTH;
1097 mbhrec->mb.BSSendAddr = mbhrec->mb.LoadEndAddr;
1099 *ldraddr = MBHloadAddr+l+10;
1100 *ldrdest = RDFLDR_DESTLOC;
1103 rdfwriteheader(f, rdfheader);
1104 rdfdoneheader(rdfheader);
1106 * Step through the segments, one at a time, writing out into
1107 * the output file
1110 for (i = 0; i < nsegs; i++)
1112 int16 s;
1113 long l;
1115 if (i == 2) continue;
1117 s = translateshort(outputseg[i].type);
1118 fwrite(&s, 2, 1, f);
1119 s = translateshort(outputseg[i].number);
1120 fwrite(&s, 2, 1, f);
1121 s = translateshort(outputseg[i].reserved);
1122 fwrite(&s, 2, 1, f);
1123 l = translatelong(outputseg[i].length);
1124 fwrite(&l, 4, 1, f);
1126 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1129 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f);
1132 /* =========================================================================
1133 * Main program
1136 void usage()
1138 printf("usage:\n");
1139 printf(" ldrdf [options] object modules ... [-llibrary ...]\n");
1140 printf(" ldrdf -r\n");
1141 printf("options:\n");
1142 printf(" -v[=n] increases verbosity by 1, or sets it to n\n");
1143 printf(" -a nn sets segment alignment value (default 16)\n");
1144 printf(" -s strips exported symbols\n");
1145 printf(" -x warn about unresolved symbols\n");
1146 printf(" -o name write output in file 'name'\n");
1147 printf(" -j path specify objects search path\n");
1148 printf(" -L path specify libraries search path\n");
1149 printf(" -mbh [address] add multiboot header to output file. Default\n");
1150 printf(" loading address is 0x110000\n");
1151 exit(0);
1154 int main(int argc, char ** argv)
1156 char * outname = "aout.rdf";
1157 int moduleloaded = 0;
1158 char *respstrings[128] = {0, };
1160 options.verbose = 0;
1161 options.align = 16;
1162 options.warnUnresolved = 0;
1163 options.strip = 0;
1165 error_file = stderr;
1167 argc --, argv ++;
1168 if (argc == 0) usage();
1169 while (argc && **argv == '-' && argv[0][1] != 'l')
1171 switch(argv[0][1]) {
1172 case 'r':
1173 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION "\n");
1174 printf( _RDOFF_H "\n");
1175 exit(0);
1176 case 'v':
1177 if (argv[0][2] == '=') {
1178 options.verbose = argv[0][3] - '0';
1179 if (options.verbose < 0 || options.verbose > 9) {
1180 fprintf(stderr, "ldrdf: verbosity level must be a number"
1181 " between 0 and 9\n");
1182 exit(1);
1185 else
1186 options.verbose++;
1187 break;
1188 case 'a':
1189 options.align = atoi(argv[1]);
1190 if (options.align <= 0) {
1191 fprintf(stderr,
1192 "ldrdf: -a expects a positive number argument\n");
1193 exit(1);
1195 argv++, argc--;
1196 break;
1197 case 's':
1198 options.strip = 1;
1199 break;
1200 case 'x':
1201 options.warnUnresolved = 1;
1202 if (argv[0][2]=='e')
1203 options.errorUnresolved = 1;
1204 break;
1205 case 'o':
1206 outname = argv[1];
1207 argv++, argc--;
1208 break;
1209 case 'j':
1210 if (!objpath)
1212 options.objpath = 1;
1213 objpath = argv[1];
1214 argv++, argc--;
1215 break;
1217 else
1219 fprintf(stderr,"ldrdf: more than one objects search path specified\n");
1220 exit(1);
1222 case 'L':
1223 if (!libpath)
1225 options.libpath = 1;
1226 libpath = argv[1];
1227 argv++, argc--;
1228 break;
1230 else
1232 fprintf(stderr,"ldrdf: more than one libraries search path specified\n");
1233 exit(1);
1235 case '@': {
1236 int i=0;
1237 char buf[256];
1238 FILE *f;
1240 options.respfile = 1;
1241 if (argv[1] != NULL) f = fopen(argv[1],"r");
1242 else
1244 fprintf(stderr,"ldrdf: no response file name specified\n");
1245 exit(1);
1248 if (f == NULL)
1250 fprintf(stderr,"ldrdf: unable to open response file\n");
1251 exit(1);
1253 argc-=2;
1254 while(fgets(buf,sizeof(buf)-1,f)!=NULL)
1256 char *p;
1257 if (buf[0]=='\n') continue;
1258 if ((p = strchr(buf,'\n')) != 0)
1259 *p=0;
1260 if (i >= 128)
1262 fprintf(stderr,"ldrdf: too many input files\n");
1263 exit(1);
1265 *(respstrings+i) = newstr(buf);
1266 argc++, i++;
1268 goto done;
1270 case '2':
1271 options.stderr_redir = 1;
1272 error_file = stdout;
1273 break;
1274 case 'm':
1275 if (argv[0][2] == 'b' && argv[0][3] == 'h') {
1276 if (argv[1][0] != '-') {
1277 MBHloadAddr = atoi(argv[1]);
1278 } else {
1279 MBHloadAddr = MB_DEFAULTLOADADDR;
1281 options.addMBheader = 1;
1282 break;
1284 default:
1285 usage();
1287 argv++, argc--;
1289 done:
1290 if (options.verbose > 4) {
1291 printf("ldrdf invoked with options:\n");
1292 printf(" section alignment: %d bytes\n", options.align);
1293 printf(" output name: `%s'\n", outname);
1294 if (options.strip)
1295 printf(" strip symbols\n");
1296 if (options.warnUnresolved)
1297 printf(" warn about unresolved symbols\n");
1298 if (options.errorUnresolved)
1299 printf(" error if unresolved symbols\n");
1300 if (options.objpath)
1301 printf(" objects search path: %s\n",objpath);
1302 if (options.libpath)
1303 printf(" libraries search path: %s\n",libpath);
1304 if (options.addMBheader)
1305 printf(" loading address for multiboot header: 0x%X\n",MBHloadAddr);
1306 printf("\n");
1309 symtab = symtabNew();
1310 initsegments();
1312 if (!symtab) {
1313 fprintf(stderr, "ldrdf: out of memory\n");
1314 exit(1);
1317 if (*respstrings) argv = respstrings;
1318 while (argc)
1320 if (!strncmp(*argv, "-l", 2)) /* library */
1322 if(libpath) add_library(newstrcat(libpath,*argv + 2));
1323 else add_library(*argv + 2);
1325 else {
1326 if(objpath) loadmodule(newstrcat(objpath,*argv));
1327 else loadmodule(*argv);
1328 moduleloaded = 1;
1330 argv++, argc--;
1333 if (! moduleloaded) {
1334 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1335 return 0;
1339 search_libraries();
1341 if (options.verbose > 2)
1343 printf ("symbol table:\n");
1344 symtabDump(symtab, stdout);
1347 write_output(outname);
1349 if (errorcount > 0) exit(1);
1350 return 0;