ldso: dynamic linking support for ARM 64-bit

* added relocation support
* added assembler invocation path for jump slot relocations

fixes issue #3260
This commit is contained in:
Sebastian Sumpf 2019-04-04 12:13:08 +02:00 committed by Christian Helmuth
parent 7dc875e8c7
commit a8d856fb65
2 changed files with 101 additions and 18 deletions

View File

@ -1,7 +1,7 @@
/**
* \brief Jump slot entry code for ARM 64-bit platforms
* \author Stefan Kalkowski
* \date 2019-03-27
* \author Sebastian Sumpf
* \date 2019-04-04
*/
/*
@ -14,6 +14,55 @@
.text
.globl _jmp_slot
.type _jmp_slot,%function
/*
* sp + 0 = &GOT[n + 3]
* sp + 8 = return address
* x30 = return address
* x16 = &GOT[2] // 'jmp_slot'
* x17 = '_jmp_slot' (this function)
*/
_jmp_slot:
1: b 1b
mov x17, sp
/* save fp, lr */
stp x29, x30, [sp, #-16]!
/* save arguments */
stp x0, x1, [sp, #-16]!
stp x2, x3, [sp, #-16]!
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, xzr, [sp, #-16]!
/* GOT[1] = Dependency */
ldr x0, [x16, #-8] /* arg 0 */
/* calculate symbol index from GOT offset (arg 1) */
ldr x2, [x17, #0] /* &GOT[n+3] */
sub x1, x2, x16 /* GOT offset */
sub x1, x1, #8 /* GOT[3] is first entry */
/* a GOT entry is 8 bytes, therefore index = offset / 8 */
lsr x1, x1, #3 /* x1 / 8 */
bl jmp_slot
/* address of function to call */
mov x17, x0
/* restore arguments */
ldp x8, xzr, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
ldp x2, x3, [sp], #16
ldp x0, x1, [sp], #16
/* frame pointer */
ldp x29, xzr, [sp], #16
/* restore lr and close frame from plt code */
ldp xzr, x30, [sp], #16
/* call function */
br x17

View File

@ -1,11 +1,12 @@
/**
* \brief ARM 64-bit specific relocations
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2014-10-26
* \date 2019-04-02
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
* Copyright (C) 2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -23,15 +24,16 @@ namespace Linker {
* Relocation types
*/
enum Reloc_types {
R_64 = 1, /* add 64 bit symbol value. */
R_COPY = 5,
R_GLOB_DAT = 6, /* GOT entry to data address */
R_JMPSLOT = 7, /* jump slot */
R_RELATIVE = 8, /* add load addr of shared object */
R_64 = 257, /* add 64 bit symbol value. */
R_COPY = 1024,
R_GLOB_DAT = 1025, /* GOT entry to data address */
R_JMPSLOT = 1026, /* jump slot */
R_RELATIVE = 1027, /* add load addr of shared object */
};
class Reloc_non_plt;
typedef Plt_got_generic<2> Plt_got;
typedef Reloc_plt_generic<Elf::Rela, DT_RELA, R_JMPSLOT> Reloc_plt;
typedef Reloc_jmpslot_generic<Elf::Rela, DT_RELA, false> Reloc_jmpslot;
typedef Reloc_bind_now_generic<Elf::Rela, DT_RELA> Reloc_bind_now;
@ -41,28 +43,60 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
{
private:
void _relative(Elf::Rela const *, Elf::Addr *)
void _relative(Elf::Rela const *rel, Elf::Addr *addr)
{
error("not implemented yet");
*addr = _dep.obj().reloc_base() + rel->addend;
}
void _glob_dat_64(Elf::Rela const *, Elf::Addr *, bool)
void _glob_dat_64(Elf::Rela const *rel, Elf::Addr *addr, bool addend)
{
error("not implemented yet");
Elf::Addr reloc_base;
Elf::Sym const *sym;
if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base)))
return;
*addr = reloc_base + sym->st_value + (addend ? rel->addend : 0);
if (verbose_reloc(_dep))
log("GLOB DAT ", addr, " -> ", *addr,
" r ", reloc_base, " v ", sym->st_value);
}
public:
Reloc_non_plt(Dependency const &dep, Elf::Rela const *, unsigned long, bool)
Reloc_non_plt(Dependency const &dep, Elf::Rela const *rel, unsigned long size,
bool second_pass)
: Reloc_non_plt_generic(dep)
{
error("not implemented yet");
Elf::Rela const *end = rel + (size / sizeof(Elf::Rela));
for (; rel < end; rel++) {
Elf::Addr *addr = (Elf::Addr *)(_dep.obj().reloc_base() + rel->offset);
if (second_pass && rel->type() != R_GLOB_DAT)
continue;
switch(rel->type()) {
case R_64:
case R_GLOB_DAT: _glob_dat_64(rel, addr, true); break;
case R_COPY: _copy<Elf::Rela>(rel, addr); break;
case R_RELATIVE: _relative(rel, addr); break;
default:
if (!_dep.obj().is_linker()) {
warning("LD: Unkown relocation ", (int)rel->type());
throw Incompatible();
}
break;
}
}
}
Reloc_non_plt(Dependency const &dep, Elf::Rel const *, unsigned long, bool)
: Reloc_non_plt_generic(dep)
{
error("not implemented yet");
error("LD: DT_REL not supported");
throw Incompatible();
}
};