Major TLS cleanups.
authorMatthew Dillon <dillon@dragonflybsd.org>
Wed, 11 May 2005 19:47:09 +0000 (19:47 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Wed, 11 May 2005 19:47:09 +0000 (19:47 +0000)
* The RTLD no longer attempts to set up an initial TLS.  The job has been
  moved to libc.  The RTLD does not use TLS itself.  The
  allocate_initial_tls() function has been removed.

* The _init_tls() call made by CRT1 is no mandatory.

* The RTLD no longer calls the library _init() functions early.  Instead it
  sets up a callback that allows CRT1 to call the library _init() functions
  after it has called _init_tls().

* LIBC now has a _libc_init_tls() function which is weakly bound as
  _init_tls().  This function initializes the TLS for the program (generally
  by calling the _rtld_allocate_tls() and then doing any required
  post-allocation initialization).  In the absence of a threading library
  this function is basically it.

  Threading libraries may replace _init_tls() with their own version.  This
  does not yet occur as of this commit.  The threading library would then
  almost certainly call _libc_init_tls() and then make further modifications
  to the TCB as necessary (e.g. populate the tcb_pthread field).

* RTLD's allocate_tls() no longer does anything fancy.  The 'old_tcb' argument
  and concept has been removed.

* We have a new tcb_errno_p field in the TCB, but as of this commit it
  is not yet being used.

Reviewed-by: Joerg Sonnenberger <joerg@britannica.bec.de>,
David Xu <davidxu@crater.dragonflybsd.org>

19 files changed:
gnu/usr.bin/cc34/cc_prep/config/dragonfly-spec.h
gnu/usr.bin/cc34/cc_prep/config/i386/dragonfly.h
lib/csu/i386/crt1.c
lib/libc/gen/tls.c
lib/libc/i386/sys/cerror.S
lib/libc/include/libc_private.h
lib/libc_r/uthread/uthread_create.c
lib/libc_r/uthread/uthread_init.c
lib/libthread_xu/arch/amd64/amd64/pthread_md.c
lib/libthread_xu/arch/i386/i386/pthread_md.c
libexec/rtld-elf/Makefile
libexec/rtld-elf/debug.h
libexec/rtld-elf/i386/reloc.c
libexec/rtld-elf/i386/rtld_machdep.h
libexec/rtld-elf/rtld.1
libexec/rtld-elf/rtld.c
libexec/rtld-elf/rtld.h
sys/cpu/i386/include/tls.h
sys/i386/include/tls.h

index 3ca6eaf..247ad67 100644 (file)
@@ -1,4 +1,4 @@
-/* $DragonFly: src/gnu/usr.bin/cc34/cc_prep/config/dragonfly-spec.h,v 1.6 2005/05/04 11:28:44 joerg Exp $ */
+/* $DragonFly: src/gnu/usr.bin/cc34/cc_prep/config/dragonfly-spec.h,v 1.7 2005/05/11 19:46:49 dillon Exp $ */
 
 /* Base configuration file for all DragonFly targets.
    Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
@@ -145,7 +145,7 @@ is built with the --enable-threads configure-time option.}          \
     %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}}\
     %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
 
-#define        DFBSD_DYNAMIC_LINKER            "/usr/libexec/ld-elf.so.1"
+#define        DFBSD_DYNAMIC_LINKER            "/usr/libexec/ld-elf.so.2"
 #define        STANDARD_STARTFILE_PREFIX_1     PREFIX2"/lib/gcc34/"
 #define        STANDARD_EXEC_PREFIX            PREFIX2"/libexec/gcc34/"
 #define        STANDARD_STARTFILE_PREFIX       PREFIX2"/lib/"
index 05f5196..f318dff 100644 (file)
@@ -1,4 +1,4 @@
-/* $DragonFly: src/gnu/usr.bin/cc34/cc_prep/config/i386/dragonfly.h,v 1.1 2004/06/14 22:27:53 joerg Exp $ */
+/* $DragonFly: src/gnu/usr.bin/cc34/cc_prep/config/i386/dragonfly.h,v 1.2 2005/05/11 19:46:50 dillon Exp $ */
 
 /* Definitions for Intel 386 running DragonFly with ELF format
    
@@ -112,7 +112,7 @@ Boston, MA 02111-1307, USA.  */
     %{!shared: \
       %{!static: \
         %{rdynamic:-export-dynamic} \
-        %{!dynamic-linker:-dynamic-linker /usr/libexec/ld-elf.so.1}} \
+        %{!dynamic-linker:-dynamic-linker /usr/libexec/ld-elf.so.2}} \
     %{static:-Bstatic}} \
   %{symbolic:-Bsymbolic}"
 
