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
34 #define LDRDF_VERSION "0.30"
36 /* global variables - those to set options: */
38 int verbose
= 0; /* reflects setting of command line switch */
40 int errors
= 0; /* set by functions to cause halt after current
41 stage of processing */
43 /* the linked list of modules that must be loaded & linked */
46 rdffile f
; /* the file */
47 long coderel
; /* module's code relocation factor */
48 long datarel
; /* module's data relocation factor */
49 long bssrel
; /* module's bss data reloc. factor */
50 void * header
; /* header location, if loaded */
51 char * name
; /* filename */
52 struct modulenode
*next
;
55 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
56 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
59 struct modulenode
*modules
= NULL
,*lastmodule
= NULL
;
61 /* the linked list of libraries to be searched for missing imported
64 struct librarynode
* libraries
= NULL
, * lastlib
= NULL
;
66 void *symtab
; /* The symbol table */
68 rdf_headerbuf
* newheader
; /* New header to be written to output */
70 /* loadmodule - find the characteristics of a module and add it to the
71 * list of those being linked together */
73 void loadmodule(char *filename
)
75 struct modulenode
*prev
;
77 modules
= malloc(sizeof(struct modulenode
));
82 lastmodule
->next
= malloc(sizeof(struct modulenode
));
84 lastmodule
= lastmodule
->next
;
88 fputs("ldrdf: not enough memory\n",stderr
);
92 if (rdfopen(&lastmodule
->f
,filename
)) {
93 rdfperror("ldrdf",filename
);
97 lastmodule
->header
= NULL
; /* header hasn't been loaded */
98 lastmodule
->name
= filename
;
99 lastmodule
->next
= NULL
;
102 lastmodule
->coderel
= prev
->coderel
+ prev
->f
.code_len
;
103 if (lastmodule
->coderel
% align
!= 0)
104 lastmodule
->coderel
+= align
- (lastmodule
->coderel
% align
);
105 lastmodule
->datarel
= prev
->datarel
+ prev
->f
.data_len
;
106 if (lastmodule
->datarel
% align
!= 0)
107 lastmodule
->datarel
+= align
- (lastmodule
->datarel
% align
);
110 lastmodule
->coderel
= 0;
111 lastmodule
->datarel
= 0;
115 printf("%s code = %08lx (+%04lx), data = %08lx (+%04lx)\n",filename
,
116 lastmodule
->coderel
,lastmodule
->f
.code_len
,
117 lastmodule
->datarel
,lastmodule
->f
.data_len
);
119 lastmodule
->header
= malloc(lastmodule
->f
.header_len
);
120 if (!lastmodule
->header
) {
121 fprintf(stderr
,"ldrdf: out of memory\n");
125 if (rdfloadseg(&lastmodule
->f
,RDOFF_HEADER
,lastmodule
->header
))
127 rdfperror("ldrdf",filename
);
132 /* load_library add a library to list of libraries to search
133 * for undefined symbols
136 void load_library(char * name
)
139 printf("adding library %s to search path\n",name
);
142 lastlib
= libraries
= malloc(sizeof(struct librarynode
));
146 lastlib
->next
= malloc(sizeof(struct librarynode
));
147 lastlib
= lastlib
->next
;
151 fprintf(stderr
, "ldrdf: out of memory\n");
154 strcpy (lastlib
->name
= malloc (1+strlen(name
)), name
);
156 lastlib
->referenced
= 0;
157 lastlib
->next
= NULL
;
161 /* build_symbols() step through each module's header, and locate
162 * exported symbols, placing them in a global table
167 void mod_addsymbols(struct modulenode
* mod
)
173 mod
->bssrel
= bsslength
;
175 rdfheaderrewind(&mod
->f
);
176 while ((r
= rdfgetheaderrec(&mod
->f
)))
179 if (r
->type
== 5) /* Allocate BSS */
180 cbBss
+= r
->b
.amount
;
182 if (r
->type
!= 3) continue; /* ignore all but export recs */
184 e
.segment
= r
->e
.segment
;
185 e
.offset
= r
->e
.offset
+
186 (e
.segment
== 0 ? mod
->coderel
: /* 0 -> code */
187 e
.segment
== 1 ? mod
->datarel
: /* 1 -> data */
188 mod
->bssrel
) ; /* 2 -> bss */
191 e
.name
= malloc(strlen(r
->e
.label
) + 1);
194 fprintf(stderr
,"ldrdf: out of memory\n");
197 strcpy(e
.name
,r
->e
.label
);
198 symtabInsert(symtab
,&e
);
205 struct modulenode
*mod
;
207 if (verbose
) printf("building global symbol table:\n");
208 newheader
= rdfnewheader();
210 symtab
= symtabNew();
211 bsslength
= 0; /* keep track of location of BSS symbols */
213 for (mod
= modules
; mod
; mod
= mod
->next
)
215 mod_addsymbols( mod
);
219 symtabDump(symtab
,stdout
);
220 printf("BSS length = %ld bytes\n\n",bsslength
);
225 /* scan_libraries() search through headers of modules for undefined
226 * symbols, and scan libraries for those symbols,
227 * adding library modules found to list of modules
230 void scan_libraries(void)
232 struct modulenode
* mod
, * nm
;
233 struct librarynode
* lib
;
238 if (verbose
) printf("Scanning libraries for unresolved symbols...\n");
244 rdfheaderrewind(&mod
->f
);
246 while ((r
= rdfgetheaderrec(&mod
->f
)))
248 if (r
->type
!= 2) continue; /* not an import record */
249 if ( symtabFind (symtab
,r
->i
.label
) )
250 continue; /* symbol already defined */
252 /* okay, we have an undefined symbol... step through
255 printf("undefined symbol '%s'...",r
->i
.label
);
262 tmp
= newstr(r
->i
.label
);
263 while (! found
&& lib
)
265 /* move this to an outer loop...! */
266 nm
= malloc(sizeof(struct modulenode
));
268 if (rdl_searchlib(lib
,tmp
,&nm
->f
))
269 { /* found a module in the library */
271 /* create a modulenode for it */
274 fprintf(stderr
,"ldrdf: out of memory\n");
278 nm
->name
= newstrcat(lib
->name
,nm
->f
.name
);
279 if (verbose
>= 2) printf("found in '%s'\n",nm
->name
);
281 nm
->coderel
= lastmodule
->coderel
+ lastmodule
->f
.code_len
;
282 if (nm
->coderel
% align
!= 0)
283 nm
->coderel
+= align
- (nm
->coderel
% align
);
285 nm
->datarel
= lastmodule
->datarel
+ lastmodule
->f
.data_len
;
286 if (nm
->datarel
% align
!= 0)
287 nm
->datarel
+= align
- (nm
->datarel
% align
);
289 nm
->header
= malloc(nm
->f
.header_len
);
292 fprintf(stderr
,"ldrdf: out of memory\n");
296 if (rdfloadseg(&nm
->f
,RDOFF_HEADER
,nm
->header
))
298 rdfperror("ldrdf",nm
->name
);
304 lastmodule
->next
= nm
;
308 printf("%s code = %08lx (+%04lx), data = %08lx "
309 "(+%04lx)\n",lastmodule
->name
,
310 lastmodule
->coderel
,lastmodule
->f
.code_len
,
311 lastmodule
->datarel
,lastmodule
->f
.data_len
);
313 /* add the module's info to the symbol table */
319 rdl_perror("ldrdf",lib
->name
);
327 if (!found
&& verbose
>= 2) printf("not found\n");
333 /* load_segments() allocates memory for & loads the code & data segs
334 * from the RDF modules
338 long textlength
,datalength
;
340 void load_segments(void)
342 struct modulenode
*mod
;
345 fprintf(stderr
,"ldrdf: nothing to do\n");
349 fprintf(stderr
,"ldrdf: panic: module list exists, but lastmodule=NULL\n");
354 printf("loading modules into memory\n");
356 /* The following stops 16 bit DOS from crashing whilst attempting to
357 work using segments > 64K */
358 if (sizeof(int) == 2) { /* expect a 'code has no effect' warning on 32 bit
360 if (lastmodule
->coderel
+ lastmodule
->f
.code_len
> 65535 ||
361 lastmodule
->datarel
+ lastmodule
->f
.data_len
> 65535) {
362 fprintf(stderr
,"ldrdf: segment length has exceeded 64K; use a 32 bit "
363 "version.\nldrdf: code size = %05lx, data size = %05lx\n",
364 lastmodule
->coderel
+ lastmodule
->f
.code_len
,
365 lastmodule
->datarel
+ lastmodule
->f
.data_len
);
370 text
= malloc(textlength
= lastmodule
->coderel
+ lastmodule
->f
.code_len
);
371 data
= malloc(datalength
= lastmodule
->datarel
+ lastmodule
->f
.data_len
);
373 if (!text
|| !data
) {
374 fprintf(stderr
,"ldrdf: out of memory\n");
379 while (mod
) { /* load the segments for each module */
380 if (verbose
>= 2) printf(" loading %s\n",mod
->name
);
381 if (rdfloadseg(&mod
->f
,RDOFF_CODE
,&text
[mod
->coderel
]) ||
382 rdfloadseg(&mod
->f
,RDOFF_DATA
,&data
[mod
->datarel
])) {
383 rdfperror("ldrdf",mod
->name
);
386 rdfclose(&mod
->f
); /* close file; segments remain */
391 /* link_segments() step through relocation records in each module's
392 * header, fixing up references.
395 void link_segments(void)
397 struct modulenode
*mod
;
405 if (verbose
) printf("linking segments\n");
407 collection_init(&imports
);
409 for (mod
= modules
; mod
; mod
= mod
->next
) {
410 if (verbose
>= 2) printf("* processing %s\n",mod
->name
);
411 rdfheaderrewind(&mod
->f
);
412 while((r
= rdfgetheaderrec(&mod
->f
))) {
413 if (verbose
>= 3) printf("record type: %d\n",r
->type
);
415 case 1: /* relocation record */
416 if (r
->r
.segment
>= 64) { /* Relative relocation; */
417 bRelative
= 1; /* need to find location relative */
418 r
->r
.segment
-= 64; /* to start of this segment */
419 relto
= r
->r
.segment
== 0 ? mod
->coderel
: mod
->datarel
;
422 bRelative
= 0; /* non-relative - need to relocate
425 /* calculate absolute offset of reference, not rel to beginning of
427 r
->r
.offset
+= r
->r
.segment
== 0 ? mod
->coderel
: mod
->datarel
;
429 /* calculate the relocation factor to apply to the operand -
430 the base address of one of this modules segments if referred
431 segment is 0 - 2, or the address of an imported symbol
434 if (r
->r
.refseg
== 0) rel
= mod
->coderel
;
435 else if (r
->r
.refseg
== 1) rel
= mod
->datarel
;
436 else if (r
->r
.refseg
== 2) rel
= mod
->bssrel
;
437 else { /* cross module link - find reference */
438 s
= *colln(&imports
,r
->r
.refseg
- 2);
440 fprintf(stderr
,"ldrdf: link to undefined segment %04x in"
441 " %s:%d\n", r
->r
.refseg
,mod
->name
,r
->r
.segment
);
447 r
->r
.refseg
= s
->segment
; /* change referred segment,
448 so that new header is
452 if (bRelative
) /* Relative - subtract current segment start */
455 { /* Add new relocation header */
456 rdfaddheader(newheader
,r
);
459 /* Work out which segment we're making changes to ... */
460 if (r
->r
.segment
== 0) seg
= text
;
461 else if (r
->r
.segment
== 1) seg
= data
;
463 fprintf(stderr
,"ldrdf: relocation in unknown segment %d in "
464 "%s\n", r
->r
.segment
,mod
->name
);
469 /* Add the relocation factor to the datum specified: */
472 printf(" - relocating %d:%08lx by %08lx\n",r
->r
.segment
,
475 /**** The following code is non-portable. Rewrite it... ****/
476 switch(r
->r
.length
) {
478 seg
[r
->r
.offset
] += (char) rel
;
481 *(int16
*)(seg
+ r
->r
.offset
) += (int16
) rel
;
484 *(long *)(seg
+ r
->r
.offset
) += rel
;
489 case 2: /* import record */
490 s
= symtabFind(symtab
, r
->i
.label
);
492 /* Need to add support for dynamic linkage */
493 fprintf(stderr
,"ldrdf: undefined symbol %s in module %s\n",
494 r
->i
.label
,mod
->name
);
499 *colln(&imports
,r
->i
.segment
- 2) = s
;
501 printf("imported %s as %04x\n", r
->i
.label
, r
->i
.segment
);
505 case 3: /* export; dump to output new version */
506 s
= symtabFind(symtab
, r
->e
.label
);
508 fprintf(stderr
,"ldrdf: internal error - undefined symbol %s "
509 "exported in header of '%s'\n",r
->e
.label
,mod
->name
);
512 r
->e
.offset
= s
->offset
;
513 rdfaddheader(newheader
,r
);
516 case 4: /* DLL record */
517 rdfaddheader(newheader
,r
); /* copy straight to output */
521 if (rdf_errno
!= 0) {
522 rdfperror("ldrdf",mod
->name
);
525 collection_reset(&imports
);
529 /* write_output() write linked program out to a file */
531 void write_output(char *filename
)
536 if (verbose
) printf("writing output to '%s'\n",filename
);
538 fp
= fopen(filename
,"wb");
541 fprintf(stderr
,"ldrdf: could not open '%s' for writing\n",filename
);
546 /* add BSS length count to header... */
550 r
.b
.amount
= bsslength
;
551 rdfaddheader(newheader
,&r
);
555 rdfwriteheader(fp
,newheader
);
556 rdfdoneheader(newheader
);
560 if (fwrite(&textlength
,1,4,fp
) != 4
561 || fwrite(text
,1,textlength
,fp
) !=textlength
)
563 fprintf(stderr
,"ldrdf: error writing %s\n",filename
);
568 if (fwrite(&datalength
,1,4,fp
) != 4 ||
569 fwrite(data
,1,datalength
,fp
) != datalength
)
571 fprintf (stderr
,"ldrdf: error writing %s\n", filename
);
578 /* main program: interpret command line, and pass parameters on to
579 * individual module loaders & the linker
581 * Command line format:
582 * ldrdf [-o outfile | -x] [-r xxxx] [-v] [--] infile [infile ...]
584 * Default action is to output a file named 'aout.rdx'. -x specifies
585 * that the linked object program should be executed, rather than
586 * written to a file. -r specifies that the object program should
587 * be prelocated at address 'xxxx'. This option cannot be used
588 * in conjunction with -x.
591 const char *usagemsg
= "usage:\n"
592 " ldrdf [-o outfile | -x] [-a x] [-v] [-p x] [--] infile [infile ...]\n"
593 " [-l<libname> ...]\n\n"
594 " ldrdf -h displays this message\n"
595 " ldrdf -r displays version information\n\n"
596 " -o selects output filename (default is aout.rdx)\n"
597 " -x causes ldrdx to link & execute rather than write to file\n"
598 " -a x causes object program to be statically relocated to address 'x'\n"
599 " -v turns on verbose mode\n"
600 " -p x causes segments to be aligned (padded) to x byte boundaries\n"
601 " (default is 16 bytes)\n"
602 " -l<name> causes 'name' to be linked in as a library. Note no search is\n"
603 " performed - the entire pathname MUST be specified.\n";
607 fputs(usagemsg
,stderr
);
610 int main(int argc
,char **argv
)
612 char *ofilename
= "aout.rdx";
613 long relocateaddr
= -1; /* -1 if no relocation is to occur */
614 int execute
= 0; /* 1 to execute after linking, 0 otherwise */
615 int procsw
= 1; /* set to 0 by '--' */
623 /* process command line switches, and add modules specified to linked list
624 of modules, keeping track of total memory required to load them */
626 while(argv
++,--argc
) {
627 if (procsw
&& !strcmp(*argv
,"-h")) { /* Help command */
630 else if (procsw
&& !strcmp(*argv
,"-r")) {
631 printf("ldrdf version %s (%s) (%s)\n",LDRDF_VERSION
,_RDOFF_H
,
632 sizeof(int) == 2 ? "16 bit" : "32 bit");
635 else if (procsw
&& !strcmp(*argv
,"-o")) {
639 fprintf(stderr
,"ldrdf: -o and -x switches incompatible\n");
642 if (verbose
> 1) printf("output filename set to '%s'\n",ofilename
);
644 else if (procsw
&& !strcmp(*argv
,"-x")) {
646 if (verbose
> 1) printf("will execute linked object\n");
648 else if (procsw
&& !strcmp(*argv
,"-a")) {
649 relocateaddr
= readnum(*++argv
,&tmp
);
652 fprintf(stderr
,"ldrdf: error in parameter to '-a' switch: '%s'\n",
657 fprintf(stderr
,"ldrdf: -a and -x switches incompatible\n");
660 if (verbose
) printf("will relocate to %08lx\n",relocateaddr
);
662 else if (procsw
&& !strcmp(*argv
,"-v")) {
664 if (verbose
== 1) printf("verbose mode selected\n");
666 else if (procsw
&& !strcmp(*argv
,"-p")) {
667 align
= readnum(*++argv
,&tmp
);
670 fprintf(stderr
,"ldrdf: error in parameter to '-p' switch: '%s'\n",
674 if (align
!= 1 && align
!= 2 && align
!= 4 && align
!= 8 && align
!= 16
675 && align
!= 32 && align
!= 256) {
676 fprintf(stderr
,"ldrdf: %d is an invalid alignment factor - must be"
677 "1,2,4,8,16 or 256\n",align
);
680 if (verbose
> 1) printf("alignment %d selected\n",align
);
682 else if (procsw
&& !strncmp(*argv
,"-l",2)) {
683 load_library(*argv
+ 2);
685 else if (procsw
&& !strcmp(*argv
,"--")) {
688 else { /* is a filename */
689 if (verbose
> 1) printf("processing module %s\n",*argv
);
694 /* we should be scanning for unresolved references, and removing
695 unreferenced modules from the list of modules here, so that
696 we know about the final size once libraries have been linked in */
698 build_symbols(); /* build a global symbol table... */
700 scan_libraries(); /* check for imported symbols not in table,
701 and ensure the relevant library modules
704 load_segments(); /* having calculated size of reqd segments, load
705 each rdoff module's segments into memory */
707 link_segments(); /* step through each module's header, and resolve
708 references to the global symbol table.
709 This also does local address fixups. */
712 fprintf(stderr
,"ldrdf: there were errors - aborted\n");
716 fprintf(stderr
,"ldrdf: module execution not yet supported\n");
719 if (relocateaddr
!= -1) {
720 fprintf(stderr
,"ldrdf: static relocation not yet supported\n");
724 write_output(ofilename
);