NASM 0.91
[nasm/avx512.git] / rdoff / ldrdf.c
blobce86b7e61212a7cc257fe50c61df6196b300c108
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 libaries (.a files - requires a 'ranlib' type utility)
16 * -s option to strip resolved symbols from exports.
19 #include <stdio.h>
20 #include <stdlib.h>
22 #include "nasm.h"
23 #include "rdoff.h"
24 #include "nasmlib.h"
25 #include "symtab.h"
26 #include "collectn.h"
28 #define LDRDF_VERSION "0.11"
30 /* global variables - those to set options: */
32 int verbose = 0; /* reflects setting of command line switch */
33 int align = 16;
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 */
39 struct modulenode {
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;
61 if (! modules) {
62 modules = malloc(sizeof(struct modulenode));
63 lastmodule = modules;
64 prev = NULL;
66 else {
67 lastmodule->next = malloc(sizeof(struct modulenode));
68 prev = lastmodule;
69 lastmodule = lastmodule->next;
72 if (! lastmodule) {
73 fputs("ldrdf: not enough memory\n",stderr);
74 exit(1);
77 if (rdfopen(&lastmodule->f,filename)) {
78 rdfperror("ldrdf",filename);
79 exit(1);
82 lastmodule->header = NULL; /* header hasn't been loaded */
83 lastmodule->name = filename;
84 lastmodule->next = NULL;
86 if (prev) {
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);
94 else {
95 lastmodule->coderel = 0;
96 lastmodule->datarel = 0;
99 if (verbose)
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
110 char *text,*data;
111 long textlength,datalength,bsslength;
113 void load_segments(void)
115 struct modulenode *mod;
117 if (!modules) {
118 fprintf(stderr,"ldrdf: nothing to do\n");
119 exit(0);
121 if (!lastmodule) {
122 fprintf(stderr,"ldrdf: panic: module list exists, but lastmodule=NULL\n");
123 exit(3);
126 if (verbose)
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
132 platforms... */
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);
139 exit(1);
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");
148 exit(1);
151 mod = modules;
152 while (mod) { /* load the segments for each module */
153 mod->header = malloc(mod->f.header_len);
154 if (!mod->header) {
155 fprintf(stderr,"ldrdf: out of memory\n");
156 exit(1);
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);
162 exit(1);
164 rdfclose(&mod->f); /* close file; segments remain */
165 mod = mod->next;
169 /* build_symbols() step through each module's header, and locate
170 * exported symbols, placing them in a global table
173 void build_symbols()
175 struct modulenode *mod;
176 rdfheaderrec *r;
177 symtabEnt e;
178 long bssloc,cbBss;
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;
189 cbBss = 0;
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 */
204 e.flags = 0;
205 e.name = malloc(strlen(r->e.label) + 1);
206 if (! e.name)
208 fprintf(stderr,"ldrdf: out of memory\n");
209 exit(1);
211 strcpy(e.name,r->e.label);
212 symtabInsert(symtab,&e);
214 bssloc += cbBss;
216 if (verbose)
218 symtabDump(symtab,stdout);
219 printf("BSS length = %ld bytes\n\n",bssloc);
221 bsslength = 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;
231 Collection imports;
232 symtabEnt *s;
233 long rel,relto = 0; /* placate gcc */
234 char *seg;
235 rdfheaderrec *r;
236 int bRelative;
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))) {
246 switch(r->type) {
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;
253 else
254 bRelative = 0; /* non-relative - need to relocate
255 * at load time */
257 /* calculate absolute offset of reference, not rel to beginning of
258 segment */
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
264 otherwise. */
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);
271 if (!s) {
272 fprintf(stderr,"ldrdf: link to undefined segment %04x in"
273 " %s:%d\n", r->r.refseg,mod->name,r->r.segment);
274 errors = 1;
275 break;
277 rel = s->offset;
279 r->r.refseg = s->segment; /* change referred segment,
280 so that new header is
281 correct */
284 if (bRelative) /* Relative - subtract current segment start */
285 rel -= relto;
286 else
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;
294 else {
295 fprintf(stderr,"ldrdf: relocation in unknown segment %d in "
296 "%s\n", r->r.segment,mod->name);
297 errors = 1;
298 break;
301 /* Add the relocation factor to the datum specified: */
303 if (verbose >= 3)
304 printf(" - relocating %d:%08lx by %08lx\n",r->r.segment,
305 r->r.offset,rel);
307 /**** The following code is non-portable. Rewrite it... ****/
308 switch(r->r.length) {
309 case 1:
310 seg[r->r.offset] += (char) rel;
311 break;
312 case 2:
313 *(int16 *)(seg + r->r.offset) += (int16) rel;
314 break;
315 case 4:
316 *(long *)(seg + r->r.offset) += rel;
317 break;
319 break;
321 case 2: /* import record */
322 s = symtabFind(symtab, r->i.label);
323 if (s == NULL) {
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);
327 errors = 1;
329 else
331 *colln(&imports,r->i.segment - 2) = s;
332 if (verbose >= 2)
333 printf("imported %s as %04x\n", r->i.label, r->i.segment);
335 break;
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);
343 break;
345 case 4: /* DLL record */
346 rdfaddheader(newheader,r); /* copy straight to output */
347 break;
350 collection_reset(&imports);
354 /* write_output() write linked program out to a file */
356 void write_output(char *filename)
358 FILE * fp;
359 rdfheaderrec r;
361 fp = fopen(filename,"wb");
362 if (! fp)
364 fprintf(stderr,"ldrdf: could not open '%s' for writing\n",filename);
365 exit(1);
369 /* add BSS length count to header... */
370 if (bsslength)
372 r.type = 5;
373 r.b.amount = bsslength;
374 rdfaddheader(newheader,&r);
377 /* Write header */
378 rdfwriteheader(fp,newheader);
379 rdfdoneheader(newheader);
380 newheader = NULL;
382 /* Write text */
383 if (fwrite(&textlength,1,4,fp) != 4
384 || fwrite(text,1,textlength,fp) !=textlength)
386 fprintf(stderr,"ldrdf: error writing %s\n",filename);
387 exit(1);
390 /* Write data */
391 if (fwrite(&datalength,1,4,fp) != 4 ||
392 fwrite(data,1,datalength,fp) != datalength)
394 fprintf (stderr,"ldrdf: error writing %s\n", filename);
395 exit(1);
397 fclose(fp);
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";
425 void usage(void)
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 '--' */
436 int tmp;
438 if (argc == 1) {
439 usage();
440 exit(1);
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 */
448 usage(); exit(1);
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");
453 exit(1);
455 else if (procsw && !strcmp(*argv,"-o")) {
456 ofilename = *++argv;
457 --argc;
458 if (execute) {
459 fprintf(stderr,"ldrdf: -o and -x switches incompatible\n");
460 exit(1);
462 if (verbose > 1) printf("output filename set to '%s'\n",ofilename);
464 else if (procsw && !strcmp(*argv,"-x")) {
465 execute++;
466 if (verbose > 1) printf("will execute linked object\n");
468 else if (procsw && !strcmp(*argv,"-a")) {
469 relocateaddr = readnum(*++argv,&tmp);
470 --argc;
471 if (tmp) {
472 fprintf(stderr,"ldrdf: error in parameter to '-a' switch: '%s'\n",
473 *argv);
474 exit(1);
476 if (execute) {
477 fprintf(stderr,"ldrdf: -a and -x switches incompatible\n");
478 exit(1);
480 if (verbose) printf("will relocate to %08lx\n",relocateaddr);
482 else if (procsw && !strcmp(*argv,"-v")) {
483 verbose++;
484 if (verbose == 1) printf("verbose mode selected\n");
486 else if (procsw && !strcmp(*argv,"-p")) {
487 align = readnum(*++argv,&tmp);
488 --argc;
489 if (tmp) {
490 fprintf(stderr,"ldrdf: error in parameter to '-p' switch: '%s'\n",
491 *argv);
492 exit(1);
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);
498 exit(1);
500 if (verbose > 1) printf("alignment %d selected\n",align);
502 else if (procsw && !strcmp(*argv,"--")) {
503 procsw = 0;
505 else { /* is a filename */
506 if (verbose > 1) printf("processing module %s\n",*argv);
507 loadmodule(*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. */
525 if (errors) {
526 fprintf(stderr,"ldrdf: there were errors - aborted\n");
527 exit(errors);
529 if (execute) {
530 fprintf(stderr,"ldrdf: module execution not yet supported\n");
531 exit(1);
533 if (relocateaddr != -1) {
534 fprintf(stderr,"ldrdf: static relocation not yet supported\n");
535 exit(1);
538 write_output(ofilename);
539 return 0;