index 30c01cc..3b67125 100644 (file)
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/csu/i386-elf/crt1.c,v 1.4.2.2 2002/11/18 04:57:13 bde Exp $
- * $DragonFly: src/lib/csu/i386/crt1.c,v 1.2 2005/03/10 11:42:27 davidxu Exp $
+ * $DragonFly: src/lib/csu/i386/crt1.c,v 1.3 2005/05/11 19:46:51 dillon Exp $
  */
 
 #ifndef __GNUC__
 #error "GCC is needed to compile this file"
 #endif
 
+#include <machine/tls.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include "crtbrand.c"
@@ -39,7 +40,6 @@ typedef void (*fptr)(void);
 extern void _fini(void);
 extern void _init(void);
 extern int main(int, char **, char **);
-extern void _init_tls(void);
 
 #ifdef GCRT
 extern void _mcleanup(void);
@@ -84,10 +84,17 @@ _start(char *arguments, ...)
                __progname = s + 1;
     }
 
+    /*
+     * Setup the initial TLS space.  The RTLD does not set up our TLS
+     * (it can't, it doesn't know how our errno is declared).  It simply
+     * does all the groundwork required so that we can call
+     * _rtld_allocate_tls().  
+     */
+    _init_tls();
+    _rtld_call_init();
+
     if(&_DYNAMIC != NULL)
        atexit(rtld_cleanup);
-    else
-       _init_tls();
 
 #ifdef GCRT
     atexit(_mcleanup);
index 4fa74b1..a713f17 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.8 2005/04/29 22:00:20 joerg Exp $
+ *     $DragonFly: src/lib/libc/gen/tls.c,v 1.9 2005/05/11 19:46:52 dillon Exp $
  */
 
 /*
 #include <string.h>
 #include <elf.h>
 #include <assert.h>
+#include <errno.h>
+#include <unistd.h>
 
 #include "libc_private.h"
 
 __weak_reference(__libc_allocate_tls, _rtld_allocate_tls);
 __weak_reference(__libc_free_tls, _rtld_free_tls);
+__weak_reference(__libc_call_init, _rtld_call_init);
 #ifdef __i386__
 __weak_reference(___libc_tls_get_addr, ___tls_get_addr);
 #endif
 __weak_reference(__libc_tls_get_addr, __tls_get_addr);
+__weak_reference(__libc_tls_get_addr_tcb, __tls_get_addr_tcb);
+__weak_reference(_libc_init_tls, _init_tls);
 
-struct tls_tcb *__libc_allocate_tls(struct tls_tcb *old_tcb);
+struct tls_tcb *__libc_allocate_tls(void);
 void __libc_free_tls(struct tls_tcb *tcb);
 
 #if !defined(RTLD_STATIC_TLS_VARIANT_II)
@@ -67,6 +72,7 @@ void __libc_free_tls(struct tls_tcb *tcb);
 static size_t tls_static_space;
 static size_t tls_init_size;
 static void *tls_init;
+static struct tls_tcb *initial_tcb;
 #endif
 
 #ifdef __i386__
@@ -85,103 +91,106 @@ ___libc_tls_get_addr(void *ti __unused)
 #endif
 
 void *__libc_tls_get_addr(void *ti);
+void *__libc_tls_get_addr_tcb(struct tls_tcb *, void *);
 
 void *
 __libc_tls_get_addr(void *ti __unused)
 {
-       return (0);
+       return (NULL);
+}
+
+void *
+__libc_tls_get_addr_tcb(struct tls_tcb *tcb __unused, void *got_ptr __unused)
+{
+       return (NULL);
 }
 
 #ifndef PIC
 
 /*
- * Free Static TLS
+ * Free Static TLS, weakly bound to _rtld_free_tls()
  */
 void
 __libc_free_tls(struct tls_tcb *tcb)
 {
        size_t data_size;
 
-       if (tcb->tcb_dtv)
-               free(tcb->tcb_dtv);
        data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) &
                    ~RTLD_STATIC_TLS_ALIGN_MASK;
-       free((char *)tcb - data_size);
+
+       if (tcb == initial_tcb) {
+               /* initial_tcb was allocated with sbrk(), cannot call free() */
+       } else {
+               free((char *)tcb - data_size);
+       }
 }
 
 /*
- * Allocate Static TLS.
+ * Allocate Static TLS, weakly bound to _rtld_allocate_tls()
  *
- * !!!WARNING!!! The first run for a static binary is done without valid
- * TLS storage.  It must not call any system calls which want to change
- * errno.
+ * NOTE!  There is a chicken-and-egg problem here because no TLS exists
+ * on the first call into this function. 
  */
 struct tls_tcb *
-__libc_allocate_tls(struct tls_tcb *old_tcb)
+__libc_allocate_tls(void)
 {
-       static int first_run = 0;
        size_t data_size;
        struct tls_tcb *tcb;
        Elf_Addr *dtv;
 
-retry:
        data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) &
                    ~RTLD_STATIC_TLS_ALIGN_MASK;
 
