rbtree: add rb_search_exact()
[nasm.git] / output / outaout.c
blobc59c78965dc2c6bb6a72cee867166ebb800adc17
1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2013 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 * ----------------------------------------------------------------------- */
34 /*
35 * outaout.c output routines for the Netwide Assembler to produce
36 * Linux a.out object files
39 #include "compiler.h"
41 #include "nctype.h"
43 #include "nasm.h"
44 #include "nasmlib.h"
45 #include "error.h"
46 #include "saa.h"
47 #include "raa.h"
48 #include "stdscan.h"
49 #include "eval.h"
50 #include "outform.h"
51 #include "outlib.h"
53 #if defined OF_AOUT || defined OF_AOUTB
55 #define RELTYPE_ABSOLUTE 0x00
56 #define RELTYPE_RELATIVE 0x01
57 #define RELTYPE_GOTPC 0x01 /* no explicit GOTPC in a.out */
58 #define RELTYPE_GOTOFF 0x10
59 #define RELTYPE_GOT 0x10 /* distinct from GOTOFF bcos sym not sect */
60 #define RELTYPE_PLT 0x21
61 #define RELTYPE_SYMFLAG 0x08
63 struct Reloc {
64 struct Reloc *next;
65 int32_t address; /* relative to _start_ of section */
66 int32_t symbol; /* symbol number or -ve section id */
67 int bytes; /* 2 or 4 */
68 int reltype; /* see above */
71 struct Symbol {
72 int32_t strpos; /* string table position of name */
73 int type; /* symbol type - see flags below */
74 int32_t value; /* address, or COMMON variable size */
75 int32_t size; /* size for data or function exports */
76 int32_t segment; /* back-reference used by gsym_reloc */
77 struct Symbol *next; /* list of globals in each section */
78 struct Symbol *nextfwd; /* list of unresolved-size symbols */
79 char *name; /* for unresolved-size symbols */
80 int32_t symnum; /* index into symbol table */
84 * Section IDs - used in Reloc.symbol when negative, and in
85 * Symbol.type when positive.
87 #define SECT_ABS 2 /* absolute value */
88 #define SECT_TEXT 4 /* text section */
89 #define SECT_DATA 6 /* data section */
90 #define SECT_BSS 8 /* bss section */
91 #define SECT_MASK 0xE /* mask out any of the above */
94 * More flags used in Symbol.type.
96 #define SYM_GLOBAL 1 /* it's a global symbol */
97 #define SYM_DATA 0x100 /* used for shared libs */
98 #define SYM_FUNCTION 0x200 /* used for shared libs */
99 #define SYM_WITH_SIZE 0x4000 /* not output; internal only */
102 * Bit more explanation of symbol types: SECT_xxx denotes a local
103 * symbol. SECT_xxx|SYM_GLOBAL denotes a global symbol, defined in
104 * this module. Just SYM_GLOBAL, with zero value, denotes an
105 * external symbol referenced in this module. And just SYM_GLOBAL,
106 * but with a non-zero value, declares a C `common' variable, of
107 * size `value'.
110 struct Section {
111 struct SAA *data;
112 uint32_t len, size, nrelocs;
113 int32_t index;
114 struct Reloc *head, **tail;
115 struct Symbol *gsyms, *asym;
118 static struct Section stext, sdata, sbss;
120 static struct SAA *syms;
121 static uint32_t nsyms;
123 static struct RAA *bsym;
125 static struct SAA *strs;
126 static uint32_t strslen;
128 static struct Symbol *fwds;
130 static int bsd;
131 static int is_pic;
133 static void aout_write(void);
134 static void aout_write_relocs(struct Reloc *);
135 static void aout_write_syms(void);
136 static void aout_sect_write(struct Section *, const uint8_t *,
137 uint32_t);
138 static void aout_pad_sections(void);
139 static void aout_fixup_relocs(struct Section *);
142 * Special section numbers which are used to define special
143 * symbols, which can be used with WRT to provide PIC relocation
144 * types.
146 static int32_t aout_gotpc_sect, aout_gotoff_sect;
147 static int32_t aout_got_sect, aout_plt_sect;
148 static int32_t aout_sym_sect;
150 static void aoutg_init(void)
152 stext.data = saa_init(1L);
153 stext.head = NULL;
154 stext.tail = &stext.head;
155 sdata.data = saa_init(1L);
156 sdata.head = NULL;
157 sdata.tail = &sdata.head;
158 stext.len = stext.size = sdata.len = sdata.size = sbss.len = 0;
159 stext.nrelocs = sdata.nrelocs = 0;
160 stext.gsyms = sdata.gsyms = sbss.gsyms = NULL;
161 stext.index = seg_alloc();
162 sdata.index = seg_alloc();
163 sbss.index = seg_alloc();
164 stext.asym = sdata.asym = sbss.asym = NULL;
165 syms = saa_init((int32_t)sizeof(struct Symbol));
166 nsyms = 0;
167 bsym = raa_init();
168 strs = saa_init(1L);
169 strslen = 0;
170 fwds = NULL;
173 #ifdef OF_AOUT
175 static void aout_init(void)
177 bsd = false;
178 aoutg_init();
180 aout_gotpc_sect = aout_gotoff_sect = aout_got_sect =
181 aout_plt_sect = aout_sym_sect = NO_SEG;
184 #endif
186 #ifdef OF_AOUTB
188 extern const struct ofmt of_aoutb;
190 static void aoutb_init(void)
192 bsd = true;
193 aoutg_init();
195 is_pic = 0x00; /* may become 0x40 */
197 aout_gotpc_sect = seg_alloc();
198 backend_label("..gotpc", aout_gotpc_sect + 1, 0L);
199 aout_gotoff_sect = seg_alloc();
200 backend_label("..gotoff", aout_gotoff_sect + 1, 0L);
201 aout_got_sect = seg_alloc();
202 backend_label("..got", aout_got_sect + 1, 0L);
203 aout_plt_sect = seg_alloc();
204 backend_label("..plt", aout_plt_sect + 1, 0L);
205 aout_sym_sect = seg_alloc();
206 backend_label("..sym", aout_sym_sect + 1, 0L);
209 #endif
211 static void aout_cleanup(void)
213 struct Reloc *r;
215 aout_pad_sections();
216 aout_fixup_relocs(&stext);
217 aout_fixup_relocs(&sdata);
218 aout_write();
219 saa_free(stext.data);
220 while (stext.head) {
221 r = stext.head;
222 stext.head = stext.head->next;
223 nasm_free(r);
225 saa_free(sdata.data);
226 while (sdata.head) {
227 r = sdata.head;
228 sdata.head = sdata.head->next;
229 nasm_free(r);
231 saa_free(syms);
232 raa_free(bsym);
233 saa_free(strs);
236 static int32_t aout_section_names(char *name, int *bits)
239 * Default to 32 bits.
241 if (!name) {
242 *bits = 32;
243 return stext.index;
246 if (!strcmp(name, ".text"))
247 return stext.index;
248 else if (!strcmp(name, ".data"))
249 return sdata.index;
250 else if (!strcmp(name, ".bss"))
251 return sbss.index;
252 else
253 return NO_SEG;
256 static void aout_deflabel(char *name, int32_t segment, int64_t offset,
257 int is_global, char *special)
259 int pos = strslen + 4;
260 struct Symbol *sym;
261 int special_used = false;
263 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
265 * This is a NASM special symbol. We never allow it into
266 * the a.out symbol table, even if it's a valid one. If it
267 * _isn't_ a valid one, we should barf immediately.
269 if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") &&
270 strcmp(name, "..got") && strcmp(name, "..plt") &&
271 strcmp(name, "..sym"))
272 nasm_nonfatal("unrecognised special symbol `%s'", name);
273 return;
276 if (is_global == 3) {
277 struct Symbol **s;
279 * Fix up a forward-reference symbol size from the first
280 * pass.
282 for (s = &fwds; *s; s = &(*s)->nextfwd)
283 if (!strcmp((*s)->name, name)) {
284 struct tokenval tokval;
285 expr *e;
286 char *p = special;
288 p = nasm_skip_spaces(nasm_skip_word(p));
289 stdscan_reset();
290 stdscan_set(p);
291 tokval.t_type = TOKEN_INVALID;
292 e = evaluate(stdscan, NULL, &tokval, NULL, 1, NULL);
293 if (e) {
294 if (!is_simple(e))
295 nasm_nonfatal("cannot use relocatable"
296 " expression as symbol size");
297 else
298 (*s)->size = reloc_value(e);
302 * Remove it from the list of unresolved sizes.
304 nasm_free((*s)->name);
305 *s = (*s)->nextfwd;
306 return;
308 return; /* it wasn't an important one */
311 saa_wbytes(strs, name, (int32_t)(1 + strlen(name)));
312 strslen += 1 + strlen(name);
314 sym = saa_wstruct(syms);
316 sym->strpos = pos;
317 sym->type = is_global ? SYM_GLOBAL : 0;
318 sym->segment = segment;
319 if (segment == NO_SEG)
320 sym->type |= SECT_ABS;
321 else if (segment == stext.index) {
322 sym->type |= SECT_TEXT;
323 if (is_global) {
324 sym->next = stext.gsyms;
325 stext.gsyms = sym;
326 } else if (!stext.asym)
327 stext.asym = sym;
328 } else if (segment == sdata.index) {
329 sym->type |= SECT_DATA;
330 if (is_global) {
331 sym->next = sdata.gsyms;
332 sdata.gsyms = sym;
333 } else if (!sdata.asym)
334 sdata.asym = sym;
335 } else if (segment == sbss.index) {
336 sym->type |= SECT_BSS;
337 if (is_global) {
338 sym->next = sbss.gsyms;
339 sbss.gsyms = sym;
340 } else if (!sbss.asym)
341 sbss.asym = sym;
342 } else
343 sym->type = SYM_GLOBAL;
344 if (is_global == 2)
345 sym->value = offset;
346 else
347 sym->value = (sym->type == SYM_GLOBAL ? 0 : offset);
349 if (is_global && sym->type != SYM_GLOBAL) {
351 * Global symbol exported _from_ this module. We must check
352 * the special text for type information.
355 if (special) {
356 int n = strcspn(special, " ");
358 if (!nasm_strnicmp(special, "function", n))
359 sym->type |= SYM_FUNCTION;
360 else if (!nasm_strnicmp(special, "data", n) ||
361 !nasm_strnicmp(special, "object", n))
362 sym->type |= SYM_DATA;
363 else
364 nasm_nonfatal("unrecognised symbol type `%.*s'",
365 n, special);
366 if (special[n]) {
367 struct tokenval tokval;
368 expr *e;
369 int fwd = false;
370 char *saveme = stdscan_get();
372 if (!bsd) {
373 nasm_nonfatal("Linux a.out does not support"
374 " symbol size information");
375 } else {
376 while (special[n] && nasm_isspace(special[n]))
377 n++;
379 * We have a size expression; attempt to
380 * evaluate it.
382 sym->type |= SYM_WITH_SIZE;
383 stdscan_reset();
384 stdscan_set(special + n);
385 tokval.t_type = TOKEN_INVALID;
386 e = evaluate(stdscan, NULL, &tokval, &fwd, 0, NULL);
387 if (fwd) {
388 sym->nextfwd = fwds;
389 fwds = sym;
390 sym->name = nasm_strdup(name);
391 } else if (e) {
392 if (!is_simple(e))
393 nasm_nonfatal("cannot use relocatable"
394 " expression as symbol size");
395 else
396 sym->size = reloc_value(e);
399 stdscan_set(saveme);
401 special_used = true;
406 * define the references from external-symbol segment numbers
407 * to these symbol records.
409 if (segment != NO_SEG && segment != stext.index &&
410 segment != sdata.index && segment != sbss.index)
411 bsym = raa_write(bsym, segment, nsyms);
412 sym->symnum = nsyms;
414 nsyms++;
415 if (sym->type & SYM_WITH_SIZE)
416 nsyms++; /* and another for the size */
418 if (special && !special_used)
419 nasm_nonfatal("no special symbol features supported here");
422 static void aout_add_reloc(struct Section *sect, int32_t segment,
423 int reltype, int bytes)
425 struct Reloc *r;
427 r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
428 sect->tail = &r->next;
429 r->next = NULL;
431 r->address = sect->len;
432 r->symbol = (segment == NO_SEG ? -SECT_ABS :
433 segment == stext.index ? -SECT_TEXT :
434 segment == sdata.index ? -SECT_DATA :
435 segment == sbss.index ? -SECT_BSS :
436 raa_read(bsym, segment));
437 r->reltype = reltype;
438 if (r->symbol >= 0)
439 r->reltype |= RELTYPE_SYMFLAG;
440 r->bytes = bytes;
442 sect->nrelocs++;
446 * This routine deals with ..got and ..sym relocations: the more
447 * complicated kinds. In shared-library writing, some relocations
448 * with respect to global symbols must refer to the precise symbol
449 * rather than referring to an offset from the base of the section
450 * _containing_ the symbol. Such relocations call to this routine,
451 * which searches the symbol list for the symbol in question.
453 * RELTYPE_GOT references require the _exact_ symbol address to be
454 * used; RELTYPE_ABSOLUTE references can be at an offset from the
455 * symbol. The boolean argument `exact' tells us this.
457 * Return value is the adjusted value of `addr', having become an
458 * offset from the symbol rather than the section. Should always be
459 * zero when returning from an exact call.
461 * Limitation: if you define two symbols at the same place,
462 * confusion will occur.
464 * Inefficiency: we search, currently, using a linked list which
465 * isn't even necessarily sorted.
467 static int32_t aout_add_gsym_reloc(struct Section *sect,
468 int32_t segment, int32_t offset,
469 int type, int bytes, int exact)
471 struct Symbol *sym, *sm, *shead;
472 struct Reloc *r;
475 * First look up the segment to find whether it's text, data,
476 * bss or an external symbol.
478 shead = NULL;
479 if (segment == stext.index)
480 shead = stext.gsyms;
481 else if (segment == sdata.index)
482 shead = sdata.gsyms;
483 else if (segment == sbss.index)
484 shead = sbss.gsyms;
485 if (!shead) {
486 if (exact && offset != 0)
487 nasm_nonfatal("unable to find a suitable global symbol"
488 " for this reference");
489 else
490 aout_add_reloc(sect, segment, type, bytes);
491 return offset;
494 if (exact) {
496 * Find a symbol pointing _exactly_ at this one.
498 list_for_each(sym, shead)
499 if (sym->value == offset)
500 break;
501 } else {
503 * Find the nearest symbol below this one.
505 sym = NULL;
506 list_for_each(sm, shead)
507 if (sm->value <= offset && (!sym || sm->value > sym->value))
508 sym = sm;
510 if (!sym && exact) {
511 nasm_nonfatal("unable to find a suitable global symbol"
512 " for this reference");
513 return 0;
516 r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
517 sect->tail = &r->next;
518 r->next = NULL;
520 r->address = sect->len;
521 r->symbol = sym->symnum;
522 r->reltype = type | RELTYPE_SYMFLAG;
523 r->bytes = bytes;
525 sect->nrelocs++;
527 return offset - sym->value;
531 * This routine deals with ..gotoff relocations. These _must_ refer
532 * to a symbol, due to a perversity of *BSD's PIC implementation,
533 * and it must be a non-global one as well; so we store `asym', the
534 * first nonglobal symbol defined in each section, and always work
535 * from that. Relocation type is always RELTYPE_GOTOFF.
537 * Return value is the adjusted value of `addr', having become an
538 * offset from the `asym' symbol rather than the section.
540 static int32_t aout_add_gotoff_reloc(struct Section *sect, int32_t segment,
541 int32_t offset, int bytes)
543 struct Reloc *r;
544 struct Symbol *asym;
547 * First look up the segment to find whether it's text, data,
548 * bss or an external symbol.
550 asym = NULL;
551 if (segment == stext.index)
552 asym = stext.asym;
553 else if (segment == sdata.index)
554 asym = sdata.asym;
555 else if (segment == sbss.index)
556 asym = sbss.asym;
557 if (!asym)
558 nasm_nonfatal("`..gotoff' relocations require a non-global"
559 " symbol in the section");
561 r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
562 sect->tail = &r->next;
563 r->next = NULL;
565 r->address = sect->len;
566 r->symbol = asym->symnum;
567 r->reltype = RELTYPE_GOTOFF;
568 r->bytes = bytes;
570 sect->nrelocs++;
572 return offset - asym->value;
575 static void aout_out(int32_t segto, const void *data,
576 enum out_type type, uint64_t size,
577 int32_t segment, int32_t wrt)
579 struct Section *s;
580 int32_t addr;
581 uint8_t mydata[4], *p;
583 if (segto == stext.index)
584 s = &stext;
585 else if (segto == sdata.index)
586 s = &sdata;
587 else if (segto == sbss.index)
588 s = NULL;
589 else {
590 nasm_warn(WARN_OTHER, "attempt to assemble code in"
591 " segment %d: defaulting to `.text'", segto);
592 s = &stext;
595 if (!s && type != OUT_RESERVE) {
596 nasm_warn(WARN_OTHER, "attempt to initialize memory in the"
597 " BSS section: ignored");
598 sbss.len += realsize(type, size);
599 return;
602 memset(mydata, 0, sizeof(mydata));
604 if (type == OUT_RESERVE) {
605 if (s) {
606 nasm_warn(WARN_ZEROING, "uninitialized space declared in"
607 " %s section: zeroing",
608 (segto == stext.index ? "code" : "data"));
609 aout_sect_write(s, NULL, size);
610 } else
611 sbss.len += size;
612 } else if (type == OUT_RAWDATA) {
613 aout_sect_write(s, data, size);
614 } else if (type == OUT_ADDRESS) {
615 int asize = abs((int)size);
616 addr = *(int64_t *)data;
617 if (segment != NO_SEG) {
618 if (segment % 2) {
619 nasm_nonfatal("a.out format does not support"
620 " segment base references");
621 } else {
622 if (wrt == NO_SEG) {
623 aout_add_reloc(s, segment, RELTYPE_ABSOLUTE, asize);
624 } else if (!bsd) {
625 nasm_nonfatal("Linux a.out format does not support"
626 " any use of WRT");
627 wrt = NO_SEG; /* we can at least _try_ to continue */
628 } else if (wrt == aout_gotpc_sect + 1) {
629 is_pic = 0x40;
630 aout_add_reloc(s, segment, RELTYPE_GOTPC, asize);
631 } else if (wrt == aout_gotoff_sect + 1) {
632 is_pic = 0x40;
633 addr = aout_add_gotoff_reloc(s, segment, addr, asize);
634 } else if (wrt == aout_got_sect + 1) {
635 is_pic = 0x40;
636 addr = aout_add_gsym_reloc(s, segment, addr, RELTYPE_GOT,
637 asize, true);
638 } else if (wrt == aout_sym_sect + 1) {
639 addr = aout_add_gsym_reloc(s, segment, addr,
640 RELTYPE_ABSOLUTE, asize,
641 false);
642 } else if (wrt == aout_plt_sect + 1) {
643 is_pic = 0x40;
644 nasm_nonfatal("a.out format cannot produce non-PC-"
645 "relative PLT references");
646 } else {
647 nasm_nonfatal("a.out format does not support this"
648 " use of WRT");
649 wrt = NO_SEG; /* we can at least _try_ to continue */
653 p = mydata;
654 if (asize == 2)
655 WRITESHORT(p, addr);
656 else
657 WRITELONG(p, addr);
658 aout_sect_write(s, mydata, asize);
659 } else if (type == OUT_REL2ADR) {
660 if (segment != NO_SEG && segment % 2) {
661 nasm_nonfatal("a.out format does not support"
662 " segment base references");
663 } else {
664 if (wrt == NO_SEG) {
665 aout_add_reloc(s, segment, RELTYPE_RELATIVE, 2);
666 } else if (!bsd) {
667 nasm_nonfatal("Linux a.out format does not support"
668 " any use of WRT");
669 wrt = NO_SEG; /* we can at least _try_ to continue */
670 } else if (wrt == aout_plt_sect + 1) {
671 is_pic = 0x40;
672 aout_add_reloc(s, segment, RELTYPE_PLT, 2);
673 } else if (wrt == aout_gotpc_sect + 1 ||
674 wrt == aout_gotoff_sect + 1 ||
675 wrt == aout_got_sect + 1) {
676 nasm_nonfatal("a.out format cannot produce PC-"
677 "relative GOT references");
678 } else {
679 nasm_nonfatal("a.out format does not support this"
680 " use of WRT");
681 wrt = NO_SEG; /* we can at least _try_ to continue */
684 p = mydata;
685 WRITESHORT(p, *(int64_t *)data - (size + s->len));
686 aout_sect_write(s, mydata, 2L);
687 } else if (type == OUT_REL4ADR) {
688 if (segment != NO_SEG && segment % 2) {
689 nasm_nonfatal("a.out format does not support"
690 " segment base references");
691 } else {
692 if (wrt == NO_SEG) {
693 aout_add_reloc(s, segment, RELTYPE_RELATIVE, 4);
694 } else if (!bsd) {
695 nasm_nonfatal("Linux a.out format does not support"
696 " any use of WRT");
697 wrt = NO_SEG; /* we can at least _try_ to continue */
698 } else if (wrt == aout_plt_sect + 1) {
699 is_pic = 0x40;
700 aout_add_reloc(s, segment, RELTYPE_PLT, 4);
701 } else if (wrt == aout_gotpc_sect + 1 ||
702 wrt == aout_gotoff_sect + 1 ||
703 wrt == aout_got_sect + 1) {
704 nasm_nonfatal("a.out format cannot produce PC-"
705 "relative GOT references");
706 } else {
707 nasm_nonfatal("a.out format does not support this"
708 " use of WRT");
709 wrt = NO_SEG; /* we can at least _try_ to continue */
712 p = mydata;
713 WRITELONG(p, *(int64_t *)data - (size + s->len));
714 aout_sect_write(s, mydata, 4L);
718 static void aout_pad_sections(void)
720 static uint8_t pad[] = { 0x90, 0x90, 0x90, 0x90 };
722 * Pad each of the text and data sections with NOPs until their
723 * length is a multiple of four. (NOP == 0x90.) Also increase
724 * the length of the BSS section similarly.
726 aout_sect_write(&stext, pad, (-(int32_t)stext.len) & 3);
727 aout_sect_write(&sdata, pad, (-(int32_t)sdata.len) & 3);
728 sbss.len = ALIGN(sbss.len, 4);
732 * a.out files have the curious property that all references to
733 * things in the data or bss sections are done by addresses which
734 * are actually relative to the start of the _text_ section, in the
735 * _file_. (No relation to what happens after linking. No idea why
736 * this should be so. It's very strange.) So we have to go through
737 * the relocation table, _after_ the final size of each section is
738 * known, and fix up the relocations pointed to.
740 static void aout_fixup_relocs(struct Section *sect)
742 struct Reloc *r;
744 saa_rewind(sect->data);
745 list_for_each(r, sect->head) {
746 uint8_t *p, *q, blk[4];
747 int32_t l;
749 saa_fread(sect->data, r->address, blk, (int32_t)r->bytes);
750 p = q = blk;
751 l = *p++;
752 if (r->bytes > 1) {
753 l += ((int32_t)*p++) << 8;
754 if (r->bytes == 4) {
755 l += ((int32_t)*p++) << 16;
756 l += ((int32_t)*p++) << 24;
759 if (r->symbol == -SECT_DATA)
760 l += stext.len;
761 else if (r->symbol == -SECT_BSS)
762 l += stext.len + sdata.len;
763 if (r->bytes == 4)
764 WRITELONG(q, l);
765 else if (r->bytes == 2)
766 WRITESHORT(q, l);
767 else
768 *q++ = l & 0xFF;
769 saa_fwrite(sect->data, r->address, blk, (int32_t)r->bytes);
773 static void aout_write(void)
776 * Emit the a.out header.
778 /* OMAGIC, M_386 or MID_I386, no flags */
779 fwriteint32_t(bsd ? 0x07018600 | is_pic : 0x640107L, ofile);
780 fwriteint32_t(stext.len, ofile);
781 fwriteint32_t(sdata.len, ofile);
782 fwriteint32_t(sbss.len, ofile);
783 fwriteint32_t(nsyms * 12, ofile); /* length of symbol table */
784 fwriteint32_t(0L, ofile); /* object files have no entry point */
785 fwriteint32_t(stext.nrelocs * 8, ofile); /* size of text relocs */
786 fwriteint32_t(sdata.nrelocs * 8, ofile); /* size of data relocs */
789 * Write out the code section and the data section.
791 saa_fpwrite(stext.data, ofile);
792 saa_fpwrite(sdata.data, ofile);
795 * Write out the relocations.
797 aout_write_relocs(stext.head);
798 aout_write_relocs(sdata.head);
801 * Write the symbol table.
803 aout_write_syms();
806 * And the string table.
808 fwriteint32_t(strslen + 4, ofile); /* length includes length count */
809 saa_fpwrite(strs, ofile);
812 static void aout_write_relocs(struct Reloc *r)
814 list_for_each(r, r) {
815 uint32_t word2;
817 fwriteint32_t(r->address, ofile);
819 if (r->symbol >= 0)
820 word2 = r->symbol;
821 else
822 word2 = -r->symbol;
823 word2 |= r->reltype << 24;
824 word2 |= (r->bytes == 1 ? 0 :
825 r->bytes == 2 ? 0x2000000L : 0x4000000L);
826 fwriteint32_t(word2, ofile);
830 static void aout_write_syms(void)
832 uint32_t i;
834 saa_rewind(syms);
835 for (i = 0; i < nsyms; i++) {
836 struct Symbol *sym = saa_rstruct(syms);
837 fwriteint32_t(sym->strpos, ofile);
838 fwriteint32_t((int32_t)sym->type & ~SYM_WITH_SIZE, ofile);
840 * Fix up the symbol value now we know the final section
841 * sizes.
843 if ((sym->type & SECT_MASK) == SECT_DATA)
844 sym->value += stext.len;
845 if ((sym->type & SECT_MASK) == SECT_BSS)
846 sym->value += stext.len + sdata.len;
847 fwriteint32_t(sym->value, ofile);
849 * Output a size record if necessary.
851 if (sym->type & SYM_WITH_SIZE) {
852 fwriteint32_t(sym->strpos, ofile);
853 fwriteint32_t(0x0DL, ofile); /* special value: means size */
854 fwriteint32_t(sym->size, ofile);
855 i++; /* use up another of `nsyms' */
860 static void aout_sect_write(struct Section *sect,
861 const uint8_t *data, uint32_t len)
863 saa_wbytes(sect->data, data, len);
864 sect->len += len;
867 extern macros_t aout_stdmac[];
869 #endif /* OF_AOUT || OF_AOUTB */
871 #ifdef OF_AOUT
873 const struct ofmt of_aout = {
874 "Linux a.out",
875 "aout",
876 ".o",
879 null_debug_arr,
880 &null_debug_form,
881 aout_stdmac,
882 aout_init,
883 null_reset,
884 nasm_do_legacy_output,
885 aout_out,
886 aout_deflabel,
887 aout_section_names,
888 NULL,
889 null_sectalign,
890 null_segbase,
891 null_directive,
892 aout_cleanup,
893 NULL /* pragma list */
896 #endif
898 #ifdef OF_AOUTB
900 const struct ofmt of_aoutb = {
901 "NetBSD/FreeBSD a.out",
902 "aoutb",
903 ".o",
906 null_debug_arr,
907 &null_debug_form,
908 aout_stdmac,
909 aoutb_init,
910 null_reset,
911 nasm_do_legacy_output,
912 aout_out,
913 aout_deflabel,
914 aout_section_names,
915 NULL,
916 null_sectalign,
917 null_segbase,
918 null_directive,
919 aout_cleanup,
920 NULL /* pragma list */
923 #endif