mirror of
https://github.com/frida/tinycc
synced 2024-11-24 08:39:37 +03:00
aarch64: Fix -run.
This adds some more support for properly transfering some offsets over the different stages of a relocations life. Still not at all psABI compliant and DSOs can't yet be generated. But it runs the testsuite in qemu-arm64.
This commit is contained in:
parent
b14ef0e24b
commit
6d055312a2
62
tccelf.c
62
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 */
|
||||
|
2
tccrun.c
2
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);
|
||||
|
Loading…
Reference in New Issue
Block a user