-       if (first_run)
-               tcb = malloc(data_size + sizeof(*tcb));
+       /*
+        * Allocate space.  malloc() may require a working TLS segment
+        * so we use sbrk() for main's TLS.
+        */
+       if (initial_tcb == NULL)
+               tcb = sbrk(data_size + sizeof(*tcb) + 3 * sizeof(Elf_Addr));
        else
-               tcb = alloca(data_size + sizeof(*tcb));
+               tcb = malloc(data_size + sizeof(*tcb));
+
        tcb = (struct tls_tcb *)((char *)tcb + data_size);
-       if (first_run)
-               dtv = malloc(3 * sizeof(Elf_Addr));
-       else
-               dtv = alloca(3 * sizeof(Elf_Addr));
+       dtv = (Elf_Addr *)(tcb + 1);
 
+       memset(tcb, 0, sizeof(*tcb));
 #ifdef RTLD_TCB_HAS_SELF_POINTER
        tcb->tcb_self = tcb;
 #endif
        tcb->tcb_dtv = dtv;
-       tcb->tcb_pthread = NULL;
 
+       /*
+        * Dummy-up the module array.  A static binary has only one.  This
+        * allows us to support the generic __tls_get_addr compiler ABI
+        * function.  However, if there is no RTLD linked in, nothing in
+        * the program should ever call __tls_get_addr (and our version
+        * of it doesn't do anything).
+        */
        dtv[0] = 1;
        dtv[1] = 1;
        dtv[2] = (Elf_Addr)((char *)tcb - tls_static_space);
 
-       if (old_tcb) {
-               /*
-                * Copy the static TLS block over whole.
-                */
-               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(old_tcb);
-       } else {
-               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);
+       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);
+
+       /*
+        * Activate the initial TCB
+        */
+       if (initial_tcb == NULL) {
+               initial_tcb = tcb;
+               tls_set_tcb(tcb);
        }
-       
-       if (first_run)
-               return (tcb);
-
-       tls_set_tcb(tcb);
-       first_run = 1;
-       goto retry;
+       return (tcb);
 }
 
 #else
 
 struct tls_tcb *
-__libc_allocate_tls(struct tls_tcb *old_tls __unused)
+__libc_allocate_tls(void)
 {
-       return (0);
+       return (NULL);
 }
 
 void
@@ -191,18 +200,28 @@ __libc_free_tls(struct tls_tcb *tcb __unused)
 
 #endif /* PIC */
 
+void
+__libc_call_init(void)
+{
+}
+
 extern char **environ;
 
-void
-_init_tls()
+struct tls_tcb *
+_libc_init_tls(void)
 {
+       struct tls_tcb *tcb;
+
 #ifndef PIC
+       /*
+        * If this is a static binary there is no RTLD and so we have not
+        * yet calculated the static space requirement.  Do so now.
+        */
        Elf_Addr *sp;
        Elf_Auxinfo *aux, *auxp;
        Elf_Phdr *phdr;
        size_t phent, phnum;
        int i;
-       struct tls_tcb *tcb;
 
        sp = (Elf_Addr *) environ;
        while (*sp++ != 0)
@@ -236,8 +255,47 @@ _init_tls()
                        tls_init = (void*) phdr[i].p_vaddr;
                }
        }
+#endif
 
-       tcb = _rtld_allocate_tls(NULL);
+       /*
+        * Allocate the initial TLS segment.  The TLS has not been set up
+        * yet for either the static or dynamic linked case (RTLD no longer
+        * sets up an initial TLS segment for us).
+        */
+       tcb = _libc_allocate_tls();
        tls_set_tcb(tcb);
+       return(tcb);
+}
+
+/*
+ * Allocate a standard TLS.  This function is called by libc and by 
+ * thread libraries to create a new TCB with libc-related fields properly
+ * initialized (whereas _rtld_allocate_tls() is unable to completely set
+ * up the TCB).
+ *
+ * Note that this is different from __libc_allocate_tls which is the
+ * weakly bound symbol that handles the case where _rtld_allocate_tls
+ * does not exist.
+ */
+struct tls_tcb *
+_libc_allocate_tls(void)
+{
+       struct tls_tcb *tcb;
+
+       tcb = _rtld_allocate_tls();
+
+#if 0
+#if defined(__thread)
+       /* non-TLS libc */
+       tcb->tcb_errno_p = &errno;
+#elif defined(PIC)
+       /* TLS libc dynamically linked */
+       tcb->tcb_errno_p = __tls_get_addr_tcb(tcb, __get_errno_GOT_ptr());
+#else
+       /* TLS libc (threaded or unthreaded) */
+       tcb->tcb_errno_p = (void *)((char *)tcb + __get_errno_GS_offset());
 #endif
+#endif
+       return(tcb);
 }
