NASM 0.94
[nasm.git] / rdoff / ldrdf.c
blobe2541fa49336e3d33b17f36f493d4a899417ac22
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.
7 */
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
20 * external utility)
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "nasm.h"
28 #include "rdoff.h"
29 #include "nasmlib.h"
30 #include "symtab.h"
31 #include "collectn.h"
32 #include "rdlib.h"
34 #define LDRDF_VERSION "0.30"
36 /* global variables - those to set options: */
38 int verbose = 0; /* reflects setting of command line switch */
39 int align = 16;
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 */
45 struct modulenode {
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
62 symbols */
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;
76 if (! modules) {
77 modules = malloc(sizeof(struct modulenode));
78 lastmodule = modules;
79 prev = NULL;
81 else {
82 lastmodule->next = malloc(sizeof(struct modulenode));
83 prev = lastmodule;
84 lastmodule = lastmodule->next;
87 if (! lastmodule) {
88 fputs("ldrdf: not enough memory\n",stderr);
89 exit(1);
92 if (rdfopen(&lastmodule->f,filename)) {
93 rdfperror("ldrdf",filename);
94 exit(1);
97 lastmodule->header = NULL; /* header hasn't been loaded */
98 lastmodule->name = filename;
99 lastmodule->next = NULL;
101 if (prev) {
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);
109 else {
110 lastmodule->coderel = 0;
111 lastmodule->datarel = 0;
114 if (verbose)
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");
122 exit(1);
125 if (rdfloadseg(&lastmodule->f,RDOFF_HEADER,lastmodule->header))
127 rdfperror("ldrdf",filename);
128 exit(1);
132 /* load_library add a library to list of libraries to search
133 * for undefined symbols
136 void load_library(char * name)
138 if (verbose)
139 printf("adding library %s to search path\n",name);
141 if (! lastlib) {
142 lastlib = libraries = malloc(sizeof(struct librarynode));
144 else
146 lastlib->next = malloc(sizeof(struct librarynode));
147 lastlib = lastlib->next;
150 if (! lastlib) {
151 fprintf(stderr, "ldrdf: out of memory\n");
152 exit(1);
154 strcpy (lastlib->name = malloc (1+strlen(name)), name);
155 lastlib->fp = NULL;
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
165 long bsslength;
167 void mod_addsymbols(struct modulenode * mod)
169 rdfheaderrec *r;
170 symtabEnt e;
171 long cbBss;
173 mod->bssrel = bsslength;
174 cbBss = 0;
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 */
190 e.flags = 0;
191 e.name = malloc(strlen(r->e.label) + 1);
192 if (! e.name)
194 fprintf(stderr,"ldrdf: out of memory\n");
195 exit(1);
197 strcpy(e.name,r->e.label);
198 symtabInsert(symtab,&e);
200 bsslength += cbBss;
203 void build_symbols()
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 );
217 if (verbose)
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
228 * to load. */
230 void scan_libraries(void)
232 struct modulenode * mod, * nm;
233 struct librarynode * lib;
234 rdfheaderrec * r;
235 int found;
236 char * tmp;
238 if (verbose) printf("Scanning libraries for unresolved symbols...\n");
240 mod = modules;
242 while (mod)
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
253 the libraries now */
254 if (verbose >= 2) {
255 printf("undefined symbol '%s'...",r->i.label);
256 fflush(stdout);
259 lib = libraries;
260 found = 0;
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 */
273 if (! nm) {
274 fprintf(stderr,"ldrdf: out of memory\n");
275 exit(1);
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);
290 if (! nm->header)
292 fprintf(stderr,"ldrdf: out of memory\n");
293 exit(1);
296 if (rdfloadseg(&nm->f,RDOFF_HEADER,nm->header))
298 rdfperror("ldrdf",nm->name);
299 exit(1);
302 nm->next = NULL;
303 found = 1;
304 lastmodule->next = nm;
305 lastmodule = nm;
307 if (verbose)
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 */
314 mod_addsymbols(nm);
316 else
318 if (rdl_error) {
319 rdl_perror("ldrdf",lib->name);
320 exit(1);
322 free(nm);
324 lib = lib->next;
326 free(tmp);
327 if (!found && verbose >= 2) printf("not found\n");
329 mod = mod->next;
333 /* load_segments() allocates memory for & loads the code & data segs
334 * from the RDF modules
337 char *text,*data;
338 long textlength,datalength;
340 void load_segments(void)
342 struct modulenode *mod;
344 if (!modules) {
345 fprintf(stderr,"ldrdf: nothing to do\n");
346 exit(0);
348 if (!lastmodule) {
349 fprintf(stderr,"ldrdf: panic: module list exists, but lastmodule=NULL\n");
350 exit(3);
353 if (verbose)
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
359 platforms... */
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);
366 exit(1);
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");
375 exit(1);
378 mod = modules;
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);
384 exit(1);
386 rdfclose(&mod->f); /* close file; segments remain */
387 mod = mod->next;
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;
398 Collection imports;
399 symtabEnt *s;
400 long rel,relto;
401 char *seg;
402 rdfheaderrec *r;
403 int bRelative;
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);
414 switch(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;
421 else
422 bRelative = 0; /* non-relative - need to relocate
423 * at load time */
425 /* calculate absolute offset of reference, not rel to beginning of
426 segment */
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
432 otherwise. */
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);
439 if (!s) {
440 fprintf(stderr,"ldrdf: link to undefined segment %04x in"
441 " %s:%d\n", r->r.refseg,mod->name,r->r.segment);
442 errors = 1;
443 break;
445 rel = s->offset;
447 r->r.refseg = s->segment; /* change referred segment,
448 so that new header is
449 correct */
452 if (bRelative) /* Relative - subtract current segment start */
453 rel -= relto;
454 else
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;
462 else {
463 fprintf(stderr,"ldrdf: relocation in unknown segment %d in "
464 "%s\n", r->r.segment,mod->name);
465 errors = 1;
466 break;
469 /* Add the relocation factor to the datum specified: */
471 if (verbose >= 3)
472 printf(" - relocating %d:%08lx by %08lx\n",r->r.segment,
473 r->r.offset,rel);
475 /**** The following code is non-portable. Rewrite it... ****/
476 switch(r->r.length) {
477 case 1:
478 seg[r->r.offset] += (char) rel;
479 break;
480 case 2:
481 *(int16 *)(seg + r->r.offset) += (int16) rel;
482 break;
483 case 4:
484 *(long *)(seg + r->r.offset) += rel;
485 break;
487 break;
489 case 2: /* import record */
490 s = symtabFind(symtab, r->i.label);
491 if (s == NULL) {
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);
495 errors = 1;
497 else
499 *colln(&imports,r->i.segment - 2) = s;
500 if (verbose >= 2)
501 printf("imported %s as %04x\n", r->i.label, r->i.segment);
503 break;
505 case 3: /* export; dump to output new version */
506 s = symtabFind(symtab, r->e.label);
507 if (! s) {
508 fprintf(stderr,"ldrdf: internal error - undefined symbol %s "
509 "exported in header of '%s'\n",r->e.label,mod->name);
510 continue;
512 r->e.offset = s->offset;
513 rdfaddheader(newheader,r);
514 break;
516 case 4: /* DLL record */
517 rdfaddheader(newheader,r); /* copy straight to output */
518 break;
521 if (rdf_errno != 0) {
522 rdfperror("ldrdf",mod->name);
523 exit(1);
525 collection_reset(&imports);
529 /* write_output() write linked program out to a file */
531 void write_output(char *filename)
533 FILE * fp;
534 rdfheaderrec r;
536 if (verbose) printf("writing output to '%s'\n",filename);
538 fp = fopen(filename,"wb");
539 if (! fp)
541 fprintf(stderr,"ldrdf: could not open '%s' for writing\n",filename);
542 exit(1);
546 /* add BSS length count to header... */
547 if (bsslength)
549 r.type = 5;
550 r.b.amount = bsslength;
551 rdfaddheader(newheader,&r);
554 /* Write header */
555 rdfwriteheader(fp,newheader);
556 rdfdoneheader(newheader);
557 newheader = NULL;
559 /* Write text */
560 if (fwrite(&textlength,1,4,fp) != 4
561 || fwrite(text,1,textlength,fp) !=textlength)
563 fprintf(stderr,"ldrdf: error writing %s\n",filename);
564 exit(1);
567 /* Write data */
568 if (fwrite(&datalength,1,4,fp) != 4 ||
569 fwrite(data,1,datalength,fp) != datalength)
571 fprintf (stderr,"ldrdf: error writing %s\n", filename);
572 exit(1);
574 fclose(fp);
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";
605 void usage(void)
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 '--' */
616 int tmp;
618 if (argc == 1) {
619 usage();
620 exit(1);
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 */
628 usage(); exit(1);
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");
633 exit(1);
635 else if (procsw && !strcmp(*argv,"-o")) {
636 ofilename = *++argv;
637 --argc;
638 if (execute) {
639 fprintf(stderr,"ldrdf: -o and -x switches incompatible\n");
640 exit(1);
642 if (verbose > 1) printf("output filename set to '%s'\n",ofilename);
644 else if (procsw && !strcmp(*argv,"-x")) {
645 execute++;
646 if (verbose > 1) printf("will execute linked object\n");
648 else if (procsw && !strcmp(*argv,"-a")) {
649 relocateaddr = readnum(*++argv,&tmp);
650 --argc;
651 if (tmp) {
652 fprintf(stderr,"ldrdf: error in parameter to '-a' switch: '%s'\n",
653 *argv);
654 exit(1);
656 if (execute) {
657 fprintf(stderr,"ldrdf: -a and -x switches incompatible\n");
658 exit(1);
660 if (verbose) printf("will relocate to %08lx\n",relocateaddr);
662 else if (procsw && !strcmp(*argv,"-v")) {
663 verbose++;
664 if (verbose == 1) printf("verbose mode selected\n");
666 else if (procsw && !strcmp(*argv,"-p")) {
667 align = readnum(*++argv,&tmp);
668 --argc;
669 if (tmp) {
670 fprintf(stderr,"ldrdf: error in parameter to '-p' switch: '%s'\n",
671 *argv);
672 exit(1);
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);
678 exit(1);
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,"--")) {
686 procsw = 0;
688 else { /* is a filename */
689 if (verbose > 1) printf("processing module %s\n",*argv);
690 loadmodule(*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
702 are loaded */
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. */
711 if (errors) {
712 fprintf(stderr,"ldrdf: there were errors - aborted\n");
713 exit(errors);
715 if (execute) {
716 fprintf(stderr,"ldrdf: module execution not yet supported\n");
717 exit(1);
719 if (relocateaddr != -1) {
720 fprintf(stderr,"ldrdf: static relocation not yet supported\n");
721 exit(1);
724 write_output(ofilename);
725 return 0;