aboutsummaryrefslogtreecommitdiff
path: root/libc/bionic/bionic_elf_tls.cpp
Commit message (Collapse)AuthorAgeFilesLines
* Add a thread-properties APIVy Nguyen2020-08-111-0/+40
| | | | | | | | | | (Based on proposal at https://sourceware.org/glibc/wiki/ThreadPropertiesAPI) This includes API to: - locate static and dynamic TLS - register thread-exit and dynamic TLS creation/destruction callbacks Change-Id: Icd9d29a5b2f47495395645e19d3b2c96826f19c8
* Move bionic_macros.h from private to platform.Josh Gao2020-01-021-1/+1
| | | | | Test: treehugger Change-Id: Ie473914f4c8924c7240b3ac22093a9daf42fc948
* Implement dynamic TLS accesses and allocationRyan Prichard2019-01-251-0/+177
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* Handle R_GENERIC_TLS_TPREL relocationsRyan Prichard2019-01-171-0/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | This relocation is used for static TLS's initial-exec (IE) accesses. A TLS symbol's value is its offset from the start of the ELF module's TLS segment. It doesn't make sense to add the load_bias to this value, so skip the call to soinfo::resolve_symbol_address. Allow TLS relocations to refer to an unresolved weak symbol. In that case, sym will be non-zero, but lsi will be nullptr. The dynamic linker resolves the TPREL relocation to 0, making &missing_weak_symbol equal the thread pointer. Recognize Gold-style relocations to STB_LOCAL TLS symbols/sections and issue an error. Remove the "case R_AARCH64_TLS_TPREL64", because the R_GENERIC_TLS_TPREL case handles it. Remove the no-op R_AARCH64_TLSDESC handler. It's better to issue an error. dlopen_library_with_ELF_TLS now fails with a consistent error about an unimplemented dynamic TLS relocation. Bug: http://b/78026329 Test: bionic unit tests (elftls tests are added in a later CL) Change-Id: Ia08e1b5c8098117e12143d3b4ebb4dfaa5ca46ec
* Avoid a dlopen abort on an invalid TLS alignmentRyan Prichard2019-01-161-13/+16
| | | | | | | | | If the alignment of a TLS segment in a shared object is invalid, return an error through dlerror() rather than aborting the process. Bug: http://b/78026329 Test: bionic unit tests Change-Id: I60e589ddd8ca897f485d55af089f08bd3ff5b1fa
* Initialize static TLS memory using module listRyan Prichard2019-01-161-0/+33
| | | | | | | | | This implementation simply iterates over each static TLS module and copies its initialization image into a new thread's static TLS block. Bug: http://b/78026329 Test: bionic unit tests Change-Id: Ib7edb665271a07010bc68e306feb5df422f2f9e6
* StaticTlsLayout: add exe/tcb and solib layoutRyan Prichard2019-01-161-2/+55
| | | | | | | | | | | | Replace reserve_tcb with reserve_exe_segment_and_tcb, which lays out both the TCB and the executable's TLS segment, accounting for the difference in layout between variant 1 and variant 2 targets. The function isn't actually called with a non-null TlsSegment* yet. Bug: http://b/78026329 Test: bionic unit tests Change-Id: Ibd6238577423a7d0451f36da7e64912046959796
* Add a __bionic_get_tls_segment functionRyan Prichard2019-01-161-0/+32
| | | | | | | | The function searches for a TLS segment in a ElfXX_Phdr table. Bug: http://b/78026329 Test: bionic unit tests Change-Id: I221b13420d1a2da33fc2174b7dd256589f6ecfdb
* Reorganize static TLS memory for ELF TLSRyan Prichard2019-01-111-0/+64
For ELF TLS "local-exec" accesses, the static linker assumes that an executable's TLS segment is located at a statically-known offset from the thread pointer (i.e. "variant 1" for ARM and "variant 2" for x86). Because these layouts are incompatible, Bionic generally needs to allocate its TLS slots differently between different architectures. To allow per-architecture TLS slots: - Replace the TLS_SLOT_xxx enumerators with macros. New ARM slots are generally negative, while new x86 slots are generally positive. - Define a bionic_tcb struct that provides two things: - a void* raw_slots_storage[BIONIC_TLS_SLOTS] field - an inline accessor function: void*& tls_slot(size_t tpindex); For ELF TLS, it's necessary to allocate a temporary TCB (i.e. TLS slots), because the runtime linker doesn't know how large the static TLS area is until after it has loaded all of the initial solibs. To accommodate Golang, it's necessary to allocate the pthread keys at a fixed, small, positive offset from the thread pointer. This CL moves the pthread keys into bionic_tls, then allocates a single mapping per thread that looks like so: - stack guard - stack [omitted for main thread and with pthread_attr_setstack] - static TLS: - bionic_tcb [exec TLS will either precede or succeed the TCB] - bionic_tls [prefixed by the pthread keys] - [solib TLS segments will be placed here] - guard page As before, if the new mapping includes a stack, the pthread_internal_t is allocated on it. At startup, Bionic allocates a temporary bionic_tcb object on the stack, then allocates a temporary bionic_tls object using mmap. This mmap is delayed because the linker can't currently call async_safe_fatal() before relocating itself. Later, Bionic allocates a stack-less thread mapping for the main thread, and copies slots from the temporary TCB to the new TCB. (See *::copy_from_bootstrap methods.) Bug: http://b/78026329 Test: bionic unit tests Test: verify that a Golang app still works Test: verify that a Golang app crashes if bionic_{tls,tcb} are swapped Merged-In: I6543063752f4ec8ef6dc9c7f2a06ce2a18fc5af3 Change-Id: I6543063752f4ec8ef6dc9c7f2a06ce2a18fc5af3 (cherry picked from commit 1e660b70da625fcbf1e43dfae09b7b4817fa1660)