NASM 0.98.08
[nasm.git] / rdoff / ldrdf1.c
blob9e4a215de52b8658c952482fff32b5852d20fb2a
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 "rdoff.h"
28 #include "nasmlib.h"
29 #include "symtab.h"
30 #include "collectn.h"
31 #include "rdlib.h"
33 #define LDRDF_VERSION "0.30"
35 /* global variables - those to set options: */
37 int verbose = 0; /* reflects setting of command line switch */
38 int align = 16;
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 */
44 struct modulenode {
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
61 symbols */
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;
75 if (! modules) {
76 modules = malloc(sizeof(struct modulenode));
77 lastmodule = modules;
78 prev = NULL;
80 else {
81 lastmodule->next = malloc(sizeof(struct modulenode));
82 prev = lastmodule;
83 lastmodule = lastmodule->next;
86 if (! lastmodule) {
87 fputs("ldrdf: not enough memory\n",stderr);
88 exit(1);
91 if (rdfopen(&lastmodule->f,filename)) {
92 rdfperror("ldrdf",filename);
93 exit(1);
96 lastmodule->header = NULL; /* header hasn't been loaded */
97 lastmodule->name = filename;
98 lastmodule->next = NULL;
100 if (prev) {
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);
108 else {
109 lastmodule->coderel = 0;
110 lastmodule->datarel = 0;
113 if (verbose)
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");
121 exit(1);
124 if (rdfloadseg(&lastmodule->f,RDOFF_HEADER,lastmodule->header))
126 rdfperror("ldrdf",filename);
127 exit(1);
131 /* load_library add a library to list of libraries to search
132 * for undefined symbols
135 void load_library(char * name)
137 if (verbose)
138 printf("adding library %s to search path\n",name);
140 if (! lastlib) {
141 lastlib = libraries = malloc(sizeof(struct librarynode));
143 else
145 lastlib->next = malloc(sizeof(struct librarynode));
146 lastlib = lastlib->next;
149 if (! lastlib) {
150 fprintf(stderr, "ldrdf: out of memory\n");
151 exit(1);
153 strcpy (lastlib->name = malloc (1+strlen(name)), name);
154 lastlib->fp = NULL;
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
164 long bsslength;
166 void mod_addsymbols(struct modulenode * mod)
168 rdfheaderrec *r;
169 symtabEnt e;
170 long cbBss;
172 mod->bssrel = bsslength;
173 cbBss = 0;
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 */
189 e.flags = 0;
190 e.name = malloc(strlen(r->e.label) + 1);
191 if (! e.name)
193 fprintf(stderr,"ldrdf: out of memory\n");
194 exit(1);
196 strcpy(e.name,r->e.label);
197 symtabInsert(symtab,&e);
199 bsslength += cbBss;
202 void build_symbols()
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 );
216 if (verbose)
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
227 * to load. */
229 void scan_libraries(void)
231 struct modulenode * mod, * nm;
232 struct librarynode * lib;
233 rdfheaderrec * r;
234 int found;
235 char * tmp;
237 if (verbose) printf("Scanning libraries for unresolved symbols...\n");
239 mod = modules;
241 while (mod)
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
252 the libraries now */
253 if (verbose >= 2) {
254 printf("undefined symbol '%s'...",r->i.label);
255 fflush(stdout);
258 lib = libraries;
259 found = 0;
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 */
272 if (! nm) {
273 fprintf(stderr,"ldrdf: out of memory\n");
274 exit(1);
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);
289 if (! nm->header)
291 fprintf(stderr,"ldrdf: out of memory\n");
292 exit(1);
295 if (rdfloadseg(&nm->f,RDOFF_HEADER,nm->header))
297 rdfperror("ldrdf",nm->name);
298 exit(1);
301 nm->next = NULL;
302 found = 1;
303 lastmodule->next = nm;
304 lastmodule = nm;
306 if (verbose)
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 */
313 mod_addsymbols(nm);
315 else
317 if (rdl_error) {
318 rdl_perror("ldrdf",lib->name);
319 exit(1);
321 free(nm);
323 lib = lib->next;
325 free(tmp);
326 if (!found && verbose >= 2) printf("not found\n");
328 mod = mod->next;
332 /* load_segments() allocates memory for & loads the code & data segs
333 * from the RDF modules
336 char *text,*data;
337 long textlength,datalength;
339 void load_segments(void)
341 struct modulenode *mod;
343 if (!modules) {
344 fprintf(stderr,"ldrdf: nothing to do\n");
345 exit(0);
347 if (!lastmodule) {
348 fprintf(stderr,"ldrdf: panic: module list exists, but lastmodule=NULL\n");
349 exit(3);
352 if (verbose)
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
358 platforms... */
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);
365 exit(1);
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");
374 exit(1);
377 mod = modules;
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);
383 exit(1);
385 rdfclose(&mod->f); /* close file; segments remain */
386 mod = mod->next;
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;
397 Collection imports;
398 symtabEnt *s;
399 long rel,relto;
400 char *seg;
401 rdfheaderrec *r;
402 int bRelative;
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);
413 switch(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;
420 else
422 bRelative = 0; /* non-relative - need to relocate
423 * at load time */
424 relto = 0; /* placate optimiser warnings */
427 /* calculate absolute offset of reference, not rel to beginning of
428 segment */
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
434 otherwise. */
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);
441 if (!s) {
442 fprintf(stderr,"ldrdf: link to undefined segment %04x in"
443 " %s:%d\n", r->r.refseg,mod->name,r->r.segment);
444 errors = 1;
445 break;
447 rel = s->offset;
449 r->r.refseg = s->segment; /* change referred segment,
450 so that new header is
451 correct */
454 if (bRelative) /* Relative - subtract current segment start */
455 rel -= relto;
456 else
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;
464 else {
465 fprintf(stderr,"ldrdf: relocation in unknown segment %d in "
466 "%s\n", r->r.segment,mod->name);
467 errors = 1;
468 break;
471 /* Add the relocation factor to the datum specified: */
473 if (verbose >= 3)
474 printf(" - relocating %d:%08lx by %08lx\n",r->r.segment,
475 r->r.offset,rel);
477 /**** The following code is non-portable. Rewrite it... ****/
478 switch(r->r.length) {
479 case 1:
480 seg[r->r.offset] += (char) rel;
481 break;
482 case 2:
483 *(int16 *)(seg + r->r.offset) += (int16) rel;
484 break;
485 case 4:
486 *(long *)(seg + r->r.offset) += rel;
487 break;
489 break;
491 case 2: /* import record */
492 s = symtabFind(symtab, r->i.label);
493 if (s == NULL) {
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);
497 errors = 1;
499 else
501 *colln(&imports,r->i.segment - 2) = s;
502 if (verbose >= 2)
503 printf("imported %s as %04x\n", r->i.label, r->i.segment);
505 break;
507 case 3: /* export; dump to output new version */
508 s = symtabFind(symtab, r->e.label);
509 if (! s) {
510 fprintf(stderr,"ldrdf: internal error - undefined symbol %s "
511 "exported in header of '%s'\n",r->e.label,mod->name);
512 continue;
514 r->e.offset = s->offset;
515 rdfaddheader(newheader,r);
516 break;
518 case 4: /* DLL record */
519 rdfaddheader(newheader,r); /* copy straight to output */
520 break;
523 if (rdf_errno != 0) {
524 rdfperror("ldrdf",mod->name);
525 exit(1);
527 collection_reset(&imports);
531 /* write_output() write linked program out to a file */
533 void write_output(char *filename)
535 FILE * fp;
536 rdfheaderrec r;
538 if (verbose) printf("writing output to '%s'\n",filename);
540 fp = fopen(filename,"wb");
541 if (! fp)
543 fprintf(stderr,"ldrdf: could not open '%s' for writing\n",filename);
544 exit(1);
548 /* add BSS length count to header... */
549 if (bsslength)
551 r.type = 5;
552 r.b.amount = bsslength;
553 rdfaddheader(newheader,&r);
556 /* Write header */
557 rdfwriteheader(fp,newheader);
558 rdfdoneheader(newheader);
559 newheader = NULL;
561 /* Write text */
562 if (fwrite(&textlength,1,4,fp) != 4
563 || fwrite(text,1,textlength,fp) !=textlength)
565 fprintf(stderr,"ldrdf: error writing %s\n",filename);
566 exit(1);
569 /* Write data */
570 if (fwrite(&datalength,1,4,fp) != 4 ||
571 fwrite(data,1,datalength,fp) != datalength)
573 fprintf (stderr,"ldrdf: error writing %s\n", filename);
574 exit(1);
576 fclose(fp);
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";
607 void usage(void)
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 '--' */
618 int tmp;
620 if (argc == 1) {
621 usage();
622 exit(1);
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 */
630 usage(); exit(1);
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");
635 exit(1);
637 else if (procsw && !strcmp(*argv,"-o")) {
638 ofilename = *++argv;
639 --argc;
640 if (execute) {
641 fprintf(stderr,"ldrdf: -o and -x switches incompatible\n");
642 exit(1);
644 if (verbose > 1) printf("output filename set to '%s'\n",ofilename);
646 else if (procsw && !strcmp(*argv,"-x")) {
647 execute++;
648 if (verbose > 1) printf("will execute linked object\n");
650 else if (procsw && !strcmp(*argv,"-a")) {
651 relocateaddr = readnum(*++argv,&tmp);
652 --argc;
653 if (tmp) {
654 fprintf(stderr,"ldrdf: error in parameter to '-a' switch: '%s'\n",
655 *argv);
656 exit(1);
658 if (execute) {
659 fprintf(stderr,"ldrdf: -a and -x switches incompatible\n");
660 exit(1);
662 if (verbose) printf("will relocate to %08lx\n",relocateaddr);
664 else if (procsw && !strcmp(*argv,"-v")) {
665 verbose++;
666 if (verbose == 1) printf("verbose mode selected\n");
668 else if (procsw && !strcmp(*argv,"-p")) {
669 align = readnum(*++argv,&tmp);
670 --argc;
671 if (tmp) {
672 fprintf(stderr,"ldrdf: error in parameter to '-p' switch: '%s'\n",
673 *argv);
674 exit(1);
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);
680 exit(1);
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,"--")) {
688 procsw = 0;
690 else { /* is a filename */
691 if (verbose > 1) printf("processing module %s\n",*argv);
692 loadmodule(*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
704 are loaded */
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. */
713 if (errors) {
714 fprintf(stderr,"ldrdf: there were errors - aborted\n");
715 exit(errors);
717 if (execute) {
718 fprintf(stderr,"ldrdf: module execution not yet supported\n");
719 exit(1);
721 if (relocateaddr != -1) {
722 fprintf(stderr,"ldrdf: static relocation not yet supported\n");
723 exit(1);
726 write_output(ofilename);
727 return 0;