aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2016-11-12 23:16:08 +0800
committerThomas Preud'homme <robotux@celest.fr>2016-12-03 17:26:51 +0000
commit25927df3b75c5ce2b64ab8acdcc5974b4e1c89c1 (patch)
treeb16a8d4b0ddd484d2b4995f9bfe96701b37258d3
parent2c38800bbe0544830863247a23594e37c531be8d (diff)
downloadtinycc-25927df3b75c5ce2b64ab8acdcc5974b4e1c89c1.tar.gz
tinycc-25927df3b75c5ce2b64ab8acdcc5974b4e1c89c1.tar.bz2
Consolidate all relocations in relocate_section
Static relocation of functions in dynamic libraries must use the PLT entry as the target. Before this commit, it used to be done in 2 parts for ARM, with the offset of the PLT entry from the beginning of the PLT being put in the relocated place in build_got_entries () and then the address of the PLT being added in relocate_section. This led to code dealing with reading the offset of a bl instruction in build_got_entries. Furthermore, the addition of the address of the start of the PLT was done based on the relocation type which does not convey whether a PLT entry should be used to reach the symbol. This commit moves the decision to use the PLT as the target in relocate_section, therefore having the instruction aware code contained to the target-specific bit of that function (in <target>-link.c). Note that relocate_syms is *not* the right place to do this because two different relocations for the same symbol can make different decision. This is the case in tcc -run mode where the static and dynamic relocation are done by tcc. Storing the PLT entry address in the symbol's st_value field and relying on the specific relocation type being used for dynamic relocation would work but the PLT entry address would then appear in the static symbol table (symtab). This would also make the static symbol table entry differ from the dynamic symbol table entry.
-rw-r--r--arm-link.c4
-rw-r--r--arm64-link.c8
-rw-r--r--tccelf.c70
-rw-r--r--x86_64-link.c6
4 files changed, 22 insertions, 66 deletions
diff --git a/arm-link.c b/arm-link.c
index 7d94048..396c2c0 100644
--- a/arm-link.c
+++ b/arm-link.c
@@ -43,8 +43,6 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
{
int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko;
x = (*(int *) ptr) & 0xffffff;
- if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_ABS)
- val = s1->plt->sh_addr;
#ifdef DEBUG_RELOC
printf ("reloc %d: x=0x%x val=0x%x ", type, x, val);
#endif
@@ -140,8 +138,6 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
}
/* Compute final offset */
- if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */
- x -= 4;
x += val - addr;
if (!to_thumb && is_call) {
blx_bit = 0; /* bl -> blx */
diff --git a/arm64-link.c b/arm64-link.c
index 9122eff..581f1ee 100644
--- a/arm64-link.c
+++ b/arm64-link.c
@@ -65,14 +65,6 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
return;
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
- /* This check must match the one in build_got_entries, testing
- if we really need a PLT slot. */
- if (sym->st_shndx == SHN_UNDEF ||
- sym->st_shndx == SHN_ABS)
- /* We've put the PLT slot offset into r_addend when generating
- it, and that's what we must use as relocation value (adjusted
- by section offset of course). */
- val = s1->plt->sh_addr + rel->r_addend;
#ifdef DEBUG_RELOC
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
(char *) symtab_section->link->data + sym->st_name);
diff --git a/tccelf.c b/tccelf.c
index e652351..f2210a3 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -654,8 +654,8 @@ ST_FUNC void relocate_common_syms(void)
true and output error if undefined symbol. */
ST_FUNC void relocate_syms(TCCState *s1, int do_resolve)
{
- ElfW(Sym) *sym, *esym;
- int sym_bind, sh_num, sym_index;
+ ElfW(Sym) *sym;
+ int sym_bind, sh_num;
const char *name;
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
@@ -676,15 +676,9 @@ ST_FUNC void relocate_syms(TCCState *s1, int do_resolve)
goto found;
}
#endif
- } else if (s1->dynsym) {
- /* if dynamic symbol exist, then use it */
- sym_index = find_elf_sym(s1->dynsym, name);
- if (sym_index) {
- esym = &((ElfW(Sym) *)s1->dynsym->data)[sym_index];
- sym->st_value = esym->st_value;
- goto found;
- }
- }
+ /* if dynamic symbol exist, it will be used in relocate_section */
+ } else if (s1->dynsym && find_elf_sym(s1->dynsym, name))
+ goto found;
/* XXX: _fp_hw seems to be part of the ABI, so we ignore
it */
if (!strcmp(name, "_fp_hw"))
@@ -714,7 +708,8 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
ElfW(Sym) *sym;
int type, sym_index;
unsigned char *ptr;
- addr_t val, addr;
+ addr_t tgt, addr;
+ struct sym_attr *symattr;
relocate_init(sr);
for_each_elem(sr, 0, rel, ElfW_Rel) {
@@ -722,14 +717,22 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
sym_index = ELFW(R_SYM)(rel->r_info);
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- val = sym->st_value;
+ type = ELFW(R_TYPE)(rel->r_info);
+ symattr = get_sym_attr(s1, sym_index, 0);
+ tgt = sym->st_value;
+ /* If static relocation to a dynamic symbol, relocate to PLT entry.
+ Note 1: in tcc -run mode we go through PLT to avoid range issues
+ Note 2: symbols compiled with libtcc and later added with
+ tcc_add_symbol are not dynamic and thus have symattr NULL */
+ if (relocs_info[type].gotplt_entry != NO_GOTPLT_ENTRY &&
+ relocs_info[type].code_reloc && symattr && symattr->plt_offset)
+ tgt = s1->plt->sh_addr + symattr->plt_offset;
#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
- val += rel->r_addend;
+ tgt += rel->r_addend;
#endif
- type = ELFW(R_TYPE)(rel->r_info);
addr = s->sh_addr + rel->r_offset;
- relocate(s1, rel, type, ptr, addr, val);
+ relocate(s1, rel, type, ptr, addr, tgt);
}
/* if the relocation is allocated, we change its symbol table */
if (sr->sh_flags & SHF_ALLOC)
@@ -1030,7 +1033,6 @@ ST_FUNC void build_got_entries(TCCState *s1)
ElfW_Rel *rel;
ElfW(Sym) *sym;
int i, type, reloc_type, sym_index;
- unsigned long ofs;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
@@ -1075,38 +1077,8 @@ ST_FUNC void build_got_entries(TCCState *s1)
reloc_type = R_JMP_SLOT;
else
reloc_type = R_GLOB_DAT;
- ofs = put_got_entry(s1, reloc_type, type, sym->st_size,
- sym->st_info, sym_index);
-
-#ifdef DEBUG_RELOC
- printf ("maybegot: %s, %d, %d --> ofs=0x%x\n",
- (char *) symtab_section->link->data + sym->st_name, type,
- sym->st_shndx, ofs);
-#endif
-
-#if defined (TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
- /* We store the place of the generated PLT slot in our addend. */
- if (relocs_info[type].pltoff_addend)
- rel->r_addend += ofs;
-
-#elif defined (TCC_TARGET_ARM)
- if (type == R_ARM_PC24 || type == R_ARM_CALL ||
- type == R_ARM_JUMP24 || type == R_ARM_PLT32) {
- addr_t *ptr = (addr_t*)(s1->sections[s->sh_info]->data
- + rel->r_offset);
- /* x must be signed! */
- int x = *ptr & 0xffffff;
- x = (x << 8) >> 8;
- x <<= 2;
- x += ofs;
- x >>= 2;
-#ifdef DEBUG_RELOC
- printf ("insn=0x%x --> 0x%x (x==0x%x)\n", *ptr,
- (*ptr & 0xff000000) | x, x);
-#endif
- *ptr = (*ptr & 0xff000000) | x;
- }
-#endif
+ put_got_entry(s1, reloc_type, type, sym->st_size, sym->st_info,
+ sym_index);
}
}
}
diff --git a/x86_64-link.c b/x86_64-link.c
index 5f8c504..a526865 100644
--- a/x86_64-link.c
+++ b/x86_64-link.c
@@ -75,11 +75,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
goto plt32pc32;
case R_X86_64_PLT32:
- /* We've put the PLT slot offset into r_addend when generating
- it, and that's what we must use as relocation value (adjusted
- by section offset of course). */
- val = s1->plt->sh_addr + rel->r_addend;
- /* fallthrough. */
+ /* fallthrough: val already holds the PLT slot address */
plt32pc32:
{