+
index cc7fb96..97e6720 100644 (file)
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc/i386/sys/cerror.S,v 1.10 1999/08/27 23:59:38 peter Exp $
- * $DragonFly: src/lib/libc/i386/sys/cerror.S,v 1.4 2005/05/03 07:29:04 joerg Exp $
+ * $DragonFly: src/lib/libc/i386/sys/cerror.S,v 1.5 2005/05/11 19:46:54 dillon Exp $
  */
 
 #include "SYS.h"
 
        .globl HIDENAME(cerror)
 
+#if 0  /* POSSIBLE FUTURE */
+
 HIDENAME(cerror):
 #ifdef PIC
        /* The caller must execute the PIC prologue before jumping to cerror. */
-#  ifdef __thread
+#ifdef __thread
        movl    %eax, PIC_GOT(CNAME(errno))
-#  else
-       pushl   %eax
-       leal    errno@TLSGD(,%ebx,1), %eax
-       call    ___tls_get_addr@PLT
-       popl    %ecx
-       movl    %ecx, (%eax)
-#  endif
+#else
+       movl    %gs:12,%edx
+       movl    %eax,(%edx)
+#endif
        PIC_EPILOGUE
 #else
-#  ifdef __thread
+
+#ifdef __thread
        movl    %eax, errno
-#  else
-       movl    %gs:0, %ecx
-       movl    %eax, errno@NTPOFF(%ecx)
-#  endif
+#else
+       movl    %gs:12, %edx
+       movl    %eax,(%edx)
+#endif
+
 #endif
        movl    $-1,%eax
        movl    $-1,%edx
        ret
 
+#endif /* #if 0 */
+
+HIDENAME(cerror):
+#ifdef PIC
+       /* The caller must execute the PIC prologue before jumping to cerror. */
+#ifdef __thread
+       movl    %eax, PIC_GOT(CNAME(errno))
+#else
+       pushl   %eax
+       leal    errno@TLSGD(,%ebx,1), %eax
+       call    ___tls_get_addr@PLT
+       popl    %ecx
+       movl    %ecx, (%eax)
+#endif
+       PIC_EPILOGUE
+#else
+#ifdef __thread
+       movl    %eax, errno
+#else
+       movl    %gs:0,%ecx
+       movl    %eax,errno@NTPOFF(%ecx)
+#endif
+#endif
+       movl    $-1,%eax
+       movl    $-1,%edx
+       ret
+
+#if !defined(PIC) && !defined(__thread)
+       /*
+        * Return the direct TLS offset for errno.  TLS non-PIC version
+        * of libc only (i.e. statically linked programs).
+        */
+       .globl __get_errno_GS_offset
+__get_errno_GS_offset:
+       movl    errno@INDNTPOFF,%eax
+       ret
+#endif
+
+#if defined(PIC) && !defined(__thread)
+       /*
+        * Return a pointer to the GOT table entry for errno.  TLS PIC version
+        * of libc only (i.e. the dynamic libc).
+        */
+       .globl __get_errno_GOT_ptr
+__get_errno_GOT_ptr:
+       PIC_PROLOGUE
+       leal    errno@TLSGD(,%ebx,1),%eax
+       PIC_EPILOGUE
+       ret
+#endif
index 7fecc57..488bfa4 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc/include/libc_private.h,v 1.3 1999/08/27 23:59:47 peter Exp $
- * $DragonFly: src/lib/libc/include/libc_private.h,v 1.5 2005/03/29 19:26:19 joerg Exp $
+ * $DragonFly: src/lib/libc/include/libc_private.h,v 1.6 2005/05/11 19:46:55 dillon Exp $
  *
  * Private definitions for libc, libc_r and libpthread.
  *
@@ -75,6 +75,7 @@ int _fseeko(FILE *, __off_t, int);
 /*
  * Initialise TLS static programs
  */
-void _init_tls(void);
+int __get_errno_GS_offset(void);
+void *__get_errno_GOT_ptr(void);
 
 #endif /* _LIBC_PRIVATE_H_ */
index b41fb2e..6778814 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc_r/uthread/uthread_create.c,v 1.24.2.6 2003/01/08 05:04:26 fjoe Exp $
- * $DragonFly: src/lib/libc_r/uthread/uthread_create.c,v 1.4 2005/04/28 22:10:48 joerg Exp $
+ * $DragonFly: src/lib/libc_r/uthread/uthread_create.c,v 1.5 2005/05/11 19:47:00 dillon Exp $
  */
 #include <errno.h>
 #include <stdlib.h>
