1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 06:14:58 +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/QuickSort.h>
#include <AK/StringBuilder.h>
#include <LibELF/Arch/GenericDynamicRelocationType.h>
#include <LibELF/DynamicLinker.h>
#include <LibELF/DynamicLoader.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.
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())
*((FlatPtr*)relocation.address().as_ptr()) += m_dynamic_object->base_address().get();
};
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);
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
// 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 };
};
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?
// Seems if the 'link editor' generates one something is funky with your code
break;
case R_AARCH64_ABS64:
case R_X86_64_64: {
case ABSOLUTE: {
auto symbol = relocation.symbol();
auto res = lookup_symbol(symbol);
if (!res.has_value()) {
@ -602,8 +603,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
*patch_ptr = call_ifunc_resolver(VirtualAddress { *patch_ptr }).get();
break;
}
case R_AARCH64_GLOB_DAT:
case R_X86_64_GLOB_DAT: {
case GLOB_DAT: {
auto symbol = relocation.symbol();
auto res = lookup_symbol(symbol);
VirtualAddress symbol_location;
@ -633,8 +633,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
*patch_ptr = symbol_location.get();
break;
}
case R_AARCH64_RELATIVE:
case R_X86_64_RELATIVE: {
case RELATIVE: {
if (!image().is_dynamic())
break;
// 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();
break;
}
case R_AARCH64_TLS_TPREL:
case R_X86_64_TPOFF64: {
case TLS_TPREL: {
auto maybe_resolution = resolve_tls_symbol(relocation);
if (!maybe_resolution.has_value())
break;
@ -660,7 +658,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
VERIFY(static_cast<ssize_t>(*patch_ptr) < 0);
break;
}
case R_X86_64_DTPMOD64: {
case TLS_DTPMOD: {
auto maybe_resolution = resolve_tls_symbol(relocation);
if (!maybe_resolution.has_value())
break;
@ -670,7 +668,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
*patch_ptr = maybe_resolution->dynamic_object.tls_offset().value();
break;
}
case R_X86_64_DTPOFF64: {
case TLS_DTPREL: {
auto maybe_resolution = resolve_tls_symbol(relocation);
if (!maybe_resolution.has_value())
break;
@ -680,7 +678,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
break;
}
#ifdef HAS_TLSDESC_SUPPORT
case R_AARCH64_TLSDESC: {
case TLSDESC: {
auto maybe_resolution = resolve_tls_symbol(relocation);
if (!maybe_resolution.has_value())
break;
@ -693,8 +691,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
break;
}
#endif
case R_AARCH64_IRELATIVE:
case R_X86_64_IRELATIVE: {
case IRELATIVE: {
if (should_call_ifunc_resolver == ShouldCallIfuncResolver::No)
return RelocationResult::CallIfuncResolver;
VirtualAddress resolver;
@ -711,8 +708,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_direct_relocation(DynamicObjec
*patch_ptr = call_ifunc_resolver(resolver).get();
break;
}
case R_AARCH64_JUMP_SLOT:
case R_X86_64_JUMP_SLOT:
case JUMP_SLOT:
VERIFY_NOT_REACHED(); // PLT relocations are handled by do_plt_relocation.
default:
// 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)
{
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* relocation_address = (FlatPtr*)relocation.address().as_ptr();

View file

@ -13,6 +13,7 @@
#include <AK/Concepts.h>
#include <AK/RefCounted.h>
#include <Kernel/Memory/VirtualAddress.h>
#include <LibELF/Arch/GenericDynamicRelocationType.h>
#include <LibELF/ELFABI.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) {
auto const reloc = relocation(i);
if (reloc.type() == 0)
if (static_cast<GenericDynamicRelocationType>(reloc.type()) == GenericDynamicRelocationType::NONE)
continue;
if (func(reloc) == IterationDecision::Break)
break;

View file

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