diff options
author | Gunnar Beutner <gbeutner@serenityos.org> | 2021-07-06 10:17:11 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-07-07 11:53:17 +0200 |
commit | 4591c0032871d1ff2682463cfffd94ca31f3ba2f (patch) | |
tree | ef2bfc961285a3779bb919bf12dd367f863f03f5 /Userland/DynamicLoader | |
parent | c351b4ad0d148e08ce741061f3cfc38785c3186d (diff) | |
download | serenity-4591c0032871d1ff2682463cfffd94ca31f3ba2f.zip |
DynamicLoader: Don't use LibELF to do the initial relocations
Using LibELF to do the initial relocations doesn't work when building
SerenityOS with Clang. We seem to be accessing a global symbol that
hasn't been relocated yet somewhere along the path to
ELF::DynamicObject::create().
Diffstat (limited to 'Userland/DynamicLoader')
-rw-r--r-- | Userland/DynamicLoader/main.cpp | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/Userland/DynamicLoader/main.cpp b/Userland/DynamicLoader/main.cpp index 0712554cb8..6fecfbc60f 100644 --- a/Userland/DynamicLoader/main.cpp +++ b/Userland/DynamicLoader/main.cpp @@ -46,17 +46,35 @@ static void perform_self_relocations(auxv_t* auxvp) if (!dynamic_section_addr) exit(1); - auto dynamic_object = ELF::DynamicObject::create({}, (VirtualAddress(base_address)), (VirtualAddress(dynamic_section_addr))); + FlatPtr relocation_section_addr = 0; + size_t relocation_table_size = 0; + size_t relocation_count = 0; + 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_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); - dynamic_object->relocation_section().for_each_relocation([base_address](auto& reloc) { + 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(reloc.type() == R_386_RELATIVE); + VERIFY(ELF32_R_TYPE(relocation->r_info) == R_386_RELATIVE); #else - VERIFY(reloc.type() == R_X86_64_RELATIVE); + VERIFY(ELF64_R_TYPE(relocation->r_info) == R_X86_64_RELATIVE); #endif - - *(FlatPtr*)reloc.address().as_ptr() += base_address; - }); + *(FlatPtr*)(base_address + relocation->r_offset) += base_address; + } } static void display_help() |