From f8628f94b8e79b6f6c9aaaa3e8b21a6445fe2770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Sat, 10 Feb 2024 20:43:07 +0100 Subject: [PATCH] LibELF: Refactor how arch-specific dynamic relocation types are handled We currently expect that the relocation type numbers are unique across all architectures. But RISC-V and x86_64 use the same numbers for different relocation types (R_X86_64_COPY = R_RISCV_JUMP_SLOT = 5). So create a generic reloc type enum which maps to the arch-specific reloc types instead of checking for all arch reloc types individually everywhere. --- .../Arch/GenericDynamicRelocationType.h | 17 +++++++++ .../aarch64/GenericDynamicRelocationType.h | 30 +++++++++++++++ .../x86_64/GenericDynamicRelocationType.h | 30 +++++++++++++++ Userland/Libraries/LibELF/DynamicLoader.cpp | 38 +++++++++---------- Userland/Libraries/LibELF/DynamicObject.h | 3 +- Userland/Libraries/LibELF/Relocation.cpp | 3 +- 6 files changed, 98 insertions(+), 23 deletions(-) create mode 100644 Userland/Libraries/LibELF/Arch/GenericDynamicRelocationType.h create mode 100644 Userland/Libraries/LibELF/Arch/aarch64/GenericDynamicRelocationType.h create mode 100644 Userland/Libraries/LibELF/Arch/x86_64/GenericDynamicRelocationType.h diff --git a/Userland/Libraries/LibELF/Arch/GenericDynamicRelocationType.h b/Userland/Libraries/LibELF/Arch/GenericDynamicRelocationType.h new file mode 100644 index 0000000000..2cf11b5544 --- /dev/null +++ b/Userland/Libraries/LibELF/Arch/GenericDynamicRelocationType.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024, Sönke Holz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +#if ARCH(AARCH64) +# include +#elif ARCH(X86_64) +# include +#else +# error Unknown architecture +#endif diff --git a/Userland/Libraries/LibELF/Arch/aarch64/GenericDynamicRelocationType.h b/Userland/Libraries/LibELF/Arch/aarch64/GenericDynamicRelocationType.h new file mode 100644 index 0000000000..48e4d2db10 --- /dev/null +++ b/Userland/Libraries/LibELF/Arch/aarch64/GenericDynamicRelocationType.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024, Sönke Holz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +#include +VALIDATE_IS_AARCH64() + +namespace ELF { + +enum class GenericDynamicRelocationType : unsigned { + NONE = R_AARCH64_NONE, + ABSOLUTE = R_AARCH64_ABS64, + COPY = R_AARCH64_COPY, + GLOB_DAT = R_AARCH64_GLOB_DAT, + JUMP_SLOT = R_AARCH64_JUMP_SLOT, + RELATIVE = R_AARCH64_RELATIVE, + TLS_DTPMOD = R_AARCH64_TLS_DTPMOD, + TLS_DTPREL = R_AARCH64_TLS_DTPREL, + TLS_TPREL = R_AARCH64_TLS_TPREL, + TLSDESC = R_AARCH64_TLSDESC, + IRELATIVE = R_AARCH64_IRELATIVE, +}; + +} diff --git a/Userland/Libraries/LibELF/Arch/x86_64/GenericDynamicRelocationType.h b/Userland/Libraries/LibELF/Arch/x86_64/GenericDynamicRelocationType.h new file mode 100644 index 0000000000..74ba9aa498 --- /dev/null +++ b/Userland/Libraries/LibELF/Arch/x86_64/GenericDynamicRelocationType.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024, Sönke Holz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +#include +VALIDATE_IS_X86() + +namespace ELF { + +enum class GenericDynamicRelocationType : unsigned { + NONE = R_X86_64_NONE, + ABSOLUTE = R_X86_64_64, + COPY = R_X86_64_COPY, + GLOB_DAT = R_X86_64_GLOB_DAT, + JUMP_SLOT = R_X86_64_JUMP_SLOT, + RELATIVE = R_X86_64_RELATIVE, + TLS_DTPMOD = R_X86_64_DTPMOD64, + TLS_DTPREL = R_X86_64_DTPOFF64, + TLS_TPREL = R_X86_64_TPOFF64, + TLSDESC = R_X86_64_TLSDESC, + IRELATIVE = R_X86_64_IRELATIVE, +}; + +} diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp index 56c7460301..481a3023a1 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.cpp +++ b/Userland/Libraries/LibELF/DynamicLoader.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -228,17 +229,17 @@ void DynamicLoader::do_main_relocations() // If the object is position-independent, the pointer to the PLT trampoline needs to be relocated. auto fixup_trampoline_pointer = [&](DynamicObject::Relocation const& relocation) { - VERIFY(relocation.type() == R_X86_64_JUMP_SLOT || relocation.type() == R_AARCH64_JUMP_SLOT); + VERIFY(static_cast(relocation.type()) == GenericDynamicRelocationType::JUMP_SLOT); if (image().is_dynamic()) *((FlatPtr*)relocation.address().as_ptr()) += m_dynamic_object->base_address().get(); }; m_dynamic_object->plt_relocation_section().for_each_relocation([&](DynamicObject::Relocation const& relocation) { - if (relocation.type() == R_X86_64_IRELATIVE || relocation.type() == R_AARCH64_IRELATIVE) { + if (static_cast(relocation.type()) == GenericDynamicRelocationType::IRELATIVE) { m_direct_ifunc_relocations.append(relocation); return; } - if (relocation.type() == R_X86_64_TLSDESC || relocation.type() == R_AARCH64_TLSDESC) { + if (static_cast(relocation.type()) == GenericDynamicRelocationType::TLSDESC) { // GNU ld for some reason puts TLSDESC relocations into .rela.plt // https://sourceware.org/bugzilla/show_bug.cgi?id=28387 @@ -574,14 +575,14 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec return ResolvedTLSSymbol { *res.value().dynamic_object, res.value().value }; }; - switch (relocation.type()) { + using enum GenericDynamicRelocationType; + switch (static_cast(relocation.type())) { - case R_X86_64_NONE: + case NONE: // Apparently most loaders will just skip these? // Seems if the 'link editor' generates one something is funky with your code break; - case R_AARCH64_ABS64: - case R_X86_64_64: { + case ABSOLUTE: { auto symbol = relocation.symbol(); auto res = lookup_symbol(symbol); if (!res.has_value()) { @@ -602,8 +603,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec *patch_ptr = call_ifunc_resolver(VirtualAddress { *patch_ptr }).get(); break; } - case R_AARCH64_GLOB_DAT: - case R_X86_64_GLOB_DAT: { + case GLOB_DAT: { auto symbol = relocation.symbol(); auto res = lookup_symbol(symbol); VirtualAddress symbol_location; @@ -633,8 +633,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec *patch_ptr = symbol_location.get(); break; } - case R_AARCH64_RELATIVE: - case R_X86_64_RELATIVE: { + case RELATIVE: { if (!image().is_dynamic()) break; // FIXME: According to the spec, R_386_relative ones must be done first. @@ -646,8 +645,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec *patch_ptr += m_dynamic_object->base_address().get(); break; } - case R_AARCH64_TLS_TPREL: - case R_X86_64_TPOFF64: { + case TLS_TPREL: { auto maybe_resolution = resolve_tls_symbol(relocation); if (!maybe_resolution.has_value()) break; @@ -660,7 +658,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec VERIFY(static_cast(*patch_ptr) < 0); break; } - case R_X86_64_DTPMOD64: { + case TLS_DTPMOD: { auto maybe_resolution = resolve_tls_symbol(relocation); if (!maybe_resolution.has_value()) break; @@ -670,7 +668,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec *patch_ptr = maybe_resolution->dynamic_object.tls_offset().value(); break; } - case R_X86_64_DTPOFF64: { + case TLS_DTPREL: { auto maybe_resolution = resolve_tls_symbol(relocation); if (!maybe_resolution.has_value()) break; @@ -680,7 +678,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec break; } #ifdef HAS_TLSDESC_SUPPORT - case R_AARCH64_TLSDESC: { + case TLSDESC: { auto maybe_resolution = resolve_tls_symbol(relocation); if (!maybe_resolution.has_value()) break; @@ -693,8 +691,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec break; } #endif - case R_AARCH64_IRELATIVE: - case R_X86_64_IRELATIVE: { + case IRELATIVE: { if (should_call_ifunc_resolver == ShouldCallIfuncResolver::No) return RelocationResult::CallIfuncResolver; VirtualAddress resolver; @@ -711,8 +708,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec *patch_ptr = call_ifunc_resolver(resolver).get(); break; } - case R_AARCH64_JUMP_SLOT: - case R_X86_64_JUMP_SLOT: + case JUMP_SLOT: VERIFY_NOT_REACHED(); // PLT relocations are handled by do_plt_relocation. default: // Raise the alarm! Someone needs to implement this relocation type @@ -724,7 +720,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec DynamicLoader::RelocationResult DynamicLoader::do_plt_relocation(DynamicObject::Relocation const& relocation, ShouldCallIfuncResolver should_call_ifunc_resolver) { - VERIFY(relocation.type() == R_X86_64_JUMP_SLOT || relocation.type() == R_AARCH64_JUMP_SLOT); + VERIFY(static_cast(relocation.type()) == GenericDynamicRelocationType::JUMP_SLOT); auto symbol = relocation.symbol(); auto* relocation_address = (FlatPtr*)relocation.address().as_ptr(); diff --git a/Userland/Libraries/LibELF/DynamicObject.h b/Userland/Libraries/LibELF/DynamicObject.h index 8d10edc955..4e89b91934 100644 --- a/Userland/Libraries/LibELF/DynamicObject.h +++ b/Userland/Libraries/LibELF/DynamicObject.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -402,7 +403,7 @@ inline void DynamicObject::RelocationSection::for_each_relocation(F func) const { for (unsigned i = 0; i < relocation_count(); ++i) { auto const reloc = relocation(i); - if (reloc.type() == 0) + if (static_cast(reloc.type()) == GenericDynamicRelocationType::NONE) continue; if (func(reloc) == IterationDecision::Break) break; diff --git a/Userland/Libraries/LibELF/Relocation.cpp b/Userland/Libraries/LibELF/Relocation.cpp index 13dc9c1e51..e09028ac85 100644 --- a/Userland/Libraries/LibELF/Relocation.cpp +++ b/Userland/Libraries/LibELF/Relocation.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include @@ -59,7 +60,7 @@ bool perform_relative_relocations(FlatPtr base_address) for (unsigned i = 0; i < relocation_count; ++i) { size_t offset_in_section = i * relocation_entry_size; auto* relocation = (Elf_Rela*)(relocation_section_addr + offset_in_section); - VERIFY(ELF64_R_TYPE(relocation->r_info) == R_X86_64_RELATIVE || ELF64_R_TYPE(relocation->r_info) == R_AARCH64_RELATIVE); + VERIFY(static_cast(ELF64_R_TYPE(relocation->r_info)) == GenericDynamicRelocationType::RELATIVE); auto* patch_address = (FlatPtr*)(base_address + relocation->r_offset); FlatPtr relocated_address; if (use_addend) {