From 8cff58d5af8f65a881ea0da59322af57843f7dfe Mon Sep 17 00:00:00 2001 From: fincs Date: Sat, 31 Aug 2024 00:40:56 +0200 Subject: [PATCH] dynamic: add support for ELF packed relocations (relr) --- nx/source/runtime/dynamic.c | 38 +++++++++++++++++++++++++++++++++++++ nx/switch.specs | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/nx/source/runtime/dynamic.c b/nx/source/runtime/dynamic.c index c9e2587eb..d92e150e2 100644 --- a/nx/source/runtime/dynamic.c +++ b/nx/source/runtime/dynamic.c @@ -36,6 +36,10 @@ static void _dynProcessRela(uintptr_t base, const Elf64_Rela* rela, size_t relas break; } + case R_AARCH64_NONE: { + break; + } + case R_AARCH64_RELATIVE: { u64* ptr = (u64*)(base + rela->r_offset); *ptr = base + rela->r_addend; @@ -45,6 +49,25 @@ static void _dynProcessRela(uintptr_t base, const Elf64_Rela* rela, size_t relas } } +static void _dynProcessRelr(uintptr_t base, const Elf64_Relr* relr, size_t relrsz) +{ + u64* ptr = NULL; + for (; relrsz--; relr++) { + if ((*relr & 1) == 0) { + ptr = (u64*)(base + *relr); + *ptr++ += base; + } else { + u64 bitmap = *relr >> 1; + while (bitmap) { + unsigned id = __builtin_ffsl(bitmap)-1; + bitmap &= ~(1UL << id); + ptr[id] += base; + } + ptr += 63; + } + } +} + void __nx_dynamic(uintptr_t base, const Mod0Header* mod0) { // Return early if MOD0 header has been invalidated @@ -65,6 +88,8 @@ void __nx_dynamic(uintptr_t base, const Mod0Header* mod0) // Extract relevant information from the ELF dynamic section const Elf64_Rela* rela = NULL; size_t relasz = 0; + const Elf64_Relr* relr = NULL; + size_t relrsz = 0; for (; dyn->d_tag != DT_NULL; dyn++) { switch (dyn->d_tag) { case DT_RELA: @@ -74,6 +99,14 @@ void __nx_dynamic(uintptr_t base, const Mod0Header* mod0) case DT_RELASZ: relasz = dyn->d_un.d_val / sizeof(Elf64_Rela); break; + + case DT_RELR: + relr = (const Elf64_Relr*)(base + dyn->d_un.d_ptr); + break; + + case DT_RELRSZ: + relrsz = dyn->d_un.d_val / sizeof(Elf64_Relr); + break; } } @@ -82,6 +115,11 @@ void __nx_dynamic(uintptr_t base, const Mod0Header* mod0) _dynProcessRela(base, rela, relasz); } + // Apply RELR relocations if present + if (relr && relrsz) { + _dynProcessRelr(base, relr, relrsz); + } + // Return early if LNY0/LNY1 extensions are not present if (mod0->magic_lny0 != 0x30594e4c || mod0->magic_lny1 != 0x31594e4c) { // LNY0, LNY1 return; diff --git a/nx/switch.specs b/nx/switch.specs index c486af8d8..a0f1eb1ef 100644 --- a/nx/switch.specs +++ b/nx/switch.specs @@ -1,5 +1,5 @@ *link: -+ -T %:getenv(DEVKITPRO /libnx/switch.ld) -pie --no-dynamic-linker --spare-dynamic-tags=0 --gc-sections -z text -z now -z nodynamic-undefined-weak --build-id=sha1 --nx-module-name ++ -T %:getenv(DEVKITPRO /libnx/switch.ld) -pie --no-dynamic-linker --spare-dynamic-tags=0 --gc-sections -z text -z now -z nodynamic-undefined-weak -z pack-relative-relocs --build-id=sha1 --nx-module-name *startfile: crti%O%s crtbegin%O%s --require-defined=main