diff options
| author | Ryan Prichard <rprichard@google.com> | 2019-01-18 01:00:59 -0800 |
|---|---|---|
| committer | Ryan Prichard <rprichard@google.com> | 2019-01-25 17:53:01 -0800 |
| commit | 16455b5100ea46b930c1fa84d6bc905b7977643d (patch) | |
| tree | 2cbeacaeecab2980c47fbf21ce860d44d86ea8c6 /libc/bionic/pthread_create.cpp | |
| parent | 3b463cf7f4f7fa54567ff42f6772091b22add2b8 (diff) | |
Implement dynamic TLS accesses and allocation
Initialize a thread's DTV to an empty zeroed DTV. Allocate the DTV and
any ELF module's TLS segment on-demand in __tls_get_addr. Use a generation
counter, incremented in the linker, to signal when threads should
update/reallocate their DTV objects.
A generation count of 0 always indicates the constant zero DTV.
Once a DTV is allocated, it isn't freed until the thread exits, because
a signal handler could interrupt the fast path of __tls_get_addr between
accessing the DTV slot and reading a field of the DTV. Bionic keeps a
linked list of DTV objects so it can free them at thread-exit.
Dynamic TLS memory is allocated using a BionicAllocator instance in
libc_shared_globals. For async-signal safety, access to the
linker/libc-shared state is protected by first blocking signals, then by
acquiring the reader-writer lock, TlsModules::rwlock. A write lock is
needed to allocate or free memory.
In pthread_exit, unconditionally block signals before freeing dynamic
TLS memory or freeing the shadow call stack.
ndk_cruft.cpp: Avoid including pthread_internal.h inside an extern "C".
(The header now includes a C++ template that doesn't compile inside
extern "C".)
Bug: http://b/78026329
Bug: http://b/123094171
Test: bionic unit tests
Change-Id: I3c9b12921c9e68b33dcc1d1dd276bff364eff5d7
Diffstat (limited to 'libc/bionic/pthread_create.cpp')
| -rw-r--r-- | libc/bionic/pthread_create.cpp | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 31e03786c..d80906ce4 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -70,6 +70,14 @@ void __init_tcb_stack_guard(bionic_tcb* tcb) { tcb->tls_slot(TLS_SLOT_STACK_GUARD) = reinterpret_cast<void*>(__stack_chk_guard); } +__attribute__((no_stack_protector)) +void __init_tcb_dtv(bionic_tcb* tcb) { + // Initialize the DTV slot to a statically-allocated empty DTV. The first + // access to a dynamic TLS variable allocates a new DTV. + static const TlsDtv zero_dtv = {}; + __set_tcb_dtv(tcb, const_cast<TlsDtv*>(&zero_dtv)); +} + void __init_bionic_tls_ptrs(bionic_tcb* tcb, bionic_tls* tls) { tcb->thread()->bionic_tls = tls; tcb->tls_slot(TLS_SLOT_BIONIC_TLS) = tls; @@ -291,6 +299,7 @@ static int __allocate_thread(pthread_attr_t* attr, bionic_tcb** tcbp, void** chi // Initialize TLS memory. __init_static_tls(mapping.static_tls); __init_tcb(tcb, thread); + __init_tcb_dtv(tcb); __init_tcb_stack_guard(tcb); __init_bionic_tls_ptrs(tcb, tls); |
