mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 13:47:45 +00:00
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.
This commit is contained in:
parent
c4e0f5e5ee
commit
cd45c2d295
4 changed files with 82 additions and 56 deletions
|
@ -7,6 +7,7 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/Debug.h>
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
#include <AK/QuickSort.h>
|
#include <AK/QuickSort.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
|
@ -199,8 +200,10 @@ bool DynamicLoader::load_stage_2(unsigned flags)
|
||||||
|
|
||||||
void DynamicLoader::do_main_relocations()
|
void DynamicLoader::do_main_relocations()
|
||||||
{
|
{
|
||||||
auto do_single_relocation = [&](const ELF::DynamicObject::Relocation& relocation) {
|
do_relr_relocations();
|
||||||
switch (do_relocation(relocation, ShouldInitializeWeak::No)) {
|
|
||||||
|
m_dynamic_object->relocation_section().for_each_relocation([&](DynamicObject::Relocation const& relocation) {
|
||||||
|
switch (do_direct_relocation(relocation, ShouldInitializeWeak::No)) {
|
||||||
case RelocationResult::Failed:
|
case RelocationResult::Failed:
|
||||||
dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name());
|
dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name());
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
|
@ -210,11 +213,42 @@ void DynamicLoader::do_main_relocations()
|
||||||
case RelocationResult::Success:
|
case RelocationResult::Success:
|
||||||
break;
|
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();
|
if (m_dynamic_object->must_bind_now()) {
|
||||||
m_dynamic_object->relocation_section().for_each_relocation(do_single_relocation);
|
m_dynamic_object->plt_relocation_section().for_each_relocation([&](DynamicObject::Relocation const& relocation) {
|
||||||
m_dynamic_object->plt_relocation_section().for_each_relocation(do_single_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)
|
Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> DynamicLoader::load_stage_3(unsigned flags)
|
||||||
|
@ -261,7 +295,7 @@ void DynamicLoader::load_stage_4()
|
||||||
void DynamicLoader::do_lazy_relocations()
|
void DynamicLoader::do_lazy_relocations()
|
||||||
{
|
{
|
||||||
for (auto const& relocation : m_unresolved_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());
|
dbgln("Loader.so: {} unresolved symbol '{}'", m_filepath, relocation.symbol().name());
|
||||||
VERIFY_NOT_REACHED();
|
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;
|
FlatPtr* patch_ptr = nullptr;
|
||||||
if (is_dynamic())
|
if (is_dynamic())
|
||||||
|
@ -566,21 +600,6 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicO
|
||||||
|
|
||||||
break;
|
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_AARCH64_IRELATIVE:
|
||||||
case R_X86_64_IRELATIVE: {
|
case R_X86_64_IRELATIVE: {
|
||||||
VirtualAddress resolver;
|
VirtualAddress resolver;
|
||||||
|
@ -597,6 +616,9 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicO
|
||||||
*patch_ptr = call_ifunc_resolver(resolver).get();
|
*patch_ptr = call_ifunc_resolver(resolver).get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case R_AARCH64_JUMP_SLOT:
|
||||||
|
case R_X86_64_JUMP_SLOT:
|
||||||
|
VERIFY_NOT_REACHED(); // PLT relocations are handled by do_plt_relocation.
|
||||||
default:
|
default:
|
||||||
// Raise the alarm! Someone needs to implement this relocation type
|
// Raise the alarm! Someone needs to implement this relocation type
|
||||||
dbgln("Found a new exciting relocation type {}", 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;
|
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()
|
void DynamicLoader::do_relr_relocations()
|
||||||
{
|
{
|
||||||
auto base_address = m_dynamic_object->base_address().get();
|
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.
|
// 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)
|
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()
|
void DynamicLoader::call_object_init_functions()
|
||||||
|
|
|
@ -40,6 +40,8 @@ enum class ShouldInitializeWeak {
|
||||||
No
|
No
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern "C" FlatPtr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset);
|
||||||
|
|
||||||
class DynamicLoader : public RefCounted<DynamicLoader> {
|
class DynamicLoader : public RefCounted<DynamicLoader> {
|
||||||
public:
|
public:
|
||||||
static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> try_create(int fd, DeprecatedString filepath);
|
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
|
ElfW(Phdr) m_program_header; // Explicitly a copy of the PHDR in the image
|
||||||
};
|
};
|
||||||
|
|
||||||
|
friend FlatPtr _fixup_plt_entry(DynamicObject*, u32);
|
||||||
|
|
||||||
// Stage 1
|
// Stage 1
|
||||||
void load_program_headers();
|
void load_program_headers();
|
||||||
|
|
||||||
|
@ -133,7 +137,8 @@ private:
|
||||||
Success = 1,
|
Success = 1,
|
||||||
ResolveLater = 2,
|
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 do_relr_relocations();
|
||||||
void find_tls_size_and_alignment();
|
void find_tls_size_and_alignment();
|
||||||
|
|
||||||
|
|
|
@ -480,33 +480,6 @@ NonnullRefPtr<DynamicObject> DynamicObject::create(DeprecatedString const& filep
|
||||||
return adopt_ref(*new DynamicObject(filepath, base_address, dynamic_section_address));
|
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
|
u32 DynamicObject::HashSymbol::gnu_hash() const
|
||||||
{
|
{
|
||||||
if (!m_gnu_hash.has_value())
|
if (!m_gnu_hash.has_value())
|
||||||
|
|
|
@ -314,9 +314,6 @@ public:
|
||||||
Optional<SymbolLookupResult> lookup_symbol(StringView name) const;
|
Optional<SymbolLookupResult> lookup_symbol(StringView name) const;
|
||||||
Optional<SymbolLookupResult> lookup_symbol(HashSymbol const& symbol) 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; }
|
bool elf_is_dynamic() const { return m_is_elf_dynamic; }
|
||||||
|
|
||||||
void* symbol_for_name(StringView name);
|
void* symbol_for_name(StringView name);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue