NASM 2.09rc4
[nasm/nasm.git] / rdoff / ldrdf.c
blob2ddada33106a6f1dbc18573e6cfad083fbddc4a2
1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2009 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>
57 #include <string.h>
59 #define RDOFF_UTILS
61 #include "rdoff.h"
62 #include "symtab.h"
63 #include "collectn.h"
64 #include "rdlib.h"
65 #include "segtab.h"
66 #include "nasmlib.h"
68 #define LDRDF_VERSION "1.07"
70 /* #define STINGY_MEMORY */
72 /* =======================================================================
73 * Types & macros that are private to this program
76 struct segment_infonode {
77 int dest_seg; /* output segment to be placed into, -1 to
78 skip linking this segment */
79 int32_t reloc; /* segment's relocation factor */
82 struct modulenode {
83 rdffile f; /* the RDOFF file structure */
84 struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
85 with each segment? */
86 void *header;
87 char *name;
88 struct modulenode *next;
89 int32_t bss_reloc;
92 #include "ldsegs.h"
94 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
95 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)
97 /* ==========================================================================
98 * Function prototypes of private utility functions
101 void processmodule(const char *filename, struct modulenode *mod);
102 int allocnewseg(uint16_t type, uint16_t reserved);
103 int findsegment(uint16_t type, uint16_t reserved);
104 void symtab_add(const char *symbol, int segment, int32_t offset);
105 int symtab_get(const char *symbol, int *segment, int32_t *offset);
107 /* =========================================================================
108 * Global data structures.
111 /* a linked list of modules that will be included in the output */
112 struct modulenode *modules = NULL;
113 struct modulenode *lastmodule = NULL;
115 /* a linked list of libraries to be searched for unresolved imported symbols */
116 struct librarynode *libraries = NULL;
117 struct librarynode *lastlib = NULL;
119 /* the symbol table */
120 void *symtab = NULL;
122 /* objects search path */
123 char *objpath = NULL;
125 /* libraries search path */
126 char *libpath = NULL;
128 /* file to embed as a generic record */
129 char *generic_rec_file = NULL;
131 /* error file */
132 static FILE *error_file;
134 /* the header of the output file, built up stage by stage */
135 rdf_headerbuf *newheader = NULL;
137 /* The current state of segment allocation, including information about
138 * which output segment numbers have been allocated, and their types and
139 * amount of data which has already been allocated inside them.
141 struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
142 int nsegs = 0;
143 int32_t bss_length;
145 /* global options which affect how the program behaves */
146 struct ldrdfoptions {
147 int verbose;
148 int align;
149 int dynalink;
150 int strip;
151 int respfile;
152 int stderr_redir;
153 int objpath;
154 int libpath;
155 } options;
157 int errorcount = 0; /* determines main program exit status */
159 /* =========================================================================
160 * Utility functions
164 * initsegments()
166 * sets up segments 0, 1, and 2, the initial code data and bss segments
168 void initsegments()
170 nsegs = 3;
171 outputseg[0].type = 1;
172 outputseg[0].number = 0;
173 outputseg[0].reserved = 0;
174 outputseg[0].length = 0;
175 outputseg[1].type = 2;
176 outputseg[1].number = 1;
177 outputseg[1].reserved = 0;
178 outputseg[1].length = 0;
179 outputseg[2].type = 0xFFFF; /* reserved segment type */
180 outputseg[2].number = 2;
181 outputseg[2].reserved = 0;
182 outputseg[2].length = 0;
183 bss_length = 0;
187 * loadmodule
189 * Determine the characteristics of a module, and decide what to do with
190 * each segment it contains (including determining destination segments and
191 * relocation factors for segments that are kept).
193 void loadmodule(const char *filename)
195 if (options.verbose)
196 printf("loading `%s'\n", filename);
198 /* allocate a new module entry on the end of the modules list */
199 if (!modules) {
200 modules = malloc(sizeof(*modules));
201 lastmodule = modules;
202 } else {
203 lastmodule->next = malloc(sizeof(*modules));
204 lastmodule = lastmodule->next;
207 if (!lastmodule) {
208 fprintf(stderr, "ldrdf: out of memory\n");
209 exit(1);
212 /* open the file using 'rdfopen', which returns nonzero on error */
213 if (rdfopen(&lastmodule->f, filename) != 0) {
214 rdfperror("ldrdf", filename);
215 exit(1);
219 * store information about the module, and determine what segments
220 * it contains, and what we should do with them (determine relocation
221 * factor if we decide to keep them)
223 lastmodule->header = NULL;
224 lastmodule->name = strdup(filename);
225 lastmodule->next = NULL;
227 processmodule(filename, lastmodule);
231 * processmodule()
233 * step through each segment, determine what exactly we're doing with
234 * it, and if we intend to keep it, determine (a) which segment to
235 * put it in and (b) whereabouts in that segment it will end up.
236 * (b) is fairly easy, because we're now keeping track of how big each
237 * segment in our output file is...
239 void processmodule(const char *filename, struct modulenode *mod)
241 struct segconfig sconf;
242 int seg, outseg;
243 void *header;
244 rdfheaderrec *hr;
245 int32_t bssamount = 0;
246 int bss_was_referenced = 0;
248 memset(&sconf, 0, sizeof sconf);
250 for (seg = 0; seg < mod->f.nsegs; seg++) {
252 * get the segment configuration for this type from the segment
253 * table. getsegconfig() is a macro, defined in ldsegs.h.
255 getsegconfig(sconf, mod->f.seg[seg].type);
257 if (options.verbose > 1) {
258 printf("%s %04x [%04x:%10s] ", filename,
259 mod->f.seg[seg].number, mod->f.seg[seg].type,
260 sconf.typedesc);
263 * sconf->dowhat tells us what to do with a segment of this type.
265 switch (sconf.dowhat) {
266 case SEG_IGNORE:
268 * Set destination segment to -1, to indicate that this segment
269 * should be ignored for the purpose of output, ie it is left
270 * out of the linked executable.
272 mod->seginfo[seg].dest_seg = -1;
273 if (options.verbose > 1)
274 printf("IGNORED\n");
275 break;
277 case SEG_NEWSEG:
279 * The configuration tells us to create a new segment for
280 * each occurrence of this segment type.
282 outseg = allocnewseg(sconf.mergetype,
283 mod->f.seg[seg].reserved);
284 mod->seginfo[seg].dest_seg = outseg;
285 mod->seginfo[seg].reloc = 0;
286 outputseg[outseg].length = mod->f.seg[seg].length;
287 if (options.verbose > 1)
288 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
289 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
290 break;
292 case SEG_MERGE:
294 * The configuration tells us to merge the segment with
295 * a previously existing segment of type 'sconf.mergetype',
296 * if one exists. Otherwise a new segment is created.
297 * This is handled transparently by 'findsegment()'.
299 outseg = findsegment(sconf.mergetype,
300 mod->f.seg[seg].reserved);
301 mod->seginfo[seg].dest_seg = outseg;
304 * We need to add alignment to these segments.
306 if (outputseg[outseg].length % options.align != 0)
307 outputseg[outseg].length +=
308 options.align -
309 (outputseg[outseg].length % options.align);
311 mod->seginfo[seg].reloc = outputseg[outseg].length;
312 outputseg[outseg].length += mod->f.seg[seg].length;
314 if (options.verbose > 1)
315 printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
316 mod->seginfo[seg].reloc, mod->f.seg[seg].length);
322 * extract symbols from the header, and dump them into the
323 * symbol table
325 header = malloc(mod->f.header_len);
326 if (!header) {
327 fprintf(stderr, "ldrdf: not enough memory\n");
328 exit(1);
330 if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
331 rdfperror("ldrdf", filename);
332 exit(1);
335 while ((hr = rdfgetheaderrec(&mod->f))) {
336 switch (hr->type) {
337 case RDFREC_IMPORT: /* imported symbol */
338 case RDFREC_FARIMPORT:
339 /* Define with seg = -1 */
340 symtab_add(hr->i.label, -1, 0);
341 break;
343 case RDFREC_GLOBAL:{ /* exported symbol */
344 int destseg;
345 int32_t destreloc;
347 if (hr->e.segment == 2) {
348 bss_was_referenced = 1;
349 destreloc = bss_length;
350 if (destreloc % options.align != 0)
351 destreloc +=
352 options.align - (destreloc % options.align);
353 destseg = 2;
354 } else {
355 if ((destseg =
356 mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
357 continue;
358 destreloc = mod->seginfo[(int)hr->e.segment].reloc;
360 symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
361 break;
364 case RDFREC_BSS: /* BSS reservation */
366 * first, amalgamate all BSS reservations in this module
367 * into one, because we allow this in the output format.
369 bssamount += hr->b.amount;
370 break;
372 case RDFREC_COMMON:{ /* Common variable */
373 symtabEnt *ste = symtabFind(symtab, hr->c.label);
375 /* Is the symbol already in the table? */
376 if (ste)
377 break;
379 /* Align the variable */
380 if (bss_length % hr->c.align != 0)
381 bss_length += hr->c.align - (bss_length % hr->c.align);
382 if (options.verbose > 1) {
383 printf("%s %04x common '%s' => 0002:%08"PRIx32" (+%04"PRIx32")\n",
384 filename, hr->c.segment, hr->c.label,
385 bss_length, hr->c.size);
388 symtab_add(hr->c.label, 2, bss_length);
389 mod->bss_reloc = bss_length;
390 bss_length += hr->c.size;
391 break;
396 if (bssamount != 0 || bss_was_referenced) {
398 * handle the BSS segment - first pad the existing bss length
399 * to the correct alignment, then store the length in bss_reloc
400 * for this module. Then add this module's BSS length onto
401 * bss_length.
403 if (bss_length % options.align != 0)
404 bss_length += options.align - (bss_length % options.align);
406 mod->bss_reloc = bss_length;
407 if (options.verbose > 1) {
408 printf("%s 0002 [ BSS] => 0002:%08"PRIx32" (+%04"PRIx32")\n",
409 filename, bss_length, bssamount);
411 bss_length += bssamount;
413 #ifdef STINGY_MEMORY
415 * we free the header buffer here, to save memory later.
416 * this isn't efficient, but probably halves the memory usage
417 * of this program...
419 mod->f.header_loc = NULL;
420 free(header);
422 #endif
427 * Return 1 if a given module is in the list, 0 otherwise.
429 int lookformodule(const char *name)
431 struct modulenode *curr = modules;
433 while (curr) {
434 if (!strcmp(name, curr->name))
435 return 1;
436 curr = curr->next;
438 return 0;
442 * allocnewseg()
443 * findsegment()
445 * These functions manipulate the array of output segments, and are used
446 * by processmodule(). allocnewseg() allocates a segment in the array,
447 * initialising it to be empty. findsegment() first scans the array for
448 * a segment of the type requested, and if one isn't found allocates a
449 * new one.
451 int allocnewseg(uint16_t type, uint16_t reserved)
453 outputseg[nsegs].type = type;
454 outputseg[nsegs].number = nsegs;
455 outputseg[nsegs].reserved = reserved;
456 outputseg[nsegs].length = 0;
457 outputseg[nsegs].offset = 0;
458 outputseg[nsegs].data = NULL;
460 return nsegs++;
463 int findsegment(uint16_t type, uint16_t reserved)
465 int i;
467 for (i = 0; i < nsegs; i++)
468 if (outputseg[i].type == type)
469 return i;
471 return allocnewseg(type, reserved);
475 * symtab_add()
477 * inserts a symbol into the global symbol table, which associates symbol
478 * names either with addresses, or a marker that the symbol hasn't been
479 * resolved yet, or possibly that the symbol has been defined as
480 * contained in a dynamic [load time/run time] linked library.
482 * segment = -1 => not yet defined
483 * segment = -2 => defined as dll symbol
485 * If the symbol is already defined, and the new segment >= 0, then
486 * if the original segment was < 0 the symbol is redefined, otherwise
487 * a duplicate symbol warning is issued. If new segment == -1, this
488 * routine won't change a previously existing symbol. It will change
489 * to segment = -2 only if the segment was previously < 0.
491 void symtab_add(const char *symbol, int segment, int32_t offset)
493 symtabEnt *ste;
495 ste = symtabFind(symtab, symbol);
496 if (ste) {
497 if (ste->segment >= 0) {
499 * symbol previously defined
501 if (segment < 0)
502 return;
503 fprintf(error_file, "warning: `%s' redefined\n", symbol);
504 return;
508 * somebody wanted the symbol, and put an undefined symbol
509 * marker into the table
511 if (segment == -1)
512 return;
514 * we have more information now - update the symbol's entry
516 ste->segment = segment;
517 ste->offset = offset;
518 ste->flags = 0;
519 return;
522 * this is the first declaration of this symbol
524 ste = malloc(sizeof(symtabEnt));
525 if (!ste) {
526 fprintf(stderr, "ldrdf: out of memory\n");
527 exit(1);
529 ste->name = strdup(symbol);
530 ste->segment = segment;
531 ste->offset = offset;
532 ste->flags = 0;
533 symtabInsert(symtab, ste);
537 * symtab_get()
539 * Retrieves the values associated with a symbol. Undefined symbols
540 * are assumed to have -1:0 associated. Returns 1 if the symbol was
541 * successfully located.
543 int symtab_get(const char *symbol, int *segment, int32_t *offset)
545 symtabEnt *ste = symtabFind(symtab, symbol);
546 if (!ste) {
547 *segment = -1;
548 *offset = 0;
549 return 0;
550 } else {
551 *segment = ste->segment;
552 *offset = ste->offset;
553 return 1;
558 * add_library()
560 * checks that a library can be opened and is in the correct format,
561 * then adds it to the linked list of libraries.
563 void add_library(const char *name)
565 if (rdl_verify(name)) {
566 rdl_perror("ldrdf", name);
567 errorcount++;
568 return;
570 if (!libraries) {
571 lastlib = libraries = malloc(sizeof(*libraries));
572 if (!libraries) {
573 fprintf(stderr, "ldrdf: out of memory\n");
574 exit(1);
576 } else {
577 lastlib->next = malloc(sizeof(*libraries));
578 if (!lastlib->next) {
579 fprintf(stderr, "ldrdf: out of memory\n");
580 exit(1);
582 lastlib = lastlib->next;
584 lastlib->next = NULL;
585 if (rdl_open(lastlib, name)) {
586 rdl_perror("ldrdf", name);
587 errorcount++;
588 return;
593 * search_libraries()
595 * scans through the list of libraries, attempting to match symbols
596 * defined in library modules against symbols that are referenced but
597 * not defined (segment = -1 in the symbol table)
599 * returns 1 if any extra library modules are included, indicating that
600 * another pass through the library list should be made (possibly).
602 int search_libraries()
604 struct librarynode *cur;
605 rdffile f;
606 int i;
607 void *header;
608 int segment;
609 int32_t offset;
610 int doneanything = 0, pass = 1, keepfile;
611 rdfheaderrec *hr;
613 cur = libraries;
615 while (cur) {
616 if (options.verbose > 2)
617 printf("scanning library `%s', pass %d...\n", cur->name, pass);
619 for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
620 if (pass == 2 && lookformodule(f.name))
621 continue;
623 if (options.verbose > 3)
624 printf(" looking in module `%s'\n", f.name);
626 header = malloc(f.header_len);
627 if (!header) {
628 fprintf(stderr, "ldrdf: not enough memory\n");
629 exit(1);
631 if (rdfloadseg(&f, RDOFF_HEADER, header)) {
632 rdfperror("ldrdf", f.name);
633 errorcount++;
634 return 0;
637 keepfile = 0;
639 while ((hr = rdfgetheaderrec(&f))) {
640 /* We're only interested in exports, so skip others */
641 if (hr->type != RDFREC_GLOBAL)
642 continue;
645 * If the symbol is marked as SYM_GLOBAL, somebody will be
646 * definitely interested in it..
648 if ((hr->e.flags & SYM_GLOBAL) == 0) {
650 * otherwise the symbol is just public. Find it in
651 * the symbol table. If the symbol isn't defined, we
652 * aren't interested, so go on to the next.
653 * If it is defined as anything but -1, we're also not
654 * interested. But if it is defined as -1, insert this
655 * module into the list of modules to use, and go
656 * immediately on to the next module...
658 if (!symtab_get(hr->e.label, &segment, &offset)
659 || segment != -1)
660 continue;
663 doneanything = 1;
664 keepfile = 1;
667 * as there are undefined symbols, we can assume that
668 * there are modules on the module list by the time
669 * we get here.
671 lastmodule->next = malloc(sizeof(*lastmodule->next));
672 if (!lastmodule->next) {
673 fprintf(stderr, "ldrdf: not enough memory\n");
674 exit(1);
676 lastmodule = lastmodule->next;
677 memcpy(&lastmodule->f, &f, sizeof(f));
678 lastmodule->name = strdup(f.name);
679 lastmodule->next = NULL;
680 processmodule(f.name, lastmodule);
681 break;
683 if (!keepfile) {
684 free(f.name);
685 f.name = NULL;
686 f.fp = NULL;
689 if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
690 rdl_perror("ldrdf", cur->name);
692 cur = cur->next;
693 if (cur == NULL && pass == 1) {
694 cur = libraries;
695 pass++;
699 return doneanything;
703 * write_output()
705 * this takes the linked list of modules, and walks through it, merging
706 * all the modules into a single output module, and then writes this to a
707 * file.
709 void write_output(const char *filename)
711 FILE *f;
712 rdf_headerbuf *rdfheader;
713 struct modulenode *cur;
714 int i, availableseg, seg, localseg, isrelative;
715 void *header;
716 rdfheaderrec *hr, newrec;
717 symtabEnt *se;
718 segtab segs;
719 int32_t offset;
720 uint8_t *data;
722 if ((f = fopen(filename, "wb")) == NULL) {
723 fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
724 exit(1);
726 if ((rdfheader = rdfnewheader()) == NULL) {
727 fprintf(stderr, "ldrdf: out of memory\n");
728 exit(1);
732 * If '-g' option was given, first record in output file will be a
733 * `generic' record, filled with a given file content.
734 * This can be useful, for example, when constructing multiboot
735 * compliant kernels.
737 if (generic_rec_file) {
738 FILE *ff;
740 if (options.verbose)
741 printf("\nadding generic record from binary file %s\n",
742 generic_rec_file);
744 hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec));
745 if ((ff = fopen(generic_rec_file, "r")) == NULL) {
746 fprintf(stderr, "ldrdf: couldn't open %s for input\n",
747 generic_rec_file);
748 exit(1);
750 i = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
751 fseek(ff, 0, SEEK_END);
752 if (ftell(ff) > (long)sizeof(hr->g.data)) {
753 fprintf(error_file,
754 "warning: maximum generic record size is %u, "
755 "rest of file ignored\n",
756 (unsigned int)sizeof(hr->g.data));
758 fclose(ff);
760 hr->g.type = 0;
761 hr->g.reclen = i;
762 rdfaddheader(rdfheader, hr);
763 free(hr);
766 if (options.verbose)
767 printf("\nbuilding output module (%d segments)\n", nsegs);
770 * Allocate the memory for the segments. We may be better off
771 * building the output module one segment at a time when running
772 * under 16 bit DOS, but that would be a slower way of doing this.
773 * And you could always use DJGPP...
775 for (i = 0; i < nsegs; i++) {
776 outputseg[i].data = NULL;
777 if (!outputseg[i].length)
778 continue;
779 outputseg[i].data = malloc(outputseg[i].length);
780 if (!outputseg[i].data) {
781 fprintf(stderr, "ldrdf: out of memory\n");
782 exit(1);
787 * initialise availableseg, used to allocate segment numbers for
788 * imported and exported labels...
790 availableseg = nsegs;
793 * Step through the modules, performing required actions on each one
795 for (cur = modules; cur; cur = cur->next) {
797 * Read the actual segment contents into the correct places in
798 * the newly allocated segments
801 for (i = 0; i < cur->f.nsegs; i++) {
802 int dest = cur->seginfo[i].dest_seg;
804 if (dest == -1)
805 continue;
806 if (rdfloadseg(&cur->f, i,
807 outputseg[dest].data + cur->seginfo[i].reloc)) {
808 rdfperror("ldrdf", cur->name);
809 exit(1);
814 * Perform fixups, and add new header records where required
817 header = malloc(cur->f.header_len);
818 if (!header) {
819 fprintf(stderr, "ldrdf: out of memory\n");
820 exit(1);
823 if (cur->f.header_loc)
824 rdfheaderrewind(&cur->f);
825 else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
826 rdfperror("ldrdf", cur->name);
827 exit(1);
831 * we need to create a local segment number -> location
832 * table for the segments in this module.
834 init_seglocations(&segs);
835 for (i = 0; i < cur->f.nsegs; i++) {
836 add_seglocation(&segs, cur->f.seg[i].number,
837 cur->seginfo[i].dest_seg,
838 cur->seginfo[i].reloc);
841 * and the BSS segment (doh!)
843 add_seglocation(&segs, 2, 2, cur->bss_reloc);
845 while ((hr = rdfgetheaderrec(&cur->f))) {
846 switch (hr->type) {
847 case RDFREC_RELOC: /* relocation record - need to do a fixup */
849 * First correct the offset stored in the segment from
850 * the start of the segment (which may well have changed).
852 * To do this we add to the number stored the relocation
853 * factor associated with the segment that contains the
854 * target segment.
856 * The relocation could be a relative relocation, in which
857 * case we have to first subtract the amount we've relocated
858 * the containing segment by.
860 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
861 fprintf(stderr,
862 "%s: reloc to undefined segment %04x\n",
863 cur->name, (int)hr->r.refseg);
864 errorcount++;
865 break;
868 isrelative =
869 (hr->r.segment & RDOFF_RELATIVEMASK) ==
870 RDOFF_RELATIVEMASK;
871 hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
873 if (hr->r.segment == 2 ||
874 (localseg =
875 rdffindsegment(&cur->f, hr->r.segment)) == -1) {
876 fprintf(stderr, "%s: reloc from %s segment (%d)\n",
877 cur->name,
878 hr->r.segment == 2 ? "BSS" : "unknown",
879 hr->r.segment);
880 errorcount++;
881 break;
884 if (hr->r.length != 1 && hr->r.length != 2 &&
885 hr->r.length != 4) {
886 fprintf(stderr, "%s: nonstandard length reloc "
887 "(%d bytes)\n", cur->name, hr->r.length);
888 errorcount++;
889 break;
893 * okay, now the relocation is in the segment pointed to by
894 * cur->seginfo[localseg], and we know everything else is
895 * okay to go ahead and do the relocation
897 data = outputseg[cur->seginfo[localseg].dest_seg].data;
898 data += cur->seginfo[localseg].reloc + hr->r.offset;
901 * data now points to the reference that needs
902 * relocation. Calculate the relocation factor.
903 * Factor is:
904 * offset of referred object in segment [in offset]
905 * (- relocation of localseg, if ref is relative)
906 * For simplicity, the result is stored in 'offset'.
907 * Then add 'offset' onto the value at data.
910 if (isrelative)
911 offset -= cur->seginfo[localseg].reloc;
912 switch (hr->r.length) {
913 case 1:
914 offset += *data;
915 if (offset < -127 || offset > 128)
916 fprintf(error_file,
917 "warning: relocation out of range "
918 "at %s(%02x:%08"PRIx32")\n", cur->name,
919 (int)hr->r.segment, hr->r.offset);
920 *data = (char)offset;
921 break;
922 case 2:
923 offset += *(int16_t *)data;
924 if (offset < -32767 || offset > 32768)
925 fprintf(error_file,
926 "warning: relocation out of range "
927 "at %s(%02x:%08"PRIx32")\n", cur->name,
928 (int)hr->r.segment, hr->r.offset);
929 *(int16_t *)data = (int16_t)offset;
930 break;
931 case 4:
932 *(int32_t *)data += offset;
933 /* we can't easily detect overflow on this one */
934 break;
938 * If the relocation was relative between two symbols in
939 * the same segment, then we're done.
941 * Otherwise, we need to output a new relocation record
942 * with the references updated segment and offset...
944 if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
945 hr->r.segment = cur->seginfo[localseg].dest_seg;
946 hr->r.offset += cur->seginfo[localseg].reloc;
947 hr->r.refseg = seg;
948 if (isrelative)
949 hr->r.segment += RDOFF_RELATIVEMASK;
950 rdfaddheader(rdfheader, hr);
952 break;
954 case RDFREC_IMPORT: /* import symbol */
955 case RDFREC_FARIMPORT:
957 * scan the global symbol table for the symbol
958 * and associate its location with the segment number
959 * for this module
961 se = symtabFind(symtab, hr->i.label);
962 if (!se || se->segment == -1) {
963 if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
964 fprintf(error_file,
965 "error: unresolved reference to `%s'"
966 " in module `%s'\n", hr->i.label,
967 cur->name);
968 errorcount++;
971 * we need to allocate a segment number for this
972 * symbol, and store it in the symbol table for
973 * future reference
975 if (!se) {
976 se = malloc(sizeof(*se));
977 if (!se) {
978 fprintf(stderr, "ldrdf: out of memory\n");
979 exit(1);
981 se->name = strdup(hr->i.label);
982 se->flags = 0;
983 se->segment = availableseg++;
984 se->offset = 0;
985 symtabInsert(symtab, se);
986 } else {
987 se->segment = availableseg++;
988 se->offset = 0;
991 * output a header record that imports it to the
992 * recently allocated segment number...
994 newrec = *hr;
995 newrec.i.segment = se->segment;
996 rdfaddheader(rdfheader, &newrec);
999 add_seglocation(&segs, hr->i.segment, se->segment,
1000 se->offset);
1001 break;
1003 case RDFREC_GLOBAL: /* export symbol */
1005 * need to insert an export for this symbol into the new
1006 * header, unless we're stripping symbols. Even if we're
1007 * stripping, put the symbol if it's marked as SYM_GLOBAL.
1009 if (options.strip && !(hr->e.flags & SYM_GLOBAL))
1010 break;
1012 if (hr->e.segment == 2) {
1013 seg = 2;
1014 offset = cur->bss_reloc;
1015 } else {
1016 localseg = rdffindsegment(&cur->f, hr->e.segment);
1017 if (localseg == -1) {
1018 fprintf(stderr, "%s: exported symbol `%s' from "
1019 "unrecognised segment\n", cur->name,
1020 hr->e.label);
1021 errorcount++;
1022 break;
1024 offset = cur->seginfo[localseg].reloc;
1025 seg = cur->seginfo[localseg].dest_seg;
1028 hr->e.segment = seg;
1029 hr->e.offset += offset;
1030 rdfaddheader(rdfheader, hr);
1031 break;
1033 case RDFREC_MODNAME: /* module name */
1035 * Insert module name record if export symbols
1036 * are not stripped.
1037 * If module name begins with '$' - insert it anyway.
1039 if (options.strip && hr->m.modname[0] != '$')
1040 break;
1041 rdfaddheader(rdfheader, hr);
1042 break;
1044 case RDFREC_DLL: /* DLL name */
1046 * Insert DLL name if it begins with '$'
1048 if (hr->d.libname[0] != '$')
1049 break;
1050 rdfaddheader(rdfheader, hr);
1051 break;
1053 case RDFREC_SEGRELOC: /* segment fixup */
1055 * modify the segment numbers if necessary, and
1056 * pass straight through to the output module header
1058 * *** FIXME ***
1060 if (hr->r.segment == 2) {
1061 fprintf(stderr, "%s: segment fixup in BSS section\n",
1062 cur->name);
1063 errorcount++;
1064 break;
1066 localseg = rdffindsegment(&cur->f, hr->r.segment);
1067 if (localseg == -1) {
1068 fprintf(stderr, "%s: segment fixup in unrecognised"
1069 " segment (%d)\n", cur->name, hr->r.segment);
1070 errorcount++;
1071 break;
1073 hr->r.segment = cur->seginfo[localseg].dest_seg;
1074 hr->r.offset += cur->seginfo[localseg].reloc;
1076 if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
1077 fprintf(stderr, "%s: segment fixup to undefined "
1078 "segment %04x\n", cur->name,
1079 (int)hr->r.refseg);
1080 errorcount++;
1081 break;
1083 hr->r.refseg = seg;
1084 rdfaddheader(rdfheader, hr);
1085 break;
1087 case RDFREC_COMMON: /* Common variable */
1088 /* Is this symbol already in the table? */
1089 se = symtabFind(symtab, hr->c.label);
1090 if (!se) {
1091 printf("%s is not in symtab yet\n", hr->c.label);
1092 break;
1094 /* Add segment location */
1095 add_seglocation(&segs, hr->c.segment, se->segment,
1096 se->offset);
1097 break;
1101 free(header);
1102 done_seglocations(&segs);
1107 * combined BSS reservation for the entire results
1109 newrec.type = RDFREC_BSS;
1110 newrec.b.reclen = 4;
1111 newrec.b.amount = bss_length;
1112 rdfaddheader(rdfheader, &newrec);
1115 * Write the header
1117 for (i = 0; i < nsegs; i++) {
1118 if (i == 2)
1119 continue;
1120 rdfaddsegment(rdfheader, outputseg[i].length);
1123 rdfwriteheader(f, rdfheader);
1124 rdfdoneheader(rdfheader);
1127 * Step through the segments, one at a time, writing out into
1128 * the output file
1130 for (i = 0; i < nsegs; i++) {
1131 uint16_t s;
1132 int32_t l;
1134 if (i == 2)
1135 continue;
1137 s = translateint16_t(outputseg[i].type);
1138 fwrite(&s, 2, 1, f);
1139 s = translateint16_t(outputseg[i].number);
1140 fwrite(&s, 2, 1, f);
1141 s = translateint16_t(outputseg[i].reserved);
1142 fwrite(&s, 2, 1, f);
1143 l = translateint32_t(outputseg[i].length);
1144 fwrite(&l, 4, 1, f);
1146 fwrite(outputseg[i].data, outputseg[i].length, 1, f);
1149 fwritezero(10, f);
1152 /* =========================================================================
1153 * Main program
1156 void usage()
1158 printf("usage:\n"
1159 " ldrdf [options] object modules ... [-llibrary ...]\n"
1160 " ldrdf -r\n"
1161 "options:\n"
1162 " -v[=n] increase verbosity by 1, or set it to n\n"
1163 " -a nn set segment alignment value (default 16)\n"
1164 " -s strip public symbols\n"
1165 " -dy Unix-style dynamic linking\n"
1166 " -o name write output in file 'name'\n"
1167 " -j path specify objects search path\n"
1168 " -L path specify libraries search path\n"
1169 " -g file embed 'file' as a first header record with type 'generic'\n");
1170 exit(0);
1173 int main(int argc, char **argv)
1175 char *outname = "aout.rdf";
1176 int moduleloaded = 0;
1177 char *respstrings[128] = { 0, };
1179 options.verbose = 0;
1180 options.align = 16;
1181 options.dynalink = 0;
1182 options.strip = 0;
1184 error_file = stderr;
1186 argc--, argv++;
1187 if (argc == 0)
1188 usage();
1189 while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
1190 switch (argv[0][1]) {
1191 case 'r':
1192 printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
1193 "\n");
1194 printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
1195 exit(0);
1196 case 'v':
1197 if (argv[0][2] == '=') {
1198 options.verbose = argv[0][3] - '0';
1199 if (options.verbose < 0 || options.verbose > 9) {
1200 fprintf(stderr,
1201 "ldrdf: verbosity level must be a number"
1202 " between 0 and 9\n");
1203 exit(1);
1205 } else
1206 options.verbose++;
1207 break;
1208 case 'a':
1209 options.align = atoi(argv[1]);
1210 if (options.align <= 0) {
1211 fprintf(stderr,
1212 "ldrdf: -a expects a positive number argument\n");
1213 exit(1);
1215 argv++, argc--;
1216 break;
1217 case 's':
1218 options.strip = 1;
1219 break;
1220 case 'd':
1221 if (argv[0][2] == 'y')
1222 options.dynalink = 1;
1223 break;
1224 case 'o':
1225 outname = argv[1];
1226 argv++, argc--;
1227 break;
1228 case 'j':
1229 if (!objpath) {
1230 options.objpath = 1;
1231 objpath = argv[1];
1232 argv++, argc--;
1233 break;
1234 } else {
1235 fprintf(stderr,
1236 "ldrdf: more than one objects search path specified\n");
1237 exit(1);
1239 case 'L':
1240 if (!libpath) {
1241 options.libpath = 1;
1242 libpath = argv[1];
1243 argv++, argc--;
1244 break;
1245 } else {
1246 fprintf(stderr,
1247 "ldrdf: more than one libraries search path specified\n");
1248 exit(1);
1250 case '@':{
1251 int i = 0;
1252 char buf[256];
1253 FILE *f;
1255 options.respfile = 1;
1256 if (argv[1] != NULL)
1257 f = fopen(argv[1], "r");
1258 else {
1259 fprintf(stderr,
1260 "ldrdf: no response file name specified\n");
1261 exit(1);
1264 if (f == NULL) {
1265 fprintf(stderr,
1266 "ldrdf: unable to open response file\n");
1267 exit(1);
1270 argv++, argc--;
1271 while (fgets(buf, sizeof(buf), f) != NULL) {
1272 char *p;
1273 if (buf[0] == '\n')
1274 continue;
1275 if ((p = strchr(buf, '\n')) != NULL)
1276 *p = '\0';
1277 if (i >= 128) {
1278 fprintf(stderr, "ldrdf: too many input files\n");
1279 exit(1);
1281 *(respstrings + i) = newstr(buf);
1282 argc++, i++;
1284 break;
1286 case '2':
1287 options.stderr_redir = 1;
1288 error_file = stdout;
1289 break;
1290 case 'g':
1291 generic_rec_file = argv[1];
1292 argv++, argc--;
1293 break;
1294 default:
1295 usage();
1297 argv++, argc--;
1300 if (options.verbose > 4) {
1301 printf("ldrdf invoked with options:\n");
1302 printf(" section alignment: %d bytes\n", options.align);
1303 printf(" output name: `%s'\n", outname);
1304 if (options.strip)
1305 printf(" strip symbols\n");
1306 if (options.dynalink)
1307 printf(" Unix-style dynamic linking\n");
1308 if (options.objpath)
1309 printf(" objects search path: %s\n", objpath);
1310 if (options.libpath)
1311 printf(" libraries search path: %s\n", libpath);
1312 printf("\n");
1315 symtab = symtabNew();
1316 initsegments();
1318 if (!symtab) {
1319 fprintf(stderr, "ldrdf: out of memory\n");
1320 exit(1);
1323 while (argc) {
1324 if (!*argv)
1325 argv = respstrings;
1326 if (!*argv)
1327 break;
1328 if (!strncmp(*argv, "-l", 2)) {
1329 if (libpath && (argv[0][2] != '/'))
1330 add_library(newstrcat(libpath, *argv + 2));
1331 else
1332 add_library(*argv + 2);
1333 } else {
1334 if (objpath && (argv[0][0] != '/'))
1335 loadmodule(newstrcat(objpath, *argv));
1336 else
1337 loadmodule(*argv);
1338 moduleloaded = 1;
1340 argv++, argc--;
1343 if (!moduleloaded) {
1344 printf("ldrdf: nothing to do. ldrdf -h for usage\n");
1345 return 0;
1348 search_libraries();
1350 if (options.verbose > 2) {
1351 printf("symbol table:\n");
1352 symtabDump(symtab, stdout);
1355 write_output(outname);
1357 if (errorcount > 0)
1358 exit(1);
1359 return 0;