@@ -166,7 +166,7 @@ _pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                } else {
                        /* Initialise the thread structure: */
                        memset(new_thread, 0, sizeof(struct pthread));
-                       new_thread->tcb = _rtld_allocate_tls(NULL);
+                       new_thread->tcb = _libc_allocate_tls();
                        if (new_thread->tcb == NULL)
                                PANIC("Cannot allocate TLS and TCB");
                        new_thread->slice_usec = -1;
index 6118ca6..93545d6 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libc_r/uthread/uthread_init.c,v 1.23.2.11 2003/02/24 23:27:32 das Exp $
- * $DragonFly: src/lib/libc_r/uthread/uthread_init.c,v 1.8 2005/05/03 07:29:04 joerg Exp $
+ * $DragonFly: src/lib/libc_r/uthread/uthread_init.c,v 1.9 2005/05/11 19:47:00 dillon Exp $
  */
 
 /* Allocate space for global thread variables here: */
@@ -192,7 +192,7 @@ _thread_init(void)
                /* Zero the global kernel thread structure: */
                memset(&_thread_kern_thread, 0, sizeof(struct pthread));
                _thread_kern_thread.flags = PTHREAD_FLAGS_PRIVATE;
-               _thread_kern_thread.tcb = _rtld_allocate_tls(NULL);
+               _thread_kern_thread.tcb = _libc_allocate_tls();
                memset(_thread_initial, 0, sizeof(struct pthread));
 
                /* Initialize the waiting and work queues: */
index 86b7bf8..7548729 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.6 2005/04/28 18:24:10 joerg Exp $
+ * $DragonFly: src/lib/libthread_xu/arch/amd64/amd64/pthread_md.c,v 1.7 2005/05/11 19:47:02 dillon Exp $
  */
 
 #include <stdlib.h>
 struct tls_tcb *
 _tcb_ctor(struct pthread *thread, int initial)
 {
-       struct tls_tcb *old_tcb, *tcb;
+       struct tls_tcb *tcb;
        int flags;
 
-       old_tcb = NULL;
        flags = 0;
 
        if (initial)
                tcb = tls_get_tcb();
        else
-               tcb = _rtld_allocate_tls(old_tcb);
+                tcb = _libc_allocate_tls();
+
        if (tcb == NULL)
                return (NULL);
 
index dd0be57..33c7a6c 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.9 2005/04/28 18:24:10 joerg Exp $
+ * $DragonFly: src/lib/libthread_xu/arch/i386/i386/pthread_md.c,v 1.10 2005/05/11 19:47:05 dillon Exp $
  */
 
 #include <sys/types.h>
 struct tls_tcb *
 _tcb_ctor(struct pthread *thread, int initial)
 {
-       struct tls_tcb *old_tcb, *tcb;
+       struct tls_tcb *tcb;
        int flags;
 
-       old_tcb = 0;
        flags = 0;
 
        if (initial)
                tcb = tls_get_tcb();
        else
-               tcb = _rtld_allocate_tls(old_tcb);
+               tcb = _libc_allocate_tls();
        if (tcb == NULL)
                return (NULL);
 
index 7e6bcb5..63bffc7 100644 (file)
@@ -1,7 +1,7 @@
 # $FreeBSD: src/libexec/rtld-elf/Makefile,v 1.10.2.6 2002/06/22 17:03:13 jdp Exp $
-# $DragonFly: src/libexec/rtld-elf/Makefile,v 1.8 2005/05/01 19:19:12 joerg Exp $
+# $DragonFly: src/libexec/rtld-elf/Makefile,v 1.9 2005/05/11 19:47:06 dillon Exp $
 
-PROG=          ld-elf.so.1
+PROG=          ld-elf.so.2
 SRCS=          rtld_start.S rtld.c lockdflt.c map_object.c malloc.c \
                xmalloc.c debug.c reloc.c
 MAN=           rtld.1
index 109e6a8..f02214e 100644 (file)
@@ -23,7 +23,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/libexec/rtld-elf/debug.h,v 1.4 1999/12/27 04:44:01 jdp Exp $
- * $DragonFly: src/libexec/rtld-elf/debug.h,v 1.2 2003/06/17 04:27:08 dillon Exp $
+ * $DragonFly: src/libexec/rtld-elf/debug.h,v 1.3 2005/05/11 19:47:06 dillon Exp $
  */
 
 /*
@@ -52,9 +52,9 @@ extern int debug;
 #endif
 
 #define assert(cond)   ((cond) ? (void) 0 :            \
-    (msg("ld-elf.so.1: assert failed: " __FILE__ ":"   \
+    (msg("ld-elf.so.2: assert failed: " __FILE__ ":"   \
       __XSTRING(__LINE__) "\n"), abort()))
 #define msg(s)         write(1, s, strlen(s))
-#define trace()                msg("ld-elf.so.1: " __XSTRING(__LINE__) "\n")
+#define trace()                msg("ld-elf.so.2: " __XSTRING(__LINE__) "\n")
 
 #endif /* DEBUG_H */
index 153ed3d..b5ed9be 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.12 2005/05/08 13:11:06 joerg Exp $
+ * $DragonFly: src/libexec/rtld-elf/i386/reloc.c,v 1.13 2005/05/11 19:47:09 dillon Exp $
  */
 
 /*
@@ -354,33 +354,6 @@ reloc_jmpslots(Obj_Entry *obj)
     return 0;
 }
 
-void
-allocate_initial_tls(Obj_Entry *objs)
-{
-    struct tls_tcb *old_tcb;
-    struct tls_info ti;
-    void *tls;
-
-    /*
-     * Fix the size of the static TLS block by using the maximum
-     * 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;
-
-    if (sys_get_tls_area(0, &ti, sizeof(ti)) == 0)
-       old_tcb = ti.base;
-    else
-       old_tcb = NULL;
-
-    tls = allocate_tls(objs, old_tcb);
-    tls_set_tcb(tls);
-}
-
 /* GNU ABI */
 __attribute__((__regparm__(1)))
 void *
@@ -402,3 +375,10 @@ __tls_get_addr(tls_index *ti)
     return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
 }
 
+/* Sun ABI */
+void *
+__tls_get_addr_tcb(struct tls_tcb *tcb, tls_index *ti)
+{
+    return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
+}
+
index 18b1083..03f1160 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/libexec/rtld-elf/i386/rtld_machdep.h,v 1.3.2.2 2002/07/02 04:10:51 jdp Exp $
- * $DragonFly: src/libexec/rtld-elf/i386/rtld_machdep.h,v 1.6 2005/03/22 22:56:36 davidxu Exp $
+ * $DragonFly: src/libexec/rtld-elf/i386/rtld_machdep.h,v 1.7 2005/05/11 19:47:09 dillon Exp $
  */
 
 #ifndef RTLD_MACHDEP_H
@@ -76,7 +76,10 @@ typedef struct {
     unsigned long ti_offset;
 } tls_index;
 
+struct tls_tcb;
+
 extern void *___tls_get_addr(tls_index *ti) __attribute__((__regparm__(1)));
 extern void *__tls_get_addr(tls_index *ti);
+extern void *__tls_get_addr_tcb(struct tls_tcb *tcb, tls_index *ti);
 
 #endif
index 57e845d..dce9a89 100644 (file)
@@ -1,5 +1,5 @@
 .\" $FreeBSD: src/libexec/rtld-elf/rtld.1,v 1.18.2.7 2002/01/10 17:51:28 ru Exp $
-.\" $DragonFly: src/libexec/rtld-elf/rtld.1,v 1.2 2003/06/17 04:27:08 dillon Exp $
+.\" $DragonFly: src/libexec/rtld-elf/rtld.1,v 1.3 2005/05/11 19:47:06 dillon Exp $
 .\"
 .\" Copyright (c) 1995 Paul Kranenburg
 .\" All rights reserved.
@@ -33,7 +33,7 @@
 .Dt RTLD 1
 .Os
 .Sh NAME
-.Nm ld-elf.so.1 ,
+.Nm ld-elf.so.2 ,
 .Nm rtld
 .Nd run-time link-editor
 .Sh DESCRIPTION
@@ -145,6 +145,12 @@ and
 .Ql \et
 are recognized and have their usual meaning.
 .El
+.Sh DIFFERENCES BETWEEN .1 and .2
+.Pp
+ABI changes have been made to support TLS allocation and initialization
+and to give threading libraries a chance to complete initialization of the
+TCB prior to the calling of the _init() functions for the dynamically loaded
+libraries.
 .Sh FILES
 .Bl -tag -width indent
 .It Pa /var/run/ld-elf.so.hints
index b5daa63..0f45248 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.22 2005/04/27 11:59:11 joerg Exp $
+ * $DragonFly: src/libexec/rtld-elf/rtld.c,v 1.23 2005/05/11 19:47:06 dillon Exp $
  */
 
 /*
@@ -58,7 +58,7 @@
 #include "debug.h"
 #include "rtld.h"
 
-#define PATH_RTLD      "/usr/libexec/ld-elf.so.1"
+#define PATH_RTLD      "/usr/libexec/ld-elf.so.2"
 #define LD_ARY_CACHE   16
 
 /* Types. */
@@ -154,6 +154,7 @@ static unsigned int obj_count;      /* Number of objects in obj_list */
 static int     ld_resident;    /* Non-zero if resident */
 static const char *ld_ary[LD_ARY_CACHE];
 static int     ld_index;
+static Objlist initlist;
 
 static Objlist list_global =   /* Objects dlopened with RTLD_GLOBAL */
   STAILQ_HEAD_INITIALIZER(list_global);
@@ -188,8 +189,10 @@ static func_ptr_type exports[] = {
     (func_ptr_type) &___tls_get_addr,
 #endif
     (func_ptr_type) &__tls_get_addr,
+    (func_ptr_type) &__tls_get_addr_tcb,
     (func_ptr_type) &_rtld_allocate_tls,
     (func_ptr_type) &_rtld_free_tls,
+    (func_ptr_type) &_rtld_call_init,
     NULL
 };
 
@@ -266,6 +269,7 @@ wlock_release(void)
  *
  * The return value is the main program's entry point.
  */
+
 func_ptr_type
 _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 {
@@ -279,7 +283,6 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
     const char *argv0;
     Objlist_Entry *entry;
     Obj_Entry *obj;
-    Objlist initlist;
 
     ld_index = 0;      /* don't use old env cache in case we are resident */
 
@@ -447,7 +450,13 @@ resident_skip1:
         */
        allocate_tls_offset(entry->obj);
     }
-    allocate_initial_tls(obj_list);
+
+    tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA;
+
+    /*
+     * Do not try to allocate the TLS here, let libc do it itself.
+     * (crt1 for the program will call _init_tls())
+     */
 
     if (relocate_objects(obj_main,
        ld_bind_now != NULL && *ld_bind_now != '\0') == -1)
@@ -498,12 +507,10 @@ resident_skip2:
 
     r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */
 
-    objlist_call_init(&initlist);
-    wlock_acquire();
-    objlist_clear(&initlist);
-    wlock_release();
-
-
+    /*
+     * Do NOT call the initlist here, give libc a chance to set up
+     * the initial TLS segment.  crt1 will then call _rtld_call_init().
+     */
 
     dbg("transferring control to program entry point = %p", obj_main->entry);
 
@@ -513,6 +520,19 @@ resident_skip2:
     return (func_ptr_type) obj_main->entry;
 }
 
+/*
+ * Call the initialization list for dynamically loaded libraries.
+ * (called from crt1.c).
+ */
+void
+_rtld_call_init(void)
+{
+    objlist_call_init(&initlist);
+    wlock_acquire();
+    objlist_clear(&initlist);
+    wlock_release();
+}
+
 Elf_Addr
 _rtld_bind(Obj_Entry *obj, Elf_Word reloff)
 {
@@ -2590,17 +2610,25 @@ tls_get_addr_common(void **dtvp, int index, size_t offset)
 /*
  * Allocate the static TLS area.  Return a pointer to the TCB.  The 
  * static area is based on negative offsets relative to the tcb.
+ *
+ * The TCB contains an errno pointer for the system call layer, but because
+ * we are the RTLD we really have no idea how the caller was compiled so
+ * the information has to be passed in.  errno can either be:
+ *
+ *     type 0  errno is a simple non-TLS global pointer.
+ *             (special case for e.g. libc_rtld)
+ *     type 1  errno accessed by GOT entry     (dynamically linked programs)
+ *     type 2  errno accessed by %gs:OFFSET    (statically linked programs)
  */
 struct tls_tcb *
-allocate_tls(Obj_Entry *objs, struct tls_tcb *old_tcb)
+allocate_tls(Obj_Entry *objs)
 {
     Obj_Entry *obj;
     size_t data_size;
     size_t dtv_size;
     struct tls_tcb *tcb;
-    Elf_Addr *dtv, *old_dtv;
+    Elf_Addr *dtv;
     Elf_Addr addr;
-    int i;
 
     /*
      * Allocate the new TCB.  static TLS storage is placed just before the
@@ -2624,40 +2652,14 @@ allocate_tls(Obj_Entry *objs, struct tls_tcb *old_tcb)
     dtv[0] = tls_dtv_generation;
     dtv[1] = tls_max_index;
 
-    /*
-     * 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.
-        */
-       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.
-        */
-       old_dtv = old_tcb->tcb_dtv;
-       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;
-           }
-       }
-       free_tls(old_tcb);
-    } else {
-       for (obj = objs; obj; obj = obj->next) {
-           if (obj->tlsoffset) {
-               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);
-               dtv[obj->tlsindex + 1] = addr;
-           }
+    for (obj = objs; obj; obj = obj->next) {
+       if (obj->tlsoffset) {
+           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);
+           dtv[obj->tlsindex + 1] = addr;
        }
     }
     return(tcb);
