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
2 changed files with 54 additions and 10 deletions
60
tccelf.c
60
tccelf.c
|
@ -451,7 +451,7 @@ ST_FUNC void relocate_syms(TCCState *s1, int do_resolve)
|
||||||
if (addr) {
|
if (addr) {
|
||||||
sym->st_value = (addr_t)addr;
|
sym->st_value = (addr_t)addr;
|
||||||
#ifdef DEBUG_RELOC
|
#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
|
#endif
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
@ -797,8 +797,21 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
||||||
break;
|
break;
|
||||||
case R_AARCH64_JUMP26:
|
case R_AARCH64_JUMP26:
|
||||||
case R_AARCH64_CALL26:
|
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)
|
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 |
|
*(uint32_t *)ptr = 0x14000000 | (type == R_AARCH64_CALL26) << 31 |
|
||||||
((val - addr) >> 2 & 0x3ffffff);
|
((val - addr) >> 2 & 0x3ffffff);
|
||||||
break;
|
break;
|
||||||
|
@ -819,6 +832,16 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
||||||
break;
|
break;
|
||||||
case R_AARCH64_COPY:
|
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:
|
default:
|
||||||
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||||
type, (unsigned)addr, ptr, (unsigned)val);
|
type, (unsigned)addr, ptr, (unsigned)val);
|
||||||
|
@ -1211,6 +1234,7 @@ static unsigned long put_got_entry(TCCState *s1,
|
||||||
plt = s1->plt;
|
plt = s1->plt;
|
||||||
if (plt->data_offset == 0)
|
if (plt->data_offset == 0)
|
||||||
section_ptr_add(plt, 32);
|
section_ptr_add(plt, 32);
|
||||||
|
symattr->plt_offset = plt->data_offset;
|
||||||
p = section_ptr_add(plt, 16);
|
p = section_ptr_add(plt, 16);
|
||||||
put32(p, s1->got->data_offset);
|
put32(p, s1->got->data_offset);
|
||||||
put32(p + 4, (uint64_t)s1->got->data_offset >> 32);
|
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,
|
put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
|
||||||
sym_index);
|
sym_index);
|
||||||
break;
|
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)
|
#elif defined(TCC_TARGET_C67)
|
||||||
case R_C60_GOT32:
|
case R_C60_GOT32:
|
||||||
case R_C60_GOTOFF:
|
case R_C60_GOTOFF:
|
||||||
|
@ -1895,8 +1936,8 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
||||||
uint64_t plt = s1->plt->sh_addr;
|
uint64_t plt = s1->plt->sh_addr;
|
||||||
uint64_t got = s1->got->sh_addr;
|
uint64_t got = s1->got->sh_addr;
|
||||||
uint64_t off = (got >> 12) - (plt >> 12);
|
uint64_t off = (got >> 12) - (plt >> 12);
|
||||||
if ((off + ((uint64_t)1 << 20)) >> 21)
|
if ((off + ((uint32_t)1 << 20)) >> 21)
|
||||||
tcc_error("Failed relocating PLT");
|
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, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
|
||||||
put32(p + 4, (0x90000010 | // adrp x16,...
|
put32(p + 4, (0x90000010 | // adrp x16,...
|
||||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
||||||
|
@ -1914,8 +1955,8 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
||||||
uint64_t addr = got +
|
uint64_t addr = got +
|
||||||
(get32(p) | (uint64_t)get32(p + 4) << 32);
|
(get32(p) | (uint64_t)get32(p + 4) << 32);
|
||||||
uint32_t off = (addr >> 12) - (pc >> 12);
|
uint32_t off = (addr >> 12) - (pc >> 12);
|
||||||
if ((off + ((uint64_t)1 << 20)) >> 21)
|
if ((off + ((uint32_t)1 << 20)) >> 21)
|
||||||
tcc_error("Failed relocating PLT");
|
tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
|
||||||
put32(p, (0x90000010 | // adrp x16,...
|
put32(p, (0x90000010 | // adrp x16,...
|
||||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
||||||
put32(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
|
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 */
|
/* relocate symbols in .dynsym now that final addresses are known */
|
||||||
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) {
|
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_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;
|
sym->st_value += s1->plt->sh_addr;
|
||||||
} else if (sym->st_shndx < SHN_LORESERVE) {
|
} else if (sym->st_shndx < SHN_LORESERVE) {
|
||||||
/* do symbol relocation */
|
/* 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))
|
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||||
continue;
|
continue;
|
||||||
length = s->data_offset;
|
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;
|
ptr = (void*)s->sh_addr;
|
||||||
if (NULL == s->data || s->sh_type == SHT_NOBITS)
|
if (NULL == s->data || s->sh_type == SHT_NOBITS)
|
||||||
memset(ptr, 0, length);
|
memset(ptr, 0, length);
|
||||||
|
|
Loading…
Reference in a new issue