diff options
-rw-r--r-- | lib/libc/gen/tls.c | 83 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.c | 88 |
2 files changed, 74 insertions, 97 deletions
diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c index 2d08a26..70de71b 100644 --- a/lib/libc/gen/tls.c +++ b/lib/libc/gen/tls.c @@ -58,7 +58,7 @@ void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); -#if defined(__ia64__) || defined(__alpha__) || defined(__powerpc__) +#if defined(__ia64__) || defined(__powerpc__) #define TLS_VARIANT_I #endif #if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \ @@ -73,9 +73,6 @@ void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); static size_t tls_static_space; static size_t tls_init_size; -#ifdef TLS_VARIANT_I -static size_t tls_init_offset; -#endif static void *tls_init; #endif @@ -102,67 +99,69 @@ __libc_tls_get_addr(void *ti __unused) #ifdef TLS_VARIANT_I +#define TLS_TCB_SIZE (2 * sizeof(void *)) + /* * Free Static TLS using the Variant I method. */ void -__libc_free_tls(void *tls, size_t tcbsize __unused, size_t tcbalign __unused) +__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) { - Elf_Addr* dtv; + Elf_Addr *dtv; + Elf_Addr **tls; - dtv = ((Elf_Addr**)tls)[0]; - free(tls); + tls = (Elf_Addr **)((Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE); + dtv = tls[0]; free(dtv); + free(tcb); } /* * Allocate Static TLS using the Variant I method. */ void * -__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign __unused) +__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused) { - size_t size; - char *tls; Elf_Addr *dtv; + Elf_Addr **tls; + char *tcb; - size = tls_static_space; - if (size < tcbsize) - size = tcbsize; - - tls = calloc(1, size); - dtv = malloc(3 * sizeof(Elf_Addr)); + if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) + return (oldtcb); - *(Elf_Addr **) tls = dtv; + tcb = calloc(1, tls_static_space + tcbsize); + tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE); - dtv[0] = 1; - dtv[1] = 1; - dtv[2] = (Elf_Addr)(tls + tls_init_offset); - if (oldtls) { - /* - * Copy the static TLS block over whole. - */ - memcpy(tls + tls_init_offset, - (char *)oldtls + tls_init_offset, - tls_static_space - tls_init_offset); + if (oldtcb != NULL) { + memcpy(tls, oldtcb, tls_static_space + TLS_TCB_SIZE); + free(oldtcb); - /* - * 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)); + /* Adjust the DTV. */ + dtv = tls[0]; + dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; } else { - memcpy(tls + tls_init_offset, tls_init, tls_init_size); - memset(tls + tls_init_offset + tls_init_size, - 0, tls_static_space - tls_init_size); + dtv = malloc(3 * sizeof(Elf_Addr)); + tls[0] = dtv; + dtv[0] = 1; + dtv[1] = 1; + dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; + + if (tls_init_size > 0) + memcpy((void*)dtv[2], tls_init, tls_init_size); + if (tls_static_space > tls_init_size) + memset((void*)(dtv[2] + tls_init_size), 0, + tls_static_space - tls_init_size); } - return tls; + return(tcb); } #endif #ifdef TLS_VARIANT_II +#define TLS_TCB_SIZE (3 * sizeof(Elf_Addr)) + /* * Free Static TLS using the Variant II method. */ @@ -293,22 +292,14 @@ _init_tls() for (i = 0; (unsigned) i < phnum; i++) { if (phdr[i].p_type == PT_TLS) { -#ifdef TLS_VARIANT_I - tls_static_space = round(2*sizeof(Elf_Addr), - phdr[i].p_align) + phdr[i].p_memsz; - tls_init_offset = round(2*sizeof(Elf_Addr), - phdr[i].p_align); -#else tls_static_space = round(phdr[i].p_memsz, phdr[i].p_align); -#endif tls_init_size = phdr[i].p_filesz; tls_init = (void*) phdr[i].p_vaddr; } } - tls = _rtld_allocate_tls(NULL, 3*sizeof(Elf_Addr), - sizeof(Elf_Addr)); + tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, 1); _set_tp(tls); #endif diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index ce8069c..68908bd 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -2690,56 +2690,46 @@ tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) /* XXX not sure what variants to use for arm. */ -#if defined(__ia64__) || defined(__alpha__) || defined(__powerpc__) +#if defined(__ia64__) || defined(__powerpc__) /* * Allocate Static TLS using the Variant I method. */ void * -allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) +allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign) { Obj_Entry *obj; - size_t size; - char *tls; - Elf_Addr *dtv, *olddtv; + char *tcb; + Elf_Addr **tls; + Elf_Addr *dtv; Elf_Addr addr; int i; - size = tls_static_space; - - tls = calloc(1, size); - dtv = calloc(1, (tls_max_index + 2) * sizeof(Elf_Addr)); + if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) + return (oldtcb); - *(Elf_Addr**) tls = dtv; + assert(tcbsize >= TLS_TCB_SIZE); + tcb = calloc(1, tls_static_space - TLS_TCB_SIZE + tcbsize); + tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE); - dtv[0] = tls_dtv_generation; - dtv[1] = tls_max_index; + if (oldtcb != NULL) { + memcpy(tls, oldtcb, tls_static_space); + free(oldtcb); - if (oldtls) { - /* - * Copy the static TLS block over whole. - */ - memcpy(tls + tcbsize, oldtls + tcbsize, tls_static_space - tcbsize); - - /* - * If any dynamic TLS blocks have been created tls_get_addr(), - * move them over. - */ - olddtv = *(Elf_Addr**) oldtls; - for (i = 0; i < olddtv[1]; i++) { - if (olddtv[i+2] < (Elf_Addr)oldtls || - olddtv[i+2] > (Elf_Addr)oldtls + tls_static_space) { - dtv[i+2] = olddtv[i+2]; - olddtv[i+2] = 0; + /* Adjust the DTV. */ + dtv = tls[0]; + for (i = 0; i < dtv[1]; i++) { + if (dtv[i+2] >= (Elf_Addr)oldtcb && + dtv[i+2] < (Elf_Addr)oldtcb + tls_static_space) { + dtv[i+2] = dtv[i+2] - (Elf_Addr)oldtcb + (Elf_Addr)tls; } } - - /* - * We assume that all tls blocks are allocated with the same - * size and alignment. - */ - free_tls(oldtls, tcbsize, tcbalign); } else { + dtv = calloc(tls_max_index + 2, sizeof(Elf_Addr)); + tls[0] = dtv; + dtv[0] = tls_dtv_generation; + dtv[1] = tls_max_index; + for (obj = objs; obj; obj = obj->next) { if (obj->tlsoffset) { addr = (Elf_Addr)tls + obj->tlsoffset; @@ -2753,34 +2743,30 @@ allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) } } - return tls; + return (tcb); } void -free_tls(void *tls, size_t tcbsize, size_t tcbalign) +free_tls(void *tcb, size_t tcbsize, size_t tcbalign) { - size_t size; - Elf_Addr* dtv; - int dtvsize, i; + Elf_Addr *dtv; Elf_Addr tlsstart, tlsend; + int dtvsize, i; - /* - * Figure out the size of the initial TLS block so that we can - * find stuff which __tls_get_addr() allocated dynamically. - */ - size = tls_static_space; + assert(tcbsize >= TLS_TCB_SIZE); + + tlsstart = (Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE; + tlsend = tlsstart + tls_static_space; - dtv = ((Elf_Addr**)tls)[0]; + dtv = *(Elf_Addr **)tlsstart; dtvsize = dtv[1]; - tlsstart = (Elf_Addr) tls; - tlsend = tlsstart + size; for (i = 0; i < dtvsize; i++) { - if (dtv[i+2] && (dtv[i+2] < tlsstart || dtv[i+2] > tlsend)) { - free((void*) dtv[i+2]); + if (dtv[i+2] && (dtv[i+2] < tlsstart || dtv[i+2] >= tlsend)) { + free((void*)dtv[i+2]); } } - - free((void*) tlsstart); + free(dtv); + free(tcb); } #endif |