travis: test avx512f should now pass
[nasm.git] / rdoff / ldrdf.c
bloba78c45046a3eb77934b369ecf3992298b1a11fb3
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2014 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * ldrdf.c - RDOFF Object File linker/loader main program.
39 * TODO:
40 * - enhance search of required export symbols in libraries (now depends
41 * on modules order in library)
42 * - keep a cache of symbol names in each library module so
43 * we don't have to constantly recheck the file
44 * - general performance improvements
46 * BUGS & LIMITATIONS: this program doesn't support multiple code, data
47 * or bss segments, therefore for 16 bit programs whose code, data or BSS
48 * segment exceeds 64K in size, it will not work. This program probably
49 * won't work if compiled by a 16 bit compiler. Try DJGPP if you're running
50 * under DOS. '#define STINGY_MEMORY' may help a little.
53 #include "compiler.h"
55 #include <stdio.h>
56 #include <stdlib.h>
58 #include "rdfutils.h"
59 #include "symtab.h"
60 #include "collectn.h"
61 #include "rdlib.h"
62 #include "segtab.h"
63 #include "nasmlib.h"
65 #define LDRDF_VERSION "1.08"
67 /* #define STINGY_MEMORY */
69 /* =======================================================================
70 * Types & macros that are private to this program
73 struct segment_infonode {
74 int dest_seg; /* output segment to be placed into, -1 to
75 skip linking this segment */
76 int32_t reloc; /* segment's relocation factor */
79 struct modulenode {
80 rdffile f; /* the RDOFF file structure */
81 struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
82 with each segment? */
83 void *header;
84 char *name;
85 struct modulenode *next;
86 int32_t bss_reloc;
89 #include "ldsegs.h"
91 /* ==========================================================================
92 * Function prototypes of private utility functions
95 void processmodule(const char *filename, struct modulenode *mod);
96 int allocnewseg(uint16_t type, uint16_t reserved);
97 int findsegment(uint16_t type, uint16_t reserved);
98 void symtab_add(const char *symbol, int segment, int32_t offset);
99 int symtab_get(const char *symbol, int *segment, int32_t *offset);
101 /* =========================================================================
102 * Global data structures.
105 /* a linked list of modules that will be included in the output */
106 struct modulenode *modules = NULL;
107 struct modulenode *lastmodule = NULL;
109 /* a linked list of libraries to be searched for unresolved imported symbols */
110 struct librarynode *libraries = NULL;
111 struct librarynode *lastlib = NULL;
113 /* the symbol table */
114 void *symtab = NULL;
116 /* objects search path */
117 char *objpath = NULL;
119 /* libraries search path */
120 char *libpath = NULL;
122 /* file to embed as a generic record */
123 char *generic_rec_file = NULL;
125 /* module name to be added at the beginning of output file */
126 char *modname_specified = NULL;
128 /* the header of the output file, built up stage by stage */
129 rdf_headerbuf *newheader = NULL;
131 /* The current state of segment allocation, including information about
132 * which output segment numbers have been allocated, and their types and
133 * amount of data which has already been allocated inside them.
135 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
136 int nsegs = 0;
137 int32_t bss_length;
139 /* global options which affect how the program behaves */
140 struct ldrdfoptions {
141 int verbose;
142 int align;
143 int dynalink;
144 int strip;
145 int respfile;
146 int stderr_redir;
147 int objpath;
148 int libpath;
149 } options;
151 int errorcount = 0; /* determines main program exit status */
153 /* =========================================================================
154 * Utility functions
158 * initsegments()
160 * sets up segments 0, 1, and 2, the initial code data and bss segments
162 static void initsegments(void)
164 nsegs = 3;
165 outputseg[0].type = 1;
166 outputseg[0].number = 0;
167 outputseg[0].reserved = 0;
168 outputseg[0].length = 0;
169 outputseg[1].type = 2;
170 outputseg[1].number = 1;
171 outputseg[1].reserved = 0;
172 outputseg[1].length = 0;
173 outputseg[2].type = 0xFFFF; /* reserved segment type */
174 outputseg[2].number = 2;
175 outputseg[2].reserved = 0;
176 outputseg[2].length = 0;
177 bss_length = 0;
181 * loadmodule()
183 * Determine the characteristics of a module, and decide what to do with
184 * each segment it contains (including determining destination segments and
185 * relocation factors for segments that are kept).
187 static void loadmodule(const char *filename)
189 if (options.verbose)
190 printf("loading `%s'\n", filename);
192 /* allocate a new module entry on the end of the modules list */
193 if (!modules) {
194 modules = nasm_malloc(sizeof(*modules));
195 lastmodule = modules;
196 } else {
197 lastmodule->next = nasm_malloc(sizeof(*modules));
198 lastmodule = lastmodule->next;
201 if (!lastmodule) {
202 fprintf(stderr, "ldrdf: out of memory\n");
203 exit(1);
206 /* open the file using 'rdfopen', which returns nonzero on error */
207 if (rdfopen(&lastmodule->f, filename) != 0) {
208 rdfperror("ldrdf", filename);
209 exit(1);
213 * store information about the module, and determine what segments
214 * it contains, and what we should do with them (determine relocation
215 * factor if we decide to keep them)
217 lastmodule->header = NULL;
218 lastmodule->name = nasm_strdup(filename);
219 lastmodule->next = NULL;
221 processmodule(filename, lastmodule);
225 * processmodule()
227 * step through each segment, determine what exactly we're doing with
228 * it, and if we intend to keep it, determine (a) which segment to
229 * put it in and (b) whereabouts in that segment it will end up.
230 * (b) is fairly easy, because we're now keeping track of how big each
231 * segment in our output file is...
233 void processmodule(const char *filename, struct modulenode *mod)
235 struct segconfig sconf;
236 int seg, outseg;
237 void *header;
238 rdfheaderrec *hr;
239 int32_t bssamount = 0;
240 int bss_was_referenced = 0;
242 memset(&sconf, 0, sizeof sconf);
244 for (seg = 0; seg < mod->f.nsegs; seg++) {
246 * get the segment configuration for this type from the segment
247 * table. getsegconfig() is a macro, defined in ldsegs.h.
249 getsegconfig(sconf, mod->f.seg[seg].type);
251 if (options.verbose > 1) {
252 printf("%s %04x [%04x:%10s] ", filename,
253 mod->f.seg[seg].number, mod->f.seg[seg].type,
254 sconf.typedesc);
257 * sconf->dowhat tells us what to do with a segment of this type.
259 switch (sconf.dowhat) {
260 case SEG_IGNORE:
262 * Set destination segment to -1, to indicate that this segment
263 * should be ignored for the purpose of output, ie it is left
264 * out of the linked executable.
266 mod->seginfo[seg].dest_seg = -1;
267 if (options.verbose > 1)
268 printf("IGNORED\n");
269 break;
271 case SEG_NEWSEG:
273 * The configuration tells us to create a new segment for
274 * each occurrence of this segment type.
276 outseg = allocnewseg(sconf.mergetype,
277 mod->f.seg[seg].reserved);
278 mod->seginfo[seg].dest_seg = outseg;
279 mod->seginfo[seg].reloc = 0;
280 outputseg[outseg].length = mod->f.seg[seg].length;
281 if (options.verbose > 1)
282 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
283 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
284 break;
286 case SEG_MERGE:
288 * The configuration tells us to merge the segment with
289 * a previously existing segment of type 'sconf.mergetype',
290 * if one exists. Otherwise a new segment is created.
291 * This is handled transparently by 'findsegment()'.
293 outseg = findsegment(sconf.mergetype,
294 mod->f.seg[seg].reserved);
295 mod->seginfo[seg].dest_seg = outseg;
298 * We need to add alignment to these segments.
300 if (outputseg[outseg].length % options.align != 0)
301 outputseg[outseg].length +=
302 options.align -
303 (outputseg[outseg].length % options.align);
305 mod->seginfo[seg].reloc = outputseg[outseg].length;
306 outputseg[outseg].length += mod->f.seg[seg].length;
308 if (options.verbose > 1)
309 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
310 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
316 * extract symbols from the header, and dump them into the
317 * symbol table
319 header = nasm_malloc(mod->f.header_len);
320 if (!header) {
321 fprintf(stderr, "ldrdf: not enough memory\n");
322 exit(1);
324 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
325 rdfperror("ldrdf", filename);
326 exit(1);
329 while ((hr = rdfgetheaderrec(&mod->f))) {
330 switch (hr->type) {
331 case RDFREC_IMPORT: /* imported symbol */
332 case RDFREC_FARIMPORT:
333 /* Define with seg = -1 */
334 symtab_add(hr->i.label, -1, 0);
335 break;
337 case RDFREC_GLOBAL:{ /* exported symbol */
338 int destseg;
339 int32_t destreloc;
341 if (hr->e.segment == 2) {
342 bss_was_referenced = 1;
343 destreloc = bss_length;
344 if (destreloc % options.align != 0)
345 destreloc +=
346 options.align - (destreloc % options.align);
347 destseg = 2;
348 } else {
349 if ((destseg =
350 mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
351 continue;
352 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
354 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
355 break;
358 case RDFREC_BSS: /* BSS reservation */
360 * first, amalgamate all BSS reservations in this module
361 * into one, because we allow this in the output format.
363 bssamount += hr->b.amount;
364 break;
366 case RDFREC_COMMON:{ /* Common variable */
367 symtabEnt *ste = symtabFind(symtab, hr->c.label);
369 /* Is the symbol already in the table? */
370 if (ste)
371 break;
373 /* Align the variable */
374 if (bss_length % hr->c.align != 0)
375 bss_length += hr->c.align - (bss_length % hr->c.align);
376 if (options.verbose > 1) {
377 printf("%s %04x common '%s' => 0002:%08"PRIx32" (+%04"PRIx32")\n",
378 filename, hr->c.segment, hr->c.label,
379 bss_length, hr->c.size);
382 symtab_add(hr->c.label, 2, bss_length);
383 mod->bss_reloc = bss_length;
384 bss_length += hr->c.size;
385 break;
390 if (bssamount != 0 || bss_was_referenced) {
392 * handle the BSS segment - first pad the existing bss length
393 * to the correct alignment, then store the length in bss_reloc
394 * for this module. Then add this module's BSS length onto
395 * bss_length.
397 if (bss_length % options.align != 0)
398 bss_length += options.align - (bss_length % options.align);
400 mod->bss_reloc = bss_length;
401 if (options.verbose > 1) {
402 printf("%s 0002 [ BSS] => 0002:%08"PRIx32" (+%04"PRIx32")\n",
403 filename, bss_length, bssamount);
405 bss_length += bssamount;
407 #ifdef STINGY_MEMORY
409 * we free the header buffer here, to save memory later.
410 * this isn't efficient, but probably halves the memory usage
411 * of this program...
413 mod->f.header_loc = NULL;
414 nasm_free(header);
416 #endif
421 * Return 1 if a given module is in the list, 0 otherwise.
423 static int lookformodule(const char *name)
425 struct modulenode *curr = modules;
427 while (curr) {
428 if (!strcmp(name, curr->name))
429 return 1;
430 curr = curr->next;
432 return 0;
436 * allocnewseg()
437 * findsegment()
439 * These functions manipulate the array of output segments, and are used
440 * by processmodule(). allocnewseg() allocates a segment in the array,
441 * initialising it to be empty. findsegment() first scans the array for
442 * a segment of the type requested, and if one isn't found allocates a
443 * new one.
445 int allocnewseg(uint16_t type, uint16_t reserved)
447 outputseg[nsegs].type = type;
448 outputseg[nsegs].number = nsegs;
449 outputseg[nsegs].reserved = reserved;
450 outputseg[nsegs].length = 0;
451 outputseg[nsegs].offset = 0;
452 outputseg[nsegs].data = NULL;
454 return nsegs++;
457 int findsegment(uint16_t type, uint16_t reserved)
459 int i;
461 for (i = 0; i < nsegs; i++)
462 if (outputseg[i].type == type)
463 return i;
465 return allocnewseg(type, reserved);
469 * symtab_add()
471 * inserts a symbol into the global symbol table, which associates symbol
472 * names either with addresses, or a marker that the symbol hasn't been
473 * resolved yet, or possibly that the symbol has been defined as
474 * contained in a dynamic [load time/run time] linked library.
476 * segment = -1 => not yet defined
477 * segment = -2 => defined as dll symbol
479 * If the symbol is already defined, and the new segment >= 0, then
480 * if the original segment was < 0 the symbol is redefined, otherwise
481 * a duplicate symbol warning is issued. If new segment == -1, this
482 * routine won't change a previously existing symbol. It will change
483 * to segment = -2 only if the segment was previously < 0.
485 void symtab_add(const char *symbol, int segment, int32_t offset)
487 symtabEnt *ste;
489 ste = symtabFind(symtab, symbol);
490 if (ste) {
491 if (ste->segment >= 0) {
493 * symbol previously defined
495 if (segment < 0)
496 return;
497 fprintf(error_file, "warning: `%s' redefined\n", symbol);
498 return;
502 * somebody wanted the symbol, and put an undefined symbol
503 * marker into the table
505 if (segment == -1)
506 return;
508 * we have more information now - update the symbol's entry
510 ste->segment = segment;
511 ste->offset = offset;
512 ste->flags = 0;
513 return;
516 * this is the first declaration of this symbol
518 ste = nasm_malloc(sizeof(symtabEnt));
519 if (!ste) {
520 fprintf(stderr, "ldrdf: out of memory\n");
521 exit(1);
523 ste->name = nasm_strdup(symbol);
524 ste->segment = segment;
525 ste->offset = offset;
526 ste->flags = 0;
527 symtabInsert(symtab, ste);
531 * symtab_get()
533 * Retrieves the values associated with a symbol. Undefined symbols
534 * are assumed to have -1:0 associated. Returns 1 if the symbol was
535 * successfully located.
537 int symtab_get(const char *symbol, int *segment, int32_t *offset)
539 symtabEnt *ste = symtabFind(symtab, symbol);
540 if (!ste) {
541 *segment = -1;
542 *offset = 0;
543 return 0;
544 } else {
545 *segment = ste->segment;
546 *offset = ste->offset;
547 return 1;
552 * add_library()
554 * checks that a library can be opened and is in the correct format,
555 * then adds it to the linked list of libraries.
557 static void add_library(const char *name)
559 if (rdl_verify(name)) {
560 rdl_perror("ldrdf", name);
561 errorcount++;
562 return;
564 if (!libraries) {
565 lastlib = libraries = nasm_malloc(sizeof(*libraries));
566 if (!libraries) {
567 fprintf(stderr, "ldrdf: out of memory\n");
568 exit(1);
570 } else {
571 lastlib->next = nasm_malloc(sizeof(*libraries));
572 if (!lastlib->next) {
573 fprintf(stderr, "ldrdf: out of memory\n");
574 exit(1);
576 lastlib = lastlib->next;
578 lastlib->next = NULL;
579 if (rdl_open(lastlib, name)) {
580 rdl_perror("ldrdf", name);
581 errorcount++;
582 return;
587 * search_libraries()
589 * scans through the list of libraries, attempting to match symbols
590 * defined in library modules against symbols that are referenced but
591 * not defined (segment = -1 in the symbol table)
593 * returns 1 if any extra library modules are included, indicating that
594 * another pass through the library list should be made (possibly).
596 static int search_libraries(void)
598 struct librarynode *cur;
599 rdffile f;
600 int i;
601 void *header;
602 int segment;
603 int32_t offset;
604 int doneanything = 0, pass = 1, keepfile;
605 rdfheaderrec *hr;
607 cur = libraries;
609 while (cur) {
610 if (options.verbose > 2)
611 printf("scanning library `%s', pass %d...\n", cur->name, pass);
613 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
614 if (pass == 2 && lookformodule(f.name))
615 continue;
617 if (options.verbose > 3)
618 printf(" looking in module `%s'\n", f.name);
620 header = nasm_malloc(f.header_len);
621 if (!header) {
622 fprintf(stderr, "ldrdf: not enough memory\n");
623 exit(1);
625 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
626 rdfperror("ldrdf", f.name);
627 errorcount++;
628 return 0;
631 keepfile = 0;
633 while ((hr = rdfgetheaderrec(&f))) {
634 /* We're only interested in exports, so skip others */
635 if (hr->type != RDFREC_GLOBAL)
636 continue;
639 * If the symbol is marked as SYM_GLOBAL, somebody will be
640 * definitely interested in it..
642 if ((hr->e.flags & SYM_GLOBAL) == 0) {
644 * otherwise the symbol is just public. Find it in
645 * the symbol table. If the symbol isn't defined, we
646 * aren't interested, so go on to the next.
647 * If it is defined as anything but -1, we're also not
648 * interested. But if it is defined as -1, insert this
649 * module into the list of modules to use, and go
650 * immediately on to the next module...
652 if (!symtab_get(hr->e.label, &segment, &offset)
653 || segment != -1)
654 continue;
657 doneanything = 1;
658 keepfile = 1;
661 * as there are undefined symbols, we can assume that
662 * there are modules on the module list by the time
663 * we get here.
665 lastmodule->next = nasm_malloc(sizeof(*lastmodule->next));
666 if (!lastmodule->next) {
667 fprintf(stderr, "ldrdf: not enough memory\n");
668 exit(1);
670 lastmodule = lastmodule->next;
671 memcpy(&lastmodule->f, &f, sizeof(f));
672 lastmodule->name = nasm_strdup(f.name);
673 lastmodule->next = NULL;
674 processmodule(f.name, lastmodule);
675 break;
677 if (!keepfile) {
678 nasm_free(f.name);
679 f.name = NULL;
680 f.fp = NULL;
683 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
684 rdl_perror("ldrdf", cur->name);
686 cur = cur->next;
687 if (cur == NULL && pass == 1) {
688 cur = libraries;
689 pass++;
693 return doneanything;
697 * write_output()
699 * this takes the linked list of modules, and walks through it, merging
700 * all the modules into a single output module, and then writes this to a
701 * file.
703 static void write_output(const char *filename)
705 FILE *f;
706 rdf_headerbuf *rdfheader;
707 struct modulenode *cur;
708 int i, n, availableseg, seg, localseg, isrelative;
709 void *header;
710 rdfheaderrec *hr, newrec;
711 symtabEnt *se;
712 segtab segs;
713 int32_t offset;
714 uint8_t *data;
716 if ((f = fopen(filename, "wb")) == NULL) {
717 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
718 exit(1);
720 if ((rdfheader = rdfnewheader()) == NULL) {
721 fprintf(stderr, "ldrdf: out of memory\n");
722 exit(1);
726 * If '-g' option was given, first record in output file will be a
727 * `generic' record, filled with a given file content.
728 * This can be useful, for example, when constructing multiboot
729 * compliant kernels.
731 if (generic_rec_file) {
732 FILE *ff;
734 if (options.verbose)
735 printf("\nadding generic record from binary file %s\n",
736 generic_rec_file);
738 hr = (rdfheaderrec *) nasm_malloc(sizeof(struct GenericRec));
739 if ((ff = fopen(generic_rec_file, "r")) == NULL) {
740 fprintf(stderr, "ldrdf: couldn't open %s for input\n",
741 generic_rec_file);
742 exit(1);
744 n = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
745 fseek(ff, 0, SEEK_END);
746 if (ftell(ff) > (long)sizeof(hr->g.data)) {
747 fprintf(error_file,
748 "warning: maximum generic record size is %u, "
749 "rest of file ignored\n",
750 (unsigned int)sizeof(hr->g.data));
752 fclose(ff);
754 hr->g.type = RDFREC_GENERIC;
755 hr->g.reclen = n;
756 rdfaddheader(rdfheader, hr);
757 nasm_free(hr);
761 * Add module name record if `-mn' option was given
763 if (modname_specified) {
764 n = strlen(modname_specified);
766 if ((n < 1) || (n >= MODLIB_NAME_MAX)) {
767 fprintf(stderr, "ldrdf: invalid length of module name `%s'\n",
768 modname_specified);
769 exit(1);
772 if (options.verbose)
773 printf("\nadding module name record %s\n", modname_specified);
775 hr = (rdfheaderrec *) nasm_malloc(sizeof(struct ModRec));
776 hr->m.type = RDFREC_MODNAME;
777 hr->m.reclen = n + 1;
778 strcpy(hr->m.modname, modname_specified);
779 rdfaddheader(rdfheader, hr);
780 nasm_free(hr);
784 if (options.verbose)
785 printf("\nbuilding output module (%d segments)\n", nsegs);
788 * Allocate the memory for the segments. We may be better off
789 * building the output module one segment at a time when running
790 * under 16 bit DOS, but that would be a slower way of doing this.
791 * And you could always use DJGPP...
793 for (i = 0; i < nsegs; i++) {
794 outputseg[i].data = NULL;
795 if (!outputseg[i].length)
796 continue;
797 outputseg[i].data = nasm_malloc(outputseg[i].length);
798 if (!outputseg[i].data) {
799 fprintf(stderr, "ldrdf: out of memory\n");
800 exit(1);
805 * initialise availableseg, used to allocate segment numbers for
806 * imported and exported labels...
808 availableseg = nsegs;
811 * Step through the modules, performing required actions on each one
813 for (cur = modules; cur; cur = cur->next) {
815 * Read the actual segment contents into the correct places in
816 * the newly allocated segments
819 for (i = 0; i < cur->f.nsegs; i++) {
820 int dest = cur->seginfo[i].dest_seg;
822 if (dest == -1)
823 continue;
824 if (rdfloadseg(&cur->f, i,
825 outputseg[dest].data + cur->seginfo[i].reloc)) {
826 rdfperror("ldrdf", cur->name);
827 exit(1);
832 * Perform fixups, and add new header records where required
835 header = nasm_malloc(cur->f.header_len);
836 if (!header) {
837 fprintf(stderr, "ldrdf: out of memory\n");
838 exit(1);
841 if (cur->f.header_loc)
842 rdfheaderrewind(&cur->f);
843 else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
844 rdfperror("ldrdf", cur->name);
845 exit(1);
849 * we need to create a local segment number -> location
850 * table for the segments in this module.
852 init_seglocations(&segs);
853 for (i = 0; i < cur->f.nsegs; i++) {
854 add_seglocation(&segs, cur->f.seg[i].number,
855 cur->seginfo[i].dest_seg,
856 cur->seginfo[i].reloc);
859 * and the BSS segment (doh!)
861 add_seglocation(&segs, 2, 2, cur->bss_reloc);
863 while ((hr = rdfgetheaderrec(&cur->f))) {
864 switch (hr->type) {
865 case RDFREC_RELOC: /* relocation record - need to do a fixup */
867 * First correct the offset stored in the segment from
868 * the start of the segment (which may well have changed).
870 * To do this we add to the number stored the relocation
871 * factor associated with the segment that contains the
872 * target segment.
874 * The relocation could be a relative relocation, in which
875 * case we have to first subtract the amount we've relocated
876 * the containing segment by.
878 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
879 fprintf(stderr,
880 "%s: reloc to undefined segment %04x\n",
881 cur->name, (int)hr->r.refseg);
882 errorcount++;
883 break;
886 isrelative =
887 (hr->r.segment & RDOFF_RELATIVEMASK) ==
888 RDOFF_RELATIVEMASK;
889 hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
891 if (hr->r.segment == 2 ||
892 (localseg =
893 rdffindsegment(&cur->f, hr->r.segment)) == -1) {
894 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
895 cur->name,
896 hr->r.segment == 2 ? "BSS" : "unknown",
897 hr->r.segment);
898 errorcount++;
899 break;
902 if (hr->r.length != 1 && hr->r.length != 2 &&
903 hr->r.length != 4) {
904 fprintf(stderr, "%s: nonstandard length reloc "
905 "(%d bytes)\n", cur->name, hr->r.length);
906 errorcount++;
907 break;
911 * okay, now the relocation is in the segment pointed to by
912 * cur->seginfo[localseg], and we know everything else is
913 * okay to go ahead and do the relocation
915 data = outputseg[cur->seginfo[localseg].dest_seg].data;
916 data += cur->seginfo[localseg].reloc + hr->r.offset;
919 * data now points to the reference that needs
920 * relocation. Calculate the relocation factor.
921 * Factor is:
922 * offset of referred object in segment [in offset]
923 * (- relocation of localseg, if ref is relative)
924 * For simplicity, the result is stored in 'offset'.
925 * Then add 'offset' onto the value at data.
928 if (isrelative)
929 offset -= cur->seginfo[localseg].reloc;
930 switch (hr->r.length) {
931 case 1:
932 offset += *data;
933 if (offset < -127 || offset > 128)
934 fprintf(error_file,
935 "warning: relocation out of range "
936 "at %s(%02x:%08"PRIx32")\n", cur->name,
937 (int)hr->r.segment, hr->r.offset);
938 *data = (char)offset;
939 break;
940 case 2:
941 offset += *(int16_t *)data;
942 if (offset < -32767 || offset > 32768)
943 fprintf(error_file,
944 "warning: relocation out of range "
945 "at %s(%02x:%08"PRIx32")\n", cur->name,
946 (int)hr->r.segment, hr->r.offset);
947 *(int16_t *)data = (int16_t)offset;
948 break;
949 case 4:
950 *(int32_t *)data += offset;
951 /* we can't easily detect overflow on this one */
952 break;
956 * If the relocation was relative between two symbols in
957 * the same segment, then we're done.
959 * Otherwise, we need to output a new relocation record
960 * with the references updated segment and offset...
962 if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
963 hr->r.segment = cur->seginfo[localseg].dest_seg;
964 hr->r.offset += cur->seginfo[localseg].reloc;
965 hr->r.refseg = seg;
966 if (isrelative)
967 hr->r.segment += RDOFF_RELATIVEMASK;
968 rdfaddheader(rdfheader, hr);
970 break;
972 case RDFREC_IMPORT: /* import symbol */
973 case RDFREC_FARIMPORT:
975 * scan the global symbol table for the symbol
976 * and associate its location with the segment number
977 * for this module
979 se = symtabFind(symtab, hr->i.label);
980 if (!se || se->segment == -1) {
981 if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
982 fprintf(error_file,
983 "error: unresolved reference to `%s'"
984 " in module `%s'\n", hr->i.label,
985 cur->name);
986 errorcount++;
989 * we need to allocate a segment number for this
990 * symbol, and store it in the symbol table for
991 * future reference
993 if (!se) {
994 se = nasm_malloc(sizeof(*se));
995 if (!se) {
996 fprintf(stderr, "ldrdf: out of memory\n");
997 exit(1);
999 se->name = nasm_strdup(hr->i.label);
1000 se->flags = 0;
1001 se->segment = availableseg++;
1002 se->offset = 0;
1003 symtabInsert(symtab, se);
1004 } else {
1005 se->segment = availableseg++;
1006 se->offset = 0;
1009 * output a header record that imports it to the
1010 * recently allocated segment number...
1012 newrec = *hr;
1013 newrec.i.segment = se->segment;
1014 rdfaddheader(rdfheader, &newrec);
1017 add_seglocation(&segs, hr->i.segment, se->segment,
1018 se->offset);
1019 break;
1021 case RDFREC_GLOBAL: /* export symbol */
1023 * need to insert an export for this symbol into the new
1024 * header, unless we're stripping symbols. Even if we're
1025 * stripping, put the symbol if it's marked as SYM_GLOBAL.
1027 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
1028 break;
1030 if (hr->e.segment == 2) {
1031 seg = 2;
1032 offset = cur->bss_reloc;
1033 } else {
1034 localseg = rdffindsegment(&cur->f, hr->e.segment);
1035 if (localseg == -1) {
1036 fprintf(stderr, "%s: exported symbol `%s' from "
1037 "unrecognised segment\n", cur->name,
1038 hr->e.label);
1039 errorcount++;
1040 break;
1042 offset = cur->seginfo[localseg].reloc;
1043 seg = cur->seginfo[localseg].dest_seg;
1046 hr->e.segment = seg;
1047 hr->e.offset += offset;
1048 rdfaddheader(rdfheader, hr);
1049 break;
1051 case RDFREC_MODNAME: /* module name */
1053 * Insert module name record if export symbols
1054 * are not stripped.
1055 * If module name begins with '$' - insert it anyway.
1057 if (options.strip && hr->m.modname[0] != '$')
1058 break;
1059 rdfaddheader(rdfheader, hr);
1060 break;
1062 case RDFREC_DLL: /* DLL name */
1064 * Insert DLL name if it begins with '$'
1066 if (hr->d.libname[0] != '$')
1067 break;
1068 rdfaddheader(rdfheader, hr);
1069 break;
1071 case RDFREC_SEGRELOC: /* segment fixup */
1073 * modify the segment numbers if necessary, and
1074 * pass straight through to the output module header
1076 * *** FIXME ***
1078 if (hr->r.segment == 2) {
1079 fprintf(stderr, "%s: segment fixup in BSS section\n",
1080 cur->name);
1081 errorcount++;
1082 break;
1084 localseg = rdffindsegment(&cur->f, hr->r.segment);
1085 if (localseg == -1) {
1086 fprintf(stderr, "%s: segment fixup in unrecognised"
1087 " segment (%d)\n", cur->name, hr->r.segment);
1088 errorcount++;
1089 break;
1091 hr->r.segment = cur->seginfo[localseg].dest_seg;
1092 hr->r.offset += cur->seginfo[localseg].reloc;
1094 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
1095 fprintf(stderr, "%s: segment fixup to undefined "
1096 "segment %04x\n", cur->name,
1097 (int)hr->r.refseg);
1098 errorcount++;
1099 break;
1101 hr->r.refseg = seg;
1102 rdfaddheader(rdfheader, hr);
1103 break;
1105 case RDFREC_COMMON: /* Common variable */
1106 /* Is this symbol already in the table? */
1107 se = symtabFind(symtab, hr->c.label);
1108 if (!se) {
1109 printf("%s is not in symtab yet\n", hr->c.label);
1110 break;
1112 /* Add segment location */
1113 add_seglocation(&segs, hr->c.segment, se->segment,
1114 se->offset);
1115 break;
1119 nasm_free(header);
1120 done_seglocations(&segs);
1125 * combined BSS reservation for the entire results
1127 newrec.type = RDFREC_BSS;
1128 newrec.b.reclen = 4;
1129 newrec.b.amount = bss_length;
1130 rdfaddheader(rdfheader, &newrec);
1133 * Write the header
1135 for (i = 0; i < nsegs; i++) {
1136 if (i == 2)
1137 continue;
1138 rdfaddsegment(rdfheader, outputseg[i].length);
1141 rdfwriteheader(f, rdfheader);
1142 rdfdoneheader(rdfheader);
1145 * Step through the segments, one at a time, writing out into
1146 * the output file
1148 for (i = 0; i < nsegs; i++) {
1149 if (i == 2)
1150 continue;
1152 fwriteint16_t(outputseg[i].type, f);
1153 fwriteint16_t(outputseg[i].number, f);
1154 fwriteint16_t(outputseg[i].reserved, f);
1155 fwriteint32_t(outputseg[i].length, f);
1156 nasm_write(outputseg[i].data, outputseg[i].length, f);
1159 fwritezero(10, f);
1162 /* =========================================================================
1163 * Main program
1166 static void usage(void)
1168 printf("usage:\n"
1169 " ldrdf [options] object modules ... [-llibrary ...]\n"
1170 " ldrdf -r\n"
1171 "options:\n"
1172 " -v[=n] increase verbosity by 1, or set it to n\n"
1173 " -a nn set segment alignment value (default 16)\n"
1174 " -s strip public symbols\n"
1175 " -dy Unix-style dynamic linking\n"
1176 " -o name write output in file 'name'\n"
1177 " -j path specify objects search path\n"
1178 " -L path specify libraries search path\n"
1179 " -g file embed 'file' as a first header record with type 'generic'\n"
1180 " -mn name add module name record at the beginning of output file\n");
1181 exit(0);
1184 int main(int argc, char **argv)
1186 char *outname = "aout.rdf";
1187 int moduleloaded = 0;
1188 char *respstrings[128] = { 0, };
1190 rdoff_init();
1192 options.verbose = 0;
1193 options.align = 16;
1194 options.dynalink = 0;
1195 options.strip = 0;
1197 error_file = stderr;
1199 argc--, argv++;
1200 if (argc == 0)
1201 usage();
1202 while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
1203 switch (argv[0][1]) {
1204 case 'r':
1205 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
1206 "\n");
1207 printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
1208 exit(0);
1209 case 'v':
1210 if (argv[0][2] == '=') {
1211 options.verbose = argv[0][3] - '0';
1212 if (options.verbose < 0 || options.verbose > 9) {
1213 fprintf(stderr,
1214 "ldrdf: verbosity level must be a number"
1215 " between 0 and 9\n");
1216 exit(1);
1218 } else
1219 options.verbose++;
1220 break;
1221 case 'a':
1222 options.align = atoi(argv[1]);
1223 if (options.align <= 0) {
1224 fprintf(stderr,
1225 "ldrdf: -a expects a positive number argument\n");
1226 exit(1);
1228 argv++, argc--;
1229 break;
1230 case 's':
1231 options.strip = 1;
1232 break;
1233 case 'd':
1234 if (argv[0][2] == 'y')
1235 options.dynalink = 1;
1236 break;
1237 case 'm':
1238 if (argv[0][2] == 'n') {
1239 modname_specified = argv[1];
1240 argv++, argc--;
1241 if (!argc) {
1242 fprintf(stderr, "ldrdf: -mn expects a module name\n");
1243 exit(1);
1246 break;
1247 case 'o':
1248 outname = argv[1];
1249 argv++, argc--;
1250 break;
1251 case 'j':
1252 if (!objpath) {
1253 options.objpath = 1;
1254 objpath = argv[1];
1255 argv++, argc--;
1256 break;
1257 } else {
1258 fprintf(stderr,
1259 "ldrdf: more than one objects search path specified\n");
1260 exit(1);
1262 case 'L':
1263 if (!libpath) {
1264 options.libpath = 1;
1265 libpath = argv[1];
1266 argv++, argc--;
1267 break;
1268 } else {
1269 fprintf(stderr,
1270 "ldrdf: more than one libraries search path specified\n");
1271 exit(1);
1273 case '@':{
1274 int i = 0;
1275 char buf[256];
1276 FILE *f;
1278 options.respfile = 1;
1279 if (argv[1] != NULL)
1280 f = fopen(argv[1], "r");
1281 else {
1282 fprintf(stderr,
1283 "ldrdf: no response file name specified\n");
1284 exit(1);
1287 if (f == NULL) {
1288 fprintf(stderr,
1289 "ldrdf: unable to open response file\n");
1290 exit(1);
1293 argv++, argc--;
1294 while (fgets(buf, sizeof(buf), f) != NULL) {
1295 char *p;
1296 if (buf[0] == '\n')
1297 continue;
1298 if ((p = strchr(buf, '\n')) != NULL)
1299 *p = '\0';
1300 if (i >= 128) {
1301 fclose(f);
1302 fprintf(stderr, "ldrdf: too many input files\n");
1303 exit(1);
1305 *(respstrings + i) = nasm_strdup(buf);
1306 argc++, i++;
1308 fclose(f);
1309 break;
1311 case '2':
1312 options.stderr_redir = 1;
1313 error_file = stdout;
1314 break;
1315 case 'g':
1316 generic_rec_file = argv[1];
1317 argv++, argc--;
1318 if (!argc) {
1319 fprintf(stderr, "ldrdf: -g expects a file name\n");
1320 exit(1);
1322 break;
1323 default:
1324 usage();
1326 argv++, argc--;
1329 if (options.verbose > 4) {
1330 printf("ldrdf invoked with options:\n");
1331 printf(" section alignment: %d bytes\n", options.align);
1332 printf(" output name: `%s'\n", outname);
1333 if (options.strip)
1334 printf(" strip symbols\n");
1335 if (options.dynalink)
1336 printf(" Unix-style dynamic linking\n");
1337 if (options.objpath)
1338 printf(" objects search path: %s\n", objpath);
1339 if (options.libpath)
1340 printf(" libraries search path: %s\n", libpath);
1341 printf("\n");
1344 symtab = symtabNew();
1345 initsegments();
1347 if (!symtab) {
1348 fprintf(stderr, "ldrdf: out of memory\n");
1349 exit(1);
1352 while (argc) {
1353 if (!*argv)
1354 argv = respstrings;
1355 if (!*argv)
1356 break;
1357 if (!strncmp(*argv, "-l", 2)) {
1358 if (libpath && (argv[0][2] != '/'))
1359 add_library(nasm_strcat(libpath, *argv + 2));
1360 else
1361 add_library(*argv + 2);
1362 } else {
1363 if (objpath && (argv[0][0] != '/'))
1364 loadmodule(nasm_strcat(objpath, *argv));
1365 else
1366 loadmodule(*argv);
1367 moduleloaded = 1;
1369 argv++, argc--;
1372 if (!moduleloaded) {
1373 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1374 return 0;
1377 search_libraries();
1379 if (options.verbose > 2) {
1380 printf("symbol table:\n");
1381 symtabDump(symtab, stdout);
1384 write_output(outname);
1386 if (errorcount > 0) {
1387 remove(outname);
1388 exit(1);
1390 return 0;