Cleanup and retool portions of the TLS support and make sure that
authorMatthew Dillon <dillon@dragonflybsd.org>
Mon, 28 Mar 2005 03:33:20 +0000 (03:33 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Mon, 28 Mar 2005 03:33:20 +0000 (03:33 +0000)
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
lib/libthread_xu/arch/amd64/amd64/pthread_md.c
lib/libthread_xu/arch/i386/i386/pthread_md.c
libexec/rtld-elf/i386/reloc.c
libexec/rtld-elf/rtld.c
libexec/rtld-elf/rtld.h
libexec/rtld-elf/rtld_tls.h
sys/sys/tls.h

index 0265ca9..30ed2db 100644 (file)
@@ -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 <sys/cdefs.h>
+#include <sys/tls.h>
 #include <stdlib.h>
 #include <string.h>
 #include <elf.h>
@@ -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
 }
index a9e1207..470d76a 100644 (file)
@@ -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 <stdlib.h>
 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;
        }
index c61c961..ae2ec6b 100644 (file)
@@ -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 <sys/types.h>
 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));
 }
index 52d40cd..8197dd1 100644 (file)
@@ -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);
 }
+
index d3dcd4f..6515a66 100644 (file)
@@ -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 <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/resident.h>
+#include <sys/tls.h>
 
 #include <dlfcn.h>
 #include <err.h>
@@ -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();
 }
+
index 7884274..c4567cc 100644 (file)
@@ -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);
index 438d4fe..7c32bad 100644 (file)
@@ -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 $
  */
 
 /*
  * 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
index a20acc4..83554df 100644 (file)
@@ -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);