NASM 0.98.22
[nasm.git] / rdoff / ldrdf.c
blobb7070fe96b5a20e30c46a599ca3460da87b32443
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.
27 * TO FIX: enhance search of required export symbols in libraries (now depends
28 * on modules order in library).
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
35 #include "multboot.h"
36 #include "rdoff.h"
37 #include "symtab.h"
38 #include "collectn.h"
39 #include "rdlib.h"
40 #include "segtab.h"
42 #define LDRDF_VERSION "1.03"
44 #define RDF_MAXSEGS 64
45 /* #define STINGY_MEMORY */
47 /* =======================================================================
48 * Types & macros that are private to this program
51 struct segment_infonode {
52 int dest_seg; /* output segment to be placed into, -1 to
53 skip linking this segment */
54 long reloc; /* segment's relocation factor */
58 struct modulenode {
59 rdffile f; /* the RDOFF file structure */
60 struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
61 with each segment? */
62 void * header;
63 char * name;
64 struct modulenode * next;
65 long bss_reloc;
68 #include "ldsegs.h"
70 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
71 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
73 /* ==========================================================================
74 * Function prototypes of private utility functions
77 void processmodule(const char * filename, struct modulenode * mod);
78 int allocnewseg(int16 type,int16 reserved);
79 int findsegment(int16 type,int16 reserved);
80 void symtab_add(const char * symbol, int segment, long offset);
81 int symtab_get(const char * symbol, int * segment, long * offset);
83 /* =========================================================================
84 * Global data structures.
87 /* a linked list of modules that will be included in the output */
88 struct modulenode * modules = NULL;
89 struct modulenode * lastmodule = NULL;
91 /* a linked list of libraries to be searched for unresolved imported symbols */
92 struct librarynode * libraries = NULL;
93 struct librarynode * lastlib = NULL;
95 /* the symbol table */
96 void * symtab = NULL;
98 /* objects search path */
99 char * objpath = NULL;
101 /* libraries search path */
102 char * libpath = NULL;
104 /* error file */
105 static FILE * error_file;
107 #ifdef _MULTBOOT_H
109 /* loading address for multiboot header */
110 unsigned MBHloadAddr;
113 * Tiny code that moves RDF loader to its working memory region:
114 * mov esi,SOURCE_ADDR ; BE xx xx xx xx
115 * mov edi,DEST_ADDR ; BF xx xx xx xx
116 * mov esp,edi ; 89 FC
117 * push edi ; 57
118 * mov ecx,RDFLDR_LENGTH/4 ; B9 xx xx xx xx
119 * cld ; FC
120 * rep movsd ; F3 A5
121 * ret ; C3
124 #define RDFLDR_LENGTH 4096 /* Loader will be moved to unused */
125 #define RDFLDR_DESTLOC 0xBF000 /* video page */
127 unsigned char RDFloaderMover[]={
128 0xBE, 0, 0, 0, 0, 0xBF, 0, 0xF0, 0xB, 0,
129 0x89, 0xFC, 0x57,
130 0xB9, 0, 4, 0, 0,
131 0xFC, 0xF3, 0xA5, 0xC3
134 #endif
136 /* the header of the output file, built up stage by stage */
137 rdf_headerbuf * newheader = NULL;
139 /* The current state of segment allocation, including information about
140 * which output segment numbers have been allocated, and their types and
141 * amount of data which has already been allocated inside them.
143 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
144 int nsegs = 0;
145 long bss_length;
147 /* global options which affect how the program behaves */
148 struct ldrdfoptions {
149 int verbose;
150 int align;
151 int warnUnresolved;
152 int errorUnresolved;
153 int strip;
154 int respfile;
155 int stderr_redir;
156 int objpath;
157 int libpath;
158 int addMBheader;
159 } options;
161 int errorcount = 0; /* determines main program exit status */
163 /* =========================================================================
164 * Utility functions
169 * initsegments()
171 * sets up segments 0, 1, and 2, the initial code data and bss segments
174 void initsegments()
176 nsegs = 3;
177 outputseg[0].type = 1;
178 outputseg[0].number = 0;
179 outputseg[0].reserved = 0;
180 outputseg[0].length = 0;
181 outputseg[1].type = 2;
182 outputseg[1].number = 1;
183 outputseg[1].reserved = 0;
184 outputseg[1].length = 0;
185 outputseg[2].type = 0xFFFF; /* reserved segment type */
186 outputseg[2].number = 2;
187 outputseg[2].reserved = 0;
188 outputseg[2].length = 0;
189 bss_length = 0;
193 * loadmodule
195 * Determine the characteristics of a module, and decide what to do with
196 * each segment it contains (including determining destination segments and
197 * relocation factors for segments that are kept).
200 void loadmodule(const char * filename)
202 if (options.verbose)
203 printf("loading `%s'\n", filename);
205 /* allocate a new module entry on the end of the modules list */
206 if (!modules)
208 modules = malloc (sizeof(*modules));
209 lastmodule = modules;
211 else
213 lastmodule->next = malloc (sizeof(*modules));
214 lastmodule = lastmodule->next;
217 if ( ! lastmodule)
219 fprintf(stderr, "ldrdf: out of memory\n");
220 exit(1);
223 /* open the file using 'rdfopen', which returns nonzero on error */
225 if (rdfopen(&lastmodule->f, filename) != 0)
227 rdfperror("ldrdf", filename);
228 exit(1);
232 * store information about the module, and determine what segments
233 * it contains, and what we should do with them (determine relocation
234 * factor if we decide to keep them)
237 lastmodule->header = NULL;
238 lastmodule->name = strdup(filename);
239 lastmodule->next = NULL;
241 processmodule(filename, lastmodule);
245 * processmodule()
247 * step through each segment, determine what exactly we're doing with
248 * it, and if we intend to keep it, determine (a) which segment to
249 * put it in and (b) whereabouts in that segment it will end up.
250 * (b) is fairly easy, cos we're now keeping track of how big each segment
251 * in our output file is...
254 void processmodule(const char * filename, struct modulenode * mod)
256 struct segconfig sconf;
257 int seg, outseg;
258 void * header;
259 rdfheaderrec * hr;
260 long bssamount = 0;
262 for (seg = 0; seg < mod->f.nsegs; seg++)
265 * get the segment configuration for this type from the segment
266 * table. getsegconfig() is a macro, defined in ldsegs.h.
268 getsegconfig(sconf, mod->f.seg[seg].type);
270 if (options.verbose > 1) {
271 printf ("%s %04x [%04x:%10s] ", filename, mod->f.seg[seg].number,
272 mod->f.seg[seg].type, sconf.typedesc);
275 * sconf->dowhat tells us what to do with a segment of this type.
277 switch (sconf.dowhat) {
278 case SEG_IGNORE:
280 * Set destination segment to -1, to indicate that this segment
281 * should be ignored for the purpose of output, ie it is left
282 * out of the linked executable.
284 mod->seginfo[seg].dest_seg = -1;
285 if (options.verbose > 1) printf("IGNORED\n");
286 break;
288 case SEG_NEWSEG:
290 * The configuration tells us to create a new segment for
291 * each occurrence of this segment type.
293 outseg = allocnewseg(sconf.mergetype,
294 mod->f.seg[seg].reserved);
295 mod->seginfo[seg].dest_seg = outseg;
296 mod->seginfo[seg].reloc = 0;
297 outputseg[outseg].length = mod->f.seg[seg].length;
298 if (options.verbose > 1)
299 printf ("=> %04x:%08lx (+%04lx)\n", outseg,
300 mod->seginfo[seg].reloc,
301 mod->f.seg[seg].length);
302 break;
304 case SEG_MERGE:
306 * The configuration tells us to merge the segment with
307 * a previously existing segment of type 'sconf.mergetype',
308 * if one exists. Otherwise a new segment is created.
309 * This is handled transparently by 'findsegment()'.
311 outseg = findsegment(sconf.mergetype,
312 mod->f.seg[seg].reserved);
313 mod->seginfo[seg].dest_seg = outseg;
316 * We need to add alignment to these segments.
318 if (outputseg[outseg].length % options.align != 0)
319 outputseg[outseg].length +=
320 options.align - (outputseg[outseg].length % options.align);
322 mod->seginfo[seg].reloc = outputseg[outseg].length;
323 outputseg[outseg].length += mod->f.seg[seg].length;
325 if (options.verbose > 1)
326 printf ("=> %04x:%08lx (+%04lx)\n", outseg,
327 mod->seginfo[seg].reloc,
328 mod->f.seg[seg].length);
334 * extract symbols from the header, and dump them into the
335 * symbol table
337 header = malloc(mod->f.header_len);
338 if (!header) {
339 fprintf(stderr, "ldrdf: not enough memory\n");
340 exit(1);
342 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
343 rdfperror("ldrdf", filename);
344 exit(1);
347 while ((hr = rdfgetheaderrec (&mod->f)))
349 switch(hr->type) {
350 case 2: /* imported symbol - define with seg = -1 */
351 case 7:
352 symtab_add(hr->i.label, -1, 0);
353 break;
355 case 3: /* exported symbol */
357 int destseg;
358 long destreloc;
360 if (hr->e.segment == 2)
362 destreloc = bss_length;
363 if (destreloc % options.align != 0)
364 destreloc += options.align - (destreloc % options.align);
365 destseg = 2;
367 else
369 if ((destseg = mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
370 continue;
371 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
373 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
374 break;
377 case 5: /* BSS reservation */
379 * first, amalgamate all BSS reservations in this module
380 * into one, because we allow this in the output format.
382 bssamount += hr->b.amount;
383 break;
387 if (bssamount != 0)
390 * handle the BSS segment - first pad the existing bss length
391 * to the correct alignment, then store the length in bss_reloc
392 * for this module. Then add this module's BSS length onto
393 * bss_length.
395 if (bss_length % options.align != 0)
396 bss_length += options.align - (bss_length % options.align);
398 mod->bss_reloc = bss_length;
399 if (options.verbose > 1) {
400 printf ("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n",
401 filename, bss_length, bssamount);
403 bss_length += bssamount;
406 #ifdef STINGY_MEMORY
408 * we free the header buffer here, to save memory later.
409 * this isn't efficient, but probably halves the memory usage
410 * of this program...
412 mod->f.header_loc = NULL;
413 free(header);
415 #endif
421 * Look in list for module by its name.
423 int lookformodule(const char *name)
425 struct modulenode *curr=modules;
427 while(curr) {
428 if (!strcmp(name,curr->name)) return 1;
429 curr = curr->next;
431 return 0;
436 * allocnewseg()
437 * findsegment()
439 * These functions manipulate the array of output segments, and are used
440 * by processmodule(). allocnewseg() allocates a segment in the array,
441 * initialising it to be empty. findsegment() first scans the array for
442 * a segment of the type requested, and if one isn't found allocates a
443 * new one.
445 int allocnewseg(int16 type,int16 reserved)
447 outputseg[nsegs].type = type;
448 outputseg[nsegs].number = nsegs;
449 outputseg[nsegs].reserved = reserved;
450 outputseg[nsegs].length = 0;
451 outputseg[nsegs].offset = 0;
452 outputseg[nsegs].data = NULL;
454 return nsegs++;
457 int findsegment(int16 type,int16 reserved)
459 int i;
461 for (i = 0; i < nsegs; i++)
462 if (outputseg[i].type == type) return i;
464 return allocnewseg(type,reserved);
468 * symtab_add()
470 * inserts a symbol into the global symbol table, which associates symbol
471 * names either with addresses, or a marker that the symbol hasn't been
472 * resolved yet, or possibly that the symbol has been defined as
473 * contained in a dynamic [load time/run time] linked library.
475 * segment = -1 => not yet defined
476 * segment = -2 => defined as dll symbol
478 * If the symbol is already defined, and the new segment >= 0, then
479 * if the original segment was < 0 the symbol is redefined, otherwise
480 * a duplicate symbol warning is issued. If new segment == -1, this
481 * routine won't change a previously existing symbol. It will change
482 * to segment = -2 only if the segment was previously < 0.
485 void symtab_add(const char * symbol, int segment, long offset)
487 symtabEnt * ste;
489 ste = symtabFind(symtab, symbol);
490 if (ste)
492 if (ste->segment >= 0) {
494 * symbol previously defined
496 if (segment < 0) return;
497 fprintf (error_file, "warning: `%s' redefined\n", symbol);
498 return;
502 * somebody wanted the symbol, and put an undefined symbol
503 * marker into the table
505 if (segment == -1) return;
507 * we have more information now - update the symbol's entry
509 ste->segment = segment;
510 ste->offset = offset;
511 ste->flags = 0;
512 return;
515 * this is the first declaration of this symbol
517 ste = malloc(sizeof(symtabEnt));
518 if (!ste) {
519 fprintf(stderr, "ldrdf: out of memory\n");
520 exit(1);
522 ste->name = strdup(symbol);
523 ste->segment = segment;
524 ste->offset = offset;
525 ste->flags = 0;
526 symtabInsert(symtab, ste);
530 * symtab_get()
532 * Retrieves the values associated with a symbol. Undefined symbols
533 * are assumed to have -1:0 associated. Returns 1 if the symbol was
534 * successfully located.
537 int symtab_get(const char * symbol, int * segment, long * offset)
539 symtabEnt * ste = symtabFind(symtab, symbol);
540 if (!ste) {
541 *segment = -1;
542 *offset = 0;
543 return 0;
545 else
547 *segment = ste->segment;
548 *offset = ste->offset;
549 return 1;
554 * add_library()
556 * checks that a library can be opened and is in the correct format,
557 * then adds it to the linked list of libraries.
560 void add_library(const char * name)
562 if (rdl_verify(name)) {
563 rdl_perror("ldrdf", name);
564 errorcount++;
565 return;
567 if (! libraries)
569 lastlib = libraries = malloc(sizeof(*libraries));
570 if (! libraries) {
571 fprintf(stderr, "ldrdf: out of memory\n");
572 exit(1);
575 else
577 lastlib->next = malloc(sizeof(*libraries));
578 if (!lastlib->next) {
579 fprintf(stderr, "ldrdf: out of memory\n");
580 exit(1);
582 lastlib = lastlib->next;
584 lastlib->next = NULL;
585 if (rdl_open(lastlib, name)) {
586 rdl_perror("ldrdf", name);
587 errorcount++;
588 return;
593 * search_libraries()
595 * scans through the list of libraries, attempting to match symbols
596 * defined in library modules against symbols that are referenced but
597 * not defined (segment = -1 in the symbol table)
599 * returns 1 if any extra library modules are included, indicating that
600 * another pass through the library list should be made (possibly).
603 int search_libraries()
605 struct librarynode * cur;
606 rdffile f;
607 int i;
608 void * header;
609 int segment;
610 long offset;
611 int doneanything = 0, pass = 1, keepfile;
612 rdfheaderrec * hr;
614 cur = libraries;
616 while (cur)
618 if (options.verbose > 2)
619 printf("scanning library `%s', pass %d...\n", cur->name, pass);
621 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++)
623 if (pass == 2 && lookformodule(f.name)) continue;
625 if (options.verbose > 3)
626 printf(" looking in module `%s'\n", f.name);
628 header = malloc(f.header_len);
629 if (!header) {
630 fprintf(stderr, "ldrdf: not enough memory\n");
631 exit(1);
633 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
634 rdfperror("ldrdf", f.name);
635 errorcount++;
636 return 0;
639 keepfile = 0;
641 while ((hr = rdfgetheaderrec (&f)))
643 /* we're only interested in exports, so skip others: */
644 if (hr->type != 3) continue;
647 * Find the symbol in the symbol table. If the symbol isn't
648 * defined, we aren't interested, so go on to the next.
649 * If it is defined as anything but -1, we're also not
650 * interested. But if it is defined as -1, insert this
651 * module into the list of modules to use, and go
652 * immediately on to the next module...
654 if (! symtab_get(hr->e.label, &segment, &offset)
655 || segment != -1)
657 continue;
660 doneanything = 1;
661 keepfile = 1;
664 * as there are undefined symbols, we can assume that
665 * there are modules on the module list by the time
666 * we get here.
668 lastmodule->next = malloc(sizeof(*lastmodule->next));
669 if (!lastmodule->next) {
670 fprintf(stderr, "ldrdf: not enough memory\n");
671 exit(1);
673 lastmodule = lastmodule->next;
674 memcpy(&lastmodule->f, &f, sizeof(f));
675 lastmodule->name = strdup(f.name);
676 lastmodule->next = NULL;
677 processmodule(f.name, lastmodule);
678 break;
680 if (!keepfile)
682 free(f.name);
683 f.name = NULL;
684 f.fp = NULL;
687 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
688 rdl_perror("ldrdf", cur->name);
690 cur = cur->next;
691 if (cur == NULL && pass == 1) {
692 cur = libraries;
693 pass++;
697 return doneanything;
701 * write_output()
703 * this takes the linked list of modules, and walks through it, merging
704 * all the modules into a single output module, and then writes this to a
705 * file.
707 void write_output(const char * filename)
709 FILE * f;
710 rdf_headerbuf * rdfheader;
711 struct modulenode * cur;
712 int i, availableseg, seg, localseg, isrelative;
713 void * header;
714 rdfheaderrec * hr, newrec;
715 symtabEnt * se;
716 segtab segs;
717 long offset;
718 byte * data;
720 if ((f = fopen(filename, "wb"))==NULL) {
721 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
722 exit(1);
724 if ((rdfheader=rdfnewheader())==NULL) {
725 fprintf(stderr, "ldrdf: out of memory\n");
726 exit(1);
730 * Add multiboot header if appropriate option is specified.
731 * Multiboot record *MUST* be the first record in output file.
733 if (options.addMBheader) {
734 if (options.verbose)
735 puts("\nadding multiboot header record");
737 hr = (rdfheaderrec *) malloc(sizeof(struct MultiBootHdrRec));
738 hr->mbh.type = 9;
739 hr->mbh.reclen = sizeof(struct tMultiBootHeader)+RDFLDRMOVER_SIZE;
741 hr->mbh.mb.Magic = MB_MAGIC;
742 hr->mbh.mb.Flags = MB_FL_KLUDGE;
743 hr->mbh.mb.Checksum = ~(MB_MAGIC+MB_FL_KLUDGE-1);
744 hr->mbh.mb.HeaderAddr = MBHloadAddr+16;
745 hr->mbh.mb.LoadAddr = MBHloadAddr;
746 hr->mbh.mb.Entry = MBHloadAddr+16+sizeof(struct tMultiBootHeader);
748 memcpy(hr->mbh.mover,RDFloaderMover,RDFLDRMOVER_SIZE);
750 rdfaddheader(rdfheader,hr);
751 free(hr);
754 if (options.verbose)
755 printf ("\nbuilding output module (%d segments)\n", nsegs);
758 * Allocate the memory for the segments. We may be better off
759 * building the output module one segment at a time when running
760 * under 16 bit DOS, but that would be a slower way of doing this.
761 * And you could always use DJGPP...
763 for (i = 0; i < nsegs; i++)
765 outputseg[i].data=NULL;
766 if(!outputseg[i].length) continue;
767 outputseg[i].data = malloc(outputseg[i].length);
768 if (!outputseg[i].data) {
769 fprintf(stderr, "ldrdf: out of memory\n");
770 exit(1);
775 * initialise availableseg, used to allocate segment numbers for
776 * imported and exported labels...
778 availableseg = nsegs;
781 * Step through the modules, performing required actions on each one
783 for (cur = modules; cur; cur=cur->next)
786 * Read the actual segment contents into the correct places in
787 * the newly allocated segments
790 for (i = 0; i < cur->f.nsegs; i++)
792 int dest = cur->seginfo[i].dest_seg;
794 if (dest == -1) continue;
795 if (rdfloadseg(&cur->f, i,
796 outputseg[dest].data + cur->seginfo[i].reloc))
798 rdfperror("ldrdf", cur->name);
799 exit(1);
804 * Perform fixups, and add new header records where required
807 header = malloc(cur->f.header_len);
808 if (!header) {
809 fprintf(stderr, "ldrdf: out of memory\n");
810 exit(1);
813 if (cur->f.header_loc)
814 rdfheaderrewind(&cur->f);
815 else
816 if (rdfloadseg(&cur->f, RDOFF_HEADER, header))
818 rdfperror("ldrdf", cur->name);
819 exit(1);
823 * we need to create a local segment number -> location
824 * table for the segments in this module.
826 init_seglocations(&segs);
827 for (i = 0; i < cur->f.nsegs; i++)
829 add_seglocation(&segs, cur->f.seg[i].number,
830 cur->seginfo[i].dest_seg, cur->seginfo[i].reloc);
833 * and the BSS segment (doh!)
835 add_seglocation (&segs, 2, 2, cur->bss_reloc);
837 while ((hr = rdfgetheaderrec(&cur->f)))
839 switch(hr->type) {
840 case 1: /* relocation record - need to do a fixup */
842 * First correct the offset stored in the segment from
843 * the start of the segment (which may well have changed).
845 * To do this we add to the number stored the relocation
846 * factor associated with the segment that contains the
847 * target segment.
849 * The relocation could be a relative relocation, in which
850 * case we have to first subtract the amount we've relocated
851 * the containing segment by.
854 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
856 fprintf(stderr, "%s: reloc to undefined segment %04x\n",
857 cur->name, (int) hr->r.refseg);
858 errorcount++;
859 break;
862 isrelative = (hr->r.segment & 64) == 64;
863 hr->r.segment &= 63;
865 if (hr->r.segment == 2 ||
866 (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1)
868 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
869 cur->name,
870 hr->r.segment == 2 ? "BSS" : "unknown",
871 hr->r.segment);
872 errorcount++;
873 break;
876 if (hr->r.length != 1 && hr->r.length != 2 && hr->r.length!=4)
878 fprintf(stderr, "%s: nonstandard length reloc "
879 "(%d bytes)\n", cur->name, hr->r.length);
880 errorcount++;
881 break;
885 * okay, now the relocation is in the segment pointed to by
886 * cur->seginfo[localseg], and we know everything else is
887 * okay to go ahead and do the relocation
889 data = outputseg[cur->seginfo[localseg].dest_seg].data;
890 data += cur->seginfo[localseg].reloc + hr->r.offset;
893 * data now points to the reference that needs
894 * relocation. Calculate the relocation factor.
895 * Factor is:
896 * offset of referred object in segment [in offset]
897 * (- relocation of localseg, if ref is relative)
898 * For simplicity, the result is stored in 'offset'.
899 * Then add 'offset' onto the value at data.
902 if (isrelative) offset -= cur->seginfo[localseg].reloc;
903 switch (hr->r.length)
905 case 1:
906 offset += *data;
907 if (offset < -127 || offset > 128)
908 fprintf(error_file, "warning: relocation out of range "
909 "at %s(%02x:%08lx)\n", cur->name,
910 (int)hr->r.segment, hr->r.offset);
911 *data = (char) offset;
912 break;
913 case 2:
914 offset += * (short *)data;
915 if (offset < -32767 || offset > 32768)
916 fprintf(error_file, "warning: relocation out of range "
917 "at %s(%02x:%08lx)\n", cur->name,
918 (int)hr->r.segment, hr->r.offset);
919 * (short *)data = (short) offset;
920 break;
921 case 4:
922 * (long *)data += offset;
923 /* we can't easily detect overflow on this one */
924 break;
928 * If the relocation was relative between two symbols in
929 * the same segment, then we're done.
931 * Otherwise, we need to output a new relocation record
932 * with the references updated segment and offset...
934 if (! isrelative
935 || cur->seginfo[localseg].dest_seg != seg)
937 hr->r.segment = cur->seginfo[localseg].dest_seg;
938 hr->r.offset += cur->seginfo[localseg].reloc;
939 hr->r.refseg = seg;
940 rdfaddheader(rdfheader, hr);
942 break;
944 case 2: /* import symbol */
945 case 7:
947 * scan the global symbol table for the symbol
948 * and associate its location with the segment number
949 * for this module
951 se = symtabFind(symtab, hr->i.label);
952 if (!se || se->segment == -1) {
953 if (options.warnUnresolved) {
954 fprintf(error_file, "warning: unresolved reference to `%s'"
955 " in module `%s'\n", hr->i.label, cur->name);
956 if (options.errorUnresolved==1) errorcount++;
959 * we need to allocate a segment number for this
960 * symbol, and store it in the symbol table for
961 * future reference
963 if (!se) {
964 se=malloc(sizeof(*se));
965 if (!se) {
966 fprintf(stderr, "ldrdf: out of memory\n");
967 exit(1);
969 se->name = strdup(hr->i.label);
970 se->flags = 0;
971 se->segment = availableseg++;
972 se->offset = 0;
973 symtabInsert(symtab, se);
975 else {
976 se->segment = availableseg++;
977 se->offset = 0;
980 * output a header record that imports it to the
981 * recently allocated segment number...
983 newrec = *hr;
984 newrec.i.segment = se->segment;
985 rdfaddheader(rdfheader, &newrec);
988 add_seglocation(&segs, hr->i.segment, se->segment, se->offset);
990 break;
992 case 3: /* export symbol */
994 * need to insert an export for this symbol into the new
995 * header, unless we're stripping symbols. Even if we're
996 * stripping, put the symbol if it's marked as SYM_GLOBAL.
998 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
999 break;
1001 if (hr->e.segment == 2) {
1002 seg = 2;
1003 offset = cur->bss_reloc;
1005 else {
1006 localseg = rdffindsegment(&cur->f, hr->e.segment);
1007 if (localseg == -1) {
1008 fprintf(stderr, "%s: exported symbol `%s' from "
1009 "unrecognised segment\n", cur->name,
1010 hr->e.label);
1011 errorcount++;
1012 break;
1014 offset = cur->seginfo[localseg].reloc;
1015 seg = cur->seginfo[localseg].dest_seg;
1018 hr->e.segment = seg;
1019 hr->e.offset += offset;
1020 rdfaddheader(rdfheader, hr);
1021 break;
1023 case 8: /* module name */
1025 * Insert module name record if export symbols
1026 * are not stripped.
1027 * If module name begins with '$' - insert it anyway.
1030 if (options.strip && hr->m.modname[0] != '$') break;
1032 rdfaddheader(rdfheader, hr);
1033 break;
1035 case 6: /* segment fixup */
1037 * modify the segment numbers if necessary, and
1038 * pass straight through to the output module header
1040 * *** FIXME ***
1042 if (hr->r.segment == 2) {
1043 fprintf(stderr, "%s: segment fixup in BSS section\n",
1044 cur->name);
1045 errorcount++;
1046 break;
1048 localseg = rdffindsegment(&cur->f, hr->r.segment);
1049 if (localseg == -1) {
1050 fprintf(stderr, "%s: segment fixup in unrecognised"
1051 " segment (%d)\n", cur->name, hr->r.segment);
1052 errorcount++;
1053 break;
1055 hr->r.segment = cur->seginfo[localseg].dest_seg;
1056 hr->r.offset += cur->seginfo[localseg].reloc;
1058 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset))
1060 fprintf(stderr, "%s: segment fixup to undefined "
1061 "segment %04x\n", cur->name, (int)hr->r.refseg);
1062 errorcount++;
1063 break;
1065 hr->r.refseg = seg;
1066 rdfaddheader(rdfheader, hr);
1067 break;
1071 free(header);
1072 done_seglocations(&segs);
1077 * combined BSS reservation for the entire results
1079 newrec.type = 5;
1080 newrec.b.reclen = 4;
1081 newrec.b.amount = bss_length;
1082 rdfaddheader(rdfheader, &newrec);
1085 * Write the header
1087 for (i = 0; i < nsegs; i++)
1089 if (i == 2) continue;
1090 rdfaddsegment (rdfheader, outputseg[i].length);
1093 if (options.addMBheader) {
1094 struct MultiBootHdrRec *mbhrec = (struct MultiBootHdrRec *)(rdfheader->buf->buffer);
1095 unsigned l = membuflength(rdfheader->buf) + 14 +
1096 10*rdfheader->nsegments + rdfheader->seglength;
1097 unsigned *ldraddr = (unsigned *)(mbhrec->mover+1);
1099 mbhrec->mb.LoadEndAddr = MBHloadAddr+l+10+RDFLDR_LENGTH;
1100 mbhrec->mb.BSSendAddr = mbhrec->mb.LoadEndAddr;
1101 *ldraddr = MBHloadAddr+l+10;
1104 rdfwriteheader(f, rdfheader);
1105 rdfdoneheader(rdfheader);
1107 * Step through the segments, one at a time, writing out into
1108 * the output file
1111 for (i = 0; i < nsegs; i++)
1113 int16 s;
1114 long l;
1116 if (i == 2) continue;
1118 s = translateshort(outputseg[i].type);
1119 fwrite(&s, 2, 1, f);
1120 s = translateshort(outputseg[i].number);
1121 fwrite(&s, 2, 1, f);
1122 s = translateshort(outputseg[i].reserved);
1123 fwrite(&s, 2, 1, f);
1124 l = translatelong(outputseg[i].length);
1125 fwrite(&l, 4, 1, f);
1127 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1130 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f);
1133 /* =========================================================================
1134 * Main program
1137 void usage()
1139 printf("usage:\n");
1140 printf(" ldrdf [options] object modules ... [-llibrary ...]\n");
1141 printf(" ldrdf -r\n");
1142 printf("options:\n");
1143 printf(" -v[=n] increases verbosity by 1, or sets it to n\n");
1144 printf(" -a nn sets segment alignment value (default 16)\n");
1145 printf(" -s strips exported symbols\n");
1146 printf(" -x warn about unresolved symbols\n");
1147 printf(" -o name write output in file 'name'\n");
1148 printf(" -j path specify objects search path\n");
1149 printf(" -L path specify libraries search path\n");
1150 printf(" -mbh [address] add multiboot header to output file. Default\n");
1151 printf(" loading address is 0x110000\n");
1152 exit(0);
1155 int main(int argc, char ** argv)
1157 char * outname = "aout.rdf";
1158 int moduleloaded = 0;
1159 char *respstrings[128] = {0, };
1161 options.verbose = 0;
1162 options.align = 16;
1163 options.warnUnresolved = 0;
1164 options.strip = 0;
1166 error_file = stderr;
1168 argc --, argv ++;
1169 if (argc == 0) usage();
1170 while (argc && **argv == '-' && argv[0][1] != 'l')
1172 switch(argv[0][1]) {
1173 case 'r':
1174 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION "\n");
1175 printf( _RDOFF_H "\n");
1176 exit(0);
1177 case 'v':
1178 if (argv[0][2] == '=') {
1179 options.verbose = argv[0][3] - '0';
1180 if (options.verbose < 0 || options.verbose > 9) {
1181 fprintf(stderr, "ldrdf: verbosity level must be a number"
1182 " between 0 and 9\n");
1183 exit(1);
1186 else
1187 options.verbose++;
1188 break;
1189 case 'a':
1190 options.align = atoi(argv[1]);
1191 if (options.align <= 0) {
1192 fprintf(stderr,
1193 "ldrdf: -a expects a positive number argument\n");
1194 exit(1);
1196 argv++, argc--;
1197 break;
1198 case 's':
1199 options.strip = 1;
1200 break;
1201 case 'x':
1202 options.warnUnresolved = 1;
1203 if (argv[0][2]=='e')
1204 options.errorUnresolved = 1;
1205 break;
1206 case 'o':
1207 outname = argv[1];
1208 argv++, argc--;
1209 break;
1210 case 'j':
1211 if (!objpath)
1213 options.objpath = 1;
1214 objpath = argv[1];
1215 argv++, argc--;
1216 break;
1218 else
1220 fprintf(stderr,"ldrdf: more than one objects search path specified\n");
1221 exit(1);
1223 case 'L':
1224 if (!libpath)
1226 options.libpath = 1;
1227 libpath = argv[1];
1228 argv++, argc--;
1229 break;
1231 else
1233 fprintf(stderr,"ldrdf: more than one libraries search path specified\n");
1234 exit(1);
1236 case '@': {
1237 int i=0;
1238 char buf[256];
1239 FILE *f;
1241 options.respfile = 1;
1242 if (argv[1] != NULL) f = fopen(argv[1],"r");
1243 else
1245 fprintf(stderr,"ldrdf: no response file name specified\n");
1246 exit(1);
1249 if (f == NULL)
1251 fprintf(stderr,"ldrdf: unable to open response file\n");
1252 exit(1);
1254 argc-=2;
1255 while(fgets(buf,sizeof(buf)-1,f)!=NULL)
1257 char *p;
1258 if (buf[0]=='\n') continue;
1259 if ((p = strchr(buf,'\n')) != 0)
1260 *p=0;
1261 if (i >= 128)
1263 fprintf(stderr,"ldrdf: too many input files\n");
1264 exit(1);
1266 *(respstrings+i) = newstr(buf);
1267 argc++, i++;
1269 goto done;
1271 case '2':
1272 options.stderr_redir = 1;
1273 error_file = stdout;
1274 break;
1275 case 'm':
1276 if (argv[0][2] == 'b' && argv[0][3] == 'h') {
1277 if (argv[1][0] != '-') {
1278 MBHloadAddr = atoi(argv[1]);
1279 } else {
1280 MBHloadAddr = MB_DEFAULTLOADADDR;
1282 options.addMBheader = 1;
1283 break;
1285 default:
1286 usage();
1288 argv++, argc--;
1290 done:
1291 if (options.verbose > 4) {
1292 printf("ldrdf invoked with options:\n");
1293 printf(" section alignment: %d bytes\n", options.align);
1294 printf(" output name: `%s'\n", outname);
1295 if (options.strip)
1296 printf(" strip symbols\n");
1297 if (options.warnUnresolved)
1298 printf(" warn about unresolved symbols\n");
1299 if (options.errorUnresolved)
1300 printf(" error if unresolved symbols\n");
1301 if (options.objpath)
1302 printf(" objects search path: %s\n",objpath);
1303 if (options.libpath)
1304 printf(" libraries search path: %s\n",libpath);
1305 if (options.addMBheader)
1306 printf(" loading address for multiboot header: 0x%X\n",MBHloadAddr);
1307 printf("\n");
1310 symtab = symtabNew();
1311 initsegments();
1313 if (!symtab) {
1314 fprintf(stderr, "ldrdf: out of memory\n");
1315 exit(1);
1318 if (*respstrings) argv = respstrings;
1319 while (argc)
1321 if (!strncmp(*argv, "-l", 2)) /* library */
1323 if(libpath) add_library(newstrcat(libpath,*argv + 2));
1324 else add_library(*argv + 2);
1326 else {
1327 if(objpath) loadmodule(newstrcat(objpath,*argv));
1328 else loadmodule(*argv);
1329 moduleloaded = 1;
1331 argv++, argc--;
1334 if (! moduleloaded) {
1335 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1336 return 0;
1340 search_libraries();
1342 if (options.verbose > 2)
1344 printf ("symbol table:\n");
1345 symtabDump(symtab, stdout);
1348 write_output(outname);
1350 if (errorcount > 0) exit(1);
1351 return 0;