aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tccelf.c62
-rw-r--r--tccrun.c2
2 files changed, 54 insertions, 10 deletions
diff --git a/tccelf.c b/tccelf.c
index 4f89224..2b07f60 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -451,7 +451,7 @@ ST_FUNC void relocate_syms(TCCState *s1, int do_resolve)
if (addr) {
sym->st_value = (addr_t)addr;
#ifdef DEBUG_RELOC
- printf ("relocate_sym: %s -> 0x%x\n", name, sym->st_value);
+ printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value);
#endif
goto found;
}
@@ -797,8 +797,21 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
break;
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)
+ /* 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);
+#endif
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
- tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed");
+ {
+ tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed (val=%lx, addr=%lx)", addr, val);
+ }
*(uint32_t *)ptr = 0x14000000 | (type == R_AARCH64_CALL26) << 31 |
((val - addr) >> 2 & 0x3ffffff);
break;
@@ -818,7 +831,17 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
& 0xff8) << 7;
break;
case R_AARCH64_COPY:
- break;
+ break;
+ case R_AARCH64_GLOB_DAT:
+ case R_AARCH64_JUMP_SLOT:
+ /* They don't need addend */
+#ifdef DEBUG_RELOC
+ printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr,
+ val - rel->r_addend,
+ (char *) symtab_section->link->data + sym->st_name);
+#endif
+ *(addr_t *)ptr = val - rel->r_addend;
+ break;
default:
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);
@@ -1211,6 +1234,7 @@ static unsigned long put_got_entry(TCCState *s1,
plt = s1->plt;
if (plt->data_offset == 0)
section_ptr_add(plt, 32);
+ symattr->plt_offset = plt->data_offset;
p = section_ptr_add(plt, 16);
put32(p, s1->got->data_offset);
put32(p + 4, (uint64_t)s1->got->data_offset >> 32);
@@ -1372,6 +1396,23 @@ ST_FUNC void build_got_entries(TCCState *s1)
put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
sym_index);
break;
+
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_CALL26:
+ if (!s1->got)
+ build_got(s1);
+ sym_index = ELFW(R_SYM)(rel->r_info);
+ sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+ if (sym->st_shndx == SHN_UNDEF) {
+ unsigned long ofs;
+ reloc_type = R_AARCH64_JUMP_SLOT;
+ ofs = put_got_entry(s1, reloc_type, sym->st_size,
+ sym->st_info, sym_index);
+ /* We store the place of the generated PLT slot
+ in our addend. */
+ rel->r_addend += ofs;
+ }
+ break;
#elif defined(TCC_TARGET_C67)
case R_C60_GOT32:
case R_C60_GOTOFF:
@@ -1895,8 +1936,8 @@ ST_FUNC void relocate_plt(TCCState *s1)
uint64_t plt = s1->plt->sh_addr;
uint64_t got = s1->got->sh_addr;
uint64_t off = (got >> 12) - (plt >> 12);
- if ((off + ((uint64_t)1 << 20)) >> 21)
- tcc_error("Failed relocating PLT");
+ if ((off + ((uint32_t)1 << 20)) >> 21)
+ tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
put32(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
put32(p + 4, (0x90000010 | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29));
@@ -1914,8 +1955,8 @@ ST_FUNC void relocate_plt(TCCState *s1)
uint64_t addr = got +
(get32(p) | (uint64_t)get32(p + 4) << 32);
uint32_t off = (addr >> 12) - (pc >> 12);
- if ((off + ((uint64_t)1 << 20)) >> 21)
- tcc_error("Failed relocating PLT");
+ if ((off + ((uint32_t)1 << 20)) >> 21)
+ tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
put32(p, (0x90000010 | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29));
put32(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
@@ -2590,9 +2631,12 @@ static int elf_output_file(TCCState *s1, const char *filename)
/* relocate symbols in .dynsym now that final addresses are known */
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) {
- /* relocate to PLT if symbol corresponds to a PLT entry */
if (sym->st_shndx == SHN_UNDEF) {
- if (sym->st_value)
+ /* relocate to PLT if symbol corresponds to a PLT entry,
+ but not if it's a weak symbol */
+ if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
+ sym->st_value = 0;
+ else if (sym->st_value)
sym->st_value += s1->plt->sh_addr;
} else if (sym->st_shndx < SHN_LORESERVE) {
/* do symbol relocation */
diff --git a/tccrun.c b/tccrun.c
index 264322b..8f7257d 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -196,7 +196,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
if (0 == (s->sh_flags & SHF_ALLOC))
continue;
length = s->data_offset;
- // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
+ // printf("%-12s %08lx %04x\n", s->name, s->sh_addr, length);
ptr = (void*)s->sh_addr;
if (NULL == s->data || s->sh_type == SHT_NOBITS)
memset(ptr, 0, length);