diff options
Diffstat (limited to 'lib/libc/gen/tls.c')
-rw-r--r-- | lib/libc/gen/tls.c | 101 |
1 files changed, 50 insertions, 51 deletions
diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c index c81ef7e9ad0e..b26b13d45589 100644 --- a/lib/libc/gen/tls.c +++ b/lib/libc/gen/tls.c @@ -32,7 +32,6 @@ * runtime from ld-elf.so.1. */ -#include <sys/cdefs.h> #include <sys/param.h> #include <stdlib.h> #include <string.h> @@ -81,13 +80,13 @@ static void *libc_tls_init; void * __libc_tls_get_addr(void *vti) { - uintptr_t *dtv; + struct dtv *dtv; tls_index *ti; dtv = _tcb_get()->tcb_dtv; ti = vti; - return ((char *)(dtv[ti->ti_module + 1] + ti->ti_offset) + - TLS_DTV_OFFSET); + return (dtv->dtv_slots[ti->ti_module - 1].dtvs_tls + + (ti->ti_offset + TLS_DTV_OFFSET)); } #ifdef __i386__ @@ -114,6 +113,8 @@ libc_malloc_aligned(size_t size, size_t align) align = sizeof(void *); mem = __je_bootstrap_malloc(size + sizeof(void *) + align - 1); + if (mem == NULL) + return (NULL); res = (void *)roundup2((uintptr_t)mem + sizeof(void *), align); *(void **)((uintptr_t)res - sizeof(void *)) = mem; return (res); @@ -150,7 +151,8 @@ libc_free_aligned(void *ptr) * where TP points (with bias) to TLS and TCB immediately precedes TLS without * any alignment gap[4]. Only TLS should be aligned. The TCB[0] points to DTV * vector and DTV values are biased by constant value (TLS_DTV_OFFSET) from - * real addresses[5]. + * real addresses. However, like RTLD, we don't actually bias the DTV values, + * instead we compensate in __tls_get_addr for ti_offset's bias. * * [1] Ulrich Drepper: ELF Handling for Thread-Local Storage * www.akkadia.org/drepper/tls.pdf @@ -166,8 +168,6 @@ libc_free_aligned(void *ptr) * but we must follow this rule due to suboptimal _tcb_set() * (aka <ARCH>_SET_TP) implementation. This function doesn't expect TP but * TCB as argument. - * - * [5] I'm not able to validate "values are biased" assertions. */ /* @@ -200,11 +200,9 @@ get_tls_block_ptr(void *tcb, size_t tcbsize) void __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) { - Elf_Addr *dtv; - Elf_Addr **tls; + struct dtv *dtv; - tls = (Elf_Addr **)tcb; - dtv = tls[0]; + dtv = ((struct tcb *)tcb)->tcb_dtv; __je_bootstrap_free(dtv); libc_free_aligned(get_tls_block_ptr(tcb, tcbsize)); } @@ -232,7 +230,8 @@ __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) void * __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) { - Elf_Addr *dtv, **tcb; + struct dtv *dtv; + struct tcb *tcb; char *tls_block, *tls; size_t extra_size, maxalign, post_size, pre_size, tls_block_size; @@ -261,7 +260,7 @@ __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) abort(); } memset(tls_block, 0, tls_block_size); - tcb = (Elf_Addr **)(tls_block + pre_size + extra_size); + tcb = (struct tcb *)(tls_block + pre_size + extra_size); tls = (char *)tcb + TLS_TCB_SIZE + post_size; if (oldtcb != NULL) { @@ -270,19 +269,20 @@ __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) libc_free_aligned(oldtcb); /* Adjust the DTV. */ - dtv = tcb[0]; - dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET); + dtv = tcb->tcb_dtv; + dtv->dtv_slots[0].dtvs_tls = tls; } else { - dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); + dtv = __je_bootstrap_malloc(sizeof(struct dtv) + + sizeof(struct dtv_slot)); if (dtv == NULL) { tls_msg("__libc_allocate_tls: Out of memory.\n"); abort(); } /* Build the DTV. */ - tcb[0] = dtv; - dtv[0] = 1; /* Generation. */ - dtv[1] = 1; /* Segments count. */ - dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET); + tcb->tcb_dtv = dtv; + dtv->dtv_gen = 1; /* Generation. */ + dtv->dtv_size = 1; /* Segments count. */ + dtv->dtv_slots[0].dtvs_tls = tls; if (libc_tls_init_size > 0) memcpy(tls, libc_tls_init, libc_tls_init_size); @@ -302,8 +302,8 @@ void __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) { size_t size; - Elf_Addr* dtv; - Elf_Addr tlsstart, tlsend; + struct dtv *dtv; + uintptr_t tlsstart, tlsend; /* * Figure out the size of the initial TLS block so that we can @@ -312,8 +312,8 @@ __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) tcbalign = MAX(tcbalign, libc_tls_init_align); size = roundup2(libc_tls_static_space, tcbalign); - dtv = ((Elf_Addr**)tcb)[1]; - tlsend = (Elf_Addr) tcb; + dtv = ((struct tcb *)tcb)->tcb_dtv; + tlsend = (uintptr_t)tcb; tlsstart = tlsend - size; libc_free_aligned((void*)tlsstart); __je_bootstrap_free(dtv); @@ -323,61 +323,60 @@ __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) * Allocate Static TLS using the Variant II method. */ void * -__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) +__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) { size_t size; - char *tls; - Elf_Addr *dtv; - Elf_Addr segbase, oldsegbase; + char *tls_block, *tls; + struct dtv *dtv; + struct tcb *tcb; tcbalign = MAX(tcbalign, libc_tls_init_align); size = roundup2(libc_tls_static_space, tcbalign); - if (tcbsize < 2 * sizeof(Elf_Addr)) - tcbsize = 2 * sizeof(Elf_Addr); - tls = libc_malloc_aligned(size + tcbsize, tcbalign); - if (tls == NULL) { + if (tcbsize < 2 * sizeof(uintptr_t)) + tcbsize = 2 * sizeof(uintptr_t); + tls_block = libc_malloc_aligned(size + tcbsize, tcbalign); + if (tls_block == NULL) { tls_msg("__libc_allocate_tls: Out of memory.\n"); abort(); } - memset(tls, 0, size + tcbsize); - dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); + memset(tls_block, 0, size + tcbsize); + dtv = __je_bootstrap_malloc(sizeof(struct dtv) + + sizeof(struct dtv_slot)); if (dtv == NULL) { tls_msg("__libc_allocate_tls: Out of memory.\n"); abort(); } - segbase = (Elf_Addr)(tls + size); - ((Elf_Addr*)segbase)[0] = segbase; - ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; + tcb = (struct tcb *)(tls_block + size); + tls = (char *)tcb - libc_tls_static_space; + tcb->tcb_self = tcb; + tcb->tcb_dtv = dtv; - dtv[0] = 1; - dtv[1] = 1; - dtv[2] = segbase - libc_tls_static_space; + dtv->dtv_gen = 1; + dtv->dtv_size = 1; + dtv->dtv_slots[0].dtvs_tls = tls; - if (oldtls) { + if (oldtcb != NULL) { /* * Copy the static TLS block over whole. */ - oldsegbase = (Elf_Addr) oldtls; - memcpy((void *)(segbase - libc_tls_static_space), - (const void *)(oldsegbase - libc_tls_static_space), + memcpy(tls, (const char *)oldtcb - libc_tls_static_space, libc_tls_static_space); /* * We assume that this block was the one we created with * allocate_initial_tls(). */ - _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); + _rtld_free_tls(oldtcb, 2 * sizeof(uintptr_t), + sizeof(uintptr_t)); } else { - memcpy((void *)(segbase - libc_tls_static_space), - libc_tls_init, libc_tls_init_size); - memset((void *)(segbase - libc_tls_static_space + - libc_tls_init_size), 0, + memcpy(tls, libc_tls_init, libc_tls_init_size); + memset(tls + libc_tls_init_size, 0, libc_tls_static_space - libc_tls_init_size); } - return (void*) segbase; + return (tcb); } #endif /* TLS_VARIANT_II */ @@ -385,7 +384,7 @@ __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) #else void * -__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, +__libc_allocate_tls(void *oldtcb __unused, size_t tcbsize __unused, size_t tcbalign __unused) { return (0); |