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 libaries (.a files - requires a 'ranlib' type utility)
16 * -s option to strip resolved symbols from exports.
28 #define LDRDF_VERSION "0.11"
30 /* global variables - those to set options: */
32 int verbose
= 0; /* reflects setting of command line switch */
34 int errors
= 0; /* set by functions to cause halt after current
35 stage of processing */
37 /* the linked list of modules that must be loaded & linked */
40 rdffile f
; /* the file */
41 long coderel
; /* module's code relocation factor */
42 long datarel
; /* module's data relocation factor */
43 long bssrel
; /* module's bss data reloc. factor */
44 void * header
; /* header location, if loaded */
45 char * name
; /* filename */
46 struct modulenode
*next
;
49 struct modulenode
*modules
= NULL
,*lastmodule
= NULL
;
51 void *symtab
; /* The symbol table */
53 rdf_headerbuf
* newheader
; /* New header to be written to output */
55 /* loadmodule - find the characteristics of a module and add it to the
56 * list of those being linked together */
58 void loadmodule(char *filename
)
60 struct modulenode
*prev
;
62 modules
= malloc(sizeof(struct modulenode
));
67 lastmodule
->next
= malloc(sizeof(struct modulenode
));
69 lastmodule
= lastmodule
->next
;
73 fputs("ldrdf: not enough memory\n",stderr
);
77 if (rdfopen(&lastmodule
->f
,filename
)) {
78 rdfperror("ldrdf",filename
);
82 lastmodule
->header
= NULL
; /* header hasn't been loaded */
83 lastmodule
->name
= filename
;
84 lastmodule
->next
= NULL
;
87 lastmodule
->coderel
= prev
->coderel
+ prev
->f
.code_len
;
88 if (lastmodule
->coderel
% align
!= 0)
89 lastmodule
->coderel
+= align
- (lastmodule
->coderel
% align
);
90 lastmodule
->datarel
= prev
->datarel
+ prev
->f
.data_len
;
91 if (lastmodule
->datarel
% align
!= 0)
92 lastmodule
->datarel
+= align
- (lastmodule
->datarel
% align
);
95 lastmodule
->coderel
= 0;
96 lastmodule
->datarel
= 0;
100 printf("%s code = %08lx (+%04lx), data = %08lx (+%04lx)\n",filename
,
101 lastmodule
->coderel
,lastmodule
->f
.code_len
,
102 lastmodule
->datarel
,lastmodule
->f
.data_len
);
106 /* load_segments() allocates memory for & loads the code & data segs
107 * from the RDF modules
111 long textlength
,datalength
,bsslength
;
113 void load_segments(void)
115 struct modulenode
*mod
;
118 fprintf(stderr
,"ldrdf: nothing to do\n");
122 fprintf(stderr
,"ldrdf: panic: module list exists, but lastmodule=NULL\n");
127 printf("loading modules into memory\n");
129 /* The following stops 16 bit DOS from crashing whilst attempting to
130 work using segments > 64K */
131 if (sizeof(int) == 2) { /* expect a 'code has no effect' warning on 32 bit
133 if (lastmodule
->coderel
+ lastmodule
->f
.code_len
> 65535 ||
134 lastmodule
->datarel
+ lastmodule
->f
.data_len
> 65535) {
135 fprintf(stderr
,"ldrdf: segment length has exceeded 64K; use a 32 bit "
136 "version.\nldrdf: code size = %05lx, data size = %05lx\n",
137 lastmodule
->coderel
+ lastmodule
->f
.code_len
,
138 lastmodule
->datarel
+ lastmodule
->f
.data_len
);
143 text
= malloc(textlength
= lastmodule
->coderel
+ lastmodule
->f
.code_len
);
144 data
= malloc(datalength
= lastmodule
->datarel
+ lastmodule
->f
.data_len
);
146 if (!text
|| !data
) {
147 fprintf(stderr
,"ldrdf: out of memory\n");
152 while (mod
) { /* load the segments for each module */
153 mod
->header
= malloc(mod
->f
.header_len
);
155 fprintf(stderr
,"ldrdf: out of memory\n");
158 if (rdfloadseg(&mod
->f
,RDOFF_HEADER
,mod
->header
) ||
159 rdfloadseg(&mod
->f
,RDOFF_CODE
,&text
[mod
->coderel
]) ||
160 rdfloadseg(&mod
->f
,RDOFF_DATA
,&data
[mod
->datarel
])) {
161 rdfperror("ldrdf",mod
->name
);
164 rdfclose(&mod
->f
); /* close file; segments remain */
169 /* build_symbols() step through each module's header, and locate
170 * exported symbols, placing them in a global table
175 struct modulenode
*mod
;
180 if (verbose
) printf("building global symbol table:\n");
181 newheader
= rdfnewheader();
183 symtab
= symtabNew();
184 bssloc
= 0; /* keep track of location of BSS symbols */
186 for (mod
= modules
; mod
; mod
= mod
->next
)
188 mod
->bssrel
= bssloc
;
190 rdfheaderrewind(&mod
->f
);
191 while ((r
= rdfgetheaderrec(&mod
->f
)))
194 if (r
->type
== 5) /* Allocate BSS */
195 cbBss
+= r
->b
.amount
;
197 if (r
->type
!= 3) continue; /* ignore all but export recs */
199 e
.segment
= r
->e
.segment
;
200 e
.offset
= r
->e
.offset
+
201 (e
.segment
== 0 ? mod
->coderel
: /* 0 -> code */
202 e
.segment
== 1 ? mod
->datarel
: /* 1 -> data */
203 mod
->bssrel
) ; /* 2 -> bss */
205 e
.name
= malloc(strlen(r
->e
.label
) + 1);
208 fprintf(stderr
,"ldrdf: out of memory\n");
211 strcpy(e
.name
,r
->e
.label
);
212 symtabInsert(symtab
,&e
);
218 symtabDump(symtab
,stdout
);
219 printf("BSS length = %ld bytes\n\n",bssloc
);
224 /* link_segments() step through relocation records in each module's
225 * header, fixing up references.
228 void link_segments(void)
230 struct modulenode
*mod
;
233 long rel
,relto
= 0; /* placate gcc */
238 if (verbose
) printf("linking segments\n");
240 collection_init(&imports
);
242 for (mod
= modules
; mod
; mod
= mod
->next
) {
243 if (verbose
>= 2) printf("* processing %s\n",mod
->name
);
244 rdfheaderrewind(&mod
->f
);
245 while((r
= rdfgetheaderrec(&mod
->f
))) {
247 case 1: /* relocation record */
248 if (r
->r
.segment
>= 64) { /* Relative relocation; */
249 bRelative
= 1; /* need to find location relative */
250 r
->r
.segment
-= 64; /* to start of this segment */
251 relto
= r
->r
.segment
== 0 ? mod
->coderel
: mod
->datarel
;
254 bRelative
= 0; /* non-relative - need to relocate
257 /* calculate absolute offset of reference, not rel to beginning of
259 r
->r
.offset
+= r
->r
.segment
== 0 ? mod
->coderel
: mod
->datarel
;
261 /* calculate the relocation factor to apply to the operand -
262 the base address of one of this modules segments if referred
263 segment is 0 - 2, or the address of an imported symbol
266 if (r
->r
.refseg
== 0) rel
= mod
->coderel
;
267 else if (r
->r
.refseg
== 1) rel
= mod
->datarel
;
268 else if (r
->r
.refseg
== 2) rel
= mod
->bssrel
;
269 else { /* cross module link - find reference */
270 s
= *colln(&imports
,r
->r
.refseg
- 2);
272 fprintf(stderr
,"ldrdf: link to undefined segment %04x in"
273 " %s:%d\n", r
->r
.refseg
,mod
->name
,r
->r
.segment
);
279 r
->r
.refseg
= s
->segment
; /* change referred segment,
280 so that new header is
284 if (bRelative
) /* Relative - subtract current segment start */
287 { /* Add new relocation header */
288 rdfaddheader(newheader
,r
);
291 /* Work out which segment we're making changes to ... */
292 if (r
->r
.segment
== 0) seg
= text
;
293 else if (r
->r
.segment
== 1) seg
= data
;
295 fprintf(stderr
,"ldrdf: relocation in unknown segment %d in "
296 "%s\n", r
->r
.segment
,mod
->name
);
301 /* Add the relocation factor to the datum specified: */
304 printf(" - relocating %d:%08lx by %08lx\n",r
->r
.segment
,
307 /**** The following code is non-portable. Rewrite it... ****/
308 switch(r
->r
.length
) {
310 seg
[r
->r
.offset
] += (char) rel
;
313 *(int16
*)(seg
+ r
->r
.offset
) += (int16
) rel
;
316 *(long *)(seg
+ r
->r
.offset
) += rel
;
321 case 2: /* import record */
322 s
= symtabFind(symtab
, r
->i
.label
);
324 /* Need to add support for dynamic linkage */
325 fprintf(stderr
,"ldrdf: undefined symbol %s in module %s\n",
326 r
->i
.label
,mod
->name
);
331 *colln(&imports
,r
->i
.segment
- 2) = s
;
333 printf("imported %s as %04x\n", r
->i
.label
, r
->i
.segment
);
337 case 3: /* export; dump to output new version */
338 s
= symtabFind(symtab
, r
->e
.label
);
339 if (! s
) continue; /* eh? probably doesn't matter... */
341 r
->e
.offset
= s
->offset
;
342 rdfaddheader(newheader
,r
);
345 case 4: /* DLL record */
346 rdfaddheader(newheader
,r
); /* copy straight to output */
350 collection_reset(&imports
);
354 /* write_output() write linked program out to a file */
356 void write_output(char *filename
)
361 fp
= fopen(filename
,"wb");
364 fprintf(stderr
,"ldrdf: could not open '%s' for writing\n",filename
);
369 /* add BSS length count to header... */
373 r
.b
.amount
= bsslength
;
374 rdfaddheader(newheader
,&r
);
378 rdfwriteheader(fp
,newheader
);
379 rdfdoneheader(newheader
);
383 if (fwrite(&textlength
,1,4,fp
) != 4
384 || fwrite(text
,1,textlength
,fp
) !=textlength
)
386 fprintf(stderr
,"ldrdf: error writing %s\n",filename
);
391 if (fwrite(&datalength
,1,4,fp
) != 4 ||
392 fwrite(data
,1,datalength
,fp
) != datalength
)
394 fprintf (stderr
,"ldrdf: error writing %s\n", filename
);
401 /* main program: interpret command line, and pass parameters on to
402 * individual module loaders & the linker
404 * Command line format:
405 * ldrdf [-o outfile | -x] [-r xxxx] [-v] [--] infile [infile ...]
407 * Default action is to output a file named 'aout.rdx'. -x specifies
408 * that the linked object program should be executed, rather than
409 * written to a file. -r specifies that the object program should
410 * be prelocated at address 'xxxx'. This option cannot be used
411 * in conjunction with -x.
414 const char *usagemsg
= "usage:\n"
415 " ldrdf [-o outfile | -x] [-a x] [-v] [-p x] [--] infile [infile ...]\n\n"
416 " ldrdf -h displays this message\n"
417 " ldrdf -r displays version information\n\n"
418 " -o selects output filename (default is aout.rdx)\n"
419 " -x causes ldrdx to link & execute rather than write to file\n"
420 " -a x causes object program to be statically relocated to address 'x'\n"
421 " -v turns on verbose mode\n"
422 " -p x causes segments to be aligned (padded) to x byte boundaries\n"
423 " (default is 16 bytes)\n";
427 fputs(usagemsg
,stderr
);
430 int main(int argc
,char **argv
)
432 char *ofilename
= "aout.rdx";
433 long relocateaddr
= -1; /* -1 if no relocation is to occur */
434 int execute
= 0; /* 1 to execute after linking, 0 otherwise */
435 int procsw
= 1; /* set to 0 by '--' */
443 /* process command line switches, and add modules specified to linked list
444 of modules, keeping track of total memory required to load them */
446 while(argv
++,--argc
) {
447 if (procsw
&& !strcmp(*argv
,"-h")) { /* Help command */
450 else if (procsw
&& !strcmp(*argv
,"-r")) {
451 printf("ldrdf version %s (%s) (%s)\n",LDRDF_VERSION
,_RDOFF_H
,
452 sizeof(int) == 2 ? "16 bit" : "32 bit");
455 else if (procsw
&& !strcmp(*argv
,"-o")) {
459 fprintf(stderr
,"ldrdf: -o and -x switches incompatible\n");
462 if (verbose
> 1) printf("output filename set to '%s'\n",ofilename
);
464 else if (procsw
&& !strcmp(*argv
,"-x")) {
466 if (verbose
> 1) printf("will execute linked object\n");
468 else if (procsw
&& !strcmp(*argv
,"-a")) {
469 relocateaddr
= readnum(*++argv
,&tmp
);
472 fprintf(stderr
,"ldrdf: error in parameter to '-a' switch: '%s'\n",
477 fprintf(stderr
,"ldrdf: -a and -x switches incompatible\n");
480 if (verbose
) printf("will relocate to %08lx\n",relocateaddr
);
482 else if (procsw
&& !strcmp(*argv
,"-v")) {
484 if (verbose
== 1) printf("verbose mode selected\n");
486 else if (procsw
&& !strcmp(*argv
,"-p")) {
487 align
= readnum(*++argv
,&tmp
);
490 fprintf(stderr
,"ldrdf: error in parameter to '-p' switch: '%s'\n",
494 if (align
!= 1 && align
!= 2 && align
!= 4 && align
!= 8 && align
!= 16
495 && align
!= 32 && align
!= 256) {
496 fprintf(stderr
,"ldrdf: %d is an invalid alignment factor - must be"
497 "1,2,4,8,16 or 256\n",align
);
500 if (verbose
> 1) printf("alignment %d selected\n",align
);
502 else if (procsw
&& !strcmp(*argv
,"--")) {
505 else { /* is a filename */
506 if (verbose
> 1) printf("processing module %s\n",*argv
);
511 /* we should be scanning for unresolved references, and removing
512 unreferenced modules from the list of modules here, so that
513 we know about the final size once libraries have been linked in */
515 load_segments(); /* having calculated size of reqd segments, load
516 each rdoff module's segments into memory */
518 build_symbols(); /* build a global symbol table...
519 perhaps this should be done before load_segs? */
521 link_segments(); /* step through each module's header, and resolve
522 references to the global symbol table.
523 This also does local address fixups. */
526 fprintf(stderr
,"ldrdf: there were errors - aborted\n");
530 fprintf(stderr
,"ldrdf: module execution not yet supported\n");
533 if (relocateaddr
!= -1) {
534 fprintf(stderr
,"ldrdf: static relocation not yet supported\n");
538 write_output(ofilename
);