@@ -2771,12 +2773,12 @@ free_tls_offset(Obj_Entry *obj)
 }
 
 struct tls_tcb *
-_rtld_allocate_tls(struct tls_tcb *old_tcb)
+_rtld_allocate_tls(void)
 {
     struct tls_tcb *new_tcb;
 
     wlock_acquire();
-    new_tcb = allocate_tls(obj_list, old_tcb);
+    new_tcb = allocate_tls(obj_list);
     wlock_release();
 
     return (new_tcb);
index 6c9b624..7e0b9a4 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.10 2005/03/30 00:49:06 joerg Exp $
+ * $DragonFly: src/libexec/rtld-elf/rtld.h,v 1.11 2005/05/11 19:47:06 dillon Exp $
  */
 
 #ifndef RTLD_H /* { */
@@ -227,7 +227,7 @@ const Elf_Sym       *symlook_obj(const char *, unsigned long, const Obj_Entry *,
                             bool);
 
 void           *tls_get_addr_common(void **, int, size_t);
-struct tls_tcb *allocate_tls(Obj_Entry *, struct tls_tcb *);
+struct tls_tcb *allocate_tls(Obj_Entry *);
 void            free_tls(struct tls_tcb *);
 void            *allocate_module_tls(int);
 bool            allocate_tls_offset(Obj_Entry *);
index b7beb82..f59352a 100644 (file)
@@ -28,7 +28,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/cpu/i386/include/tls.h,v 1.5 2005/05/11 15:50:14 joerg Exp $
+ * $DragonFly: src/sys/cpu/i386/include/tls.h,v 1.6 2005/05/11 19:46:47 dillon Exp $
  */
 
 #ifndef        _MACHINE_TLS_H_
 #include <sys/types.h>
 #include <sys/tls.h>
 
+/*
+ * NOTE: the tcb_{self,dtv,pthread,errno) fields must be declared
+ * in the structure in the specified order as assembly will access the
+ * fields with a hardwired offset.
+ *
+ * Outside of this file, the system call layer generation will hardwire
+ * the offset for tcb_errno.
+ */
 struct tls_tcb {
        struct tls_tcb *tcb_self;       /* pointer to self*/
        void *tcb_dtv;                  /* Dynamic Thread Vector */
        void *tcb_pthread;              /* thread library's data*/
+       int *tcb_errno_p;               /* pointer to per-thread errno */
+       void *tcb_unused[4];
 };
 
 struct tls_dtv {
@@ -93,7 +103,12 @@ tls_set_tcb(struct tls_tcb *tcb)
        __asm __volatile("movl %0, %%gs" : : "r" (seg));
 }
 
-struct tls_tcb *_rtld_allocate_tls(struct tls_tcb *);
+struct tls_tcb *_rtld_allocate_tls(void);
+struct tls_tcb *_libc_allocate_tls(void);
 void            _rtld_free_tls(struct tls_tcb *);
+void            _libc_free_tls(struct tls_tcb *);
+void            _rtld_call_init(void);
+struct tls_tcb *_libc_init_tls(void);
+struct tls_tcb *_init_tls(void);
 
 #endif /* !_MACHINE_TLS_H_ */
index b7f3d1a..0601dac 100644 (file)
@@ -28,7 +28,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/i386/include/Attic/tls.h,v 1.5 2005/05/11 15:50:14 joerg Exp $
+ * $DragonFly: src/sys/i386/include/Attic/tls.h,v 1.6 2005/05/11 19:46:47 dillon Exp $
  */
 
 #ifndef        _MACHINE_TLS_H_
 #include <sys/types.h>
 #include <sys/tls.h>
 
+/*
+ * NOTE: the tcb_{self,dtv,pthread,errno) fields must be declared
+ * in the structure in the specified order as assembly will access the
+ * fields with a hardwired offset.
+ *
+ * Outside of this file, the system call layer generation will hardwire
+ * the offset for tcb_errno.
+ */
 struct tls_tcb {
        struct tls_tcb *tcb_self;       /* pointer to self*/
        void *tcb_dtv;                  /* Dynamic Thread Vector */
        void *tcb_pthread;              /* thread library's data*/
+       int *tcb_errno_p;               /* pointer to per-thread errno */
+       void *tcb_unused[4];
 };
 
 struct tls_dtv {
@@ -93,7 +103,12 @@ tls_set_tcb(struct tls_tcb *tcb)
        __asm __volatile("movl %0, %%gs" : : "r" (seg));
 }
 
-struct tls_tcb *_rtld_allocate_tls(struct tls_tcb *);
+struct tls_tcb *_rtld_allocate_tls(void);
+struct tls_tcb *_libc_allocate_tls(void);
 void            _rtld_free_tls(struct tls_tcb *);
+void            _libc_free_tls(struct tls_tcb *);
+void            _rtld_call_init(void);
+struct tls_tcb *_libc_init_tls(void);
+struct tls_tcb *_init_tls(void);
 
 #endif /* !_MACHINE_TLS_H_ */