aad599979d
_rtld_tls_allocate and _rtld_tls_free. libpthread uses this functions to setup the thread private area of all new threads. ld.elf_so is responsible for setting up the private area for the initial thread. Similar functions are called from _libc_init for static binaries, using dl_iterate_phdr to access the ELF Program Header. Add test cases to exercise the different TLS storage models. Test cases are compiled and installed on all platforms, but are skipped on platforms not marked for TLS support. This material is based upon work partially supported by The NetBSD Foundation under a contract with Joerg Sonnenberger. It is inspired by the TLS support in FreeBSD by Doug Rabson and the clean ups of the DragonFly port of the original FreeBSD modifications.
82 lines
2.9 KiB
Plaintext
82 lines
2.9 KiB
Plaintext
Steps for adding TLS support for a new platform:
|
|
|
|
(1) Declare TLS variant in machine/types.h by defining either
|
|
__HAVE_TLS_VARIANT_I or __HAVE_TLS_VARIANT_II.
|
|
|
|
(2) crt0.o has to call _rtld_tls_static_setup() if _DYNAMIC == NULL.
|
|
This part is already done if the new src/lib/csu/arch layout is used
|
|
by the architecture.
|
|
|
|
(3) _lwp_makecontext has to set the reserved register or kernel transfer
|
|
variable in uc_mcontext to the provided value of 'private'.
|
|
|
|
This is not possible on the VAX as there is no free space in ucontext_t.
|
|
This requires either a special version of _lwp_create or versioning
|
|
everything using ucontext_t. Debug support depends on getting the data from
|
|
ucontext_t, so the second option is possibly required.
|
|
|
|
(4) _lwp_setprivate(2) has to update the same register as
|
|
_lwp_makecontext. cpu_lwp_setprivate has to call _lwp_setprivate(2) to
|
|
reflect the kernel view. cpu_switch has to update the mapping.
|
|
|
|
_lwp_setprivate is used for the initial thread, all other threads
|
|
created by libpthread use _lwp_makecontext for this purpose.
|
|
|
|
(5) Provide __tls_get_addr and possible other MD functions for dynamic
|
|
TLS offset computation. If such alternative entry points exist (currently
|
|
only i386), also add a weak reference to 0 in src/lib/libc/tls/tls.c.
|
|
|
|
The generic implementation is:
|
|
|
|
#include <sys/cdefs.h>
|
|
#include <sys/tls.h>
|
|
#include <lwp.h>
|
|
|
|
/* Weak entry is overriden by ld.elf_so for dynamic linkage */
|
|
weak_alias(__tls_get_addr, __libc__tls_get_addr)
|
|
|
|
void *
|
|
__libc__tls_get_addr(size_t idx[2])
|
|
{
|
|
struct tls_tcb *tcb;
|
|
|
|
tcb = _lwp_getprivate();
|
|
return _rtld_tls_get_addr(tcb, idx[0], idx[1]);
|
|
}
|
|
|
|
XXX Document optimisations based idx[0]
|
|
|
|
(6) Implement the necessary relocation records in mdreloc.c. There are
|
|
typically three relocation types found in dynamic binaries:
|
|
|
|
(a) R_TYPE(TLS_DTPOFF): Offset inside the module. The common TLS code
|
|
ensures that the DTV vector points to offset 0 inside the module TLS block.
|
|
This is normally def->st_value + rela->r_addend.
|
|
|
|
(b) R_TYPE(TLS_DTPMOD): Module index.
|
|
|
|
(c) R_TYPE(TLS_TPOFF): Static TLS offset. The code has to check whether
|
|
the static TLS offset for this module has been allocated
|
|
(defobj->tls_done) and otherwise call _rtld_tls_offset_allocate(). This
|
|
may fail if no static space is available and the object has been pulled
|
|
in via dlopen(3).
|
|
|
|
For TLS Variant I, this is typically:
|
|
|
|
def->st_value + rela->r_addend + defobj->tlsoffset + sizeof(struct tls_tcb)
|
|
|
|
e.g. the relocation doesn't include the fixed TCB.
|
|
|
|
For TLS Variant II, this is typically:
|
|
|
|
def->st_value - defobj->tlsoffset + rela->r_addend
|
|
|
|
e.g. starting offset is counting down from the TCB.
|
|
|
|
(7) Implement _lwp_getprivate_fast() in machine/mcontext.h and set
|
|
__HAVE___LWP_GETPRIVATE_FAST.
|
|
|
|
(8) Test using src/tests/lib/libc/tls. Make sure with "objdump -R" that
|
|
t_tls_dynamic has two TPOFF relocations and h_tls_dlopen.so.1 and
|
|
libh_tls_dynamic.so.1 have both two DTPMOD and DTPOFF relocations.
|