📄 outelf64.c
字号:
* complicated kinds. In shared-library writing, some relocations
* with respect to global symbols must refer to the precise symbol
* rather than referring to an offset from the base of the section
* _containing_ the symbol. Such relocations call to this routine,
* which searches the symbol list for the symbol in question.
*
* R_386_GOT32 references require the _exact_ symbol address to be
* used; R_386_32 references can be at an offset from the symbol.
* The boolean argument `exact' tells us this.
*
* Return value is the adjusted value of `addr', having become an
* offset from the symbol rather than the section. Should always be
* zero when returning from an exact call.
*
* Limitation: if you define two symbols at the same place,
* confusion will occur.
*
* Inefficiency: we search, currently, using a linked list which
* isn't even necessarily sorted.
*/
static void elf_add_gsym_reloc(struct Section *sect,
int32_t segment, int64_t offset, int64_t pcrel,
int type, bool exact)
{
struct Reloc *r;
struct Section *s;
struct Symbol *sym, *sm;
int i;
/*
* First look up the segment/offset pair and find a global
* symbol corresponding to it. If it's not one of our segments,
* then it must be an external symbol, in which case we're fine
* doing a normal elf_add_reloc after first sanity-checking
* that the offset from the symbol is zero.
*/
s = NULL;
for (i = 0; i < nsects; i++)
if (segment == sects[i]->index) {
s = sects[i];
break;
}
if (!s) {
if (exact && offset)
error(ERR_NONFATAL, "invalid access to an external symbol");
else
elf_add_reloc(sect, segment, offset - pcrel, type);
return;
}
if (exact) {
/*
* Find a symbol pointing _exactly_ at this one.
*/
for (sym = s->gsyms; sym; sym = sym->next)
if (sym->value == offset)
break;
if (!sym) {
error(ERR_NONFATAL, "unable to find a suitable global symbol"
" for this reference");
return;
}
} else {
/*
* Find the nearest symbol below this one.
*/
sym = NULL;
for (sm = s->gsyms; sm; sm = sm->next)
if (sm->value <= offset && (!sym || sm->value > sym->value))
sym = sm;
}
r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
sect->tail = &r->next;
r->next = NULL;
r->address = sect->len;
r->offset = offset - pcrel - sym->value;
r->symbol = GLOBAL_TEMP_BASE + sym->globnum;
r->type = type;
sect->nrelocs++;
}
static void elf_out(int32_t segto, const void *data,
enum out_type type, uint64_t size,
int32_t segment, int32_t wrt)
{
struct Section *s;
int64_t addr, zero;
int i;
static struct symlininfo sinfo;
zero = 0;
#if defined(DEBUG) && DEBUG>2
if (data) fprintf(stderr,
" elf_out line: %d type: %x seg: %d segto: %d bytes: %x data: %"PRIx64"\n",
currentline, type, segment, segto, size, *(int64_t *)data);
else fprintf(stderr,
" elf_out line: %d type: %x seg: %d segto: %d bytes: %x\n",
currentline, type, segment, segto, size);
#endif
/*
* 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;
}
}
/* invoke current debug_output routine */
if (of_elf64.current_dfmt) {
sinfo.offset = s->len;
sinfo.section = i;
sinfo.segto = segto;
sinfo.name = s->name;
of_elf64.current_dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo);
}
/* end of debugging stuff */
if (s->type == SHT_NOBITS && type != OUT_RESERVE) {
error(ERR_WARNING, "attempt to initialize memory in"
" BSS section `%s': ignored", s->name);
switch (type) {
case OUT_REL2ADR:
size = 2;
break;
case OUT_REL4ADR:
size = 4;
break;
case OUT_REL8ADR:
size = 8;
break;
default:
break; /* size is already set */
}
s->len += size;
return;
}
if (type == OUT_RESERVE) {
if (s->type == SHT_PROGBITS) {
error(ERR_WARNING, "uninitialized space declared in"
" non-BSS section `%s': zeroing", s->name);
elf_sect_write(s, NULL, size);
} else
s->len += size;
} else if (type == OUT_RAWDATA) {
if (segment != NO_SEG)
error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
elf_sect_write(s, data, size);
} else if (type == OUT_ADDRESS) {
addr = *(int64_t *)data;
if (segment == NO_SEG) {
/* Do nothing */
} else if (segment % 2) {
error(ERR_NONFATAL, "ELF format does not support"
" segment base references");
} else {
if (wrt == NO_SEG) {
switch ((int)size) {
case 1:
elf_add_reloc(s, segment, addr, R_X86_64_8);
break;
case 2:
elf_add_reloc(s, segment, addr, R_X86_64_16);
break;
case 4:
elf_add_reloc(s, segment, addr, R_X86_64_32);
break;
case 8:
elf_add_reloc(s, segment, addr, R_X86_64_64);
break;
default:
error(ERR_PANIC, "internal error elf64-hpa-871");
break;
}
addr = 0;
} 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, addr, R_X86_64_GOTPC32);
addr = 0;
} else if (wrt == elf_gotoff_sect + 1) {
if (size != 8) {
error(ERR_NONFATAL, "ELF64 requires ..gotoff "
"references to be qword absolute");
} else {
elf_add_reloc(s, segment, addr, R_X86_64_GOTOFF64);
addr = 0;
}
} else if (wrt == elf_got_sect + 1) {
switch ((int)size) {
case 4:
elf_add_gsym_reloc(s, segment, addr, 0,
R_X86_64_GOT32, true);
addr = 0;
break;
case 8:
elf_add_gsym_reloc(s, segment, addr, 0,
R_X86_64_GOT64, true);
addr = 0;
break;
default:
error(ERR_NONFATAL, "invalid ..got reference");
break;
}
} else if (wrt == elf_sym_sect + 1) {
switch ((int)size) {
case 1:
elf_add_gsym_reloc(s, segment, addr, 0,
R_X86_64_8, false);
addr = 0;
break;
case 2:
elf_add_gsym_reloc(s, segment, addr, 0,
R_X86_64_16, false);
addr = 0;
break;
case 4:
elf_add_gsym_reloc(s, segment, addr, 0,
R_X86_64_32, false);
addr = 0;
break;
case 8:
elf_add_gsym_reloc(s, segment, addr, 0,
R_X86_64_64, false);
addr = 0;
break;
default:
error(ERR_PANIC, "internal error elf64-hpa-903");
break;
}
} 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");
}
}
elf_sect_writeaddr(s, addr, size);
} else if (type == OUT_REL2ADR) {
addr = *(int64_t *)data;
if (segment == segto)
error(ERR_PANIC, "intra-segment OUT_REL2ADR");
if (segment == NO_SEG) {
/* Do nothing */
} else if (segment % 2) {
error(ERR_NONFATAL, "ELF format does not support"
" segment base references");
} else {
if (wrt == NO_SEG) {
elf_add_reloc(s, segment, addr-size, R_X86_64_PC16);
addr = 0;
} else {
error(ERR_NONFATAL,
"Unsupported non-32-bit ELF relocation [2]");
}
}
elf_sect_writeaddr(s, addr, 2);
} else if (type == OUT_REL4ADR) {
addr = *(int64_t *)data;
if (segment == segto)
error(ERR_PANIC, "intra-segment OUT_REL4ADR");
if (segment == NO_SEG) {
/* Do nothing */
} else if (segment % 2) {
error(ERR_NONFATAL, "ELF64 format does not support"
" segment base references");
} else {
if (wrt == NO_SEG) {
elf_add_reloc(s, segment, addr-size, R_X86_64_PC32);
addr = 0;
} else if (wrt == elf_plt_sect + 1) {
elf_add_gsym_reloc(s, segment, addr, size,
R_X86_64_PLT32, true);
addr = 0;
} else if (wrt == elf_gotpc_sect + 1 ||
wrt == elf_got_sect + 1) {
printf("addr = %ld, pcrel = %ld\n", addr, size);
elf_add_gsym_reloc(s, segment, addr, size,
R_X86_64_GOTPCREL, true);
addr = 0;
} else if (wrt == elf_gotoff_sect + 1 ||
wrt == elf_got_sect + 1) {
error(ERR_NONFATAL, "ELF64 requires ..gotoff references to be "
"qword absolute");
} else {
error(ERR_NONFATAL, "ELF64 format does not support this"
" use of WRT");
}
}
elf_sect_writeaddr(s, addr, 4);
} else if (type == OUT_REL8ADR) {
addr = *(int64_t *)data;
if (segment == segto)
error(ERR_PANIC, "intra-segment OUT_REL8ADR");
if (segment == NO_SEG) {
/* Do nothing */
} else if (segment % 2) {
error(ERR_NONFATAL, "ELF64 format does not support"
" segment base references");
} else {
if (wrt == NO_SEG) {
elf_add_reloc(s, segment, addr-size, R_X86_64_PC64);
addr = 0;
} else if (wrt == elf_gotpc_sect + 1 ||
wrt == elf_got_sect + 1) {
elf_add_gsym_reloc(s, segment, addr, size,
R_X86_64_GOTPCREL64, true);
addr = 0;
} else if (wrt == elf_gotoff_sect + 1 ||
wrt == elf_got_sect + 1) {
error(ERR_NONFATAL, "ELF64 requires ..gotoff references to be "
"qword absolute");
} else {
error(ERR_NONFATAL, "ELF64 format does not support this"
" use of WRT");
}
}
elf_sect_writeaddr(s, addr, 8);
}
}
static void elf_write(void)
{
int align;
int scount;
char *p;
int commlen;
char comment[64];
int i;
struct SAA *symtab;
int32_t symtablen, symtablocal;
/*
* Work out how many sections we will have. We have SHN_UNDEF,
* then the flexible user sections, then the four fixed
* sections `.comment', `.shstrtab', `.symtab' and `.strtab',
* then optionally relocation sections for the user sections.
*/
if (of_elf64.current_dfmt == &df_stabs)
nsections = 8;
else if (of_elf64.current_dfmt == &df_dwarf)
nsections = 15;
else
nsections = 5; /* SHN_UNDEF and the fixed ones */
add_sectname("", ".comment");
add_sectname("", ".shstrtab");
add_sectname("", ".symtab");
add_sectname("", ".strtab");
for (i = 0; i < nsects; i++) {
nsections++; /* for the section itself */
if (sects[i]->head) {
nsections++; /* for its relocations */
add_sectname(".rela", sects[i]->name);
}
}
if (of_elf64.current_dfmt == &df_stabs) {
/* in case the debug information is wanted, just add these three sections... */
add_sectname("", ".stab");
add_sectname("", ".stabstr");
add_sectname(".rel", ".stab");
}
else if (of_elf64.current_dfmt == &df_dwarf) {
/* the dwarf debug standard specifies the following ten sections,
not all of which are currently implemented,
although all of them are defined. */
#define debug_aranges (int64_t) (nsections-10)
#define debug_info (int64_t) (nsections-7)
#define debug_abbrev (int64_t) (nsections-5)
#define debug_line (int64_t) (nsections-4)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -