/* * a.out files have the curious property that all references to * things in the data or bss sections are done by addresses which * are actually relative to the start of the _text_ section, in the * _file_. (No relation to what happens after linking. No idea why * this should be so. It's very strange.) So we have to go through * the relocation table, _after_ the final size of each section is * known, and fix up the relocations pointed to. */ static void aout_fixup_relocs(struct Section *sect) { struct Reloc *r; saa_rewind (sect->data); for (r = sect->head; r; r = r->next) { unsigned char *p, *q, blk[4]; long l; saa_fread (sect->data, r->address, blk, (long)r->bytes); p = q = blk; l = *p++; if (r->bytes > 1) { l += ((long)*p++) << 8; if (r->bytes == 4) { l += ((long)*p++) << 16; l += ((long)*p++) << 24; } } if (r->symbol == -SECT_DATA) l += stext.len; else if (r->symbol == -SECT_BSS) l += stext.len + sdata.len; if (r->bytes == 4) WRITELONG(q, l); else if (r->bytes == 2) WRITESHORT(q, l); else *q++ = l & 0xFF; saa_fwrite (sect->data, r->address, blk, (long)r->bytes); } }
static void elf_out(long segto, const void *data, unsigned long type, long segment, long wrt) { struct Section *s; long realbytes = type & OUT_SIZMASK; long addr; unsigned char mydata[4], *p; int i; static struct symlininfo sinfo; type &= OUT_TYPMASK; /* * handle absolute-assembly (structure definitions) */ if (segto == NO_SEG) { if (type != OUT_RESERVE) error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" " space"); return; } s = NULL; for (i = 0; i < nsects; i++) if (segto == sects[i]->index) { s = sects[i]; break; } if (!s) { int tempint; /* ignored */ if (segto != elf_section_names(".text", 2, &tempint)) error(ERR_PANIC, "strange segment conditions in ELF driver"); else { s = sects[nsects - 1]; i = nsects - 1; } } /* again some stabs debugging stuff */ if (of_elf.current_dfmt) { sinfo.offset = s->len; sinfo.section = i; sinfo.name = s->name; of_elf.current_dfmt->debug_output(TY_STABSSYMLIN, &sinfo); } /* end of debugging stuff */ if (s->type == SHT_NOBITS && type != OUT_RESERVE) { error(ERR_WARNING, "attempt to initialise memory in" " BSS section `%s': ignored", s->name); if (type == OUT_REL2ADR) realbytes = 2; else if (type == OUT_REL4ADR) realbytes = 4; s->len += realbytes; return; } if (type == OUT_RESERVE) { if (s->type == SHT_PROGBITS) { error(ERR_WARNING, "uninitialised space declared in" " non-BSS section `%s': zeroing", s->name); elf_sect_write(s, NULL, realbytes); } else s->len += realbytes; } else if (type == OUT_RAWDATA) { if (segment != NO_SEG) error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); elf_sect_write(s, data, realbytes); } else if (type == OUT_ADDRESS) { int gnu16 = 0; addr = *(long *)data; if (segment != NO_SEG) { if (segment % 2) { error(ERR_NONFATAL, "ELF format does not support" " segment base references"); } else { if (wrt == NO_SEG) { if (realbytes == 2) { gnu16 = 1; elf_add_reloc(s, segment, R_386_16); } else { elf_add_reloc(s, segment, R_386_32); } } else if (wrt == elf_gotpc_sect + 1) { /* * The user will supply GOT relative to $$. ELF * will let us have GOT relative to $. So we * need to fix up the data item by $-$$. */ addr += s->len; elf_add_reloc(s, segment, R_386_GOTPC); } else if (wrt == elf_gotoff_sect + 1) { elf_add_reloc(s, segment, R_386_GOTOFF); } else if (wrt == elf_got_sect + 1) { addr = elf_add_gsym_reloc(s, segment, addr, R_386_GOT32, TRUE); } else if (wrt == elf_sym_sect + 1) { if (realbytes == 2) { gnu16 = 1; addr = elf_add_gsym_reloc(s, segment, addr, R_386_16, FALSE); } else { addr = elf_add_gsym_reloc(s, segment, addr, R_386_32, FALSE); } } else if (wrt == elf_plt_sect + 1) { error(ERR_NONFATAL, "ELF format cannot produce non-PC-" "relative PLT references"); } else { error(ERR_NONFATAL, "ELF format does not support this" " use of WRT"); wrt = NO_SEG; /* we can at least _try_ to continue */ } } } p = mydata; if (gnu16) { error(ERR_WARNING | ERR_WARN_GNUELF, "16-bit relocations in ELF is a GNU extension"); WRITESHORT(p, addr); } else { if (realbytes != 4 && segment != NO_SEG) { error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation"); } WRITELONG(p, addr); } elf_sect_write(s, mydata, realbytes); } else if (type == OUT_REL2ADR) { if (segment == segto) error(ERR_PANIC, "intra-segment OUT_REL2ADR"); if (segment != NO_SEG && segment % 2) { error(ERR_NONFATAL, "ELF format does not support" " segment base references"); } else { if (wrt == NO_SEG) { error(ERR_WARNING | ERR_WARN_GNUELF, "16-bit relocations in ELF is a GNU extension"); elf_add_reloc(s, segment, R_386_PC16); } else { error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation"); } } p = mydata; WRITESHORT(p, *(long *)data - realbytes); elf_sect_write(s, mydata, 2L); } else if (type == OUT_REL4ADR) { if (segment == segto) error(ERR_PANIC, "intra-segment OUT_REL4ADR"); if (segment != NO_SEG && segment % 2) { error(ERR_NONFATAL, "ELF format does not support" " segment base references"); } else { if (wrt == NO_SEG) { elf_add_reloc(s, segment, R_386_PC32); } else if (wrt == elf_plt_sect + 1) { elf_add_reloc(s, segment, R_386_PLT32); } else if (wrt == elf_gotpc_sect + 1 || wrt == elf_gotoff_sect + 1 || wrt == elf_got_sect + 1) { error(ERR_NONFATAL, "ELF format cannot produce PC-" "relative GOT references"); } else { error(ERR_NONFATAL, "ELF format does not support this" " use of WRT"); wrt = NO_SEG; /* we can at least _try_ to continue */ } } p = mydata; WRITELONG(p, *(long *)data - realbytes); elf_sect_write(s, mydata, 4L); } }
static struct SAA *elf_build_symtab(long *len, long *local) { struct SAA *s = saa_init(1L); struct Symbol *sym; unsigned char entry[16], *p; int i; *len = *local = 0; /* * First, an all-zeros entry, required by the ELF spec. */ saa_wbytes(s, NULL, 16L); /* null symbol table entry */ *len += 16; (*local)++; /* * Next, an entry for the file name. */ p = entry; WRITELONG(p, 1); /* we know it's 1st thing in strtab */ WRITELONG(p, 0); /* no value */ WRITELONG(p, 0); /* no size either */ WRITESHORT(p, 4); /* type FILE */ WRITESHORT(p, SHN_ABS); saa_wbytes(s, entry, 16L); *len += 16; (*local)++; /* * Now some standard symbols defining the segments, for relocation * purposes. */ for (i = 1; i <= nsects + 1; i++) { p = entry; WRITELONG(p, 0); /* no symbol name */ WRITELONG(p, 0); /* offset zero */ WRITELONG(p, 0); /* size zero */ WRITESHORT(p, 3); /* local section-type thing */ WRITESHORT(p, (i == 1 ? SHN_ABS : i - 1)); /* the section id */ saa_wbytes(s, entry, 16L); *len += 16; (*local)++; } /* * Now the other local symbols. */ saa_rewind(syms); while ((sym = saa_rstruct(syms))) { if (sym->type & SYM_GLOBAL) continue; p = entry; WRITELONG(p, sym->strpos); WRITELONG(p, sym->value); WRITELONG(p, sym->size); WRITESHORT(p, sym->type); /* local non-typed thing */ WRITESHORT(p, sym->section); saa_wbytes(s, entry, 16L); *len += 16; (*local)++; } /* * Now the global symbols. */ saa_rewind(syms); while ((sym = saa_rstruct(syms))) { if (!(sym->type & SYM_GLOBAL)) continue; p = entry; WRITELONG(p, sym->strpos); WRITELONG(p, sym->value); WRITELONG(p, sym->size); WRITESHORT(p, sym->type); /* global non-typed thing */ WRITESHORT(p, sym->section); saa_wbytes(s, entry, 16L); *len += 16; } return s; }
static void aout_out (long segto, const void *data, unsigned long type, long segment, long wrt) { struct Section *s; long realbytes = type & OUT_SIZMASK; long addr; unsigned char mydata[4], *p; type &= OUT_TYPMASK; /* * handle absolute-assembly (structure definitions) */ if (segto == NO_SEG) { if (type != OUT_RESERVE) error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" " space"); return; } if (segto == stext.index) s = &stext; else if (segto == sdata.index) s = &sdata; else if (segto == sbss.index) s = NULL; else { error(ERR_WARNING, "attempt to assemble code in" " segment %d: defaulting to `.text'", segto); s = &stext; } if (!s && type != OUT_RESERVE) { error(ERR_WARNING, "attempt to initialise memory in the" " BSS section: ignored"); if (type == OUT_REL2ADR) realbytes = 2; else if (type == OUT_REL4ADR) realbytes = 4; sbss.len += realbytes; return; } if (type == OUT_RESERVE) { if (s) { error(ERR_WARNING, "uninitialised space declared in" " %s section: zeroing", (segto == stext.index ? "code" : "data")); aout_sect_write (s, NULL, realbytes); } else sbss.len += realbytes; } else if (type == OUT_RAWDATA) { if (segment != NO_SEG) error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); aout_sect_write (s, data, realbytes); } else if (type == OUT_ADDRESS) { addr = *(long *)data; if (segment != NO_SEG) { if (segment % 2) { error(ERR_NONFATAL, "a.out format does not support" " segment base references"); } else { if (wrt == NO_SEG) { aout_add_reloc (s, segment, RELTYPE_ABSOLUTE, realbytes); } else if (!bsd) { error (ERR_NONFATAL, "Linux a.out format does not support" " any use of WRT"); wrt = NO_SEG; /* we can at least _try_ to continue */ } else if (wrt == aout_gotpc_sect+1) { is_pic = 0x40; aout_add_reloc (s, segment, RELTYPE_GOTPC, realbytes); } else if (wrt == aout_gotoff_sect+1) { is_pic = 0x40; addr = aout_add_gotoff_reloc (s, segment, addr, realbytes); } else if (wrt == aout_got_sect+1) { is_pic = 0x40; addr = aout_add_gsym_reloc (s, segment, addr, RELTYPE_GOT, realbytes, TRUE); } else if (wrt == aout_sym_sect+1) { addr = aout_add_gsym_reloc (s, segment, addr, RELTYPE_ABSOLUTE, realbytes, FALSE); } else if (wrt == aout_plt_sect+1) { is_pic = 0x40; error(ERR_NONFATAL, "a.out format cannot produce non-PC-" "relative PLT references"); } else { error (ERR_NONFATAL, "a.out format does not support this" " use of WRT"); wrt = NO_SEG; /* we can at least _try_ to continue */ } } } p = mydata; if (realbytes == 2) WRITESHORT (p, addr); else WRITELONG (p, addr); aout_sect_write (s, mydata, realbytes); } else if (type == OUT_REL2ADR) { if (segment == segto) error(ERR_PANIC, "intra-segment OUT_REL2ADR"); if (segment != NO_SEG && segment % 2) { error(ERR_NONFATAL, "a.out format does not support" " segment base references"); } else { if (wrt == NO_SEG) { aout_add_reloc (s, segment, RELTYPE_RELATIVE, 2); } else if (!bsd) { error (ERR_NONFATAL, "Linux a.out format does not support" " any use of WRT"); wrt = NO_SEG; /* we can at least _try_ to continue */ } else if (wrt == aout_plt_sect+1) { is_pic = 0x40; aout_add_reloc (s, segment, RELTYPE_PLT, 2); } else if (wrt == aout_gotpc_sect+1 || wrt == aout_gotoff_sect+1 || wrt == aout_got_sect+1) { error(ERR_NONFATAL, "a.out format cannot produce PC-" "relative GOT references"); } else { error (ERR_NONFATAL, "a.out format does not support this" " use of WRT"); wrt = NO_SEG; /* we can at least _try_ to continue */ } } p = mydata; WRITESHORT (p, *(long*)data-(realbytes + s->len)); aout_sect_write (s, mydata, 2L); } else if (type == OUT_REL4ADR) { if (segment == segto) error(ERR_PANIC, "intra-segment OUT_REL4ADR"); if (segment != NO_SEG && segment % 2) { error(ERR_NONFATAL, "a.out format does not support" " segment base references"); } else { if (wrt == NO_SEG) { aout_add_reloc (s, segment, RELTYPE_RELATIVE, 4); } else if (!bsd) { error (ERR_NONFATAL, "Linux a.out format does not support" " any use of WRT"); wrt = NO_SEG; /* we can at least _try_ to continue */ } else if (wrt == aout_plt_sect+1) { is_pic = 0x40; aout_add_reloc (s, segment, RELTYPE_PLT, 4); } else if (wrt == aout_gotpc_sect+1 || wrt == aout_gotoff_sect+1 || wrt == aout_got_sect+1) { error(ERR_NONFATAL, "a.out format cannot produce PC-" "relative GOT references"); } else { error (ERR_NONFATAL, "a.out format does not support this" " use of WRT"); wrt = NO_SEG; /* we can at least _try_ to continue */ } } p = mydata; WRITELONG (p, *(long*)data-(realbytes + s->len)); aout_sect_write (s, mydata, 4L); } }
static void list_output(long offset, const void *data, unsigned long type) { unsigned long typ, size; if (!listp || suppress || user_nolist) /* fbk - 9/2/00 */ return; typ = type & OUT_TYPMASK; size = type & OUT_SIZMASK; if (typ == OUT_RAWDATA) { unsigned char const *p = data; char q[3]; while (size--) { HEX(q, *p); q[2] = '\0'; list_out(offset++, q); p++; } } else if (typ == OUT_ADDRESS) { unsigned long d = *(long *)data; char q[11]; unsigned char p[4], *r = p; if (size == 4) { q[0] = '['; q[9] = ']'; q[10] = '\0'; WRITELONG(r, d); HEX(q + 1, p[0]); HEX(q + 3, p[1]); HEX(q + 5, p[2]); HEX(q + 7, p[3]); list_out(offset, q); } else { q[0] = '['; q[5] = ']'; q[6] = '\0'; WRITESHORT(r, d); HEX(q + 1, p[0]); HEX(q + 3, p[1]); list_out(offset, q); } } else if (typ == OUT_REL2ADR) { unsigned long d = *(long *)data; char q[11]; unsigned char p[4], *r = p; q[0] = '('; q[5] = ')'; q[6] = '\0'; WRITESHORT(r, d); HEX(q + 1, p[0]); HEX(q + 3, p[1]); list_out(offset, q); } else if (typ == OUT_REL4ADR) { unsigned long d = *(long *)data; char q[11]; unsigned char p[4], *r = p; q[0] = '('; q[9] = ')'; q[10] = '\0'; WRITELONG(r, d); HEX(q + 1, p[0]); HEX(q + 3, p[1]); HEX(q + 5, p[2]); HEX(q + 7, p[3]); list_out(offset, q); } else if (typ == OUT_RESERVE) { char q[20]; snprintf(q, sizeof(q), "<res %08lX>", size); list_out(offset, q); } }