2 * ldrdf.c - RDOFF Object File linker/loader main program.
4 * Copyright (c) 1996,99 Julian Hall. All rights reserved.
5 * Improvements and fixes (c) 1999-2004 RET & COM Research.
7 * This file is distributed under the terms and conditions of the
8 * GNU Lesser Public License (LGPL), version 2.1.
9 * See http://www.gnu.org/copyleft/lgpl.html for details.
14 * - enhance search of required export symbols in libraries (now depends
15 * on modules order in library)
16 * - keep a cache of symbol names in each library module so
17 * we don't have to constantly recheck the file
18 * - general performance improvements
20 * BUGS & LIMITATIONS: this program doesn't support multiple code, data
21 * or bss segments, therefore for 16 bit programs whose code, data or BSS
22 * segment exceeds 64K in size, it will not work. This program probably
23 * won't work if compiled by a 16 bit compiler. Try DJGPP if you're running
24 * under DOS. '#define STINGY_MEMORY' may help a little.
39 #define LDRDF_VERSION "1.07"
41 /* #define STINGY_MEMORY */
43 /* =======================================================================
44 * Types & macros that are private to this program
47 struct segment_infonode
{
48 int dest_seg
; /* output segment to be placed into, -1 to
49 skip linking this segment */
50 long reloc
; /* segment's relocation factor */
55 rdffile f
; /* the RDOFF file structure */
56 struct segment_infonode seginfo
[RDF_MAXSEGS
]; /* what are we doing
60 struct modulenode
* next
;
66 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
67 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
69 /* ==========================================================================
70 * Function prototypes of private utility functions
73 void processmodule(const char * filename
, struct modulenode
* mod
);
74 int allocnewseg(uint16 type
,uint16 reserved
);
75 int findsegment(uint16 type
,uint16 reserved
);
76 void symtab_add(const char * symbol
, int segment
, long offset
);
77 int symtab_get(const char * symbol
, int * segment
, long * offset
);
79 /* =========================================================================
80 * Global data structures.
83 /* a linked list of modules that will be included in the output */
84 struct modulenode
* modules
= NULL
;
85 struct modulenode
* lastmodule
= NULL
;
87 /* a linked list of libraries to be searched for unresolved imported symbols */
88 struct librarynode
* libraries
= NULL
;
89 struct librarynode
* lastlib
= NULL
;
91 /* the symbol table */
94 /* objects search path */
95 char * objpath
= NULL
;
97 /* libraries search path */
98 char * libpath
= NULL
;
100 /* file to embed as a generic record */
101 char * generic_rec_file
= NULL
;
104 static FILE * error_file
;
106 /* the header of the output file, built up stage by stage */
107 rdf_headerbuf
* newheader
= NULL
;
109 /* The current state of segment allocation, including information about
110 * which output segment numbers have been allocated, and their types and
111 * amount of data which has already been allocated inside them.
113 struct SegmentHeaderRec outputseg
[RDF_MAXSEGS
];
117 /* global options which affect how the program behaves */
118 struct ldrdfoptions
{
129 int errorcount
= 0; /* determines main program exit status */
132 /* =========================================================================
139 * sets up segments 0, 1, and 2, the initial code data and bss segments
144 outputseg
[0].type
= 1;
145 outputseg
[0].number
= 0;
146 outputseg
[0].reserved
= 0;
147 outputseg
[0].length
= 0;
148 outputseg
[1].type
= 2;
149 outputseg
[1].number
= 1;
150 outputseg
[1].reserved
= 0;
151 outputseg
[1].length
= 0;
152 outputseg
[2].type
= 0xFFFF; /* reserved segment type */
153 outputseg
[2].number
= 2;
154 outputseg
[2].reserved
= 0;
155 outputseg
[2].length
= 0;
163 * Determine the characteristics of a module, and decide what to do with
164 * each segment it contains (including determining destination segments and
165 * relocation factors for segments that are kept).
167 void loadmodule(const char * filename
)
170 printf("loading `%s'\n", filename
);
172 /* allocate a new module entry on the end of the modules list */
174 modules
= malloc (sizeof(*modules
));
175 lastmodule
= modules
;
177 lastmodule
->next
= malloc (sizeof(*modules
));
178 lastmodule
= lastmodule
->next
;
182 fprintf(stderr
, "ldrdf: out of memory\n");
186 /* open the file using 'rdfopen', which returns nonzero on error */
187 if (rdfopen(&lastmodule
->f
, filename
) != 0) {
188 rdfperror("ldrdf", filename
);
193 * store information about the module, and determine what segments
194 * it contains, and what we should do with them (determine relocation
195 * factor if we decide to keep them)
197 lastmodule
->header
= NULL
;
198 lastmodule
->name
= strdup(filename
);
199 lastmodule
->next
= NULL
;
201 processmodule(filename
, lastmodule
);
208 * step through each segment, determine what exactly we're doing with
209 * it, and if we intend to keep it, determine (a) which segment to
210 * put it in and (b) whereabouts in that segment it will end up.
211 * (b) is fairly easy, because we're now keeping track of how big each
212 * segment in our output file is...
214 void processmodule(const char * filename
, struct modulenode
* mod
)
216 struct segconfig sconf
;
221 int bss_was_referenced
= 0;
223 for (seg
= 0; seg
< mod
->f
.nsegs
; seg
++) {
225 * get the segment configuration for this type from the segment
226 * table. getsegconfig() is a macro, defined in ldsegs.h.
228 getsegconfig(sconf
, mod
->f
.seg
[seg
].type
);
230 if (options
.verbose
> 1) {
231 printf ("%s %04x [%04x:%10s] ", filename
, mod
->f
.seg
[seg
].number
,
232 mod
->f
.seg
[seg
].type
, sconf
.typedesc
);
235 * sconf->dowhat tells us what to do with a segment of this type.
237 switch (sconf
.dowhat
) {
240 * Set destination segment to -1, to indicate that this segment
241 * should be ignored for the purpose of output, ie it is left
242 * out of the linked executable.
244 mod
->seginfo
[seg
].dest_seg
= -1;
245 if (options
.verbose
> 1) printf("IGNORED\n");
250 * The configuration tells us to create a new segment for
251 * each occurrence of this segment type.
253 outseg
= allocnewseg(sconf
.mergetype
,
254 mod
->f
.seg
[seg
].reserved
);
255 mod
->seginfo
[seg
].dest_seg
= outseg
;
256 mod
->seginfo
[seg
].reloc
= 0;
257 outputseg
[outseg
].length
= mod
->f
.seg
[seg
].length
;
258 if (options
.verbose
> 1)
259 printf ("=> %04x:%08lx (+%04lx)\n", outseg
,
260 mod
->seginfo
[seg
].reloc
,
261 mod
->f
.seg
[seg
].length
);
266 * The configuration tells us to merge the segment with
267 * a previously existing segment of type 'sconf.mergetype',
268 * if one exists. Otherwise a new segment is created.
269 * This is handled transparently by 'findsegment()'.
271 outseg
= findsegment(sconf
.mergetype
,
272 mod
->f
.seg
[seg
].reserved
);
273 mod
->seginfo
[seg
].dest_seg
= outseg
;
276 * We need to add alignment to these segments.
278 if (outputseg
[outseg
].length
% options
.align
!= 0)
279 outputseg
[outseg
].length
+=
280 options
.align
- (outputseg
[outseg
].length
% options
.align
);
282 mod
->seginfo
[seg
].reloc
= outputseg
[outseg
].length
;
283 outputseg
[outseg
].length
+= mod
->f
.seg
[seg
].length
;
285 if (options
.verbose
> 1)
286 printf ("=> %04x:%08lx (+%04lx)\n", outseg
,
287 mod
->seginfo
[seg
].reloc
,
288 mod
->f
.seg
[seg
].length
);
294 * extract symbols from the header, and dump them into the
297 header
= malloc(mod
->f
.header_len
);
299 fprintf(stderr
, "ldrdf: not enough memory\n");
302 if (rdfloadseg(&mod
->f
, RDOFF_HEADER
, header
)) {
303 rdfperror("ldrdf", filename
);
307 while ((hr
= rdfgetheaderrec (&mod
->f
))) {
309 case RDFREC_IMPORT
: /* imported symbol */
310 case RDFREC_FARIMPORT
:
311 /* Define with seg = -1 */
312 symtab_add(hr
->i
.label
, -1, 0);
315 case RDFREC_GLOBAL
: { /* exported symbol */
319 if (hr
->e
.segment
== 2) {
320 bss_was_referenced
= 1;
321 destreloc
= bss_length
;
322 if (destreloc
% options
.align
!= 0)
323 destreloc
+= options
.align
- (destreloc
% options
.align
);
326 if ((destseg
= mod
->seginfo
[(int)hr
->e
.segment
].dest_seg
) == -1)
328 destreloc
= mod
->seginfo
[(int)hr
->e
.segment
].reloc
;
330 symtab_add(hr
->e
.label
, destseg
, destreloc
+ hr
->e
.offset
);
334 case RDFREC_BSS
: /* BSS reservation */
336 * first, amalgamate all BSS reservations in this module
337 * into one, because we allow this in the output format.
339 bssamount
+= hr
->b
.amount
;
342 case RDFREC_COMMON
: { /* Common variable */
343 symtabEnt
*ste
= symtabFind(symtab
, hr
->c
.label
);
345 /* Is the symbol already in the table? */
348 /* Align the variable */
349 if (bss_length
% hr
->c
.align
!= 0)
350 bss_length
+= hr
->c
.align
- (bss_length
% hr
->c
.align
);
351 if (options
.verbose
> 1) {
352 printf ("%s %04x common '%s' => 0002:%08lx (+%04lx)\n",
353 filename
, hr
->c
.segment
, hr
->c
.label
, bss_length
, hr
->c
.size
);
356 symtab_add(hr
->c
.label
, 2, bss_length
);
357 mod
->bss_reloc
= bss_length
;
358 bss_length
+= hr
->c
.size
;
364 if (bssamount
!= 0 || bss_was_referenced
) {
366 * handle the BSS segment - first pad the existing bss length
367 * to the correct alignment, then store the length in bss_reloc
368 * for this module. Then add this module's BSS length onto
371 if (bss_length
% options
.align
!= 0)
372 bss_length
+= options
.align
- (bss_length
% options
.align
);
374 mod
->bss_reloc
= bss_length
;
375 if (options
.verbose
> 1) {
376 printf ("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n",
377 filename
, bss_length
, bssamount
);
379 bss_length
+= bssamount
;
384 * we free the header buffer here, to save memory later.
385 * this isn't efficient, but probably halves the memory usage
388 mod
->f
.header_loc
= NULL
;
397 * Return 1 if a given module is in the list, 0 otherwise.
399 int lookformodule(const char *name
)
401 struct modulenode
*curr
= modules
;
404 if (!strcmp(name
, curr
->name
)) return 1;
415 * These functions manipulate the array of output segments, and are used
416 * by processmodule(). allocnewseg() allocates a segment in the array,
417 * initialising it to be empty. findsegment() first scans the array for
418 * a segment of the type requested, and if one isn't found allocates a
421 int allocnewseg(uint16 type
,uint16 reserved
)
423 outputseg
[nsegs
].type
= type
;
424 outputseg
[nsegs
].number
= nsegs
;
425 outputseg
[nsegs
].reserved
= reserved
;
426 outputseg
[nsegs
].length
= 0;
427 outputseg
[nsegs
].offset
= 0;
428 outputseg
[nsegs
].data
= NULL
;
433 int findsegment(uint16 type
,uint16 reserved
)
437 for (i
= 0; i
< nsegs
; i
++)
438 if (outputseg
[i
].type
== type
) return i
;
440 return allocnewseg(type
,reserved
);
447 * inserts a symbol into the global symbol table, which associates symbol
448 * names either with addresses, or a marker that the symbol hasn't been
449 * resolved yet, or possibly that the symbol has been defined as
450 * contained in a dynamic [load time/run time] linked library.
452 * segment = -1 => not yet defined
453 * segment = -2 => defined as dll symbol
455 * If the symbol is already defined, and the new segment >= 0, then
456 * if the original segment was < 0 the symbol is redefined, otherwise
457 * a duplicate symbol warning is issued. If new segment == -1, this
458 * routine won't change a previously existing symbol. It will change
459 * to segment = -2 only if the segment was previously < 0.
461 void symtab_add(const char * symbol
, int segment
, long offset
)
465 ste
= symtabFind(symtab
, symbol
);
467 if (ste
->segment
>= 0) {
469 * symbol previously defined
471 if (segment
< 0) return;
472 fprintf (error_file
, "warning: `%s' redefined\n", symbol
);
477 * somebody wanted the symbol, and put an undefined symbol
478 * marker into the table
480 if (segment
== -1) return;
482 * we have more information now - update the symbol's entry
484 ste
->segment
= segment
;
485 ste
->offset
= offset
;
490 * this is the first declaration of this symbol
492 ste
= malloc(sizeof(symtabEnt
));
494 fprintf(stderr
, "ldrdf: out of memory\n");
497 ste
->name
= strdup(symbol
);
498 ste
->segment
= segment
;
499 ste
->offset
= offset
;
501 symtabInsert(symtab
, ste
);
507 * Retrieves the values associated with a symbol. Undefined symbols
508 * are assumed to have -1:0 associated. Returns 1 if the symbol was
509 * successfully located.
511 int symtab_get(const char * symbol
, int * segment
, long * offset
)
513 symtabEnt
* ste
= symtabFind(symtab
, symbol
);
519 *segment
= ste
->segment
;
520 *offset
= ste
->offset
;
529 * checks that a library can be opened and is in the correct format,
530 * then adds it to the linked list of libraries.
532 void add_library(const char * name
)
534 if (rdl_verify(name
)) {
535 rdl_perror("ldrdf", name
);
540 lastlib
= libraries
= malloc(sizeof(*libraries
));
542 fprintf(stderr
, "ldrdf: out of memory\n");
546 lastlib
->next
= malloc(sizeof(*libraries
));
547 if (!lastlib
->next
) {
548 fprintf(stderr
, "ldrdf: out of memory\n");
551 lastlib
= lastlib
->next
;
553 lastlib
->next
= NULL
;
554 if (rdl_open(lastlib
, name
)) {
555 rdl_perror("ldrdf", name
);
565 * scans through the list of libraries, attempting to match symbols
566 * defined in library modules against symbols that are referenced but
567 * not defined (segment = -1 in the symbol table)
569 * returns 1 if any extra library modules are included, indicating that
570 * another pass through the library list should be made (possibly).
572 int search_libraries()
574 struct librarynode
* cur
;
580 int doneanything
= 0, pass
= 1, keepfile
;
586 if (options
.verbose
> 2)
587 printf("scanning library `%s', pass %d...\n", cur
->name
, pass
);
589 for (i
= 0; rdl_openmodule(cur
, i
, &f
) == 0; i
++) {
590 if (pass
== 2 && lookformodule(f
.name
)) continue;
592 if (options
.verbose
> 3)
593 printf(" looking in module `%s'\n", f
.name
);
595 header
= malloc(f
.header_len
);
597 fprintf(stderr
, "ldrdf: not enough memory\n");
600 if (rdfloadseg(&f
, RDOFF_HEADER
, header
)) {
601 rdfperror("ldrdf", f
.name
);
608 while ((hr
= rdfgetheaderrec (&f
))) {
609 /* We're only interested in exports, so skip others */
610 if (hr
->type
!= RDFREC_GLOBAL
) continue;
613 * If the symbol is marked as SYM_GLOBAL, somebody will be
614 * definitely interested in it..
616 if ((hr
->e
.flags
& SYM_GLOBAL
) == 0) {
618 * otherwise the symbol is just public. Find it in
619 * the symbol table. If the symbol isn't defined, we
620 * aren't interested, so go on to the next.
621 * If it is defined as anything but -1, we're also not
622 * interested. But if it is defined as -1, insert this
623 * module into the list of modules to use, and go
624 * immediately on to the next module...
626 if (!symtab_get(hr
->e
.label
, &segment
, &offset
) || segment
!= -1)
634 * as there are undefined symbols, we can assume that
635 * there are modules on the module list by the time
638 lastmodule
->next
= malloc(sizeof(*lastmodule
->next
));
639 if (!lastmodule
->next
) {
640 fprintf(stderr
, "ldrdf: not enough memory\n");
643 lastmodule
= lastmodule
->next
;
644 memcpy(&lastmodule
->f
, &f
, sizeof(f
));
645 lastmodule
->name
= strdup(f
.name
);
646 lastmodule
->next
= NULL
;
647 processmodule(f
.name
, lastmodule
);
656 if (rdl_error
!= 0 && rdl_error
!= RDL_ENOTFOUND
)
657 rdl_perror("ldrdf", cur
->name
);
660 if (cur
== NULL
&& pass
== 1) {
673 * this takes the linked list of modules, and walks through it, merging
674 * all the modules into a single output module, and then writes this to a
677 void write_output(const char * filename
)
680 rdf_headerbuf
* rdfheader
;
681 struct modulenode
* cur
;
682 int i
, availableseg
, seg
, localseg
, isrelative
;
684 rdfheaderrec
* hr
, newrec
;
690 if ((f
= fopen(filename
, "wb"))==NULL
) {
691 fprintf(stderr
, "ldrdf: couldn't open %s for output\n", filename
);
694 if ((rdfheader
=rdfnewheader())==NULL
) {
695 fprintf(stderr
, "ldrdf: out of memory\n");
700 * If '-g' option was given, first record in output file will be a
701 * `generic' record, filled with a given file content.
702 * This can be useful, for example, when constructing multiboot
705 if (generic_rec_file
) {
709 printf("\nadding generic record from binary file %s\n", generic_rec_file
);
711 hr
= (rdfheaderrec
*) malloc(sizeof(struct GenericRec
));
712 if ((ff
= fopen(generic_rec_file
, "r")) == NULL
) {
713 fprintf(stderr
, "ldrdf: couldn't open %s for input\n", generic_rec_file
);
716 i
= fread(hr
->g
.data
, 1, sizeof(hr
->g
.data
), ff
);
717 fseek(ff
, 0, SEEK_END
);
718 if (ftell(ff
) > sizeof(hr
->g
.data
)) {
719 fprintf (error_file
, "warning: maximum generic record size is %d, rest of file ignored\n", sizeof(hr
->g
.data
));
725 rdfaddheader(rdfheader
, hr
);
730 printf ("\nbuilding output module (%d segments)\n", nsegs
);
733 * Allocate the memory for the segments. We may be better off
734 * building the output module one segment at a time when running
735 * under 16 bit DOS, but that would be a slower way of doing this.
736 * And you could always use DJGPP...
738 for (i
= 0; i
< nsegs
; i
++) {
739 outputseg
[i
].data
=NULL
;
740 if(!outputseg
[i
].length
) continue;
741 outputseg
[i
].data
= malloc(outputseg
[i
].length
);
742 if (!outputseg
[i
].data
) {
743 fprintf(stderr
, "ldrdf: out of memory\n");
749 * initialise availableseg, used to allocate segment numbers for
750 * imported and exported labels...
752 availableseg
= nsegs
;
755 * Step through the modules, performing required actions on each one
757 for (cur
= modules
; cur
; cur
=cur
->next
) {
759 * Read the actual segment contents into the correct places in
760 * the newly allocated segments
763 for (i
= 0; i
< cur
->f
.nsegs
; i
++) {
764 int dest
= cur
->seginfo
[i
].dest_seg
;
766 if (dest
== -1) continue;
767 if (rdfloadseg(&cur
->f
, i
,
768 outputseg
[dest
].data
+ cur
->seginfo
[i
].reloc
)) {
769 rdfperror("ldrdf", cur
->name
);
775 * Perform fixups, and add new header records where required
778 header
= malloc(cur
->f
.header_len
);
780 fprintf(stderr
, "ldrdf: out of memory\n");
784 if (cur
->f
.header_loc
)
785 rdfheaderrewind(&cur
->f
);
787 if (rdfloadseg(&cur
->f
, RDOFF_HEADER
, header
)) {
788 rdfperror("ldrdf", cur
->name
);
793 * we need to create a local segment number -> location
794 * table for the segments in this module.
796 init_seglocations(&segs
);
797 for (i
= 0; i
< cur
->f
.nsegs
; i
++) {
798 add_seglocation(&segs
, cur
->f
.seg
[i
].number
,
799 cur
->seginfo
[i
].dest_seg
, cur
->seginfo
[i
].reloc
);
802 * and the BSS segment (doh!)
804 add_seglocation(&segs
, 2, 2, cur
->bss_reloc
);
806 while ((hr
= rdfgetheaderrec(&cur
->f
))) {
808 case RDFREC_RELOC
: /* relocation record - need to do a fixup */
810 * First correct the offset stored in the segment from
811 * the start of the segment (which may well have changed).
813 * To do this we add to the number stored the relocation
814 * factor associated with the segment that contains the
817 * The relocation could be a relative relocation, in which
818 * case we have to first subtract the amount we've relocated
819 * the containing segment by.
821 if (!get_seglocation(&segs
, hr
->r
.refseg
, &seg
, &offset
)) {
822 fprintf(stderr
, "%s: reloc to undefined segment %04x\n",
823 cur
->name
, (int) hr
->r
.refseg
);
828 isrelative
= (hr
->r
.segment
& RDOFF_RELATIVEMASK
) == RDOFF_RELATIVEMASK
;
829 hr
->r
.segment
&= (RDOFF_RELATIVEMASK
-1);
831 if (hr
->r
.segment
== 2 ||
832 (localseg
= rdffindsegment(&cur
->f
, hr
->r
.segment
)) == -1) {
833 fprintf(stderr
, "%s: reloc from %s segment (%d)\n",
835 hr
->r
.segment
== 2 ? "BSS" : "unknown",
841 if (hr
->r
.length
!= 1 && hr
->r
.length
!= 2 &&
842 hr
->r
.length
!= 4 ) {
843 fprintf(stderr
, "%s: nonstandard length reloc "
844 "(%d bytes)\n", cur
->name
, hr
->r
.length
);
850 * okay, now the relocation is in the segment pointed to by
851 * cur->seginfo[localseg], and we know everything else is
852 * okay to go ahead and do the relocation
854 data
= outputseg
[cur
->seginfo
[localseg
].dest_seg
].data
;
855 data
+= cur
->seginfo
[localseg
].reloc
+ hr
->r
.offset
;
858 * data now points to the reference that needs
859 * relocation. Calculate the relocation factor.
861 * offset of referred object in segment [in offset]
862 * (- relocation of localseg, if ref is relative)
863 * For simplicity, the result is stored in 'offset'.
864 * Then add 'offset' onto the value at data.
868 offset
-= cur
->seginfo
[localseg
].reloc
;
869 switch (hr
->r
.length
) {
872 if (offset
< -127 || offset
> 128)
873 fprintf(error_file
, "warning: relocation out of range "
874 "at %s(%02x:%08lx)\n", cur
->name
,
875 (int)hr
->r
.segment
, hr
->r
.offset
);
876 *data
= (char) offset
;
879 offset
+= * (short *)data
;
880 if (offset
< -32767 || offset
> 32768)
881 fprintf(error_file
, "warning: relocation out of range "
882 "at %s(%02x:%08lx)\n", cur
->name
,
883 (int)hr
->r
.segment
, hr
->r
.offset
);
884 * (short *)data
= (short) offset
;
887 * (long *)data
+= offset
;
888 /* we can't easily detect overflow on this one */
893 * If the relocation was relative between two symbols in
894 * the same segment, then we're done.
896 * Otherwise, we need to output a new relocation record
897 * with the references updated segment and offset...
899 if (!isrelative
|| cur
->seginfo
[localseg
].dest_seg
!= seg
) {
900 hr
->r
.segment
= cur
->seginfo
[localseg
].dest_seg
;
901 hr
->r
.offset
+= cur
->seginfo
[localseg
].reloc
;
904 hr
->r
.segment
+= RDOFF_RELATIVEMASK
;
905 rdfaddheader(rdfheader
, hr
);
909 case RDFREC_IMPORT
: /* import symbol */
910 case RDFREC_FARIMPORT
:
912 * scan the global symbol table for the symbol
913 * and associate its location with the segment number
916 se
= symtabFind(symtab
, hr
->i
.label
);
917 if (!se
|| se
->segment
== -1) {
918 if (!options
.dynalink
&& !(hr
->i
.flags
& SYM_IMPORT
)) {
919 fprintf(error_file
, "error: unresolved reference to `%s'"
920 " in module `%s'\n", hr
->i
.label
, cur
->name
);
924 * we need to allocate a segment number for this
925 * symbol, and store it in the symbol table for
929 se
=malloc(sizeof(*se
));
931 fprintf(stderr
, "ldrdf: out of memory\n");
934 se
->name
= strdup(hr
->i
.label
);
936 se
->segment
= availableseg
++;
938 symtabInsert(symtab
, se
);
941 se
->segment
= availableseg
++;
945 * output a header record that imports it to the
946 * recently allocated segment number...
949 newrec
.i
.segment
= se
->segment
;
950 rdfaddheader(rdfheader
, &newrec
);
953 add_seglocation(&segs
, hr
->i
.segment
, se
->segment
, se
->offset
);
956 case RDFREC_GLOBAL
: /* export symbol */
958 * need to insert an export for this symbol into the new
959 * header, unless we're stripping symbols. Even if we're
960 * stripping, put the symbol if it's marked as SYM_GLOBAL.
962 if (options
.strip
&& !(hr
->e
.flags
& SYM_GLOBAL
))
965 if (hr
->e
.segment
== 2) {
967 offset
= cur
->bss_reloc
;
970 localseg
= rdffindsegment(&cur
->f
, hr
->e
.segment
);
971 if (localseg
== -1) {
972 fprintf(stderr
, "%s: exported symbol `%s' from "
973 "unrecognised segment\n", cur
->name
,
978 offset
= cur
->seginfo
[localseg
].reloc
;
979 seg
= cur
->seginfo
[localseg
].dest_seg
;
983 hr
->e
.offset
+= offset
;
984 rdfaddheader(rdfheader
, hr
);
987 case RDFREC_MODNAME
: /* module name */
989 * Insert module name record if export symbols
991 * If module name begins with '$' - insert it anyway.
993 if (options
.strip
&& hr
->m
.modname
[0] != '$') break;
994 rdfaddheader(rdfheader
, hr
);
997 case RDFREC_DLL
: /* DLL name */
999 * Insert DLL name if it begins with '$'
1001 if (hr
->d
.libname
[0] != '$') break;
1002 rdfaddheader(rdfheader
, hr
);
1005 case RDFREC_SEGRELOC
: /* segment fixup */
1007 * modify the segment numbers if necessary, and
1008 * pass straight through to the output module header
1012 if (hr
->r
.segment
== 2) {
1013 fprintf(stderr
, "%s: segment fixup in BSS section\n",
1018 localseg
= rdffindsegment(&cur
->f
, hr
->r
.segment
);
1019 if (localseg
== -1) {
1020 fprintf(stderr
, "%s: segment fixup in unrecognised"
1021 " segment (%d)\n", cur
->name
, hr
->r
.segment
);
1025 hr
->r
.segment
= cur
->seginfo
[localseg
].dest_seg
;
1026 hr
->r
.offset
+= cur
->seginfo
[localseg
].reloc
;
1028 if (!get_seglocation(&segs
, hr
->r
.refseg
, &seg
, &offset
)) {
1029 fprintf(stderr
, "%s: segment fixup to undefined "
1030 "segment %04x\n", cur
->name
, (int)hr
->r
.refseg
);
1035 rdfaddheader(rdfheader
, hr
);
1038 case RDFREC_COMMON
: /* Common variable */
1039 /* Is this symbol already in the table? */
1040 se
= symtabFind(symtab
, hr
->c
.label
);
1042 printf("%s is not in symtab yet\n", hr
->c
.label
);
1045 /* Add segment location */
1046 add_seglocation(&segs
, hr
->c
.segment
, se
->segment
, se
->offset
);
1052 done_seglocations(&segs
);
1057 * combined BSS reservation for the entire results
1059 newrec
.type
= RDFREC_BSS
;
1060 newrec
.b
.reclen
= 4;
1061 newrec
.b
.amount
= bss_length
;
1062 rdfaddheader(rdfheader
, &newrec
);
1067 for (i
= 0; i
< nsegs
; i
++) {
1068 if (i
== 2) continue;
1069 rdfaddsegment (rdfheader
, outputseg
[i
].length
);
1072 rdfwriteheader(f
, rdfheader
);
1073 rdfdoneheader(rdfheader
);
1076 * Step through the segments, one at a time, writing out into
1079 for (i
= 0; i
< nsegs
; i
++) {
1083 if (i
== 2) continue;
1085 s
= translateshort(outputseg
[i
].type
);
1086 fwrite(&s
, 2, 1, f
);
1087 s
= translateshort(outputseg
[i
].number
);
1088 fwrite(&s
, 2, 1, f
);
1089 s
= translateshort(outputseg
[i
].reserved
);
1090 fwrite(&s
, 2, 1, f
);
1091 l
= translatelong(outputseg
[i
].length
);
1092 fwrite(&l
, 4, 1, f
);
1094 fwrite(outputseg
[i
].data
, outputseg
[i
].length
, 1, f
);
1097 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f
);
1100 /* =========================================================================
1107 " ldrdf [options] object modules ... [-llibrary ...]\n"
1110 " -v[=n] increase verbosity by 1, or set it to n\n"
1111 " -a nn set segment alignment value (default 16)\n"
1112 " -s strip public symbols\n"
1113 " -dy Unix-style dynamic linking\n"
1114 " -o name write output in file 'name'\n"
1115 " -j path specify objects search path\n"
1116 " -L path specify libraries search path\n"
1117 " -g file embed 'file' as a first header record with type 'generic'\n");
1121 int main(int argc
, char ** argv
)
1123 char * outname
= "aout.rdf";
1124 int moduleloaded
= 0;
1125 char *respstrings
[128] = {0, };
1127 options
.verbose
= 0;
1129 options
.dynalink
= 0;
1132 error_file
= stderr
;
1135 if (argc
== 0) usage();
1136 while (argc
&& *argv
&& **argv
== '-' && argv
[0][1] != 'l') {
1137 switch(argv
[0][1]) {
1139 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
"\n");
1140 printf("RDOFF2 revision %s\n", RDOFF2_REVISION
);
1143 if (argv
[0][2] == '=') {
1144 options
.verbose
= argv
[0][3] - '0';
1145 if (options
.verbose
< 0 || options
.verbose
> 9) {
1146 fprintf(stderr
, "ldrdf: verbosity level must be a number"
1147 " between 0 and 9\n");
1155 options
.align
= atoi(argv
[1]);
1156 if (options
.align
<= 0) {
1158 "ldrdf: -a expects a positive number argument\n");
1167 if (argv
[0][2] == 'y') options
.dynalink
= 1;
1175 options
.objpath
= 1;
1180 fprintf(stderr
,"ldrdf: more than one objects search path specified\n");
1185 options
.libpath
= 1;
1190 fprintf(stderr
,"ldrdf: more than one libraries search path specified\n");
1198 options
.respfile
= 1;
1199 if (argv
[1] != NULL
) f
= fopen(argv
[1],"r");
1201 fprintf(stderr
,"ldrdf: no response file name specified\n");
1206 fprintf(stderr
,"ldrdf: unable to open response file\n");
1211 while (fgets(buf
, sizeof(buf
), f
) != NULL
) {
1213 if (buf
[0]=='\n') continue;
1214 if ((p
= strchr(buf
,'\n')) != NULL
) *p
= '\0';
1216 fprintf(stderr
,"ldrdf: too many input files\n");
1219 *(respstrings
+ i
) = newstr(buf
);
1225 options
.stderr_redir
= 1;
1226 error_file
= stdout
;
1229 generic_rec_file
= argv
[1];
1238 if (options
.verbose
> 4) {
1239 printf("ldrdf invoked with options:\n");
1240 printf(" section alignment: %d bytes\n", options
.align
);
1241 printf(" output name: `%s'\n", outname
);
1243 printf(" strip symbols\n");
1244 if (options
.dynalink
)
1245 printf(" Unix-style dynamic linking\n");
1246 if (options
.objpath
)
1247 printf(" objects search path: %s\n", objpath
);
1248 if (options
.libpath
)
1249 printf(" libraries search path: %s\n", libpath
);
1253 symtab
= symtabNew();
1257 fprintf(stderr
, "ldrdf: out of memory\n");
1262 if (!*argv
) argv
= respstrings
;
1264 if (!strncmp(*argv
, "-l", 2)) {
1265 if(libpath
&& (argv
[0][2] != '/'))
1266 add_library(newstrcat(libpath
,*argv
+ 2));
1268 add_library(*argv
+ 2);
1270 if(objpath
&& (argv
[0][0] != '/'))
1271 loadmodule(newstrcat(objpath
, *argv
));
1279 if (! moduleloaded
) {
1280 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1286 if (options
.verbose
> 2)
1288 printf ("symbol table:\n");
1289 symtabDump(symtab
, stdout
);
1292 write_output(outname
);
1294 if (errorcount
> 0) exit(1);