Kaynağa Gözat

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.
Daniel Bertalan 2 yıl önce
ebeveyn
işleme
cd45c2d295

+ 76 - 25
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()

+ 6 - 1
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();
 

+ 0 - 27
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())

+ 0 - 3
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);