From a8d856fb65796ca06bd23ca95fb40fb8afb10ea7 Mon Sep 17 00:00:00 2001 From: Sebastian Sumpf Date: Thu, 4 Apr 2019 12:13:08 +0200 Subject: [PATCH] ldso: dynamic linking support for ARM 64-bit * added relocation support * added assembler invocation path for jump slot relocations fixes issue #3260 --- .../base/src/lib/ldso/spec/arm_64/jmp_slot.s | 57 +++++++++++++++-- .../src/lib/ldso/spec/arm_64/relocation.h | 62 ++++++++++++++----- 2 files changed, 101 insertions(+), 18 deletions(-) diff --git a/repos/base/src/lib/ldso/spec/arm_64/jmp_slot.s b/repos/base/src/lib/ldso/spec/arm_64/jmp_slot.s index 9dc186e38..7dcccfe2a 100644 --- a/repos/base/src/lib/ldso/spec/arm_64/jmp_slot.s +++ b/repos/base/src/lib/ldso/spec/arm_64/jmp_slot.s @@ -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 diff --git a/repos/base/src/lib/ldso/spec/arm_64/relocation.h b/repos/base/src/lib/ldso/spec/arm_64/relocation.h index 142c4fb29..e423491f4 100644 --- a/repos/base/src/lib/ldso/spec/arm_64/relocation.h +++ b/repos/base/src/lib/ldso/spec/arm_64/relocation.h @@ -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 Reloc_plt; typedef Reloc_jmpslot_generic Reloc_jmpslot; typedef Reloc_bind_now_generic 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(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(); } };