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.
9 /* TODO: Make the system skip a module (other than the first) if none
10 * of the other specified modules contain a reference to it.
11 * May require the system to make an extra pass of the modules to be
12 * loaded eliminating those that aren't required.
14 * Support all the existing documented options...
16 * Support libaries (.a files - requires a 'ranlib' type utility)
17 * (I think I've got this working, so I've upped the version)
19 * -s option to strip resolved symbols from exports. (Could make this an
33 #define LDRDF_VERSION "0.30"
35 /* global variables - those to set options: */
37 int verbose
= 0; /* reflects setting of command line switch */
39 int errors
= 0; /* set by functions to cause halt after current
40 stage of processing */
42 /* the linked list of modules that must be loaded & linked */
45 rdffile f
; /* the file */
46 long coderel
; /* module's code relocation factor */
47 long datarel
; /* module's data relocation factor */
48 long bssrel
; /* module's bss data reloc. factor */
49 void * header
; /* header location, if loaded */
50 char * name
; /* filename */
51 struct modulenode
*next
;
54 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
55 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
58 struct modulenode
*modules
= NULL
,*lastmodule
= NULL
;
60 /* the linked list of libraries to be searched for missing imported
63 struct librarynode
* libraries
= NULL
, * lastlib
= NULL
;
65 void *symtab
; /* The symbol table */
67 rdf_headerbuf
* newheader
; /* New header to be written to output */
69 /* loadmodule - find the characteristics of a module and add it to the
70 * list of those being linked together */
72 void loadmodule(char *filename
)
74 struct modulenode
*prev
;
76 modules
= malloc(sizeof(struct modulenode
));
81 lastmodule
->next
= malloc(sizeof(struct modulenode
));
83 lastmodule
= lastmodule
->next
;
87 fputs("ldrdf: not enough memory\n",stderr
);
91 if (rdfopen(&lastmodule
->f
,filename
)) {
92 rdfperror("ldrdf",filename
);
96 lastmodule
->header
= NULL
; /* header hasn't been loaded */
97 lastmodule
->name
= filename
;
98 lastmodule
->next
= NULL
;
101 lastmodule
->coderel
= prev
->coderel
+ prev
->f
.code_len
;
102 if (lastmodule
->coderel
% align
!= 0)
103 lastmodule
->coderel
+= align
- (lastmodule
->coderel
% align
);
104 lastmodule
->datarel
= prev
->datarel
+ prev
->f
.data_len
;
105 if (lastmodule
->datarel
% align
!= 0)
106 lastmodule
->datarel
+= align
- (lastmodule
->datarel
% align
);
109 lastmodule
->coderel
= 0;
110 lastmodule
->datarel
= 0;
114 printf("%s code = %08lx (+%04lx), data = %08lx (+%04lx)\n",filename
,
115 lastmodule
->coderel
,lastmodule
->f
.code_len
,
116 lastmodule
->datarel
,lastmodule
->f
.data_len
);
118 lastmodule
->header
= malloc(lastmodule
->f
.header_len
);
119 if (!lastmodule
->header
) {
120 fprintf(stderr
,"ldrdf: out of memory\n");
124 if (rdfloadseg(&lastmodule
->f
,RDOFF_HEADER
,lastmodule
->header
))
126 rdfperror("ldrdf",filename
);
131 /* load_library add a library to list of libraries to search
132 * for undefined symbols
135 void load_library(char * name
)
138 printf("adding library %s to search path\n",name
);
141 lastlib
= libraries
= malloc(sizeof(struct librarynode
));
145 lastlib
->next
= malloc(sizeof(struct librarynode
));
146 lastlib
= lastlib
->next
;
150 fprintf(stderr
, "ldrdf: out of memory\n");
153 strcpy (lastlib
->name
= malloc (1+strlen(name
)), name
);
155 lastlib
->referenced
= 0;
156 lastlib
->next
= NULL
;
160 /* build_symbols() step through each module's header, and locate
161 * exported symbols, placing them in a global table
166 void mod_addsymbols(struct modulenode
* mod
)
172 mod
->bssrel
= bsslength
;
174 rdfheaderrewind(&mod
->f
);
175 while ((r
= rdfgetheaderrec(&mod
->f
)))
178 if (r
->type
== 5) /* Allocate BSS */
179 cbBss
+= r
->b
.amount
;
181 if (r
->type
!= 3) continue; /* ignore all but export recs */
183 e
.segment
= r
->e
.segment
;
184 e
.offset
= r
->e
.offset
+
185 (e
.segment
== 0 ? mod
->coderel
: /* 0 -> code */
186 e
.segment
== 1 ? mod
->datarel
: /* 1 -> data */
187 mod
->bssrel
) ; /* 2 -> bss */
190 e
.name
= malloc(strlen(r
->e
.label
) + 1);
193 fprintf(stderr
,"ldrdf: out of memory\n");
196 strcpy(e
.name
,r
->e
.label
);
197 symtabInsert(symtab
,&e
);
204 struct modulenode
*mod
;
206 if (verbose
) printf("building global symbol table:\n");
207 newheader
= rdfnewheader();
209 symtab
= symtabNew();
210 bsslength
= 0; /* keep track of location of BSS symbols */
212 for (mod
= modules
; mod
; mod
= mod
->next
)
214 mod_addsymbols( mod
);
218 symtabDump(symtab
,stdout
);
219 printf("BSS length = %ld bytes\n\n",bsslength
);
224 /* scan_libraries() search through headers of modules for undefined
225 * symbols, and scan libraries for those symbols,
226 * adding library modules found to list of modules
229 void scan_libraries(void)
231 struct modulenode
* mod
, * nm
;
232 struct librarynode
* lib
;
237 if (verbose
) printf("Scanning libraries for unresolved symbols...\n");
243 rdfheaderrewind(&mod
->f
);
245 while ((r
= rdfgetheaderrec(&mod
->f
)))
247 if (r
->type
!= 2) continue; /* not an import record */
248 if ( symtabFind (symtab
,r
->i
.label
) )
249 continue; /* symbol already defined */
251 /* okay, we have an undefined symbol... step through
254 printf("undefined symbol '%s'...",r
->i
.label
);
261 tmp
= newstr(r
->i
.label
);
262 while (! found
&& lib
)
264 /* move this to an outer loop...! */
265 nm
= malloc(sizeof(struct modulenode
));
267 if (rdl_searchlib(lib
,tmp
,&nm
->f
))
268 { /* found a module in the library */
270 /* create a modulenode for it */
273 fprintf(stderr
,"ldrdf: out of memory\n");
277 nm
->name
= newstrcat(lib
->name
,nm
->f
.name
);
278 if (verbose
>= 2) printf("found in '%s'\n",nm
->name
);
280 nm
->coderel
= lastmodule
->coderel
+ lastmodule
->f
.code_len
;
281 if (nm
->coderel
% align
!= 0)
282 nm
->coderel
+= align
- (nm
->coderel
% align
);
284 nm
->datarel
= lastmodule
->datarel
+ lastmodule
->f
.data_len
;
285 if (nm
->datarel
% align
!= 0)
286 nm
->datarel
+= align
- (nm
->datarel
% align
);
288 nm
->header
= malloc(nm
->f
.header_len
);
291 fprintf(stderr
,"ldrdf: out of memory\n");
295 if (rdfloadseg(&nm
->f
,RDOFF_HEADER
,nm
->header
))
297 rdfperror("ldrdf",nm
->name
);
303 lastmodule
->next
= nm
;
307 printf("%s code = %08lx (+%04lx), data = %08lx "
308 "(+%04lx)\n",lastmodule
->name
,
309 lastmodule
->coderel
,lastmodule
->f
.code_len
,
310 lastmodule
->datarel
,lastmodule
->f
.data_len
);
312 /* add the module's info to the symbol table */
318 rdl_perror("ldrdf",lib
->name
);
326 if (!found
&& verbose
>= 2) printf("not found\n");
332 /* load_segments() allocates memory for & loads the code & data segs
333 * from the RDF modules
337 long textlength
,datalength
;
339 void load_segments(void)
341 struct modulenode
*mod
;
344 fprintf(stderr
,"ldrdf: nothing to do\n");
348 fprintf(stderr
,"ldrdf: panic: module list exists, but lastmodule=NULL\n");
353 printf("loading modules into memory\n");
355 /* The following stops 16 bit DOS from crashing whilst attempting to
356 work using segments > 64K */
357 if (sizeof(int) == 2) { /* expect a 'code has no effect' warning on 32 bit
359 if (lastmodule
->coderel
+ lastmodule
->f
.code_len
> 65535 ||
360 lastmodule
->datarel
+ lastmodule
->f
.data_len
> 65535) {
361 fprintf(stderr
,"ldrdf: segment length has exceeded 64K; use a 32 bit "
362 "version.\nldrdf: code size = %05lx, data size = %05lx\n",
363 lastmodule
->coderel
+ lastmodule
->f
.code_len
,
364 lastmodule
->datarel
+ lastmodule
->f
.data_len
);
369 text
= malloc(textlength
= lastmodule
->coderel
+ lastmodule
->f
.code_len
);
370 data
= malloc(datalength
= lastmodule
->datarel
+ lastmodule
->f
.data_len
);
372 if (!text
|| !data
) {
373 fprintf(stderr
,"ldrdf: out of memory\n");
378 while (mod
) { /* load the segments for each module */
379 if (verbose
>= 2) printf(" loading %s\n",mod
->name
);
380 if (rdfloadseg(&mod
->f
,RDOFF_CODE
,&text
[mod
->coderel
]) ||
381 rdfloadseg(&mod
->f
,RDOFF_DATA
,&data
[mod
->datarel
])) {
382 rdfperror("ldrdf",mod
->name
);
385 rdfclose(&mod
->f
); /* close file; segments remain */
390 /* link_segments() step through relocation records in each module's
391 * header, fixing up references.
394 void link_segments(void)
396 struct modulenode
*mod
;
404 if (verbose
) printf("linking segments\n");
406 collection_init(&imports
);
408 for (mod
= modules
; mod
; mod
= mod
->next
) {
409 if (verbose
>= 2) printf("* processing %s\n",mod
->name
);
410 rdfheaderrewind(&mod
->f
);
411 while((r
= rdfgetheaderrec(&mod
->f
))) {
412 if (verbose
>= 3) printf("record type: %d\n",r
->type
);
414 case 1: /* relocation record */
415 if (r
->r
.segment
>= 64) { /* Relative relocation; */
416 bRelative
= 1; /* need to find location relative */
417 r
->r
.segment
-= 64; /* to start of this segment */
418 relto
= r
->r
.segment
== 0 ? mod
->coderel
: mod
->datarel
;
422 bRelative
= 0; /* non-relative - need to relocate
424 relto
= 0; /* placate optimiser warnings */
427 /* calculate absolute offset of reference, not rel to beginning of
429 r
->r
.offset
+= r
->r
.segment
== 0 ? mod
->coderel
: mod
->datarel
;
431 /* calculate the relocation factor to apply to the operand -
432 the base address of one of this modules segments if referred
433 segment is 0 - 2, or the address of an imported symbol
436 if (r
->r
.refseg
== 0) rel
= mod
->coderel
;
437 else if (r
->r
.refseg
== 1) rel
= mod
->datarel
;
438 else if (r
->r
.refseg
== 2) rel
= mod
->bssrel
;
439 else { /* cross module link - find reference */
440 s
= *colln(&imports
,r
->r
.refseg
- 2);
442 fprintf(stderr
,"ldrdf: link to undefined segment %04x in"
443 " %s:%d\n", r
->r
.refseg
,mod
->name
,r
->r
.segment
);
449 r
->r
.refseg
= s
->segment
; /* change referred segment,
450 so that new header is
454 if (bRelative
) /* Relative - subtract current segment start */
457 { /* Add new relocation header */
458 rdfaddheader(newheader
,r
);
461 /* Work out which segment we're making changes to ... */
462 if (r
->r
.segment
== 0) seg
= text
;
463 else if (r
->r
.segment
== 1) seg
= data
;
465 fprintf(stderr
,"ldrdf: relocation in unknown segment %d in "
466 "%s\n", r
->r
.segment
,mod
->name
);
471 /* Add the relocation factor to the datum specified: */
474 printf(" - relocating %d:%08lx by %08lx\n",r
->r
.segment
,
477 /**** The following code is non-portable. Rewrite it... ****/
478 switch(r
->r
.length
) {
480 seg
[r
->r
.offset
] += (char) rel
;
483 *(int16
*)(seg
+ r
->r
.offset
) += (int16
) rel
;
486 *(long *)(seg
+ r
->r
.offset
) += rel
;
491 case 2: /* import record */
492 s
= symtabFind(symtab
, r
->i
.label
);
494 /* Need to add support for dynamic linkage */
495 fprintf(stderr
,"ldrdf: undefined symbol %s in module %s\n",
496 r
->i
.label
,mod
->name
);
501 *colln(&imports
,r
->i
.segment
- 2) = s
;
503 printf("imported %s as %04x\n", r
->i
.label
, r
->i
.segment
);
507 case 3: /* export; dump to output new version */
508 s
= symtabFind(symtab
, r
->e
.label
);
510 fprintf(stderr
,"ldrdf: internal error - undefined symbol %s "
511 "exported in header of '%s'\n",r
->e
.label
,mod
->name
);
514 r
->e
.offset
= s
->offset
;
515 rdfaddheader(newheader
,r
);
518 case 4: /* DLL record */
519 rdfaddheader(newheader
,r
); /* copy straight to output */
523 if (rdf_errno
!= 0) {
524 rdfperror("ldrdf",mod
->name
);
527 collection_reset(&imports
);
531 /* write_output() write linked program out to a file */
533 void write_output(char *filename
)
538 if (verbose
) printf("writing output to '%s'\n",filename
);
540 fp
= fopen(filename
,"wb");
543 fprintf(stderr
,"ldrdf: could not open '%s' for writing\n",filename
);
548 /* add BSS length count to header... */
552 r
.b
.amount
= bsslength
;
553 rdfaddheader(newheader
,&r
);
557 rdfwriteheader(fp
,newheader
);
558 rdfdoneheader(newheader
);
562 if (fwrite(&textlength
,1,4,fp
) != 4
563 || fwrite(text
,1,textlength
,fp
) !=textlength
)
565 fprintf(stderr
,"ldrdf: error writing %s\n",filename
);
570 if (fwrite(&datalength
,1,4,fp
) != 4 ||
571 fwrite(data
,1,datalength
,fp
) != datalength
)
573 fprintf (stderr
,"ldrdf: error writing %s\n", filename
);
580 /* main program: interpret command line, and pass parameters on to
581 * individual module loaders & the linker
583 * Command line format:
584 * ldrdf [-o outfile | -x] [-r xxxx] [-v] [--] infile [infile ...]
586 * Default action is to output a file named 'aout.rdx'. -x specifies
587 * that the linked object program should be executed, rather than
588 * written to a file. -r specifies that the object program should
589 * be prelocated at address 'xxxx'. This option cannot be used
590 * in conjunction with -x.
593 const char *usagemsg
= "usage:\n"
594 " ldrdf [-o outfile | -x] [-a x] [-v] [-p x] [--] infile [infile ...]\n"
595 " [-l<libname> ...]\n\n"
596 " ldrdf -h displays this message\n"
597 " ldrdf -r displays version information\n\n"
598 " -o selects output filename (default is aout.rdx)\n"
599 " -x causes ldrdx to link & execute rather than write to file\n"
600 " -a x causes object program to be statically relocated to address 'x'\n"
601 " -v turns on verbose mode\n"
602 " -p x causes segments to be aligned (padded) to x byte boundaries\n"
603 " (default is 16 bytes)\n"
604 " -l<name> causes 'name' to be linked in as a library. Note no search is\n"
605 " performed - the entire pathname MUST be specified.\n";
609 fputs(usagemsg
,stderr
);
612 int main(int argc
,char **argv
)
614 char *ofilename
= "aout.rdx";
615 long relocateaddr
= -1; /* -1 if no relocation is to occur */
616 int execute
= 0; /* 1 to execute after linking, 0 otherwise */
617 int procsw
= 1; /* set to 0 by '--' */
625 /* process command line switches, and add modules specified to linked list
626 of modules, keeping track of total memory required to load them */
628 while(argv
++,--argc
) {
629 if (procsw
&& !strcmp(*argv
,"-h")) { /* Help command */
632 else if (procsw
&& !strcmp(*argv
,"-r")) {
633 printf("ldrdf version %s (%s) (%s)\n",LDRDF_VERSION
,_RDOFF_H
,
634 sizeof(int) == 2 ? "16 bit" : "32 bit");
637 else if (procsw
&& !strcmp(*argv
,"-o")) {
641 fprintf(stderr
,"ldrdf: -o and -x switches incompatible\n");
644 if (verbose
> 1) printf("output filename set to '%s'\n",ofilename
);
646 else if (procsw
&& !strcmp(*argv
,"-x")) {
648 if (verbose
> 1) printf("will execute linked object\n");
650 else if (procsw
&& !strcmp(*argv
,"-a")) {
651 relocateaddr
= readnum(*++argv
,&tmp
);
654 fprintf(stderr
,"ldrdf: error in parameter to '-a' switch: '%s'\n",
659 fprintf(stderr
,"ldrdf: -a and -x switches incompatible\n");
662 if (verbose
) printf("will relocate to %08lx\n",relocateaddr
);
664 else if (procsw
&& !strcmp(*argv
,"-v")) {
666 if (verbose
== 1) printf("verbose mode selected\n");
668 else if (procsw
&& !strcmp(*argv
,"-p")) {
669 align
= readnum(*++argv
,&tmp
);
672 fprintf(stderr
,"ldrdf: error in parameter to '-p' switch: '%s'\n",
676 if (align
!= 1 && align
!= 2 && align
!= 4 && align
!= 8 && align
!= 16
677 && align
!= 32 && align
!= 256) {
678 fprintf(stderr
,"ldrdf: %d is an invalid alignment factor - must be"
679 "1,2,4,8,16 or 256\n",align
);
682 if (verbose
> 1) printf("alignment %d selected\n",align
);
684 else if (procsw
&& !strncmp(*argv
,"-l",2)) {
685 load_library(*argv
+ 2);
687 else if (procsw
&& !strcmp(*argv
,"--")) {
690 else { /* is a filename */
691 if (verbose
> 1) printf("processing module %s\n",*argv
);
696 /* we should be scanning for unresolved references, and removing
697 unreferenced modules from the list of modules here, so that
698 we know about the final size once libraries have been linked in */
700 build_symbols(); /* build a global symbol table... */
702 scan_libraries(); /* check for imported symbols not in table,
703 and ensure the relevant library modules
706 load_segments(); /* having calculated size of reqd segments, load
707 each rdoff module's segments into memory */
709 link_segments(); /* step through each module's header, and resolve
710 references to the global symbol table.
711 This also does local address fixups. */
714 fprintf(stderr
,"ldrdf: there were errors - aborted\n");
718 fprintf(stderr
,"ldrdf: module execution not yet supported\n");
721 if (relocateaddr
!= -1) {
722 fprintf(stderr
,"ldrdf: static relocation not yet supported\n");
726 write_output(ofilename
);