1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 15:28:11 +00:00

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.
This commit is contained in:
Sönke Holz 2024-02-10 20:43:07 +01:00 committed by Andrew Kaster
parent c216e7439f
commit f8628f94b8
6 changed files with 98 additions and 23 deletions

View file

@ -0,0 +1,17 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Platform.h>
#if ARCH(AARCH64)
# include <Userland/Libraries/LibELF/Arch/aarch64/GenericDynamicRelocationType.h>
#elif ARCH(X86_64)
# include <Userland/Libraries/LibELF/Arch/x86_64/GenericDynamicRelocationType.h>
#else
# error Unknown architecture
#endif

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <Userland/Libraries/LibELF/ELFABI.h>
#include <AK/Platform.h>
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,
};
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <Userland/Libraries/LibELF/ELFABI.h>
#include <AK/Platform.h>
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,
};
}

View file

@ -11,6 +11,7 @@
#include <AK/Optional.h> #include <AK/Optional.h>
#include <AK/QuickSort.h> #include <AK/QuickSort.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibELF/Arch/GenericDynamicRelocationType.h>
#include <LibELF/DynamicLinker.h> #include <LibELF/DynamicLinker.h>
#include <LibELF/DynamicLoader.h> #include <LibELF/DynamicLoader.h>
#include <LibELF/Hashes.h> #include <LibELF/Hashes.h>
@ -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. // If the object is position-independent, the pointer to the PLT trampoline needs to be relocated.
auto fixup_trampoline_pointer = [&](DynamicObject::Relocation const& relocation) { 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<GenericDynamicRelocationType>(relocation.type()) == GenericDynamicRelocationType::JUMP_SLOT);
if (image().is_dynamic()) if (image().is_dynamic())
*((FlatPtr*)relocation.address().as_ptr()) += m_dynamic_object->base_address().get(); *((FlatPtr*)relocation.address().as_ptr()) += m_dynamic_object->base_address().get();
}; };
m_dynamic_object->plt_relocation_section().for_each_relocation([&](DynamicObject::Relocation const& relocation) { 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<GenericDynamicRelocationType>(relocation.type()) == GenericDynamicRelocationType::IRELATIVE) {
m_direct_ifunc_relocations.append(relocation); m_direct_ifunc_relocations.append(relocation);
return; return;
} }
if (relocation.type() == R_X86_64_TLSDESC || relocation.type() == R_AARCH64_TLSDESC) { if (static_cast<GenericDynamicRelocationType>(relocation.type()) == GenericDynamicRelocationType::TLSDESC) {
// GNU ld for some reason puts TLSDESC relocations into .rela.plt // GNU ld for some reason puts TLSDESC relocations into .rela.plt
// https://sourceware.org/bugzilla/show_bug.cgi?id=28387 // 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 }; return ResolvedTLSSymbol { *res.value().dynamic_object, res.value().value };
}; };
switch (relocation.type()) { using enum GenericDynamicRelocationType;
switch (static_cast<GenericDynamicRelocationType>(relocation.type())) {
case R_X86_64_NONE: case NONE:
// Apparently most loaders will just skip these? // Apparently most loaders will just skip these?
// Seems if the 'link editor' generates one something is funky with your code // Seems if the 'link editor' generates one something is funky with your code
break; break;
case R_AARCH64_ABS64: case ABSOLUTE: {
case R_X86_64_64: {
auto symbol = relocation.symbol(); auto symbol = relocation.symbol();
auto res = lookup_symbol(symbol); auto res = lookup_symbol(symbol);
if (!res.has_value()) { if (!res.has_value()) {
@ -602,8 +603,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
*patch_ptr = call_ifunc_resolver(VirtualAddress { *patch_ptr }).get(); *patch_ptr = call_ifunc_resolver(VirtualAddress { *patch_ptr }).get();
break; break;
} }
case R_AARCH64_GLOB_DAT: case GLOB_DAT: {
case R_X86_64_GLOB_DAT: {
auto symbol = relocation.symbol(); auto symbol = relocation.symbol();
auto res = lookup_symbol(symbol); auto res = lookup_symbol(symbol);
VirtualAddress symbol_location; VirtualAddress symbol_location;
@ -633,8 +633,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
*patch_ptr = symbol_location.get(); *patch_ptr = symbol_location.get();
break; break;
} }
case R_AARCH64_RELATIVE: case RELATIVE: {
case R_X86_64_RELATIVE: {
if (!image().is_dynamic()) if (!image().is_dynamic())
break; break;
// FIXME: According to the spec, R_386_relative ones must be done first. // 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(); *patch_ptr += m_dynamic_object->base_address().get();
break; break;
} }
case R_AARCH64_TLS_TPREL: case TLS_TPREL: {
case R_X86_64_TPOFF64: {
auto maybe_resolution = resolve_tls_symbol(relocation); auto maybe_resolution = resolve_tls_symbol(relocation);
if (!maybe_resolution.has_value()) if (!maybe_resolution.has_value())
break; break;
@ -660,7 +658,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
VERIFY(static_cast<ssize_t>(*patch_ptr) < 0); VERIFY(static_cast<ssize_t>(*patch_ptr) < 0);
break; break;
} }
case R_X86_64_DTPMOD64: { case TLS_DTPMOD: {
auto maybe_resolution = resolve_tls_symbol(relocation); auto maybe_resolution = resolve_tls_symbol(relocation);
if (!maybe_resolution.has_value()) if (!maybe_resolution.has_value())
break; break;
@ -670,7 +668,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
*patch_ptr = maybe_resolution->dynamic_object.tls_offset().value(); *patch_ptr = maybe_resolution->dynamic_object.tls_offset().value();
break; break;
} }
case R_X86_64_DTPOFF64: { case TLS_DTPREL: {
auto maybe_resolution = resolve_tls_symbol(relocation); auto maybe_resolution = resolve_tls_symbol(relocation);
if (!maybe_resolution.has_value()) if (!maybe_resolution.has_value())
break; break;
@ -680,7 +678,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
break; break;
} }
#ifdef HAS_TLSDESC_SUPPORT #ifdef HAS_TLSDESC_SUPPORT
case R_AARCH64_TLSDESC: { case TLSDESC: {
auto maybe_resolution = resolve_tls_symbol(relocation); auto maybe_resolution = resolve_tls_symbol(relocation);
if (!maybe_resolution.has_value()) if (!maybe_resolution.has_value())
break; break;
@ -693,8 +691,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
break; break;
} }
#endif #endif
case R_AARCH64_IRELATIVE: case IRELATIVE: {
case R_X86_64_IRELATIVE: {
if (should_call_ifunc_resolver == ShouldCallIfuncResolver::No) if (should_call_ifunc_resolver == ShouldCallIfuncResolver::No)
return RelocationResult::CallIfuncResolver; return RelocationResult::CallIfuncResolver;
VirtualAddress resolver; VirtualAddress resolver;
@ -711,8 +708,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
*patch_ptr = call_ifunc_resolver(resolver).get(); *patch_ptr = call_ifunc_resolver(resolver).get();
break; break;
} }
case R_AARCH64_JUMP_SLOT: case JUMP_SLOT:
case R_X86_64_JUMP_SLOT:
VERIFY_NOT_REACHED(); // PLT relocations are handled by do_plt_relocation. 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
@ -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) 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<GenericDynamicRelocationType>(relocation.type()) == GenericDynamicRelocationType::JUMP_SLOT);
auto symbol = relocation.symbol(); auto symbol = relocation.symbol();
auto* relocation_address = (FlatPtr*)relocation.address().as_ptr(); auto* relocation_address = (FlatPtr*)relocation.address().as_ptr();

View file

@ -13,6 +13,7 @@
#include <AK/Concepts.h> #include <AK/Concepts.h>
#include <AK/RefCounted.h> #include <AK/RefCounted.h>
#include <Kernel/Memory/VirtualAddress.h> #include <Kernel/Memory/VirtualAddress.h>
#include <LibELF/Arch/GenericDynamicRelocationType.h>
#include <LibELF/ELFABI.h> #include <LibELF/ELFABI.h>
#include <link.h> #include <link.h>
@ -402,7 +403,7 @@ inline void DynamicObject::RelocationSection::for_each_relocation(F func) const
{ {
for (unsigned i = 0; i < relocation_count(); ++i) { for (unsigned i = 0; i < relocation_count(); ++i) {
auto const reloc = relocation(i); auto const reloc = relocation(i);
if (reloc.type() == 0) if (static_cast<GenericDynamicRelocationType>(reloc.type()) == GenericDynamicRelocationType::NONE)
continue; continue;
if (func(reloc) == IterationDecision::Break) if (func(reloc) == IterationDecision::Break)
break; break;

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibELF/Arch/GenericDynamicRelocationType.h>
#include <LibELF/ELFABI.h> #include <LibELF/ELFABI.h>
#include <LibELF/Relocation.h> #include <LibELF/Relocation.h>
@ -59,7 +60,7 @@ bool perform_relative_relocations(FlatPtr base_address)
for (unsigned i = 0; i < relocation_count; ++i) { for (unsigned i = 0; i < relocation_count; ++i) {
size_t offset_in_section = i * relocation_entry_size; size_t offset_in_section = i * relocation_entry_size;
auto* relocation = (Elf_Rela*)(relocation_section_addr + offset_in_section); 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<GenericDynamicRelocationType>(ELF64_R_TYPE(relocation->r_info)) == GenericDynamicRelocationType::RELATIVE);
auto* patch_address = (FlatPtr*)(base_address + relocation->r_offset); auto* patch_address = (FlatPtr*)(base_address + relocation->r_offset);
FlatPtr relocated_address; FlatPtr relocated_address;
if (use_addend) { if (use_addend) {