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.
38 #define LDRDF_VERSION "1.00 alpha 1"
40 #define RDF_MAXSEGS 64
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(int16 type
,int16 reserved
);
75 int findsegment(int16 type
,int16 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 /* the header of the output file, built up stage by stage */
95 rdf_headerbuf
* newheader
= NULL
;
97 /* The current state of segment allocation, including information about
98 * which output segment numbers have been allocated, and their types and
99 * amount of data which has already been allocated inside them.
101 struct SegmentHeaderRec outputseg
[RDF_MAXSEGS
];
105 /* global options which affect how the program behaves */
106 struct ldrdfoptions
{
113 int errorcount
= 0; /* determines main program exit status */
115 /* =========================================================================
123 * sets up segments 0, 1, and 2, the initial code data and bss segments
129 outputseg
[0].type
= 1;
130 outputseg
[0].number
= 0;
131 outputseg
[0].reserved
= 0;
132 outputseg
[0].length
= 0;
133 outputseg
[1].type
= 2;
134 outputseg
[1].number
= 1;
135 outputseg
[1].reserved
= 0;
136 outputseg
[1].length
= 0;
137 outputseg
[2].type
= 0xFFFF; /* reserved segment type */
138 outputseg
[2].number
= 2;
139 outputseg
[2].reserved
= 0;
140 outputseg
[2].length
= 0;
147 * Determine the characteristics of a module, and decide what to do with
148 * each segment it contains (including determining destination segments and
149 * relocation factors for segments that are kept).
152 void loadmodule(const char * filename
)
155 printf("loading `%s'\n", filename
);
157 /* allocate a new module entry on the end of the modules list */
160 modules
= malloc (sizeof(*modules
));
161 lastmodule
= modules
;
165 lastmodule
->next
= malloc (sizeof(*modules
));
166 lastmodule
= lastmodule
->next
;
171 fprintf(stderr
, "ldrdf: out of memory\n");
175 /* open the file using 'rdfopen', which returns nonzero on error */
177 if (rdfopen(&lastmodule
->f
, filename
) != 0)
179 rdfperror("ldrdf", filename
);
184 * store information about the module, and determine what segments
185 * it contains, and what we should do with them (determine relocation
186 * factor if we decide to keep them)
189 lastmodule
->header
= NULL
;
190 lastmodule
->name
= strdup(filename
);
191 lastmodule
->next
= NULL
;
193 processmodule(filename
, lastmodule
);
199 * step through each segment, determine what exactly we're doing with
200 * it, and if we intend to keep it, determine (a) which segment to
201 * put it in and (b) whereabouts in that segment it will end up.
202 * (b) is fairly easy, cos we're now keeping track of how big each segment
203 * in our output file is...
206 void processmodule(const char * filename
, struct modulenode
* mod
)
208 struct segconfig sconf
;
214 for (seg
= 0; seg
< mod
->f
.nsegs
; seg
++)
217 * get the segment configuration for this type from the segment
218 * table. getsegconfig() is a macro, defined in ldsegs.h.
220 getsegconfig(sconf
, mod
->f
.seg
[seg
].type
);
222 if (options
.verbose
> 1) {
223 printf ("%s %04x [%04x:%10s] ", filename
, mod
->f
.seg
[seg
].number
,
224 mod
->f
.seg
[seg
].type
, sconf
.typedesc
);
227 * sconf->dowhat tells us what to do with a segment of this type.
229 switch (sconf
.dowhat
) {
232 * Set destination segment to -1, to indicate that this segment
233 * should be ignored for the purpose of output, ie it is left
234 * out of the linked executable.
236 mod
->seginfo
[seg
].dest_seg
= -1;
237 if (options
.verbose
> 1) printf("IGNORED\n");
242 * The configuration tells us to create a new segment for
243 * each occurrence of this segment type.
245 outseg
= allocnewseg(sconf
.mergetype
,
246 mod
->f
.seg
[seg
].reserved
);
247 mod
->seginfo
[seg
].dest_seg
= outseg
;
248 mod
->seginfo
[seg
].reloc
= 0;
249 outputseg
[outseg
].length
= mod
->f
.seg
[seg
].length
;
250 if (options
.verbose
> 1)
251 printf ("=> %04x:%08lx (+%04lx)\n", outseg
,
252 mod
->seginfo
[seg
].reloc
,
253 mod
->f
.seg
[seg
].length
);
258 * The configuration tells us to merge the segment with
259 * a previously existing segment of type 'sconf.mergetype',
260 * if one exists. Otherwise a new segment is created.
261 * This is handled transparently by 'findsegment()'.
263 outseg
= findsegment(sconf
.mergetype
,
264 mod
->f
.seg
[seg
].reserved
);
265 mod
->seginfo
[seg
].dest_seg
= outseg
;
268 * We need to add alignment to these segments.
270 if (outputseg
[outseg
].length
% options
.align
!= 0)
271 outputseg
[outseg
].length
+=
272 options
.align
- (outputseg
[outseg
].length
% options
.align
);
274 mod
->seginfo
[seg
].reloc
= outputseg
[outseg
].length
;
275 outputseg
[outseg
].length
+= mod
->f
.seg
[seg
].length
;
277 if (options
.verbose
> 1)
278 printf ("=> %04x:%08lx (+%04lx)\n", outseg
,
279 mod
->seginfo
[seg
].reloc
,
280 mod
->f
.seg
[seg
].length
);
286 * extract symbols from the header, and dump them into the
289 header
= malloc(mod
->f
.header_len
);
291 fprintf(stderr
, "ldrdf: not enough memory\n");
294 if (rdfloadseg(&mod
->f
, RDOFF_HEADER
, header
)) {
295 rdfperror("ldrdf", filename
);
299 while ((hr
= rdfgetheaderrec (&mod
->f
)))
302 case 2: /* imported symbol - define with seg = -1 */
304 symtab_add(hr
->i
.label
, -1, 0);
307 case 3: /* exported symbol */
308 if (mod
->seginfo
[(int)hr
->e
.segment
].dest_seg
== -1)
310 symtab_add(hr
->e
.label
, mod
->seginfo
[(int)hr
->e
.segment
].dest_seg
,
311 mod
->seginfo
[(int)hr
->e
.segment
].reloc
+ hr
->e
.offset
);
314 case 5: /* BSS reservation */
316 * first, amalgamate all BSS reservations in this module
317 * into one, because we allow this in the output format.
319 bssamount
+= hr
->b
.amount
;
327 * handle the BSS segment - first pad the existing bss length
328 * to the correct alignment, then store the length in bss_reloc
329 * for this module. Then add this module's BSS length onto
332 if (bss_length
% options
.align
!= 0)
333 bss_length
+= options
.align
- (bss_length
% options
.align
);
335 mod
->bss_reloc
= bss_length
;
336 if (options
.verbose
> 1) {
337 printf ("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n",
338 filename
, bss_length
, bssamount
);
340 bss_length
+= bssamount
;
345 * we free the header buffer here, to save memory later.
346 * this isn't efficient, but probably halves the memory usage
349 mod
->f
.header_loc
= NULL
;
360 * These functions manipulate the array of output segments, and are used
361 * by processmodule(). allocnewseg() allocates a segment in the array,
362 * initialising it to be empty. findsegment() first scans the array for
363 * a segment of the type requested, and if one isn't found allocates a
366 int allocnewseg(int16 type
,int16 reserved
)
368 outputseg
[nsegs
].type
= type
;
369 outputseg
[nsegs
].number
= nsegs
;
370 outputseg
[nsegs
].reserved
= reserved
;
371 outputseg
[nsegs
].length
= 0;
372 outputseg
[nsegs
].offset
= 0;
373 outputseg
[nsegs
].data
= NULL
;
378 int findsegment(int16 type
,int16 reserved
)
382 for (i
= 0; i
< nsegs
; i
++)
383 if (outputseg
[i
].type
== type
) return i
;
385 return allocnewseg(type
,reserved
);
391 * inserts a symbol into the global symbol table, which associates symbol
392 * names either with addresses, or a marker that the symbol hasn't been
393 * resolved yet, or possibly that the symbol has been defined as
394 * contained in a dynamic [load time/run time] linked library.
396 * segment = -1 => not yet defined
397 * segment = -2 => defined as dll symbol
399 * If the symbol is already defined, and the new segment >= 0, then
400 * if the original segment was < 0 the symbol is redefined, otherwise
401 * a duplicate symbol warning is issued. If new segment == -1, this
402 * routine won't change a previously existing symbol. It will change
403 * to segment = -2 only if the segment was previously < 0.
406 void symtab_add(const char * symbol
, int segment
, long offset
)
410 ste
= symtabFind(symtab
, symbol
);
413 if (ste
->segment
>= 0) {
415 * symbol previously defined
417 if (segment
< 0) return;
418 fprintf (stderr
, "warning: `%s' redefined\n", symbol
);
423 * somebody wanted the symbol, and put an undefined symbol
424 * marker into the table
426 if (segment
== -1) return;
428 * we have more information now - update the symbol's entry
430 ste
->segment
= segment
;
431 ste
->offset
= offset
;
436 * this is the first declaration of this symbol
438 ste
= malloc(sizeof(symtabEnt
));
440 fprintf(stderr
, "ldrdf: out of memory\n");
443 ste
->name
= strdup(symbol
);
444 ste
->segment
= segment
;
445 ste
->offset
= offset
;
447 symtabInsert(symtab
, ste
);
453 * Retrieves the values associated with a symbol. Undefined symbols
454 * are assumed to have -1:0 associated. Returns 1 if the symbol was
455 * successfully located.
458 int symtab_get(const char * symbol
, int * segment
, long * offset
)
460 symtabEnt
* ste
= symtabFind(symtab
, symbol
);
468 *segment
= ste
->segment
;
469 *offset
= ste
->offset
;
477 * checks that a library can be opened and is in the correct format,
478 * then adds it to the linked list of libraries.
481 void add_library(const char * name
)
483 if (rdl_verify(name
)) {
484 rdl_perror("ldrdf", name
);
490 lastlib
= libraries
= malloc(sizeof(*libraries
));
492 fprintf(stderr
, "ldrdf: out of memory\n");
498 lastlib
->next
= malloc(sizeof(*libraries
));
499 if (!lastlib
->next
) {
500 fprintf(stderr
, "ldrdf: out of memory\n");
503 lastlib
= lastlib
->next
;
505 if (rdl_open(lastlib
, name
)) {
506 rdl_perror("ldrdf", name
);
515 * scans through the list of libraries, attempting to match symbols
516 * defined in library modules against symbols that are referenced but
517 * not defined (segment = -1 in the symbol table)
519 * returns 1 if any extra library modules are included, indicating that
520 * another pass through the library list should be made (possibly).
523 int search_libraries()
525 struct librarynode
* cur
;
531 int doneanything
= 0, keepfile
;
538 if (options
.verbose
> 2)
539 printf("scanning library `%s'...\n", cur
->name
);
541 for (i
= 0; rdl_openmodule(cur
, i
, &f
) == 0; i
++)
543 if (options
.verbose
> 3)
544 printf(" looking in module `%s'\n", f
.name
);
546 header
= malloc(f
.header_len
);
548 fprintf(stderr
, "ldrdf: not enough memory\n");
551 if (rdfloadseg(&f
, RDOFF_HEADER
, header
)) {
552 rdfperror("ldrdf", f
.name
);
559 while ((hr
= rdfgetheaderrec (&f
)))
561 /* we're only interested in exports, so skip others: */
562 if (hr
->type
!= 3) continue;
565 * Find the symbol in the symbol table. If the symbol isn't
566 * defined, we aren't interested, so go on to the next.
567 * If it is defined as anything but -1, we're also not
568 * interested. But if it is defined as -1, insert this
569 * module into the list of modules to use, and go
570 * immediately on to the next module...
572 if (! symtab_get(hr
->e
.label
, &segment
, &offset
)
582 * as there are undefined symbols, we can assume that
583 * there are modules on the module list by the time
586 lastmodule
->next
= malloc(sizeof(*lastmodule
->next
));
587 if (!lastmodule
->next
) {
588 fprintf(stderr
, "ldrdf: not enough memory\n");
591 lastmodule
= lastmodule
->next
;
592 memcpy(&lastmodule
->f
, &f
, sizeof(f
));
593 lastmodule
->name
= strdup(f
.name
);
594 processmodule(f
.name
, lastmodule
);
600 if (rdl_error
!= 0 && rdl_error
!= RDL_ENOTFOUND
)
601 rdl_perror("ldrdf", cur
->name
);
611 * this takes the linked list of modules, and walks through it, merging
612 * all the modules into a single output module, and then writes this to a
615 void write_output(const char * filename
)
617 FILE * f
= fopen(filename
, "wb");
618 rdf_headerbuf
* rdfheader
= rdfnewheader();
619 struct modulenode
* cur
;
620 int i
, availableseg
, seg
, localseg
, isrelative
;
622 rdfheaderrec
* hr
, newrec
;
629 fprintf(stderr
, "ldrdf: couldn't open %s for output\n", filename
);
633 fprintf(stderr
, "ldrdf: out of memory\n");
638 printf ("\nbuilding output module (%d segments)\n", nsegs
);
641 * Allocate the memory for the segments. We may be better off
642 * building the output module one segment at a time when running
643 * under 16 bit DOS, but that would be a slower way of doing this.
644 * And you could always use DJGPP...
646 for (i
= 0; i
< nsegs
; i
++)
648 outputseg
[i
].data
= malloc(outputseg
[i
].length
);
649 if (!outputseg
[i
].data
) {
650 fprintf(stderr
, "ldrdf: out of memory\n");
656 * initialise availableseg, used to allocate segment numbers for
657 * imported and exported labels...
659 availableseg
= nsegs
;
662 * Step through the modules, performing required actions on each one
664 for (cur
= modules
; cur
; cur
=cur
->next
)
667 * Read the actual segment contents into the correct places in
668 * the newly allocated segments
671 for (i
= 0; i
< cur
->f
.nsegs
; i
++)
673 int dest
= cur
->seginfo
[i
].dest_seg
;
675 if (dest
== -1) continue;
676 if (rdfloadseg(&cur
->f
, i
,
677 outputseg
[dest
].data
+ cur
->seginfo
[i
].reloc
))
679 rdfperror("ldrdf", cur
->name
);
685 * Perform fixups, and add new header records where required
688 header
= malloc(cur
->f
.header_len
);
690 fprintf(stderr
, "ldrdf: out of memory\n");
694 if (cur
->f
.header_loc
)
695 rdfheaderrewind(&cur
->f
);
697 if (rdfloadseg(&cur
->f
, RDOFF_HEADER
, header
))
699 rdfperror("ldrdf", cur
->name
);
704 * we need to create a local segment number -> location
705 * table for the segments in this module.
707 init_seglocations(&segs
);
708 for (i
= 0; i
< cur
->f
.nsegs
; i
++)
710 add_seglocation(&segs
, cur
->f
.seg
[i
].number
,
711 cur
->seginfo
[i
].dest_seg
, cur
->seginfo
[i
].reloc
);
714 * and the BSS segment (doh!)
716 add_seglocation (&segs
, 2, 2, cur
->bss_reloc
);
718 while ((hr
= rdfgetheaderrec(&cur
->f
)))
721 case 1: /* relocation record - need to do a fixup */
723 * First correct the offset stored in the segment from
724 * the start of the segment (which may well have changed).
726 * To do this we add to the number stored the relocation
727 * factor associated with the segment that contains the
730 * The relocation could be a relative relocation, in which
731 * case we have to first subtract the amount we've relocated
732 * the containing segment by.
735 if (!get_seglocation(&segs
, hr
->r
.refseg
, &seg
, &offset
))
737 fprintf(stderr
, "%s: reloc to undefined segment %04x\n",
738 cur
->name
, (int) hr
->r
.refseg
);
743 isrelative
= (hr
->r
.segment
& 64) == 64;
746 if (hr
->r
.segment
== 2 ||
747 (localseg
= rdffindsegment(&cur
->f
, hr
->r
.segment
)) == -1)
749 fprintf(stderr
, "%s: reloc from %s segment (%d)\n",
751 hr
->r
.segment
== 2 ? "BSS" : "unknown",
757 if (hr
->r
.length
!= 1 && hr
->r
.length
!= 2 && hr
->r
.length
!=4)
759 fprintf(stderr
, "%s: nonstandard length reloc "
760 "(%d bytes)\n", cur
->name
, hr
->r
.length
);
766 * okay, now the relocation is in the segment pointed to by
767 * cur->seginfo[localseg], and we know everything else is
768 * okay to go ahead and do the relocation
770 data
= outputseg
[cur
->seginfo
[localseg
].dest_seg
].data
;
771 data
+= cur
->seginfo
[localseg
].reloc
+ hr
->r
.offset
;
774 * data now points to the reference that needs
775 * relocation. Calculate the relocation factor.
777 * offset of referred object in segment [in offset]
778 * (- relocation of localseg, if ref is relative)
779 * For simplicity, the result is stored in 'offset'.
780 * Then add 'offset' onto the value at data.
783 if (isrelative
) offset
-= cur
->seginfo
[localseg
].reloc
;
784 switch (hr
->r
.length
)
788 if (offset
< -127 || offset
> 128)
789 fprintf(stderr
, "warning: relocation out of range "
790 "at %s(%02x:%08lx)\n", cur
->name
,
791 (int)hr
->r
.segment
, hr
->r
.offset
);
792 *data
= (char) offset
;
795 offset
+= * (short *)data
;
796 if (offset
< -32767 || offset
> 32768)
797 fprintf(stderr
, "warning: relocation out of range "
798 "at %s(%02x:%08lx)\n", cur
->name
,
799 (int)hr
->r
.segment
, hr
->r
.offset
);
800 * (short *)data
= (short) offset
;
803 * (long *)data
+= offset
;
804 /* we can't easily detect overflow on this one */
809 * If the relocation was relative between two symbols in
810 * the same segment, then we're done.
812 * Otherwise, we need to output a new relocation record
813 * with the references updated segment and offset...
816 || cur
->seginfo
[localseg
].dest_seg
!= seg
)
818 hr
->r
.segment
= cur
->seginfo
[localseg
].dest_seg
;
819 hr
->r
.offset
+= cur
->seginfo
[localseg
].reloc
;
821 rdfaddheader(rdfheader
, hr
);
825 case 2: /* import symbol */
828 * scan the global symbol table for the symbol
829 * and associate its location with the segment number
832 se
= symtabFind(symtab
, hr
->i
.label
);
833 if (!se
|| se
->segment
== -1) {
834 if (options
.warnUnresolved
) {
835 fprintf(stderr
, "warning: unresolved reference to `%s'"
836 " in module `%s'\n", hr
->i
.label
, cur
->name
);
839 * we need to allocate a segment number for this
840 * symbol, and store it in the symbol table for
844 se
=malloc(sizeof(*se
));
846 fprintf(stderr
, "ldrdf: out of memory\n");
849 se
->name
= strdup(hr
->i
.label
);
851 se
->segment
= availableseg
++;
853 symtabInsert(symtab
, se
);
856 se
->segment
= availableseg
++;
860 * output a header record that imports it to the
861 * recently allocated segment number...
864 newrec
.i
.segment
= se
->segment
;
865 rdfaddheader(rdfheader
, &newrec
);
868 add_seglocation(&segs
, hr
->i
.segment
, se
->segment
, se
->offset
);
872 case 3: /* export symbol */
874 * need to insert an export for this symbol into the new
875 * header, unless we're stripping symbols [unless this
876 * symbol is in an explicit keep list]. *** FIXME ***
881 if (hr
->e
.segment
== 2) {
883 offset
= cur
->bss_reloc
;
886 localseg
= rdffindsegment(&cur
->f
, hr
->e
.segment
);
887 if (localseg
== -1) {
888 fprintf(stderr
, "%s: exported symbol `%s' from "
889 "unrecognised segment\n", cur
->name
,
894 offset
= cur
->seginfo
[localseg
].reloc
;
895 seg
= cur
->seginfo
[localseg
].dest_seg
;
899 hr
->e
.offset
+= offset
;
900 rdfaddheader(rdfheader
, hr
);
903 case 6: /* segment fixup */
905 * modify the segment numbers if necessary, and
906 * pass straight through to the output module header
910 if (hr
->r
.segment
== 2) {
911 fprintf(stderr
, "%s: segment fixup in BSS section\n",
916 localseg
= rdffindsegment(&cur
->f
, hr
->r
.segment
);
917 if (localseg
== -1) {
918 fprintf(stderr
, "%s: segment fixup in unrecognised"
919 " segment (%d)\n", cur
->name
, hr
->r
.segment
);
923 hr
->r
.segment
= cur
->seginfo
[localseg
].dest_seg
;
924 hr
->r
.offset
+= cur
->seginfo
[localseg
].reloc
;
926 if (!get_seglocation(&segs
, hr
->r
.refseg
, &seg
, &offset
))
928 fprintf(stderr
, "%s: segment fixup to undefined "
929 "segment %04x\n", cur
->name
, (int)hr
->r
.refseg
);
934 rdfaddheader(rdfheader
, hr
);
940 done_seglocations(&segs
);
945 * combined BSS reservation for the entire results
949 newrec
.b
.amount
= bss_length
;
950 rdfaddheader(rdfheader
, &newrec
);
955 for (i
= 0; i
< nsegs
; i
++)
957 if (i
== 2) continue;
958 rdfaddsegment (rdfheader
, outputseg
[i
].length
);
960 rdfwriteheader(f
, rdfheader
);
961 rdfdoneheader(rdfheader
);
963 * Step through the segments, one at a time, writing out into
967 for (i
= 0; i
< nsegs
; i
++)
972 if (i
== 2) continue;
974 s
= translateshort(outputseg
[i
].type
);
976 s
= translateshort(outputseg
[i
].number
);
978 s
= translateshort(outputseg
[i
].reserved
);
980 l
= translatelong(outputseg
[i
].length
);
983 fwrite(outputseg
[i
].data
, outputseg
[i
].length
, 1, f
);
986 fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f
);
989 /* =========================================================================
996 printf(" ldrdf [options] object modules ... [-llibrary ...]\n");
997 printf(" ldrdf -r\n");
998 printf("options:\n");
999 printf(" -v[=n] increases verbosity by 1, or sets it to n\n");
1000 printf(" -a nn sets segment alignment value (default 16)\n");
1001 printf(" -s strips exported symbols\n");
1002 printf(" -x warn about unresolved symbols\n");
1003 printf(" -o name write output in file 'name'\n");
1005 printf("Note: no library searching is performed. Please specify full\n");
1006 printf("paths to all files referenced.\n");
1010 int main(int argc
, char ** argv
)
1012 char * outname
= "aout.rdf";
1013 int moduleloaded
= 0;
1015 options
.verbose
= 0;
1017 options
.warnUnresolved
= 0;
1021 if (argc
== 0) usage();
1022 while (argc
&& **argv
== '-' && argv
[0][1] != 'l')
1024 switch(argv
[0][1]) {
1026 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
"\n");
1027 printf( _RDOFF_H
"\n");
1030 if (argv
[0][2] == '=') {
1031 options
.verbose
= argv
[0][3] - '0';
1032 if (options
.verbose
< 0 || options
.verbose
> 9) {
1033 fprintf(stderr
, "ldrdf: verbosity level must be a number"
1034 " between 0 and 9\n");
1042 options
.align
= atoi(argv
[1]);
1043 if (options
.align
<= 0) {
1045 "ldrdf: -a expects a positive number argument\n");
1054 options
.warnUnresolved
= 1;
1066 if (options
.verbose
> 4) {
1067 printf("ldrdf invoked with options:\n");
1068 printf(" section alignment: %d bytes\n", options
.align
);
1069 printf(" output name: `%s'\n", outname
);
1071 printf(" strip symbols\n");
1072 if (options
.warnUnresolved
)
1073 printf(" warn about unresolved symbols\n");
1077 symtab
= symtabNew();
1081 fprintf(stderr
, "ldrdf: out of memory\n");
1087 if (!strncmp(*argv
, "-l", 2)) /* library */
1088 add_library(*argv
+ 2);
1096 if (! moduleloaded
) {
1097 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1104 if (options
.verbose
> 2)
1106 printf ("symbol table:\n");
1107 symtabDump(symtab
, stdout
);
1110 write_output(outname
);