summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibELF/DynamicLoader.cpp101
-rw-r--r--Userland/Libraries/LibELF/DynamicLoader.h7
-rw-r--r--Userland/Libraries/LibELF/DynamicObject.cpp27
-rw-r--r--Userland/Libraries/LibELF/DynamicObject.h3
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);