diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp index 5b5126b0df..ba6d1dbccd 100644 --- a/Userland/Libraries/LibELF/DynamicLinker.cpp +++ b/Userland/Libraries/LibELF/DynamicLinker.cpp @@ -170,7 +170,7 @@ static void allocate_tls() // Initialize TLS data for (const auto& entry : s_loaders) { - entry.value->copy_initial_tls_data_into(initial_tls_data, s_total_tls_size); + entry.value->copy_initial_tls_data_into(initial_tls_data); } void* master_tls = ::allocate_tls((char*)initial_tls_data.data(), initial_tls_data.size()); @@ -282,14 +282,14 @@ static Result, DlErrorMessage> load_main_library(co } for (auto& loader : loaders) { - bool success = loader.link(flags, s_total_tls_size); + bool success = loader.link(flags); if (!success) { return DlErrorMessage { String::formatted("Failed to link library {}", loader.filename()) }; } } for (auto& loader : loaders) { - auto result = loader.load_stage_3(flags, s_total_tls_size); + auto result = loader.load_stage_3(flags); VERIFY(!result.is_error()); auto& object = result.value(); diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp index 6b5225393a..5b7573d260 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.cpp +++ b/Userland/Libraries/LibELF/DynamicLoader.cpp @@ -146,12 +146,12 @@ RefPtr DynamicLoader::map() return m_dynamic_object; } -bool DynamicLoader::link(unsigned flags, size_t total_tls_size) +bool DynamicLoader::link(unsigned flags) { - return load_stage_2(flags, total_tls_size); + return load_stage_2(flags); } -bool DynamicLoader::load_stage_2(unsigned flags, size_t total_tls_size) +bool DynamicLoader::load_stage_2(unsigned flags) { VERIFY(flags & RTLD_GLOBAL); @@ -173,14 +173,14 @@ bool DynamicLoader::load_stage_2(unsigned flags, size_t total_tls_size) } } } - do_main_relocations(total_tls_size); + do_main_relocations(); return true; } -void DynamicLoader::do_main_relocations(size_t total_tls_size) +void DynamicLoader::do_main_relocations() { auto do_single_relocation = [&](const ELF::DynamicObject::Relocation& relocation) { - switch (do_relocation(total_tls_size, relocation, ShouldInitializeWeak::No)) { + switch (do_relocation(relocation, ShouldInitializeWeak::No)) { case RelocationResult::Failed: dbgln("Loader.so: {} unresolved symbol '{}'", m_filename, relocation.symbol().name()); VERIFY_NOT_REACHED(); @@ -196,9 +196,9 @@ void DynamicLoader::do_main_relocations(size_t total_tls_size) m_dynamic_object->plt_relocation_section().for_each_relocation(do_single_relocation); } -Result, DlErrorMessage> DynamicLoader::load_stage_3(unsigned flags, size_t total_tls_size) +Result, DlErrorMessage> DynamicLoader::load_stage_3(unsigned flags) { - do_lazy_relocations(total_tls_size); + do_lazy_relocations(); if (flags & RTLD_LAZY) { if (m_dynamic_object->has_plt()) setup_plt_trampoline(); @@ -230,10 +230,10 @@ void DynamicLoader::load_stage_4() call_object_init_functions(); } -void DynamicLoader::do_lazy_relocations(size_t total_tls_size) +void DynamicLoader::do_lazy_relocations() { for (const auto& relocation : m_unresolved_relocations) { - if (auto res = do_relocation(total_tls_size, relocation, ShouldInitializeWeak::Yes); res != RelocationResult::Success) { + if (auto res = do_relocation(relocation, ShouldInitializeWeak::Yes); res != RelocationResult::Success) { dbgln("Loader.so: {} unresolved symbol '{}'", m_filename, relocation.symbol().name()); VERIFY_NOT_REACHED(); } @@ -389,7 +389,7 @@ void DynamicLoader::load_program_headers() // FIXME: Initialize the values in the TLS section. Currently, it is zeroed. } -DynamicLoader::RelocationResult DynamicLoader::do_relocation(size_t total_tls_size, const ELF::DynamicObject::Relocation& relocation, ShouldInitializeWeak should_initialize_weak) +DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicObject::Relocation& relocation, ShouldInitializeWeak should_initialize_weak) { FlatPtr* patch_ptr = nullptr; if (is_dynamic()) @@ -462,7 +462,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(size_t total_tls_si break; auto* dynamic_object_of_symbol = res.value().dynamic_object; VERIFY(dynamic_object_of_symbol); - *patch_ptr = negative_offset_from_tls_block_end(res.value().value, dynamic_object_of_symbol->tls_offset().value(), total_tls_size); + *patch_ptr = negative_offset_from_tls_block_end(res.value().value, dynamic_object_of_symbol->tls_offset().value(), res.value().size); break; } case R_386_JMP_SLOT: { @@ -487,15 +487,16 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(size_t total_tls_si return RelocationResult::Success; } -ssize_t DynamicLoader::negative_offset_from_tls_block_end(size_t value_of_symbol, size_t tls_offset, size_t total_tls_size) const +ssize_t DynamicLoader::negative_offset_from_tls_block_end(size_t value_of_symbol, size_t tls_offset, size_t symbol_size) const { - auto negative_offset = static_cast(tls_offset + value_of_symbol - total_tls_size); - // Offset has to be strictly negative. Otherwise we'd collide with the thread's ThreadSpecificData structure. - VERIFY(negative_offset < 0); - return negative_offset; + VERIFY(symbol_size > 0); + ssize_t offset = -static_cast(value_of_symbol + tls_offset + symbol_size); + // At offset 0 there's the thread's ThreadSpecificData structure, we don't want to collide with it. + VERIFY(offset < 0); + return offset; } -void DynamicLoader::copy_initial_tls_data_into(ByteBuffer& buffer, size_t total_tls_size) const +void DynamicLoader::copy_initial_tls_data_into(ByteBuffer& buffer) const { const u8* tls_data = nullptr; size_t tls_size_in_image = 0; @@ -512,11 +513,11 @@ void DynamicLoader::copy_initial_tls_data_into(ByteBuffer& buffer, size_t total_ if (!tls_data || !tls_size_in_image) return; - m_elf_image.for_each_symbol([this, &buffer, total_tls_size, tls_data](ELF::Image::Symbol symbol) { + m_elf_image.for_each_symbol([this, &buffer, tls_data](ELF::Image::Symbol symbol) { if (symbol.type() != STT_TLS) return IterationDecision::Continue; - ssize_t negative_offset = negative_offset_from_tls_block_end(symbol.value(), m_tls_offset, total_tls_size); + ssize_t negative_offset = negative_offset_from_tls_block_end(symbol.value(), m_tls_offset, symbol.size()); VERIFY(symbol.size() != 0); VERIFY(buffer.size() + negative_offset + symbol.size() <= buffer.size()); memcpy(buffer.data() + buffer.size() + negative_offset, tls_data + symbol.value(), symbol.size()); @@ -576,7 +577,8 @@ Optional DynamicLoader::lookup_symbol(const E { if (symbol.is_undefined() || symbol.bind() == STB_WEAK) return DynamicLinker::lookup_global_symbol(symbol.name()); - return DynamicObject::SymbolLookupResult { symbol.value(), symbol.address(), symbol.bind(), &symbol.object() }; + + return DynamicObject::SymbolLookupResult { symbol.value(), symbol.size(), symbol.address(), symbol.bind(), &symbol.object() }; } } // end namespace ELF diff --git a/Userland/Libraries/LibELF/DynamicLoader.h b/Userland/Libraries/LibELF/DynamicLoader.h index 0cccd48791..bfcd2184bb 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.h +++ b/Userland/Libraries/LibELF/DynamicLoader.h @@ -54,13 +54,13 @@ public: // Note that the DynamicObject will not be linked yet. Callers are responsible for calling link() to finish it. RefPtr map(); - bool link(unsigned flags, size_t total_tls_size); + bool link(unsigned flags); // Stage 2 of loading: dynamic object loading and primary relocations - bool load_stage_2(unsigned flags, size_t total_tls_size); + bool load_stage_2(unsigned flags); // Stage 3 of loading: lazy relocations - Result, DlErrorMessage> load_stage_3(unsigned flags, size_t total_tls_size); + Result, DlErrorMessage> load_stage_3(unsigned flags); // Stage 4 of loading: initializers void load_stage_4(); @@ -78,7 +78,7 @@ public: bool is_dynamic() const { return m_elf_image.is_dynamic(); } static Optional lookup_symbol(const ELF::DynamicObject::Symbol&); - void copy_initial_tls_data_into(ByteBuffer& buffer, size_t total_tls_size) const; + void copy_initial_tls_data_into(ByteBuffer& buffer) const; private: DynamicLoader(int fd, String filename, void* file_data, size_t file_size); @@ -113,10 +113,10 @@ private: void load_program_headers(); // Stage 2 - void do_main_relocations(size_t total_tls_size); + void do_main_relocations(); // Stage 3 - void do_lazy_relocations(size_t total_tls_size); + void do_lazy_relocations(); void setup_plt_trampoline(); // Stage 4 @@ -129,9 +129,9 @@ private: Success = 1, ResolveLater = 2, }; - RelocationResult do_relocation(size_t total_tls_size, const DynamicObject::Relocation&, ShouldInitializeWeak should_initialize_weak); + RelocationResult do_relocation(const DynamicObject::Relocation&, ShouldInitializeWeak should_initialize_weak); size_t calculate_tls_size() const; - ssize_t negative_offset_from_tls_block_end(size_t value_of_symbol, size_t tls_offset, size_t total_tls_size) const; + ssize_t negative_offset_from_tls_block_end(size_t value_of_symbol, size_t tls_offset, size_t symbol_size) const; String m_filename; String m_program_interpreter; diff --git a/Userland/Libraries/LibELF/DynamicObject.cpp b/Userland/Libraries/LibELF/DynamicObject.cpp index d552357d24..d4e0b842f6 100644 --- a/Userland/Libraries/LibELF/DynamicObject.cpp +++ b/Userland/Libraries/LibELF/DynamicObject.cpp @@ -440,7 +440,7 @@ auto DynamicObject::lookup_symbol(const HashSymbol& symbol) const -> Optional DynamicObject::create(const String& filename, VirtualAddress base_address, VirtualAddress dynamic_section_address) diff --git a/Userland/Libraries/LibELF/DynamicObject.h b/Userland/Libraries/LibELF/DynamicObject.h index 98c59f713e..06d30b87b9 100644 --- a/Userland/Libraries/LibELF/DynamicObject.h +++ b/Userland/Libraries/LibELF/DynamicObject.h @@ -264,6 +264,7 @@ public: struct SymbolLookupResult { FlatPtr value { 0 }; + size_t size { 0 }; VirtualAddress address; unsigned bind { STB_LOCAL }; const ELF::DynamicObject* dynamic_object { nullptr }; // The object in which the symbol is defined