From daeb371180263f25b2d57c580990f9bf250d8739 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Mon, 26 Jul 2021 15:03:29 +0200 Subject: [PATCH] DynamicLoader+LibELF: Move self-relocation code into a separate file --- Userland/DynamicLoader/main.cpp | 47 +---------------- Userland/Libraries/LibC/elf.h | 1 + Userland/Libraries/LibELF/Relocation.cpp | 64 ++++++++++++++++++++++++ Userland/Libraries/LibELF/Relocation.h | 18 +++++++ 4 files changed, 85 insertions(+), 45 deletions(-) create mode 100644 Userland/Libraries/LibELF/Relocation.cpp create mode 100644 Userland/Libraries/LibELF/Relocation.h diff --git a/Userland/DynamicLoader/main.cpp b/Userland/DynamicLoader/main.cpp index e9e07a575d..cae531a67e 100644 --- a/Userland/DynamicLoader/main.cpp +++ b/Userland/DynamicLoader/main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include char* __static_environ[] = { nullptr }; // We don't get the environment without some libc workarounds.. @@ -35,52 +36,8 @@ static void perform_self_relocations(auxv_t* auxvp) } } VERIFY(found_base_address); - ElfW(Ehdr)* header = (ElfW(Ehdr)*)(base_address); - ElfW(Phdr)* pheader = (ElfW(Phdr)*)(base_address + header->e_phoff); - FlatPtr dynamic_section_addr = 0; - for (size_t i = 0; i < (size_t)header->e_phnum; ++i, ++pheader) { - if (pheader->p_type != PT_DYNAMIC) - continue; - dynamic_section_addr = pheader->p_vaddr + base_address; - } - if (!dynamic_section_addr) + if (!ELF::perform_relative_relocations(base_address)) exit(1); - - FlatPtr relocation_section_addr = 0; - size_t relocation_table_size = 0; - size_t relocation_count = 0; - bool use_addend = false; - auto* dyns = reinterpret_cast(dynamic_section_addr); - for (unsigned i = 0;; ++i) { - auto& dyn = dyns[i]; - if (dyn.d_tag == DT_NULL) - break; - if (dyn.d_tag == DT_RELA) - use_addend = true; - if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELA) - relocation_section_addr = base_address + dyn.d_un.d_ptr; - else if (dyn.d_tag == DT_RELCOUNT || dyn.d_tag == DT_RELACOUNT) - relocation_count = dyn.d_un.d_val; - else if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) - relocation_table_size = dyn.d_un.d_val; - } - if (!relocation_section_addr || !relocation_table_size || !relocation_count) - exit(1); - - auto relocation_entry_size = relocation_table_size / relocation_count; - for (unsigned i = 0; i < relocation_count; ++i) { - size_t offset_in_section = i * relocation_entry_size; - auto* relocation = (ElfW(Rela)*)(relocation_section_addr + offset_in_section); -#if ARCH(I386) - VERIFY(ELF32_R_TYPE(relocation->r_info) == R_386_RELATIVE); -#else - VERIFY(ELF64_R_TYPE(relocation->r_info) == R_X86_64_RELATIVE); -#endif - if (use_addend) - *(FlatPtr*)(base_address + relocation->r_offset) = base_address + relocation->r_addend; - else - *(FlatPtr*)(base_address + relocation->r_offset) += base_address; - } } static void display_help() diff --git a/Userland/Libraries/LibC/elf.h b/Userland/Libraries/LibC/elf.h index c50742b80c..425a83234d 100644 --- a/Userland/Libraries/LibC/elf.h +++ b/Userland/Libraries/LibC/elf.h @@ -33,6 +33,7 @@ #pragma once #ifndef KERNEL +# include # include #else # include diff --git a/Userland/Libraries/LibELF/Relocation.cpp b/Userland/Libraries/LibELF/Relocation.cpp new file mode 100644 index 0000000000..f6e25ffcd4 --- /dev/null +++ b/Userland/Libraries/LibELF/Relocation.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021, Gunnar Beutner + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace ELF { + +bool perform_relative_relocations(FlatPtr base_address) +{ + + ElfW(Ehdr)* header = (ElfW(Ehdr)*)(base_address); + ElfW(Phdr)* pheader = (ElfW(Phdr)*)(base_address + header->e_phoff); + FlatPtr dynamic_section_addr = 0; + for (size_t i = 0; i < (size_t)header->e_phnum; ++i, ++pheader) { + if (pheader->p_type != PT_DYNAMIC) + continue; + dynamic_section_addr = pheader->p_vaddr + base_address; + } + if (!dynamic_section_addr) + return false; + + FlatPtr relocation_section_addr = 0; + size_t relocation_table_size = 0; + size_t relocation_count = 0; + bool use_addend = false; + auto* dyns = reinterpret_cast(dynamic_section_addr); + for (unsigned i = 0;; ++i) { + auto& dyn = dyns[i]; + if (dyn.d_tag == DT_NULL) + break; + if (dyn.d_tag == DT_RELA) + use_addend = true; + if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELA) + relocation_section_addr = base_address + dyn.d_un.d_ptr; + else if (dyn.d_tag == DT_RELCOUNT || dyn.d_tag == DT_RELACOUNT) + relocation_count = dyn.d_un.d_val; + else if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) + relocation_table_size = dyn.d_un.d_val; + } + if (!relocation_section_addr || !relocation_table_size || !relocation_count) + return false; + + auto relocation_entry_size = relocation_table_size / relocation_count; + for (unsigned i = 0; i < relocation_count; ++i) { + size_t offset_in_section = i * relocation_entry_size; + auto* relocation = (ElfW(Rela)*)(relocation_section_addr + offset_in_section); +#if ARCH(I386) + VERIFY(ELF32_R_TYPE(relocation->r_info) == R_386_RELATIVE); +#else + VERIFY(ELF64_R_TYPE(relocation->r_info) == R_X86_64_RELATIVE); +#endif + if (use_addend) + *(FlatPtr*)(base_address + relocation->r_offset) = base_address + relocation->r_addend; + else + *(FlatPtr*)(base_address + relocation->r_offset) += base_address; + } + + return true; +} +} diff --git a/Userland/Libraries/LibELF/Relocation.h b/Userland/Libraries/LibELF/Relocation.h new file mode 100644 index 0000000000..d9fc4da084 --- /dev/null +++ b/Userland/Libraries/LibELF/Relocation.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021, Gunnar Beutner + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace ELF { + +bool perform_relative_relocations(FlatPtr base_address); + +}