1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 20:17:44 +00:00

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.
This commit is contained in:
Itamar 2021-04-24 11:30:20 +03:00 committed by Andreas Kling
parent db76702d71
commit 6bbd2ebf83
7 changed files with 63 additions and 12 deletions

View file

@ -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)