Skip to content

Commit

Permalink
dynamic: add support for ELF packed relocations (relr)
Browse files Browse the repository at this point in the history
  • Loading branch information
fincs committed Aug 30, 2024
1 parent d66e3aa commit 8cff58d
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
38 changes: 38 additions & 0 deletions nx/source/runtime/dynamic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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;
}
}

Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion nx/switch.specs
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 8cff58d

Please sign in to comment.