From bc633d631d552c37d0e3a5c21b317af07ac9507b Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 28 Mar 2005 03:33:20 +0000 Subject: [PATCH] Cleanup and retool portions of the TLS support and make sure that non-threaded binaries remain compatible with older kernels. * Removes the tcb alignment argument. Instead an alignment #define is placed in sys/tls.h * Gets rid of the Variant I code (we can add it in later, it just gets in the way). * Retools the Variant II code to support %gs:OFFSET (negative offset) AND %gs:0 relative accesses, supporting both -mtls-direct-seg-refs and -mno-tls-direct-seg-refs. * Changes the Elf_Addr array for the TCB into a real structure in sys/tls.h * Retains the DTV methodology. * Retains the TCB methodology, but note that the area 'after' the tcb is now available for future use (at least with Variant I removed). Frankly I'm not sure we would ever want to support having the 'data' area after the TCB instead of before the TCB, at least not for i386. * Do not try to call sys_set_tls_area() if there is no TLS storage. i.e. so non-threaded binaries remain compatible with old kernels. The TLS is only initialized if (a) There is thread local storage, aka gcc3's __thread keyword, or (b) The program is linked against a threading library. The threading library makes the appropriate calls to set up the TLS. --- lib/libc/gen/tls.c | 181 ++++---------- .../arch/amd64/amd64/pthread_md.c | 23 +- lib/libthread_xu/arch/i386/i386/pthread_md.c | 26 +- libexec/rtld-elf/i386/reloc.c | 60 +++-- libexec/rtld-elf/rtld.c | 232 ++++++------------ libexec/rtld-elf/rtld.h | 10 +- libexec/rtld-elf/rtld_tls.h | 7 +- sys/sys/tls.h | 16 +- 8 files changed, 216 insertions(+), 339 deletions(-) diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c index 0265ca9273..30ed2dbd63 100644 --- a/lib/libc/gen/tls.c +++ b/lib/libc/gen/tls.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/lib/libc/gen/tls.c,v 1.7 2005/03/01 23:42:00 davidxu Exp $ - * $DragonFly: src/lib/libc/gen/tls.c,v 1.3 2005/03/20 14:57:28 joerg Exp $ + * $DragonFly: src/lib/libc/gen/tls.c,v 1.4 2005/03/28 03:33:12 dillon Exp $ */ /* @@ -34,6 +34,7 @@ */ #include +#include #include #include #include @@ -48,10 +49,11 @@ __weak_reference(___libc_tls_get_addr, ___tls_get_addr); #endif __weak_reference(__libc_tls_get_addr, __tls_get_addr); -void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); -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); +struct tls_tcb *_rtld_allocate_tls(struct tls_tcb *, size_t tcbsize, int flags); +void _rtld_free_tls(struct tls_tcb *tcb, size_t tcb_size); +struct tls_tcb *__libc_allocate_tls(struct tls_tcb *old_tcb, size_t tcbsize, + int flags); +void __libc_free_tls(struct tls_tcb *tcb, size_t tcb_size); #if defined(__ia64__) || defined(__powerpc__) #define TLS_VARIANT_I @@ -68,9 +70,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 @@ -90,6 +89,7 @@ ___libc_tls_get_addr(void *ti __unused) #endif void *__libc_tls_get_addr(void *ti); + void * __libc_tls_get_addr(void *ti __unused) { @@ -98,155 +98,77 @@ __libc_tls_get_addr(void *ti __unused) #ifndef PIC -#ifdef TLS_VARIANT_I - /* - * Free Static TLS using the Variant I method. + * Free Static TLS */ void -__libc_free_tls(void *tls, size_t tcbsize __unused, size_t tcbalign __unused) +__libc_free_tls(struct tls_tcb *tcb, size_t tcb_size __unused) { - Elf_Addr* dtv; + size_t data_size; - dtv = *(Elf_Addr **)tls; - free(tls); - free(dtv); + if (tcb->dtv_base) + free(tcb->dtv_base); + data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) & + ~RTLD_STATIC_TLS_ALIGN_MASK; + free((char *)tcb - data_size); } /* - * Allocate Static TLS using the Variant I method. + * Allocate Static TLS. */ -void * -__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign __unused) +struct tls_tcb * +__libc_allocate_tls(struct tls_tcb *old_tcb, size_t tcb_size, int flags) { - size_t size; - char *tls; + size_t data_size; + struct tls_tcb *tcb; Elf_Addr *dtv; - size = tls_static_space; - if (size < tcbsize) - size = tcbsize; - - tls = malloc(size); + data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) & + ~RTLD_STATIC_TLS_ALIGN_MASK; + tcb = malloc(data_size + tcb_size); + tcb = (struct tls_tcb *)((char *)tcb + data_size); + bzero(tcb, tcb_size); dtv = malloc(3 * sizeof(Elf_Addr)); - - *(Elf_Addr **) tls = dtv; + tcb->tcb_base = tcb; + tcb->dtv_base = dtv; 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, - (const uint8_t *) oldtls + tls_init_offset, - tls_static_space - tls_init_offset); + dtv[2] = (Elf_Addr)((char *)tcb - 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)); - } 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); - } - - return tls; -} - -#endif - -#ifdef TLS_VARIANT_II - -/* - * Free Static TLS using the Variant II method. - */ -void -__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) -{ - size_t size; - Elf_Addr* dtv; - Elf_Addr tlsstart, tlsend; - - /* - * Figure out the size of the initial TLS block so that we can - * find stuff which ___tls_get_addr() allocated dynamically. - */ - size = round(tls_static_space, tcbalign); - - dtv = ((Elf_Addr**)tcb)[1]; - tlsend = (Elf_Addr) tcb; - tlsstart = tlsend - size; - free((void*) tlsstart); - free(dtv); -} - -/* - * Allocate Static TLS using the Variant II method. - */ -void * -__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) -{ - size_t size; - char *tls; - Elf_Addr *dtv; - Elf_Addr segbase, oldsegbase; - - size = round(tls_static_space, tcbalign); - - assert(tcbsize >= 2*sizeof(Elf_Addr)); - tls = malloc(size + tcbsize); - dtv = malloc(3 * sizeof(Elf_Addr)); - - segbase = (Elf_Addr)(tls + size); - ((Elf_Addr*)segbase)[0] = segbase; - ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; - - dtv[0] = 1; - dtv[1] = 1; - dtv[2] = segbase - tls_static_space; - - if (oldtls) { + if (old_tcb) { /* * Copy the static TLS block over whole. */ - oldsegbase = (Elf_Addr) oldtls; - memcpy((void *)(segbase - tls_static_space), - (const void *)(oldsegbase - tls_static_space), - tls_static_space); + memcpy((char *)tcb - tls_static_space, + (char *)old_tcb - tls_static_space, + 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(old_tcb, sizeof(struct tls_tcb)); } else { - memcpy((void *)(segbase - tls_static_space), - tls_init, tls_init_size); - memset((void *)(segbase - tls_static_space + tls_init_size), - 0, tls_static_space - tls_init_size); + memcpy((char *)tcb - tls_static_space, + tls_init, tls_init_size); + memset((char *)tcb - tls_static_space + tls_init_size, + 0, tls_static_space - tls_init_size); } - - return (void*) segbase; + return (tcb); } -#endif /* TLS_VARIANT_II */ - #else -void * -__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, - size_t tcbalign __unused) +struct tls_tcb * +__libc_allocate_tls(struct tls_tcb *old_tls __unused, size_t tcb_size __unused, + int flags __unused) { return (0); } void -__libc_free_tls(void *tcb __unused, size_t tcbsize __unused, - size_t tcbalign __unused) +__libc_free_tls(struct tls_tcb *tcb __unused, size_t tcb_size __unused) { } @@ -263,7 +185,7 @@ _init_tls() Elf_Phdr *phdr; size_t phent, phnum; int i; - void *tls; + struct tls_tcb *tcb; sp = (Elf_Addr *) environ; while (*sp++ != 0) @@ -291,23 +213,16 @@ _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, 2*sizeof(Elf_Addr), - sizeof(Elf_Addr)); - - _set_tp(tls, 2 * sizeof(Elf_Addr)); + if (tls_static_space) { + tcb = _rtld_allocate_tls(NULL, sizeof(struct tls_tcb), 0); + _set_tp(tcb, (size_t)-1); + } #endif } diff --git a/lib/libthread_xu/arch/amd64/amd64/pthread_md.c b/lib/libthread_xu/arch/amd64/amd64/pthread_md.c index a9e1207ba9..470d76aaf1 100644 --- a/lib/libthread_xu/arch/amd64/amd64/pthread_md.c +++ b/lib/libthread_xu/arch/amd64/amd64/pthread_md.c @@ -24,7 +24,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/lib/libpthread/arch/amd64/amd64/pthread_md.c,v 1.4 2004/11/06 03:33:19 peter Exp $ - * $DragonFly: src/lib/libthread_xu/arch/amd64/amd64/pthread_md.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/arch/amd64/amd64/pthread_md.c,v 1.2 2005/03/28 03:33:13 dillon Exp $ */ #include @@ -38,16 +38,25 @@ struct tcb * _tcb_ctor(struct pthread *thread, int initial) { + struct tcb *old_tcb; struct tcb *tcb; - void *oldtls; + int flags; + + old_tcb = NULL; + flags = 0; if (initial) { - __asm __volatile("movq %%fs:0, %0" : "=r" (oldtls)); - } else { - oldtls = NULL; + /* + * We may have to replace a TLS already created by the low + * level libc startup code + */ + struct tls_info info; + if (sys_get_tls_area(0, &info, sizeof(info)) == 0) { + old_tcb = info.base; + flags = RTLD_ALLOC_TLS_FREE_OLD; + } } - - tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16); + tcb = _rtld_allocate_tls(old_tcb, sizeof(struct tcb), flags); if (tcb) { tcb->tcb_thread = thread; } diff --git a/lib/libthread_xu/arch/i386/i386/pthread_md.c b/lib/libthread_xu/arch/i386/i386/pthread_md.c index c61c9612ba..ae2ec6b745 100644 --- a/lib/libthread_xu/arch/i386/i386/pthread_md.c +++ b/lib/libthread_xu/arch/i386/i386/pthread_md.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/lib/libthread_xu/arch/i386/i386/pthread_md.c,v 1.4 2005/03/22 23:07:24 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/arch/i386/i386/pthread_md.c,v 1.5 2005/03/28 03:33:14 dillon Exp $ */ #include @@ -37,15 +37,25 @@ struct tcb * _tcb_ctor(struct pthread *thread, int initial) { + struct tcb *old_tcb; struct tcb *tcb; - void *oldtls; + int flags; - if (initial) - __asm __volatile("movl %%gs:0, %0" : "=r" (oldtls)); - else - oldtls = NULL; + old_tcb = 0; + flags = 0; - tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16); + if (initial) { + /* + * We may have to replace a TLS already created by the low + * level libc startup code + */ + struct tls_info info; + if (sys_get_tls_area(0, &info, sizeof(info)) == 0) { + old_tcb = info.base; + flags = RTLD_ALLOC_TLS_FREE_OLD; + } + } + tcb = _rtld_allocate_tls(old_tcb, sizeof(struct tcb), flags); if (tcb) { tcb->tcb_thread = thread; tcb->tcb_seg = -1; @@ -68,5 +78,5 @@ _tcb_set(struct tcb *tcb) void _tcb_dtor(struct tcb *tcb) { - _rtld_free_tls(tcb, sizeof(struct tcb), 16); + _rtld_free_tls(tcb, sizeof(struct tcb)); } diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c index 52d40cde1b..8197dd1255 100644 --- a/libexec/rtld-elf/i386/reloc.c +++ b/libexec/rtld-elf/i386/reloc.c @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/i386/reloc.c,v 1.6.2.2 2002/06/16 20:02:09 dillon Exp $ - * $DragonFly: src/libexec/rtld-elf/i386/reloc.c,v 1.4 2005/03/22 22:56:36 davidxu Exp $ + * $DragonFly: src/libexec/rtld-elf/i386/reloc.c,v 1.5 2005/03/28 03:33:20 dillon Exp $ */ /* @@ -325,44 +325,56 @@ reloc_jmpslots(Obj_Entry *obj) void allocate_initial_tls(Obj_Entry *objs) { + struct tls_tcb *old_tcb; struct tls_info ti; - void* tls; + int flags; + void *tls; int sel; /* * Fix the size of the static TLS block by using the maximum - * offset allocated so far and adding a bit for dynamic modules to - * use. + * offset allocated so far. + * + * The tls returned by allocate_tls is offset to point at the TCB, + * the static space is allocated through negative offsets. + * + * We may have to replace an 'initial' TLS previously created by libc. */ - tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; - tls = allocate_tls(objs, NULL, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); - ti.base = tls; - ti.size = 2 * sizeof(Elf_Addr); - sel = sys_set_tls_area(0, &ti, sizeof(ti)); - __asm __volatile("movl %0,%%gs" : : "rm" (sel)); + tls_static_space = tls_last_offset /*+ RTLD_STATIC_TLS_EXTRA*/; + if (tls_static_space) { + if (sys_get_tls_area(0, &ti, sizeof(ti)) == 0) { + old_tcb = ti.base; + flags = RTLD_ALLOC_TLS_FREE_OLD; + } else { + old_tcb = NULL; + flags = 0; + } + tls = allocate_tls(objs, old_tcb, sizeof(struct tls_tcb), flags); + ti.base = tls; + ti.size = -1; + sel = sys_set_tls_area(0, &ti, sizeof(ti)); + __asm __volatile("movl %0,%%gs" : : "rm" (sel)); + } } /* GNU ABI */ __attribute__((__regparm__(1))) -void *___tls_get_addr(tls_index *ti) +void * +___tls_get_addr(tls_index *ti) { - Elf_Addr** segbase; - Elf_Addr* dtv; - - __asm __volatile("movl %%gs:0, %0" : "=r" (segbase)); - dtv = segbase[1]; + struct tls_tcb *tcb; - return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); + __asm __volatile("movl %%gs:0, %0" : "=r" (tcb)); + return tls_get_addr_common(&tcb->dtv_base, ti->ti_module, ti->ti_offset); } /* Sun ABI */ -void *__tls_get_addr(tls_index *ti) +void * +__tls_get_addr(tls_index *ti) { - Elf_Addr** segbase; - Elf_Addr* dtv; + struct tls_tcb *tcb; - __asm __volatile("movl %%gs:0, %0" : "=r" (segbase)); - dtv = segbase[1]; - - return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); + __asm __volatile("movl %%gs:0, %0" : "=r" (tcb)); + return tls_get_addr_common(&tcb->dtv_base, ti->ti_module, ti->ti_offset); } + diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index d3dcd4f93f..6515a66a6b 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -24,7 +24,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.43.2.15 2003/02/20 20:42:46 kan Exp $ - * $DragonFly: src/libexec/rtld-elf/rtld.c,v 1.18 2005/03/22 23:54:18 joerg Exp $ + * $DragonFly: src/libexec/rtld-elf/rtld.c,v 1.19 2005/03/28 03:33:16 dillon Exp $ */ /* @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -2566,7 +2567,7 @@ unref_dag(Obj_Entry *root) * Common code for MD __tls_get_addr(). */ void * -tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) +tls_get_addr_common(void **dtvp, int index, size_t offset) { Elf_Addr* dtv = *dtvp; @@ -2585,10 +2586,9 @@ tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) newdtv[0] = tls_dtv_generation; newdtv[1] = tls_max_index; free(dtv); + *dtvp = newdtv; wlock_release(); - - *dtvp = newdtv; } /* Dynamically allocate module TLS if necessary */ @@ -2611,96 +2611,7 @@ tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) #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) -{ - Obj_Entry *obj; - size_t size; - char *tls; - Elf_Addr *dtv, *olddtv; - Elf_Addr addr; - int i; - - size = tls_static_space; - - tls = malloc(size); - dtv = calloc(1, (tls_max_index + 2) * sizeof(Elf_Addr)); - - *(Elf_Addr**) tls = dtv; - - dtv[0] = tls_dtv_generation; - dtv[1] = tls_max_index; - - 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; - } - } - - /* - * We assume that all tls blocks are allocated with the same - * size and alignment. - */ - free_tls(oldtls, tcbsize, tcbalign); - } else { - for (obj = objs; obj; obj = obj->next) { - if (obj->tlsoffset) { - addr = (Elf_Addr)tls + obj->tlsoffset; - memset((void*) (addr + obj->tlsinitsize), - 0, obj->tlssize - obj->tlsinitsize); - if (obj->tlsinit) - memcpy((void*) addr, obj->tlsinit, - obj->tlsinitsize); - dtv[obj->tlsindex + 1] = addr; - } - } - } - - return tls; -} - -void -free_tls(void *tls, size_t tcbsize, size_t tcbalign) -{ - size_t size; - Elf_Addr* dtv; - int dtvsize, i; - Elf_Addr tlsstart, tlsend; - - /* - * 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; - - dtv = ((Elf_Addr**)tls)[0]; - dtvsize = dtv[1]; - tlsstart = (Elf_Addr) tls; - tlsend = tlsstart + size; - for (i = 0; i < dtvsize; i++) { - if (dtv[i+2] != NULL && (dtv[i+2] < tlsstart || dtv[i+2] > tlsend)) { - free((void*) dtv[i+2]); - } - } - - free((void*) tlsstart); -} +#error x #endif @@ -2708,62 +2619,74 @@ free_tls(void *tls, size_t tcbsize, size_t tcbalign) defined(__arm__) /* - * Allocate Static TLS using the Variant II method. + * Allocate the static TLS area. Return a pointer to the TCB. The + * static area is based on negative offsets relative to the tcb. */ -void * -allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) +struct tls_tcb * +allocate_tls(Obj_Entry *objs, struct tls_tcb *old_tcb, + size_t tcb_size, int flags) { Obj_Entry *obj; - size_t size; - char *tls; - Elf_Addr *dtv, *olddtv; - Elf_Addr segbase, oldsegbase, addr; + size_t data_size; + size_t full_size; + size_t dtv_size; + struct tls_tcb *tcb; + Elf_Addr *dtv, *old_dtv; + Elf_Addr addr; int i; - size = round(tls_static_space, tcbalign); + /* + * Allocate the new TCB. static TLS storage is placed just before the + * TCB to support the %gs:OFFSET (negative offset) model. + */ + assert(tcb_size >= 2*sizeof(Elf_Addr)); + data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) & + ~RTLD_STATIC_TLS_ALIGN_MASK; + full_size = data_size + tcb_size; + tcb = malloc(full_size); + tcb = (void *)((char *)tcb + data_size); /* actual tcb location */ + bzero(tcb, tcb_size); - assert(tcbsize >= 2*sizeof(Elf_Addr)); - tls = malloc(size + tcbsize); - dtv = calloc(1, (tls_max_index + 2) * sizeof(Elf_Addr)); + dtv_size = (tls_max_index + 2) * sizeof(Elf_Addr); + dtv = malloc(dtv_size); + bzero(dtv, dtv_size); - segbase = (Elf_Addr)(tls + size); - ((Elf_Addr*)segbase)[0] = segbase; - ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; + tcb->tcb_base = tcb; + tcb->dtv_base = dtv; dtv[0] = tls_dtv_generation; dtv[1] = tls_max_index; - if (oldtls) { + /* + * If a template tcb is supplied, copy the TLS storage from the template + * to the new tcb, otherwise create a pristine data set. + */ + if (old_tcb) { /* * Copy the static TLS block over whole. */ - oldsegbase = (Elf_Addr) oldtls; - memcpy((void *)(segbase - tls_static_space), - (const void *)(oldsegbase - tls_static_space), - tls_static_space); + memcpy((char *)tcb - data_size, (char *)old_tcb - data_size, data_size); /* * If any dynamic TLS blocks have been created tls_get_addr(), * move them over. */ - olddtv = ((Elf_Addr**)oldsegbase)[1]; - for (i = 0; i < olddtv[1]; i++) { - if (olddtv[i+2] < oldsegbase - size || olddtv[i+2] > oldsegbase) { - dtv[i+2] = olddtv[i+2]; - olddtv[i+2] = 0; + old_dtv = old_tcb->dtv_base; + for (i = 0; i < old_dtv[1]; i++) { + if (old_dtv[i+2] < (Elf_Addr)((char *)old_tcb - data_size) || + old_dtv[i+2] >= (Elf_Addr)((char *)old_tcb) + ) { + dtv[i + 2] = old_dtv[i + 2]; + old_dtv[i + 2] = 0; } } - - /* - * We assume that this block was the one we created with - * allocate_initial_tls(). - */ - free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); + if (flags & RTLD_ALLOC_TLS_FREE_OLD) + free_tls(old_tcb, tcb_size); } else { for (obj = objs; obj; obj = obj->next) { if (obj->tlsoffset) { - addr = segbase - obj->tlsoffset; - memset((void*) (addr + obj->tlsinitsize), + addr = (Elf_Addr)tcb - obj->tlsoffset; + memset((void *)(addr + obj->tlsinitsize), 0, obj->tlssize - obj->tlsinitsize); if (obj->tlsinit) memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize); @@ -2771,35 +2694,29 @@ allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) } } } - - return (void*) segbase; + return(tcb); } void -free_tls(void *tls, size_t tcbsize, size_t tcbalign) -{ - size_t size; - Elf_Addr* dtv; - int dtvsize, i; - Elf_Addr tlsstart, tlsend; - - /* - * Figure out the size of the initial TLS block so that we can - * find stuff which ___tls_get_addr() allocated dynamically. - */ - size = round(tls_static_space, tcbalign); - - dtv = ((Elf_Addr**)tls)[1]; - dtvsize = dtv[1]; - tlsend = (Elf_Addr) tls; - tlsstart = tlsend - size; - for (i = 0; i < dtvsize; i++) { - if (dtv[i+2] != NULL && (dtv[i+2] < tlsstart || dtv[i+2] > tlsend)) { - free((void*) dtv[i+2]); +free_tls(struct tls_tcb *tcb, size_t tcb_size) +{ + Elf_Addr *dtv; + int dtv_size, i; + Elf_Addr tls_start, tls_end; + size_t data_size; + + data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) & + ~RTLD_STATIC_TLS_ALIGN_MASK; + dtv = tcb->dtv_base; + dtv_size = dtv[1]; + tls_end = (Elf_Addr)tcb; + tls_start = (Elf_Addr)tcb - data_size; + for (i = 0; i < dtv_size; i++) { + if (dtv[i+2] != NULL && (dtv[i+2] < tls_start || dtv[i+2] > tls_end)) { + free((void *)dtv[i+2]); } } - - free((void*) tlsstart); + free((void *)tls_start); } #endif @@ -2886,22 +2803,23 @@ free_tls_offset(Obj_Entry *obj) #endif } -void * -_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) +struct tls_tcb * +_rtld_allocate_tls(struct tls_tcb *old_tcb, size_t tcb_size, int flags) { - void *ret; + struct tls_tcb *new_tcb; wlock_acquire(); - ret = allocate_tls(obj_list, oldtls, tcbsize, tcbalign); + new_tcb = allocate_tls(obj_list, old_tcb, tcb_size, flags); wlock_release(); - return (ret); + return (new_tcb); } void -_rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign) +_rtld_free_tls(struct tls_tcb *tcb, size_t tcb_size) { wlock_acquire(); - free_tls(tcb, tcbsize, tcbalign); + free_tls(tcb, tcb_size); wlock_release(); } + diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 78842748d8..c4567cc077 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/rtld.h,v 1.15.2.6 2003/02/20 20:42:46 kan Exp $ - * $DragonFly: src/libexec/rtld-elf/rtld.h,v 1.7 2005/03/22 22:56:36 davidxu Exp $ + * $DragonFly: src/libexec/rtld-elf/rtld.h,v 1.8 2005/03/28 03:33:17 dillon Exp $ */ #ifndef RTLD_H /* { */ @@ -184,8 +184,6 @@ typedef struct Struct_Obj_Entry { #define RTLD_MAGIC 0xd550b87a #define RTLD_VERSION 1 -#define RTLD_STATIC_TLS_EXTRA 64 - /* * Symbol cache entry used during relocation to avoid multiple lookups * of the same symbol. @@ -227,9 +225,9 @@ void _rtld_bind_start(void); const Elf_Sym *symlook_obj(const char *, unsigned long, const Obj_Entry *, bool); -void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset); -void *allocate_tls(Obj_Entry *, void *, size_t, size_t); -void free_tls(void *, size_t, size_t); +void *tls_get_addr_common(void **dtvp, int index, size_t offset); +struct tls_tcb *allocate_tls(Obj_Entry *, struct tls_tcb *, size_t, int); +void free_tls(struct tls_tcb *, size_t); void *allocate_module_tls(int index); bool allocate_tls_offset(Obj_Entry *obj); void free_tls_offset(Obj_Entry *obj); diff --git a/libexec/rtld-elf/rtld_tls.h b/libexec/rtld-elf/rtld_tls.h index 438d4fe7f7..7c32bad040 100644 --- a/libexec/rtld-elf/rtld_tls.h +++ b/libexec/rtld-elf/rtld_tls.h @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/rtld_tls.h,v 1.1 2004/08/03 08:50:58 dfr Exp $ - * $DragonFly: src/libexec/rtld-elf/Attic/rtld_tls.h,v 1.1 2005/03/22 22:56:36 davidxu Exp $ + * $DragonFly: src/libexec/rtld-elf/Attic/rtld_tls.h,v 1.2 2005/03/28 03:33:17 dillon Exp $ */ /* @@ -58,13 +58,14 @@ * The value returned from this function is suitable for installing * directly into the thread pointer register. */ -extern void *_rtld_allocate_tls(void* oldtls, size_t tcbsize, size_t tcbalign); +extern struct tls_tcb *_rtld_allocate_tls(struct tls_tcb *old_tls, + size_t tcb_size, int flags); /* * Free a TLS block allocated using _rtld_allocate_tls(). The tcbsize * and tcbalign parameters must be the same as those used to allocate * the block. */ -extern void _rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign); +extern void _rtld_free_tls(struct tls_tcb *tcb, size_t tcb_size); #endif diff --git a/sys/sys/tls.h b/sys/sys/tls.h index a20acc43a7..83554df2c5 100644 --- a/sys/sys/tls.h +++ b/sys/sys/tls.h @@ -3,7 +3,7 @@ * * Implements the architecture independant TLS info structure. * - * $DragonFly: src/sys/sys/tls.h,v 1.4 2005/03/21 23:08:55 joerg Exp $ + * $DragonFly: src/sys/sys/tls.h,v 1.5 2005/03/28 03:33:08 dillon Exp $ */ #ifndef _SYS_TLS_H_ @@ -16,6 +16,20 @@ struct tls_info { int size; }; +struct tls_tcb { + struct tls_tcb *tcb_base; /* self pointer (data at -OFFSET) */ + void *dtv_base; /* RTLD tls_get_addr info base */ + void *reserved[6]; +}; + +#define RTLD_STATIC_TLS_ALIGN 16 +#define RTLD_STATIC_TLS_ALIGN_MASK (RTLD_STATIC_TLS_ALIGN - 1) + +/* + * flags for _rtld_allocate_tls() and allocate_tls() + */ +#define RTLD_ALLOC_TLS_FREE_OLD 0x0001 + #ifndef _KERNEL int sys_set_tls_area(int which, struct tls_info *info, size_t infosize); int sys_get_tls_area(int which, struct tls_info *info, size_t infosize); -- 2.41.0