diff options
author | Daniel Bertalan <dani@danielbertalan.dev> | 2023-04-22 11:44:02 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-05-14 13:47:53 +0200 |
commit | cd45c2d295f638adc73fd0730b7e83c9351449a8 (patch) | |
tree | 046c68caa6b5bdc35a124773de48307764b7900b /Userland | |
parent | c4e0f5e5eed248fc06aabd8531b13f0440c8c9e0 (diff) | |
download | serenity-cd45c2d295f638adc73fd0730b7e83c9351449a8.zip |
LibELF: Split `do_relocation` into `do_{direct,plt}_relocation`
No functional changes intended. This is in preparation of a commit that
overhauls how IFUNCs are resolved.
This commit lets us move the implementation of PLT patching from
`DynamicObject` to `DynamicLoader` where all other relocation code
lives. For this, got[2] now stores the loader's address instead of the
object's.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibELF/DynamicLoader.cpp | 101 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicLoader.h | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicObject.cpp | 27 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicObject.h | 3 |
4 files changed, 82 insertions, 56 deletions
diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp index 98711e9ef0..279b0cf5d8 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.cpp +++ b/Userland/Libraries/LibELF/DynamicLoader.cpp @@ -7,6 +7,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/Debug.h> #include <AK/Optional.h> #include <AK/QuickSort.h> #include <AK/StringBuilder.h> @@ -199,8 +200,10 @@ bool DynamicLoader::load_stage_2(unsigned flags) void DynamicLoader::do_main_relocations() { - auto do_single_relocation = [&](const ELF::DynamicObject::Relocation& relocation) { - switch (do_relocation(relocation, ShouldInitializeWeak::No)) { + do_relr_relocations(); + + m_dynamic_object->relocation_section().for_each_relocation([&](DynamicObject::Relocation const& relocation) { + switch (do_direct_relocation(relocation, ShouldInitializeWeak::No)) { case RelocationResult::Failed: dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name()); VERIFY_NOT_REACHED(); @@ -210,11 +213,42 @@ void DynamicLoader::do_main_relocations() case RelocationResult::Success: break; } + }); + + auto fixup_trampoline_pointer = [&](DynamicObject::Relocation const& relocation) { + VERIFY(relocation.type() == R_X86_64_JUMP_SLOT || relocation.type() == R_AARCH64_JUMP_SLOT); + if (image().is_dynamic()) + *((FlatPtr*)relocation.address().as_ptr()) += m_dynamic_object->base_address().get(); }; - do_relr_relocations(); - m_dynamic_object->relocation_section().for_each_relocation(do_single_relocation); - m_dynamic_object->plt_relocation_section().for_each_relocation(do_single_relocation); + if (m_dynamic_object->must_bind_now()) { + m_dynamic_object->plt_relocation_section().for_each_relocation([&](DynamicObject::Relocation const& relocation) { + RelocationResult result; + if (relocation.type() == R_X86_64_IRELATIVE || relocation.type() == R_AARCH64_IRELATIVE) { + result = do_direct_relocation(relocation, ShouldInitializeWeak::No); + } else { + result = do_plt_relocation(relocation); + } + + switch (result) { + case RelocationResult::Failed: + dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name()); + VERIFY_NOT_REACHED(); + case RelocationResult::ResolveLater: + VERIFY_NOT_REACHED(); + case RelocationResult::Success: + break; + } + }); + } else { + 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) { + do_direct_relocation(relocation, ShouldInitializeWeak::No); + return; + } + fixup_trampoline_pointer(relocation); + }); + } } Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> DynamicLoader::load_stage_3(unsigned flags) @@ -261,7 +295,7 @@ void DynamicLoader::load_stage_4() void DynamicLoader::do_lazy_relocations() { for (auto const& relocation : m_unresolved_relocations) { - if (auto res = do_relocation(relocation, ShouldInitializeWeak::Yes); res != RelocationResult::Success) { + if (auto res = do_direct_relocation(relocation, ShouldInitializeWeak::Yes); res != RelocationResult::Success) { dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name()); VERIFY_NOT_REACHED(); } @@ -461,7 +495,7 @@ void DynamicLoader::load_program_headers() } } -DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicObject::Relocation& relocation, ShouldInitializeWeak should_initialize_weak) +DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObject::Relocation const& relocation, ShouldInitializeWeak should_initialize_weak) { FlatPtr* patch_ptr = nullptr; if (is_dynamic()) @@ -566,21 +600,6 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicO break; } - case R_AARCH64_JUMP_SLOT: - case R_X86_64_JUMP_SLOT: { - // FIXME: Or BIND_NOW flag passed in? - if (m_dynamic_object->must_bind_now()) { - // Eagerly BIND_NOW the PLT entries, doing all the symbol looking goodness - // The patch method returns the address for the LAZY fixup path, but we don't need it here - m_dynamic_object->patch_plt_entry(relocation.offset_in_section()); - } else { - auto relocation_address = (FlatPtr*)relocation.address().as_ptr(); - - if (image().is_dynamic()) - *relocation_address += m_dynamic_object->base_address().get(); - } - break; - } case R_AARCH64_IRELATIVE: case R_X86_64_IRELATIVE: { VirtualAddress resolver; @@ -597,6 +616,9 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicO *patch_ptr = call_ifunc_resolver(resolver).get(); break; } + case R_AARCH64_JUMP_SLOT: + case R_X86_64_JUMP_SLOT: + VERIFY_NOT_REACHED(); // PLT relocations are handled by do_plt_relocation. default: // Raise the alarm! Someone needs to implement this relocation type dbgln("Found a new exciting relocation type {}", relocation.type()); @@ -605,6 +627,31 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicO return RelocationResult::Success; } +DynamicLoader::RelocationResult DynamicLoader::do_plt_relocation(DynamicObject::Relocation const& relocation) +{ + VERIFY(relocation.type() == R_X86_64_JUMP_SLOT || relocation.type() == R_AARCH64_JUMP_SLOT); + auto symbol = relocation.symbol(); + auto* relocation_address = (FlatPtr*)relocation.address().as_ptr(); + + VirtualAddress symbol_location {}; + if (auto result = lookup_symbol(symbol); result.has_value()) { + auto address = result.value().address; + + if (result.value().type == STT_GNU_IFUNC) { + symbol_location = VirtualAddress { reinterpret_cast<DynamicObject::IfuncResolver>(address.get())() }; + } else { + symbol_location = address; + } + } else if (symbol.bind() != STB_WEAK) { + return RelocationResult::Failed; + } + + dbgln_if(DYNAMIC_LOAD_DEBUG, "DynamicLoader: Jump slot relocation: putting {} ({}) into PLT at {}", symbol.name(), symbol_location, (void*)relocation_address); + *relocation_address = symbol_location.get(); + + return RelocationResult::Success; +} + void DynamicLoader::do_relr_relocations() { auto base_address = m_dynamic_object->base_address().get(); @@ -651,11 +698,15 @@ void DynamicLoader::setup_plt_trampoline() } // Called from our ASM routine _plt_trampoline. -// Tell the compiler that it might be called from other places: -extern "C" FlatPtr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset); extern "C" FlatPtr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset) { - return object->patch_plt_entry(relocation_offset).get(); + auto const& relocation = object->plt_relocation_section().relocation_at_offset(relocation_offset); + auto result = DynamicLoader::do_plt_relocation(relocation); + if (result != DynamicLoader::RelocationResult::Success) { + dbgln("Loader.so: {} unresolved symbol '{}'", object->filepath(), relocation.symbol().name()); + VERIFY_NOT_REACHED(); + } + return *reinterpret_cast<FlatPtr*>(relocation.address().as_ptr()); } void DynamicLoader::call_object_init_functions() diff --git a/Userland/Libraries/LibELF/DynamicLoader.h b/Userland/Libraries/LibELF/DynamicLoader.h index 199bf13e22..47b7e303ea 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.h +++ b/Userland/Libraries/LibELF/DynamicLoader.h @@ -40,6 +40,8 @@ enum class ShouldInitializeWeak { No }; +extern "C" FlatPtr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset); + class DynamicLoader : public RefCounted<DynamicLoader> { public: static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> try_create(int fd, DeprecatedString filepath); @@ -113,6 +115,8 @@ private: ElfW(Phdr) m_program_header; // Explicitly a copy of the PHDR in the image }; + friend FlatPtr _fixup_plt_entry(DynamicObject*, u32); + // Stage 1 void load_program_headers(); @@ -133,7 +137,8 @@ private: Success = 1, ResolveLater = 2, }; - RelocationResult do_relocation(DynamicObject::Relocation const&, ShouldInitializeWeak should_initialize_weak); + RelocationResult do_direct_relocation(DynamicObject::Relocation const&, ShouldInitializeWeak); + static RelocationResult do_plt_relocation(DynamicObject::Relocation const&); void do_relr_relocations(); void find_tls_size_and_alignment(); diff --git a/Userland/Libraries/LibELF/DynamicObject.cpp b/Userland/Libraries/LibELF/DynamicObject.cpp index 4ba5392926..c371611d3c 100644 --- a/Userland/Libraries/LibELF/DynamicObject.cpp +++ b/Userland/Libraries/LibELF/DynamicObject.cpp @@ -480,33 +480,6 @@ NonnullRefPtr<DynamicObject> DynamicObject::create(DeprecatedString const& filep return adopt_ref(*new DynamicObject(filepath, base_address, dynamic_section_address)); } -// offset is in PLT relocation table -VirtualAddress DynamicObject::patch_plt_entry(u32 relocation_offset) -{ - auto relocation = plt_relocation_section().relocation_at_offset(relocation_offset); - VERIFY(relocation.type() == R_X86_64_JUMP_SLOT || relocation.type() == R_AARCH64_JUMP_SLOT); - auto symbol = relocation.symbol(); - auto relocation_address = (FlatPtr*)relocation.address().as_ptr(); - - VirtualAddress symbol_location; - auto result = DynamicLoader::lookup_symbol(symbol); - if (result.has_value()) { - symbol_location = result.value().address; - - if (result.value().type == STT_GNU_IFUNC) - symbol_location = VirtualAddress { reinterpret_cast<IfuncResolver>(symbol_location.get())() }; - } else if (symbol.bind() != STB_WEAK) { - dbgln("did not find symbol while doing relocations for library {}: {}", m_filepath, symbol.name()); - VERIFY_NOT_REACHED(); - } - - dbgln_if(DYNAMIC_LOAD_DEBUG, "DynamicLoader: Jump slot relocation: putting {} ({}) into PLT at {}", symbol.name(), symbol_location, (void*)relocation_address); - - *relocation_address = symbol_location.get(); - - return symbol_location; -} - u32 DynamicObject::HashSymbol::gnu_hash() const { if (!m_gnu_hash.has_value()) diff --git a/Userland/Libraries/LibELF/DynamicObject.h b/Userland/Libraries/LibELF/DynamicObject.h index fe0d3bfb39..b515785c2b 100644 --- a/Userland/Libraries/LibELF/DynamicObject.h +++ b/Userland/Libraries/LibELF/DynamicObject.h @@ -314,9 +314,6 @@ public: Optional<SymbolLookupResult> lookup_symbol(StringView name) const; Optional<SymbolLookupResult> lookup_symbol(HashSymbol const& symbol) const; - // Will be called from _fixup_plt_entry, as part of the PLT trampoline - VirtualAddress patch_plt_entry(u32 relocation_offset); - bool elf_is_dynamic() const { return m_is_elf_dynamic; } void* symbol_for_name(StringView name); |