tccelf: some linker cleanup

- generate and use SYM@PLT for plt addresses
- get rid of patch_dynsym_undef hack (no idea what it did on FreeBSD)
- use sym_attrs instead of symtab_to_dynsym
- special case for function pointers into .so on i386
- libtcc_test: test tcc_add_symbol with data object
- move target specicic code to *-link.c files
- add R_XXX_RELATIVE (needed for PE)
This commit is contained in:
grischka
2016-12-15 17:01:22 +01:00
parent fe6453f8f0
commit ca92bfc3c6
9 changed files with 466 additions and 441 deletions

View File

@ -14,8 +14,8 @@
#define ELF_START_ADDR 0x400000
#define ELF_PAGE_SIZE 0x200000
#define HAVE_SECTION_RELOC
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 1
#else /* !TARGET_DEFS_ONLY */
@ -36,6 +36,7 @@ int code_reloc (int reloc_type)
case R_X86_64_GOT32:
case R_X86_64_GLOB_DAT:
case R_X86_64_COPY:
case R_X86_64_RELATIVE:
return 0;
case R_X86_64_PC32:
@ -57,6 +58,7 @@ int gotplt_entry_type (int reloc_type)
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
case R_X86_64_COPY:
case R_X86_64_RELATIVE:
return NO_GOTPLT_ENTRY;
case R_X86_64_32:
@ -80,6 +82,71 @@ int gotplt_entry_type (int reloc_type)
return -1;
}
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
{
Section *plt = s1->plt;
uint8_t *p;
int modrm;
unsigned plt_offset, relofs;
modrm = 0x25;
/* empty PLT: create PLT0 entry that pushes the library indentifier
(GOT + PTR_SIZE) and jumps to ld.so resolution routine
(GOT + 2 * PTR_SIZE) */
if (plt->data_offset == 0) {
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* pushl got + PTR_SIZE */
p[1] = modrm + 0x10;
write32le(p + 2, PTR_SIZE);
p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
p[7] = modrm;
write32le(p + 8, PTR_SIZE * 2);
}
plt_offset = plt->data_offset;
/* The PLT slot refers to the relocation entry it needs via offset.
The reloc entry is created below, so its offset is the current
data_offset */
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0;
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* jmp *(got + x) */
p[1] = modrm;
write32le(p + 2, got_offset);
p[6] = 0x68; /* push $xxx */
/* On x86-64, the relocation is referred to by _index_ */
write32le(p + 7, relofs / sizeof (ElfW_Rel));
p[11] = 0xe9; /* jmp plt_start */
write32le(p + 12, -(plt->data_offset));
return plt_offset;
}
/* relocate the PLT: compute addresses and offsets in the PLT now that final
address for PLT and GOT are known (see fill_program_header) */
ST_FUNC void relocate_plt(TCCState *s1)
{
uint8_t *p, *p_end;
if (!s1->plt)
return;
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
int x = s1->got->sh_addr - s1->plt->sh_addr - 6;
add32le(p + 2, x);
add32le(p + 8, x - 6);
p += 16;
while (p < p_end) {
add32le(p + 2, x + s1->plt->data - p);
p += 16;
}
}
}
static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
void relocate_init(Section *sr)
@ -96,7 +163,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
switch (type) {
case R_X86_64_64:
if (s1->output_type == TCC_OUTPUT_DLL) {
esym_index = s1->symtab_to_dynsym[sym_index];
esym_index = s1->sym_attrs[sym_index].dyn_index;
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64);
@ -127,7 +194,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
case R_X86_64_PC32:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
esym_index = s1->symtab_to_dynsym[sym_index];
esym_index = s1->sym_attrs[sym_index].dyn_index;
if (esym_index) {
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32);
@ -170,6 +237,9 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
/* we load the got offset */
add32le(ptr, s1->sym_attrs[sym_index].got_offset);
break;
case R_X86_64_RELATIVE:
/* do nothing */
break;
}
}