mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 18:57:34 +00:00
DynamicLoader+LibELF: Move self-relocation code into a separate file
This commit is contained in:
parent
3c616ae00f
commit
daeb371180
4 changed files with 85 additions and 45 deletions
|
@ -8,6 +8,7 @@
|
||||||
#include <LibC/unistd.h>
|
#include <LibC/unistd.h>
|
||||||
#include <LibELF/AuxiliaryVector.h>
|
#include <LibELF/AuxiliaryVector.h>
|
||||||
#include <LibELF/DynamicLinker.h>
|
#include <LibELF/DynamicLinker.h>
|
||||||
|
#include <LibELF/Relocation.h>
|
||||||
|
|
||||||
char* __static_environ[] = { nullptr }; // We don't get the environment without some libc workarounds..
|
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);
|
VERIFY(found_base_address);
|
||||||
ElfW(Ehdr)* header = (ElfW(Ehdr)*)(base_address);
|
if (!ELF::perform_relative_relocations(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)
|
|
||||||
exit(1);
|
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<const ElfW(Dyn)*>(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()
|
static void display_help()
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef KERNEL
|
#ifndef KERNEL
|
||||||
|
# include <stdint.h>
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
#else
|
#else
|
||||||
# include <AK/Types.h>
|
# include <AK/Types.h>
|
||||||
|
|
64
Userland/Libraries/LibELF/Relocation.cpp
Normal file
64
Userland/Libraries/LibELF/Relocation.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibC/elf.h>
|
||||||
|
#include <LibELF/Relocation.h>
|
||||||
|
|
||||||
|
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<const ElfW(Dyn)*>(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;
|
||||||
|
}
|
||||||
|
}
|
18
Userland/Libraries/LibELF/Relocation.h
Normal file
18
Userland/Libraries/LibELF/Relocation.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Concepts.h>
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
#include <Kernel/VirtualAddress.h>
|
||||||
|
|
||||||
|
namespace ELF {
|
||||||
|
|
||||||
|
bool perform_relative_relocations(FlatPtr base_address);
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue