From ca92bfc3c64128872793c167de3a58a78b9a1299 Mon Sep 17 00:00:00 2001 From: grischka Date: Thu, 15 Dec 2016 17:01:22 +0100 Subject: 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) --- x86_64-link.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 3 deletions(-) (limited to 'x86_64-link.c') diff --git a/x86_64-link.c b/x86_64-link.c index 92404e4..9ff234b 100644 --- a/x86_64-link.c +++ b/x86_64-link.c @@ -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; } } -- cgit v1.3.1