diff options
author | Itamar <itamar8910@gmail.com> | 2021-04-24 11:30:20 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-04-30 18:47:39 +0200 |
commit | 6bbd2ebf83c4b8c0a11462f9abd65352c592b976 (patch) | |
tree | c8be718bf5bc02fded321451b0c1fb476e28d7c9 /Userland/Libraries/LibELF/DynamicLinker.cpp | |
parent | db76702d7173f9c8141397a4b3fa60340041132b (diff) | |
download | serenity-6bbd2ebf83c4b8c0a11462f9abd65352c592b976.zip |
Kernel+LibELF: Support initializing values of TLS data
Previously, TLS data was always zero-initialized.
To support initializing the values of TLS data, sys$allocate_tls now
receives a buffer with the desired initial data, and copies it to the
master TLS region of the process.
The DynamicLinker gathers the initial TLS image and passes it to
sys$allocate_tls.
We also now require the size passed to sys$allocate_tls to be
page-aligned, to make things easier. Note that this doesn't waste memory
as the TLS data has to be allocated in separate pages anyway.
Diffstat (limited to 'Userland/Libraries/LibELF/DynamicLinker.cpp')
-rw-r--r-- | Userland/Libraries/LibELF/DynamicLinker.cpp | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp index 5ddf812a26..5b5126b0df 100644 --- a/Userland/Libraries/LibELF/DynamicLinker.cpp +++ b/Userland/Libraries/LibELF/DynamicLinker.cpp @@ -6,6 +6,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/ByteBuffer.h> #include <AK/Debug.h> #include <AK/HashMap.h> #include <AK/HashTable.h> @@ -25,6 +26,7 @@ #include <LibELF/DynamicObject.h> #include <LibELF/Hashes.h> #include <fcntl.h> +#include <string.h> #include <sys/types.h> #include <syscall.h> @@ -154,16 +156,26 @@ static Result<void, DlErrorMessage> map_dependencies(const String& name) static void allocate_tls() { - size_t total_tls_size = 0; + s_total_tls_size = 0; for (const auto& data : s_loaders) { dbgln_if(DYNAMIC_LOAD_DEBUG, "{}: TLS Size: {}", data.key, data.value->tls_size_of_current_object()); - total_tls_size += data.value->tls_size_of_current_object(); + s_total_tls_size += data.value->tls_size_of_current_object(); } - if (total_tls_size) { - [[maybe_unused]] void* tls_address = ::allocate_tls(total_tls_size); - dbgln_if(DYNAMIC_LOAD_DEBUG, "from userspace, tls_address: {:p}", tls_address); + + if (!s_total_tls_size) + return; + + auto page_aligned_size = align_up_to(s_total_tls_size, PAGE_SIZE); + ByteBuffer initial_tls_data = ByteBuffer::create_zeroed(page_aligned_size); + + // Initialize TLS data + for (const auto& entry : s_loaders) { + entry.value->copy_initial_tls_data_into(initial_tls_data, s_total_tls_size); } - s_total_tls_size = total_tls_size; + + void* master_tls = ::allocate_tls((char*)initial_tls_data.data(), initial_tls_data.size()); + VERIFY(master_tls != (void*)-1); + dbgln_if(DYNAMIC_LOAD_DEBUG, "from userspace, master_tls: {:p}", master_tls); } static int __dl_iterate_phdr(DlIteratePhdrCallbackFunction callback, void* data) |