aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tccelf.c76
-rw-r--r--x86_64-gen.c2
2 files changed, 41 insertions, 37 deletions
diff --git a/tccelf.c b/tccelf.c
index 932cf03..38d3e3e 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -802,9 +802,18 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
#elif defined(TCC_TARGET_X86_64)
case R_X86_64_64:
if (s1->output_type == TCC_OUTPUT_DLL) {
- qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
- qrel->r_addend = *(long long *)ptr + val;
- qrel++;
+ esym_index = s1->symtab_to_dynsym[sym_index];
+ qrel->r_offset = rel->r_offset;
+ if (esym_index) {
+ qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64);
+ qrel->r_addend = rel->r_addend;
+ qrel++;
+ break;
+ } else {
+ qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
+ qrel->r_addend = *(long long *)ptr + val;
+ qrel++;
+ }
}
*(long long *)ptr += val;
break;
@@ -1013,6 +1022,7 @@ static void put_got_entry(TCCState *s1,
ElfW(Sym) *sym;
unsigned long offset;
int *ptr;
+ struct sym_attr *symattr;
if (!s1->got)
build_got(s1);
@@ -1037,7 +1047,10 @@ static void put_got_entry(TCCState *s1,
got_entry_present = 1;
}
- alloc_sym_attr(s1, sym_index)->got_offset = s1->got->data_offset;
+ symattr = alloc_sym_attr(s1, sym_index);
+ /* Only store the GOT offset if it's not generated for the PLT entry. */
+ if (!need_plt_entry)
+ symattr->got_offset = s1->got->data_offset;
if (s1->dynsym) {
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
@@ -1048,6 +1061,7 @@ static void put_got_entry(TCCState *s1,
Section *plt;
uint8_t *p;
int modrm;
+ unsigned long relofs;
#if defined(TCC_OUTPUT_DLL_WITH_PLT)
modrm = 0x25;
@@ -1072,12 +1086,21 @@ static void put_got_entry(TCCState *s1,
put32(p + 8, PTR_SIZE * 2);
}
+ /* 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;
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* jmp *(got + x) */
p[1] = modrm;
put32(p + 2, s1->got->data_offset);
p[6] = 0x68; /* push $xxx */
- put32(p + 7, (plt->data_offset - 32) >> 1);
+#ifdef TCC_TARGET_X86_64
+ /* On x86-64, the relocation is referred to by _index_. */
+ put32(p + 7, relofs / sizeof (ElfW_Rel));
+#else
+ put32(p + 7, relofs);
+#endif
p[11] = 0xe9; /* jmp plt_start */
put32(p + 12, -(plt->data_offset));
@@ -1087,7 +1110,7 @@ static void put_got_entry(TCCState *s1,
if (s1->output_type == TCC_OUTPUT_EXE)
#endif
offset = plt->data_offset - 16;
- s1->sym_attrs[sym_index].has_plt_entry = 1;
+ symattr->has_plt_entry = 1;
}
#elif defined(TCC_TARGET_ARM)
if (need_plt_entry) {
@@ -1109,7 +1132,7 @@ static void put_got_entry(TCCState *s1,
put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
}
- if (s1->sym_attrs[sym_index].plt_thumb_stub) {
+ if (symattr->plt_thumb_stub) {
p = section_ptr_add(plt, 20);
put32(p, 0x4778); /* bx pc */
put32(p+2, 0x46c0); /* nop */
@@ -1125,27 +1148,23 @@ static void put_got_entry(TCCState *s1,
the PLT */
if (s1->output_type == TCC_OUTPUT_EXE)
offset = plt->data_offset - 16;
- s1->sym_attrs[sym_index].has_plt_entry = 1;
+ symattr->has_plt_entry = 1;
}
#elif defined(TCC_TARGET_C67)
tcc_error("C67 got not implemented");
#else
#error unsupported CPU
#endif
+ /* XXX This might generate multiple syms for name. */
index = put_elf_sym(s1->dynsym, offset,
size, info, 0, sym->st_shndx, name);
- if (got_entry_present) {
- put_elf_reloc(s1->dynsym, s1->got,
- s1->sym_attrs[sym_index].got_offset,
- reloc_type, index);
- return;
- }
-
- /* put a got entry */
+ /* Create the relocation (it's against the GOT for PLT
+ and GOT relocs). */
put_elf_reloc(s1->dynsym, s1->got,
s1->got->data_offset,
reloc_type, index);
}
+ /* And now create the GOT slot itself. */
ptr = section_ptr_add(s1->got, PTR_SIZE);
*ptr = 0;
}
@@ -1697,26 +1716,11 @@ static void export_global_syms(TCCState *s1)
s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms);
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
-#if defined(TCC_OUTPUT_DLL_WITH_PLT)
- int type = ELFW(ST_TYPE)(sym->st_info);
- if ((type == STT_FUNC || type == STT_GNU_IFUNC)
- && sym->st_shndx == SHN_UNDEF) {
- int visibility = ELFW(ST_BIND)(sym->st_info);
- put_got_entry(s1, R_JMP_SLOT, sym->st_size,
- ELFW(ST_INFO)(visibility, STT_FUNC),
- sym - (ElfW(Sym) *) symtab_section->data);
- } else if (type == STT_OBJECT) {
- put_got_entry(s1, R_X86_64_GLOB_DAT, sym->st_size, sym->st_info,
- sym - (ElfW(Sym) *) symtab_section->data);
- } else
-#endif
- {
- name = (char *) symtab_section->link->data + sym->st_name;
- dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
- sym->st_info, 0, sym->st_shndx, name);
- index = sym - (ElfW(Sym) *) symtab_section->data;
- s1->symtab_to_dynsym[index] = dynindex;
- }
+ name = (char *) symtab_section->link->data + sym->st_name;
+ dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
+ sym->st_info, 0, sym->st_shndx, name);
+ index = sym - (ElfW(Sym) *) symtab_section->data;
+ s1->symtab_to_dynsym[index] = dynindex;
}
}
}
diff --git a/x86_64-gen.c b/x86_64-gen.c
index fc4178e..9a9221d 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -604,7 +604,7 @@ static void gcall_or_jmp(int is_jmp)
if (vtop->r & VT_SYM) {
/* relocation case */
greloc(cur_text_section, vtop->sym,
- ind + 1, R_X86_64_PC32);
+ ind + 1, R_X86_64_PLT32);
} else {
/* put an empty PC32 relocation */
put_elf_reloc(symtab_section, cur_text_section,