aboutsummaryrefslogtreecommitdiff
path: root/x86_64-link.c
diff options
context:
space:
mode:
authorgrischka <grischka>2016-12-15 17:01:22 +0100
committergrischka <grischka>2016-12-15 17:01:22 +0100
commitca92bfc3c64128872793c167de3a58a78b9a1299 (patch)
treed8fe09de7934dc0c23aef2417ce2bb9d589512f3 /x86_64-link.c
parentfe6453f8f08b5c21a339b3169a837772a9864d62 (diff)
downloadtinycc-ca92bfc3c64128872793c167de3a58a78b9a1299.tar.gz
tinycc-ca92bfc3c64128872793c167de3a58a78b9a1299.tar.bz2
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)
Diffstat (limited to 'x86_64-link.c')
-rw-r--r--x86_64-link.c76
1 files changed, 73 insertions, 3 deletions
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;
}
}