aboutsummaryrefslogtreecommitdiff
path: root/tccelf.c
diff options
context:
space:
mode:
Diffstat (limited to 'tccelf.c')
-rw-r--r--tccelf.c70
1 files changed, 21 insertions, 49 deletions
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);
}
}
}