diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp index 84ffeef4cd..3ed092d2a0 100644 --- a/Userland/Libraries/LibELF/DynamicLinker.cpp +++ b/Userland/Libraries/LibELF/DynamicLinker.cpp @@ -96,6 +96,8 @@ static Result, DlErrorMessage> map_library(String c s_loaders.set(get_library_name(filename), *loader); s_current_tls_offset -= loader->tls_size_of_current_object(); + if (loader->tls_alignment_of_current_object()) + s_current_tls_offset = align_down_to(s_current_tls_offset, loader->tls_alignment_of_current_object()); loader->set_tls_offset(s_current_tls_offset); // This actually maps the library at the intended and final place. @@ -196,8 +198,8 @@ static void allocate_tls() { s_total_tls_size = 0; for (auto const& data : s_loaders) { - dbgln_if(DYNAMIC_LOAD_DEBUG, "{}: TLS Size: {}", data.key, data.value->tls_size_of_current_object()); - s_total_tls_size += data.value->tls_size_of_current_object(); + dbgln_if(DYNAMIC_LOAD_DEBUG, "{}: TLS Size: {}, TLS Alignment: {}", data.key, data.value->tls_size_of_current_object(), data.value->tls_alignment_of_current_object()); + s_total_tls_size += data.value->tls_size_of_current_object() + data.value->tls_alignment_of_current_object(); } if (!s_total_tls_size) @@ -393,7 +395,7 @@ static Optional verify_tls_for_dlopen(DynamicLoader const& loade if (loader.tls_size_of_current_object() == 0) return {}; - if (s_total_tls_size + loader.tls_size_of_current_object() > s_allocated_tls_block_size) + if (s_total_tls_size + loader.tls_size_of_current_object() + loader.tls_alignment_of_current_object() > s_allocated_tls_block_size) return DlErrorMessage("TLS size too large"); bool tls_data_is_all_zero = true; @@ -461,7 +463,7 @@ static Result __dlopen(char const* filename, int flags) if (result.is_error()) return result.error(); - s_total_tls_size += result1.value()->tls_size_of_current_object(); + s_total_tls_size += result1.value()->tls_size_of_current_object() + result1.value()->tls_alignment_of_current_object(); auto object = s_global_objects.get(library_name); if (!object.has_value()) @@ -586,7 +588,7 @@ void ELF::DynamicLinker::linker_main(String&& main_program_name, int main_progra dbgln_if(DYNAMIC_LOAD_DEBUG, "loaded all dependencies"); for ([[maybe_unused]] auto& lib : s_loaders) { - dbgln_if(DYNAMIC_LOAD_DEBUG, "{} - tls size: {}, tls offset: {}", lib.key, lib.value->tls_size_of_current_object(), lib.value->tls_offset()); + dbgln_if(DYNAMIC_LOAD_DEBUG, "{} - tls size: {}, tls alignment: {}, tls offset: {}", lib.key, lib.value->tls_size_of_current_object(), lib.value->tls_alignment_of_current_object(), lib.value->tls_offset()); } allocate_tls(); diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp index 0d815c7124..7925b0dc66 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.cpp +++ b/Userland/Libraries/LibELF/DynamicLoader.cpp @@ -71,7 +71,7 @@ DynamicLoader::DynamicLoader(int fd, String filename, void* data, size_t size, S m_elf_image = adopt_own(*new ELF::Image((u8*)m_file_data, m_file_size)); m_valid = validate(); if (m_valid) - m_tls_size_of_current_object = calculate_tls_size(); + find_tls_size_and_alignment(); else dbgln("Image validation failed for file {}", m_filename); } @@ -105,15 +105,18 @@ DynamicObject const& DynamicLoader::dynamic_object() const return *m_cached_dynamic_object; } -size_t DynamicLoader::calculate_tls_size() const +void DynamicLoader::find_tls_size_and_alignment() { - size_t tls_size = 0; - image().for_each_program_header([&tls_size](auto program_header) { + image().for_each_program_header([this](auto program_header) { if (program_header.type() == PT_TLS) { - tls_size = program_header.size_in_memory(); + m_tls_size_of_current_object = program_header.size_in_memory(); + auto alignment = program_header.alignment(); + VERIFY(!alignment || is_power_of_two(alignment)); + m_tls_alignment_of_current_object = alignment > 1 ? alignment : 0; // No need to reserve extra space for single byte alignment + return IterationDecision::Break; } + return IterationDecision::Continue; }); - return tls_size; } bool DynamicLoader::validate() diff --git a/Userland/Libraries/LibELF/DynamicLoader.h b/Userland/Libraries/LibELF/DynamicLoader.h index 5f8b72bda3..5968464554 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.h +++ b/Userland/Libraries/LibELF/DynamicLoader.h @@ -67,6 +67,7 @@ public: void set_tls_offset(size_t offset) { m_tls_offset = offset; }; size_t tls_size_of_current_object() const { return m_tls_size_of_current_object; } + size_t tls_alignment_of_current_object() const { return m_tls_alignment_of_current_object; } size_t tls_offset() const { return m_tls_offset; } const ELF::Image& image() const { return *m_elf_image; } @@ -134,7 +135,7 @@ private: }; RelocationResult do_relocation(DynamicObject::Relocation const&, ShouldInitializeWeak should_initialize_weak); void do_relr_relocations(); - size_t calculate_tls_size() const; + void find_tls_size_and_alignment(); ssize_t negative_offset_from_tls_block_end(ssize_t tls_offset, size_t value_of_symbol) const; String m_filename; @@ -157,6 +158,7 @@ private: ssize_t m_tls_offset { 0 }; size_t m_tls_size_of_current_object { 0 }; + size_t m_tls_alignment_of_current_object { 0 }; Vector m_unresolved_relocations;