diff --git a/Libraries/LibELF/DynamicLoader.cpp b/Libraries/LibELF/DynamicLoader.cpp index dd19a687a51..ff5f7028e6c 100644 --- a/Libraries/LibELF/DynamicLoader.cpp +++ b/Libraries/LibELF/DynamicLoader.cpp @@ -144,9 +144,10 @@ void* DynamicLoader::symbol_for_name(const char* name) RefPtr DynamicLoader::load_from_image(unsigned flags, size_t total_tls_size) { - m_valid = m_elf_image.is_valid() && m_elf_image.is_dynamic(); + m_valid = m_elf_image.is_valid(); if (!m_valid) { + dbgprintf("DynamicLoader::load_from_image failed: image is invalid\n"); return nullptr; } @@ -163,8 +164,10 @@ RefPtr DynamicLoader::load_from_image(unsigned flags, size_t tota m_dynamic_object->m_global_symbol_lookup_func = m_global_symbol_lookup_func; auto rc = load_stage_2(flags, total_tls_size); - if (!rc) + if (!rc) { + dbgprintf("DynamicLoader::load_from_image failed at load_stage_2\n"); return nullptr; + } return m_dynamic_object; } @@ -235,7 +238,9 @@ void DynamicLoader::load_program_headers() // Process regions in order: .text, .data, .tls auto* region = text_region_ptr; - void* text_segment_begin = mmap_with_name(nullptr, + void* requested_load_address = m_elf_image.is_dynamic() ? nullptr : region->desired_load_address().as_ptr(); + void* text_segment_begin = mmap_with_name( + requested_load_address, region->required_load_size(), region->mmap_prot(), MAP_PRIVATE, @@ -245,13 +250,18 @@ void DynamicLoader::load_program_headers() if (MAP_FAILED == text_segment_begin) { ASSERT_NOT_REACHED(); } + ASSERT(requested_load_address == nullptr || requested_load_address == text_segment_begin); m_text_segment_size = region->required_load_size(); m_text_segment_load_address = VirtualAddress { (FlatPtr)text_segment_begin }; - m_dynamic_section_address = dynamic_region_desired_vaddr.offset(m_text_segment_load_address.get()); + if (m_elf_image.is_dynamic()) + m_dynamic_section_address = dynamic_region_desired_vaddr.offset(m_text_segment_load_address.get()); + else + m_dynamic_section_address = dynamic_region_desired_vaddr; region = data_region_ptr; - void* data_segment_begin = mmap_with_name((u8*)text_segment_begin + m_text_segment_size, + void* data_segment_begin = mmap_with_name( + (u8*)text_segment_begin + m_text_segment_size, region->required_load_size(), region->mmap_prot(), MAP_ANONYMOUS | MAP_PRIVATE, @@ -261,10 +271,14 @@ void DynamicLoader::load_program_headers() if (MAP_FAILED == data_segment_begin) { ASSERT_NOT_REACHED(); } - VirtualAddress data_segment_actual_addr = region->desired_load_address().offset((FlatPtr)text_segment_begin); + VirtualAddress data_segment_actual_addr; + if (m_elf_image.is_dynamic()) { + data_segment_actual_addr = region->desired_load_address().offset((FlatPtr)text_segment_begin); + } else { + data_segment_actual_addr = region->desired_load_address(); + } memcpy(data_segment_actual_addr.as_ptr(), (u8*)m_file_mapping + region->offset(), region->size_in_image()); - - // FIXME: Initialize the values in the TLS section. Currently, it will always be zeroed. + // FIXME: Initialize the values in the TLS section. Currently, it is zeroed. } void DynamicLoader::do_relocations(size_t total_tls_size) @@ -272,7 +286,12 @@ void DynamicLoader::do_relocations(size_t total_tls_size) auto main_relocation_section = m_dynamic_object->relocation_section(); main_relocation_section.for_each_relocation([&](ELF::DynamicObject::Relocation relocation) { VERBOSE("Relocation symbol: %s, type: %d\n", relocation.symbol().name(), relocation.type()); - u32* patch_ptr = (u32*)(m_dynamic_object->base_address().as_ptr() + relocation.offset()); + FlatPtr* patch_ptr = nullptr; + if (is_dynamic()) + patch_ptr = (FlatPtr*)(m_dynamic_object->base_address().as_ptr() + relocation.offset()); + else + patch_ptr = (FlatPtr*)(FlatPtr)relocation.offset(); + // VERBOSE("dynamic object name: %s\n", dynamic_object.object_name()); VERBOSE("dynamic object base address: %p\n", m_dynamic_object->base_address()); VERBOSE("relocation offset: 0x%x\n", relocation.offset()); @@ -393,13 +412,12 @@ void DynamicLoader::do_relocations(size_t total_tls_size) VERBOSE("patching plt reloaction: 0x%x\n", relocation.offset_in_section()); [[maybe_unused]] auto rc = m_dynamic_object->patch_plt_entry(relocation.offset_in_section()); } else { - // LAZY-ily bind the PLT slots by just adding the base address to the offsets stored there - // This avoids doing symbol lookup, which might be expensive ASSERT(relocation.type() == R_386_JMP_SLOT); u8* relocation_address = relocation.address().as_ptr(); - *(u32*)relocation_address += (FlatPtr)m_dynamic_object->base_address().as_ptr(); + if (m_elf_image.is_dynamic()) + *(u32*)relocation_address += (FlatPtr)m_dynamic_object->base_address().as_ptr(); } return IterationDecision::Continue; }); diff --git a/Libraries/LibELF/DynamicLoader.h b/Libraries/LibELF/DynamicLoader.h index fcc2886d6ce..3ced5ae4e51 100644 --- a/Libraries/LibELF/DynamicLoader.h +++ b/Libraries/LibELF/DynamicLoader.h @@ -79,6 +79,7 @@ public: void set_global_symbol_lookup_function(DynamicObject::SymbolLookupFunction func) { m_global_symbol_lookup_func = func; } VirtualAddress text_segment_load_address() const { return m_text_segment_load_address; } + bool is_dynamic() const { return m_elf_image.is_dynamic(); } private: class ProgramHeaderRegion { diff --git a/Libraries/LibELF/DynamicObject.cpp b/Libraries/LibELF/DynamicObject.cpp index 25973e5de38..f025a3a5d88 100644 --- a/Libraries/LibELF/DynamicObject.cpp +++ b/Libraries/LibELF/DynamicObject.cpp @@ -50,6 +50,14 @@ DynamicObject::DynamicObject(VirtualAddress base_address, VirtualAddress dynamic : m_base_address(base_address) , m_dynamic_address(dynamic_section_addresss) { + Elf32_Ehdr* header = (Elf32_Ehdr*)base_address.as_ptr(); + Elf32_Phdr* pheader = (Elf32_Phdr*)(base_address.as_ptr() + header->e_phoff); + m_elf_base_address = VirtualAddress(pheader->p_vaddr - pheader->p_offset); + if (header->e_type == ET_DYN) + m_is_elf_dynamic = true; + else + m_is_elf_dynamic = false; + parse(); } @@ -82,31 +90,31 @@ void DynamicObject::parse() for_each_dynamic_entry([&](const DynamicEntry& entry) { switch (entry.tag()) { case DT_INIT: - m_init_offset = entry.ptr(); + m_init_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_FINI: - m_fini_offset = entry.ptr(); + m_fini_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_INIT_ARRAY: - m_init_array_offset = entry.ptr(); + m_init_array_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_INIT_ARRAYSZ: m_init_array_size = entry.val(); break; case DT_FINI_ARRAY: - m_fini_array_offset = entry.ptr(); + m_fini_array_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_FINI_ARRAYSZ: m_fini_array_size = entry.val(); break; case DT_HASH: - m_hash_table_offset = entry.ptr(); + m_hash_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_SYMTAB: - m_symbol_table_offset = entry.ptr(); + m_symbol_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_STRTAB: - m_string_table_offset = entry.ptr(); + m_string_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_STRSZ: m_size_of_string_table = entry.val(); @@ -115,7 +123,7 @@ void DynamicObject::parse() m_size_of_symbol_table_entry = entry.val(); break; case DT_PLTGOT: - m_procedure_linkage_table_offset = entry.ptr(); + m_procedure_linkage_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_PLTRELSZ: m_size_of_plt_relocation_entry_list = entry.val(); @@ -125,11 +133,11 @@ void DynamicObject::parse() ASSERT(m_procedure_linkage_table_relocation_type & (DT_REL | DT_RELA)); break; case DT_JMPREL: - m_plt_relocation_offset_location = entry.ptr(); + m_plt_relocation_offset_location = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_RELA: case DT_REL: - m_relocation_table_offset = entry.ptr(); + m_relocation_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); break; case DT_RELASZ: case DT_RELSZ: @@ -171,12 +179,13 @@ void DynamicObject::parse() if (!m_size_of_relocation_entry) { // TODO: FIXME, this shouldn't be hardcoded - // The reason we need this here is the for some reason, when there only PLT relocations, the compiler + // The reason we need this here is that for some reason, when there only PLT relocations, the compiler // doesn't insert a 'PLTRELSZ' entry to the dynamic section m_size_of_relocation_entry = sizeof(Elf32_Rel); } auto hash_section_address = hash_section().address().as_ptr(); + // TODO: consider base address - it might not be zero auto num_hash_chains = ((u32*)hash_section_address)[1]; m_symbol_count = num_hash_chains; } @@ -287,9 +296,7 @@ const DynamicObject::Symbol DynamicObject::HashSection::lookup_symbol(const char for (u32 i = buckets[hash_value % num_buckets]; i; i = chains[i]) { auto symbol = m_dynamic.symbol(i); if (strcmp(name, symbol.name()) == 0) { -#ifdef DYNAMIC_LOAD_DEBUG - dbgprintf("Returning dynamic symbol with index %u for %s: %p\n", i, symbol.name(), symbol.address().as_ptr()); -#endif + VERBOSE("Returning dynamic symbol with index %u for %s: %p\n", i, symbol.name(), symbol.address().as_ptr()); return symbol; } } diff --git a/Libraries/LibELF/DynamicObject.h b/Libraries/LibELF/DynamicObject.h index 08c536c43c2..b9a8d3e9b9c 100644 --- a/Libraries/LibELF/DynamicObject.h +++ b/Libraries/LibELF/DynamicObject.h @@ -105,7 +105,12 @@ public: { return m_is_undefined; } - VirtualAddress address() const { return m_dynamic.base_address().offset(value()); } + VirtualAddress address() const + { + if (m_dynamic.elf_is_dynamic()) + return m_dynamic.base_address().offset(value()); + return VirtualAddress { value() }; + } const DynamicObject& object() const { return m_dynamic; } private: @@ -135,7 +140,10 @@ public: { return !entry_size() ? 0 : size() / entry_size(); } - VirtualAddress address() const { return m_dynamic.base_address().offset(m_section_offset); } + VirtualAddress address() const + { + return m_dynamic.base_address().offset(m_section_offset); + } protected: friend class RelocationSection; @@ -176,7 +184,12 @@ public: unsigned type() const { return ELF32_R_TYPE(m_rel.r_info); } unsigned symbol_index() const { return ELF32_R_SYM(m_rel.r_info); } const Symbol symbol() const { return m_dynamic.symbol(symbol_index()); } - VirtualAddress address() const { return m_dynamic.base_address().offset(offset()); } + VirtualAddress address() const + { + if (m_dynamic.elf_is_dynamic()) + return m_dynamic.base_address().offset(offset()); + return VirtualAddress { offset() }; + } private: const DynamicObject& m_dynamic; @@ -274,6 +287,8 @@ public: using SymbolLookupFunction = DynamicObject::SymbolLookupResult (*)(const char*); SymbolLookupFunction m_global_symbol_lookup_func { nullptr }; + bool elf_is_dynamic() const { return m_is_elf_dynamic; } + private: explicit DynamicObject(VirtualAddress base_address, VirtualAddress dynamic_section_address); @@ -288,6 +303,7 @@ private: VirtualAddress m_base_address; VirtualAddress m_dynamic_address; + VirtualAddress m_elf_base_address; unsigned m_symbol_count { 0 }; @@ -318,6 +334,7 @@ private: size_t m_size_of_relocation_entry { 0 }; size_t m_size_of_relocation_table { 0 }; FlatPtr m_relocation_table_offset { 0 }; + bool m_is_elf_dynamic { false }; // DT_FLAGS Elf32_Word m_dt_flags { 0 }; @@ -356,7 +373,6 @@ inline void DynamicObject::for_each_dynamic_entry(F func) const { auto* dyns = reinterpret_cast(m_dynamic_address.as_ptr()); for (unsigned i = 0;; ++i) { - // dbgprintf("%d\n", i); auto&& dyn = DynamicEntry(dyns[i]); if (dyn.tag() == DT_NULL) break; diff --git a/Userland/DynamicLoader/main.cpp b/Userland/DynamicLoader/main.cpp index b3886cc8cad..5c9049f1ef2 100644 --- a/Userland/DynamicLoader/main.cpp +++ b/Userland/DynamicLoader/main.cpp @@ -107,6 +107,7 @@ static void perform_self_relocations(auxv_t* auxvp) dynamic_object->relocation_section().for_each_relocation([base_address](auto& reloc) { if (reloc.type() != R_386_RELATIVE) return IterationDecision::Continue; + *(u32*)reloc.address().as_ptr() += base_address; return IterationDecision::Continue; }); @@ -171,10 +172,10 @@ static Vector get_dependencies(const String& name) static void map_dependencies(const String& name) { - VERBOSE("mapping dependencies for: %s", name.characters()); + VERBOSE("mapping dependencies for: %s\n", name.characters()); for (const auto& needed_name : get_dependencies(name)) { - VERBOSE("needed library: %s", needed_name.characters()); + VERBOSE("needed library: %s\n", needed_name.characters()); String library_name = get_library_name(needed_name); if (!g_loaders.contains(library_name)) { @@ -193,7 +194,7 @@ static void allocate_tls() } if (total_tls_size) { [[maybe_unused]] void* tls_address = allocate_tls(total_tls_size); - VERBOSE("from userspace, tls_address: %p", tls_address); + VERBOSE("from userspace, tls_address: %p\n", tls_address); } g_total_tls_size = total_tls_size; } @@ -224,17 +225,17 @@ static void initialize_libc() static void load_elf(const String& name) { - VERBOSE("load_elf: %s", name.characters()); + VERBOSE("load_elf: %s\n", name.characters()); auto loader = g_loaders.get(name).value(); + VERBOSE("a1\n"); for (const auto& needed_name : get_dependencies(name)) { - VERBOSE("needed library: %s", needed_name.characters()); + VERBOSE("needed library: %s\n", needed_name.characters()); String library_name = get_library_name(needed_name); if (!g_loaded_objects.contains(library_name)) { load_elf(library_name); } } - VERBOSE("loading: %s", name.characters()); auto dynamic_object = loader->load_from_image(RTLD_GLOBAL | RTLD_LAZY, g_total_tls_size); ASSERT(!dynamic_object.is_null()); g_loaded_objects.set(name, dynamic_object.release_nonnull()); @@ -270,7 +271,7 @@ static FlatPtr loader_main(auxv_t* auxvp) VERBOSE("loaded all dependencies"); for ([[maybe_unused]] auto& lib : g_loaders) { - VERBOSE("%s - tls size: %u, tls offset: %u", lib.key.characters(), lib.value->tls_size(), lib.value->tls_offset()); + VERBOSE("%s - tls size: %u, tls offset: %u\n", lib.key.characters(), lib.value->tls_size(), lib.value->tls_offset()); } allocate_tls(); @@ -278,8 +279,12 @@ static FlatPtr loader_main(auxv_t* auxvp) load_elf(main_program_name); auto main_program_lib = g_loaders.get(main_program_name).value(); - FlatPtr entry_point = reinterpret_cast(main_program_lib->image().entry().as_ptr() + (FlatPtr)main_program_lib->text_segment_load_address().as_ptr()); - VERBOSE("entry point: %p", entry_point); + + FlatPtr entry_point = reinterpret_cast(main_program_lib->image().entry().as_ptr()); + if (main_program_lib->is_dynamic()) + entry_point += reinterpret_cast(main_program_lib->text_segment_load_address().as_ptr()); + + VERBOSE("entry point: %p\n", entry_point); // This will unmap the temporary memory maps we had for loading the libraries clear_temporary_objects_mappings(); @@ -310,9 +315,9 @@ void _start(int argc, char** argv, char** envp) } MainFunction main_function = (MainFunction)(entry); - VERBOSE("jumping to main program entry point: %p", main_function); + VERBOSE("jumping to main program entry point: %p\n", main_function); int rc = main_function(argc, argv, envp); - VERBOSE("rc: %d", rc); + VERBOSE("rc: %d\n", rc); if (g_libc_exit != nullptr) { g_libc_exit(rc); } else {