mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 20:27:46 +00:00
LibC+LibELF: Support loading shared libraries compiled with dynamic TLS
This is a prerequisite for upstreaming our LLVM patches, as our current hack forcing `-ftls-model=initial-exec` in the Clang driver is not acceptable upstream. Currently, our kernel-managed TLS implementation limits us to only having a single block of storage for all thread-local variables that's initialized at load time. This PR merely implements the dynamic TLS interface (`__tls_get_addr` and TLSDESC) on top of our static TLS infrastructure. The current model's limitations still stand: - a single static TLS block is reserved at load time, `dlopen()`-ing shared libraries that define thread-local variables might cause us to run out of space. - the initial TLS image is not changeable post-load, so `dlopen()`-ing libraries with non-zero-initialized TLS variables is not supported. The way we repurpose `ti_module` to mean "offset within static TLS block" instead of "module index" is not ABI-compliant.
This commit is contained in:
parent
192ee4594c
commit
ad9e674fa0
6 changed files with 166 additions and 21 deletions
63
Userland/Libraries/LibELF/Arch/aarch64/tls.S
Normal file
63
Userland/Libraries/LibELF/Arch/aarch64/tls.S
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Daniel Bertalan <dani@danielbertalan.dev>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// This file implements the runtime components of the AArch64 TLSDESC ABI,
|
||||
// which is used when accessing thread-local variables which might not be
|
||||
// stored in the static TLS block (global-dynamic and local-dynamic access
|
||||
// models). Compilers default to this when creating shared libraries, as they
|
||||
// may be loaded after program startup by `dlopen()`.
|
||||
//
|
||||
// Each referenced thread-local symbol is associated with a descriptor:
|
||||
//
|
||||
// struct TlsDescriptor {
|
||||
// size_t (*resolver)(TlsDescriptor*);
|
||||
// union {
|
||||
// size_t tpoff; // for static TLS
|
||||
// struct {
|
||||
// size_t module_id;
|
||||
// size_t module_offset;
|
||||
// } *dynamic; // for dynamic TLS, not yet implemented
|
||||
// };
|
||||
// };
|
||||
//
|
||||
// The resolver takes a pointer to the descriptor as an argument and returns
|
||||
// the symbol's offset to the thread pointer (tpidr_el1). The second field of
|
||||
// the descriptor is an implementation-defined value which the resolver uses to
|
||||
// identify the symbol.
|
||||
//
|
||||
// Thus, the address of a thread-local variable is retrieved as follows:
|
||||
//
|
||||
// &var = thread_pointer + descriptor.resolver(&descriptor);
|
||||
//
|
||||
// The two essential types of resolver functions are:
|
||||
//
|
||||
// - `__tlsdesc_static`: If the variable is located in the static TLS block,
|
||||
// its thread pointer offset is a load-time constant, which can be stored in
|
||||
// the descriptor. This function simply returns that.
|
||||
//
|
||||
// - `tlsdesc_dynamic`: Looks up a variable by its module ID and module offset.
|
||||
// This is used if the TLS block is allocated separately, so might have a
|
||||
// different thread pointer offset for each thread. This works similarly to
|
||||
// the traditional TLS ABI's __tls_get_addr function. Not yet implemented in
|
||||
// SerenityOS.
|
||||
//
|
||||
// The TLSDESC format strives to make the code sequence for thread-local
|
||||
// variable access as short as possible, hence the resolver functions follow a
|
||||
// special calling convention: they must not clobber any registers. To ensure
|
||||
// that even the usually volatile registers are saved off, we need to implement
|
||||
// the resolvers in assembly.
|
||||
|
||||
// size_t __tlsdesc_static(TlsDescriptor* desc)
|
||||
// {
|
||||
// return desc->tpoff;
|
||||
// }
|
||||
.p2align 4
|
||||
.globl __tlsdesc_static
|
||||
.hidden __tlsdesc_static
|
||||
.type __tlsdesc_static,@function
|
||||
__tlsdesc_static:
|
||||
ldr x0, [x0, #8]
|
||||
ret
|
Loading…
Add table
Add a link
Reference in a new issue