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.
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.
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 */
56 rdffile f
; /* the RDOFF file structure */
57 struct segment_infonode seginfo
[RDF_MAXSEGS
]; /* what are we doing
61 struct modulenode
* next
;
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 */
95 /* objects search path */
96 char * objpath
= NULL
;
98 /* libraries search path */
99 char * libpath
= NULL
;
102 static FILE * error_file
;
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
115 * mov ecx,RDFLDR_LENGTH/4 ; B9 xx xx xx xx
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,
128 0xFC, 0xF3, 0xA5, 0xC3
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
];
144 /* global options which affect how the program behaves */
145 struct ldrdfoptions
{
158 int errorcount
= 0; /* determines main program exit status */
160 /* =========================================================================
168 * sets up segments 0, 1, and 2, the initial code data and bss segments
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;
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
)
200 printf("loading `%s'\n", filename
);
202 /* allocate a new module entry on the end of the modules list */
205 modules
= malloc (sizeof(*modules
));
206 lastmodule
= modules
;
210 lastmodule
->next
= malloc (sizeof(*modules
));
211 lastmodule
= lastmodule
->next
;
216 fprintf(stderr
, "ldrdf: out of memory\n");
220 /* open the file using 'rdfopen', which returns nonzero on error */
222 if (rdfopen(&lastmodule
->f
, filename
) != 0)
224 rdfperror("ldrdf", filename
);
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
);
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
;
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
) {
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");
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
);
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
334 header
= malloc(mod
->f
.header_len
);
336 fprintf(stderr
, "ldrdf: not enough memory\n");
339 if (rdfloadseg(&mod
->f
, RDOFF_HEADER
, header
)) {
340 rdfperror("ldrdf", filename
);
344 while ((hr
= rdfgetheaderrec (&mod
->f
)))
347 case 2: /* imported symbol - define with seg = -1 */
349 symtab_add(hr
->i
.label
, -1, 0);
352 case 3: /* exported symbol */
357 if (hr
->e
.segment
== 2)
359 destreloc
= bss_length
;
360 if (destreloc
% options
.align
!= 0)
361 destreloc
+= options
.align
- (destreloc
% options
.align
);
366 if ((destseg
= mod
->seginfo
[(int)hr
->e
.segment
].dest_seg
) == -1)
368 destreloc
= mod
->seginfo
[(int)hr
->e
.segment
].reloc
;
370 symtab_add(hr
->e
.label
, destseg
, destreloc
+ hr
->e
.offset
);
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
;
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
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
;
405 * we free the header buffer here, to save memory later.
406 * this isn't efficient, but probably halves the memory usage
409 mod
->f
.header_loc
= NULL
;
418 * Look in list for module by its name.
420 int lookformodule(const char *name
)
422 struct modulenode
*curr
=modules
;
425 if (!strcmp(name
,curr
->name
)) return 1;
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
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
;
454 int findsegment(int16 type
,int16 reserved
)
458 for (i
= 0; i
< nsegs
; i
++)
459 if (outputseg
[i
].type
== type
) return i
;
461 return allocnewseg(type
,reserved
);
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
)
486 ste
= symtabFind(symtab
, symbol
);
489 if (ste
->segment
>= 0) {
491 * symbol previously defined
493 if (segment
< 0) return;
494 fprintf (error_file
, "warning: `%s' redefined\n", symbol
);
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
;
512 * this is the first declaration of this symbol
514 ste
= malloc(sizeof(symtabEnt
));
516 fprintf(stderr
, "ldrdf: out of memory\n");
519 ste
->name
= strdup(symbol
);
520 ste
->segment
= segment
;
521 ste
->offset
= offset
;
523 symtabInsert(symtab
, ste
);
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
);
544 *segment
= ste
->segment
;
545 *offset
= ste
->offset
;
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
);
566 lastlib
= libraries
= malloc(sizeof(*libraries
));
568 fprintf(stderr
, "ldrdf: out of memory\n");
574 lastlib
->next
= malloc(sizeof(*libraries
));
575 if (!lastlib
->next
) {
576 fprintf(stderr
, "ldrdf: out of memory\n");
579 lastlib
= lastlib
->next
;
581 lastlib
->next
= NULL
;
582 if (rdl_open(lastlib
, name
)) {
583 rdl_perror("ldrdf", name
);
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
;
608 int doneanything
= 0, pass
= 1, keepfile
;
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
);
627 fprintf(stderr
, "ldrdf: not enough memory\n");
630 if (rdfloadseg(&f
, RDOFF_HEADER
, header
)) {
631 rdfperror("ldrdf", f
.name
);
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
)
661 * as there are undefined symbols, we can assume that
662 * there are modules on the module list by the time
665 lastmodule
->next
= malloc(sizeof(*lastmodule
->next
));
666 if (!lastmodule
->next
) {
667 fprintf(stderr
, "ldrdf: not enough memory\n");
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
);
684 if (rdl_error
!= 0 && rdl_error
!= RDL_ENOTFOUND
)
685 rdl_perror("ldrdf", cur
->name
);
688 if (cur
== NULL
&& pass
== 1) {
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
704 void write_output(const char * filename
)
707 rdf_headerbuf
* rdfheader
;
708 struct modulenode
* cur
;
709 int i
, availableseg
, seg
, localseg
, isrelative
;
711 rdfheaderrec
* hr
, newrec
;
717 if ((f
= fopen(filename
, "wb"))==NULL
) {
718 fprintf(stderr
, "ldrdf: couldn't open %s for output\n", filename
);
721 if ((rdfheader
=rdfnewheader())==NULL
) {
722 fprintf(stderr
, "ldrdf: out of memory\n");
727 * Add multiboot header if appropriate option is specified.
728 * Multiboot record *MUST* be the first record in output file.
730 if (options
.addMBheader
) {
732 puts("\nadding multiboot header record");
734 hr
= (rdfheaderrec
*) malloc(sizeof(struct MultiBootHdrRec
));
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
);
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");
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
);
801 * Perform fixups, and add new header records where required
804 header
= malloc(cur
->f
.header_len
);
806 fprintf(stderr
, "ldrdf: out of memory\n");
810 if (cur
->f
.header_loc
)
811 rdfheaderrewind(&cur
->f
);
813 if (rdfloadseg(&cur
->f
, RDOFF_HEADER
, header
))
815 rdfperror("ldrdf", cur
->name
);
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
)))
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
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
);
859 isrelative
= (hr
->r
.segment
& 64) == 64;
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",
867 hr
->r
.segment
== 2 ? "BSS" : "unknown",
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
);
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.
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
)
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
;
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
;
919 * (long *)data
+= offset
;
920 /* we can't easily detect overflow on this one */
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...
932 || cur
->seginfo
[localseg
].dest_seg
!= seg
)
934 hr
->r
.segment
= cur
->seginfo
[localseg
].dest_seg
;
935 hr
->r
.offset
+= cur
->seginfo
[localseg
].reloc
;
937 rdfaddheader(rdfheader
, hr
);
941 case 2: /* import symbol */
944 * scan the global symbol table for the symbol
945 * and associate its location with the segment number
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
961 se
=malloc(sizeof(*se
));
963 fprintf(stderr
, "ldrdf: out of memory\n");
966 se
->name
= strdup(hr
->i
.label
);
968 se
->segment
= availableseg
++;
970 symtabInsert(symtab
, se
);
973 se
->segment
= availableseg
++;
977 * output a header record that imports it to the
978 * recently allocated segment number...
981 newrec
.i
.segment
= se
->segment
;
982 rdfaddheader(rdfheader
, &newrec
);
985 add_seglocation(&segs
, hr
->i
.segment
, se
->segment
, se
->offset
);
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 ***
998 if (hr
->e
.segment
== 2) {
1000 offset
= cur
->bss_reloc
;
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
,
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
);
1020 case 8: /* module name */
1022 * insert module name record if export symbols
1025 if (options
.strip
) break;
1027 rdfaddheader(rdfheader
, hr
);
1030 case 6: /* segment fixup */
1032 * modify the segment numbers if necessary, and
1033 * pass straight through to the output module header
1037 if (hr
->r
.segment
== 2) {
1038 fprintf(stderr
, "%s: segment fixup in BSS section\n",
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
);
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
);
1061 rdfaddheader(rdfheader
, hr
);
1067 done_seglocations(&segs
);
1072 * combined BSS reservation for the entire results
1075 newrec
.b
.reclen
= 4;
1076 newrec
.b
.amount
= bss_length
;
1077 rdfaddheader(rdfheader
, &newrec
);
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
1106 for (i
= 0; i
< nsegs
; i
++)
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 /* =========================================================================
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");
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;
1158 options
.warnUnresolved
= 0;
1161 error_file
= stderr
;
1164 if (argc
== 0) usage();
1165 while (argc
&& **argv
== '-' && argv
[0][1] != 'l')
1167 switch(argv
[0][1]) {
1169 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
"\n");
1170 printf( _RDOFF_H
"\n");
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");
1185 options
.align
= atoi(argv
[1]);
1186 if (options
.align
<= 0) {
1188 "ldrdf: -a expects a positive number argument\n");
1197 options
.warnUnresolved
= 1;
1198 if (argv
[0][2]=='e')
1199 options
.errorUnresolved
= 1;
1208 options
.objpath
= 1;
1215 fprintf(stderr
,"ldrdf: more than one objects search path specified\n");
1221 options
.libpath
= 1;
1228 fprintf(stderr
,"ldrdf: more than one libraries search path specified\n");
1236 options
.respfile
= 1;
1237 if (argv
[1] != NULL
) f
= fopen(argv
[1],"r");
1240 fprintf(stderr
,"ldrdf: no response file name specified\n");
1246 fprintf(stderr
,"ldrdf: unable to open response file\n");
1250 while(fgets(buf
,sizeof(buf
)-1,f
)!=NULL
)
1253 if (buf
[0]=='\n') continue;
1254 if ((p
= strchr(buf
,'\n')) != 0)
1258 fprintf(stderr
,"ldrdf: too many input files\n");
1261 *(respstrings
+i
) = newstr(buf
);
1267 options
.stderr_redir
= 1;
1268 error_file
= stdout
;
1271 if (argv
[0][2] == 'b' && argv
[0][3] == 'h') {
1272 if (argv
[1][0] != '-') {
1273 MBHloadAddr
= atoi(argv
[1]);
1275 MBHloadAddr
= MB_DEFAULTLOADADDR
;
1277 options
.addMBheader
= 1;
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
);
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
);
1305 symtab
= symtabNew();
1309 fprintf(stderr
, "ldrdf: out of memory\n");
1313 if (*respstrings
) argv
= respstrings
;
1316 if (!strncmp(*argv
, "-l", 2)) /* library */
1318 if(libpath
) add_library(newstrcat(libpath
,*argv
+ 2));
1319 else add_library(*argv
+ 2);
1322 if(objpath
) loadmodule(newstrcat(objpath
,*argv
));
1323 else loadmodule(*argv
);
1329 if (! moduleloaded
) {
1330 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1337 if (options
.verbose
> 2)
1339 printf ("symbol table:\n");
1340 symtabDump(symtab
, stdout
);
1343 write_output(outname
);
1345 if (errorcount
> 0) exit(1);