tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

TLS support, MI part



Hi all,
attached is the MI part of supporting Thread Locale Storage.
I've also attached SH3 as example for the MD part.

This patch doesn't change anything for platforms (currently) without TLS
support. TLS support is enabled by defining __HAVE_TLS_VARIANT_I or
__HAVE_TLS_VARIANT_II. The TLS variants are part of the ABI
specification. Generally, platforms with newer TLS ABI use variant I,
platforms with early TLS ABI use variant II.

Joerg
Index: src/distrib/sets/lists/comp/mi
===================================================================
--- src/distrib/sets/lists/comp/mi
+++ src/distrib/sets/lists/comp/mi
@@ -2171,10 +2171,11 @@
 ./usr/include/sys/time.h                       comp-c-include
 ./usr/include/sys/timeb.h                      comp-c-include
 ./usr/include/sys/timepps.h                    comp-c-include
 ./usr/include/sys/times.h                      comp-c-include
 ./usr/include/sys/timex.h                      comp-c-include
+./usr/include/sys/tls.h                                comp-c-include
 ./usr/include/sys/tprintf.h                    comp-obsolete           obsolete
 ./usr/include/sys/trace.h                      comp-c-include
 ./usr/include/sys/tree.h                       comp-c-include
 ./usr/include/sys/tty.h                                comp-c-include
 ./usr/include/sys/ttychars.h                   comp-c-include

Index: src/distrib/sets/lists/tests/mi
===================================================================
--- src/distrib/sets/lists/tests/mi
+++ src/distrib/sets/lists/tests/mi
@@ -418,10 +418,14 @@
 ./usr/libdata/debug/usr/tests/lib/libc/sys                             
tests-lib-debug
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_clone.debug               
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_context.debug             
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_cerror.debug              
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_sigqueue.debug            
tests-lib-debug         debug,atf
+./usr/libdata/debug/usr/tests/lib/libc/tls                             
tests-lib-debug
+./usr/libdata/debug/usr/tests/lib/libc/tls/t_tls_dlopen.debug          
tests-lib-debug         debug,atf
+./usr/libdata/debug/usr/tests/lib/libc/tls/t_tls_dynamic.debug         
tests-lib-debug         debug,atf
+./usr/libdata/debug/usr/tests/lib/libc/tls/t_tls_static.debug          
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/ttyio                           
tests-lib-debug
 ./usr/libdata/debug/usr/tests/lib/libc/ttyio/t_ptm.debug               
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/ttyio/t_ttyio.debug             
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/t_cerror.debug                  
tests-obsolete          obsolete
 ./usr/libdata/debug/usr/tests/lib/libc/t_clone.debug                   
tests-obsolete          obsolete
@@ -1845,10 +1849,19 @@
 ./usr/tests/lib/libc/sys/Atffile               tests-lib-tests         atf
 ./usr/tests/lib/libc/sys/t_clone               tests-lib-tests         atf
 ./usr/tests/lib/libc/sys/t_context             tests-lib-tests         atf
 ./usr/tests/lib/libc/sys/t_cerror              tests-lib-tests         atf
 ./usr/tests/lib/libc/sys/t_sigqueue            tests-lib-tests         atf
+./usr/tests/lib/libc/tls                       tests-lib-tests
+./usr/tests/lib/libc/tls/Atffile               tests-lib-tests         atf
+./usr/tests/lib/libc/tls/h_tls_dlopen.so       tests-lib-tests         atf
+./usr/tests/lib/libc/tls/h_tls_dlopen.so.1     tests-lib-tests         atf
+./usr/tests/lib/libc/tls/libh_tls_dynamic.so   tests-lib-tests         atf
+./usr/tests/lib/libc/tls/libh_tls_dynamic.so.1 tests-lib-tests         atf
+./usr/tests/lib/libc/tls/t_tls_dlopen          tests-lib-tests         atf
+./usr/tests/lib/libc/tls/t_tls_dynamic         tests-lib-tests         atf
+./usr/tests/lib/libc/tls/t_tls_static          tests-lib-tests         atf
 ./usr/tests/lib/libc/ttyio                     tests-lib-tests
 ./usr/tests/lib/libc/ttyio/Atffile             tests-lib-tests         atf
 ./usr/tests/lib/libc/ttyio/t_ptm               tests-lib-tests         atf
 ./usr/tests/lib/libc/ttyio/t_ttyio             tests-lib-tests         atf
 ./usr/tests/lib/libc/t_atexit                  tests-obsolete          obsolete

Index: src/etc/mtree/NetBSD.dist.tests
===================================================================
--- src/etc/mtree/NetBSD.dist.tests
+++ src/etc/mtree/NetBSD.dist.tests
@@ -59,10 +59,11 @@
 ./usr/libdata/debug/usr/tests/lib/libc/ssp
 ./usr/libdata/debug/usr/tests/lib/libc/stdio
 ./usr/libdata/debug/usr/tests/lib/libc/stdlib
 ./usr/libdata/debug/usr/tests/lib/libc/string
 ./usr/libdata/debug/usr/tests/lib/libc/sys
+./usr/libdata/debug/usr/tests/lib/libc/tls
 ./usr/libdata/debug/usr/tests/lib/libc/ttyio
 ./usr/libdata/debug/usr/tests/lib/libc/time
 ./usr/libdata/debug/usr/tests/lib/libdes
 ./usr/libdata/debug/usr/tests/lib/libevent
 ./usr/libdata/debug/usr/tests/lib/semaphore
@@ -173,10 +174,11 @@
 ./usr/tests/lib/libc/ssp
 ./usr/tests/lib/libc/stdio
 ./usr/tests/lib/libc/stdlib
 ./usr/tests/lib/libc/string
 ./usr/tests/lib/libc/sys
+./usr/tests/lib/libc/tls
 ./usr/tests/lib/libc/ttyio
 ./usr/tests/lib/libc/time
 ./usr/tests/lib/libdes
 ./usr/tests/lib/semaphore
 ./usr/tests/lib/semaphore/pthread

Index: src/lib/libc/Makefile
===================================================================
--- src/lib/libc/Makefile
+++ src/lib/libc/Makefile
@@ -90,10 +90,11 @@
 .include "${.CURDIR}/stdlib/Makefile.inc"
 .include "${.CURDIR}/string/Makefile.inc"
 .include "${.CURDIR}/termios/Makefile.inc"
 .include "${.CURDIR}/thread-stub/Makefile.inc"
 .include "${.CURDIR}/time/Makefile.inc"
+.include "${.CURDIR}/tls/Makefile.inc"
 .include "${.CURDIR}/sys/Makefile.inc"
 .include "${.CURDIR}/uuid/Makefile.inc"
 .if (${MKYP} != "no")
 .include "${.CURDIR}/yp/Makefile.inc"
 .endif

Index: src/lib/libc/misc/initfini.c
===================================================================
--- src/lib/libc/misc/initfini.c
+++ src/lib/libc/misc/initfini.c
@@ -36,19 +36,24 @@
 #include "namespace.h"
 #endif
 
 #include <sys/param.h>
 #include <sys/exec.h>
+#include <sys/tls.h>
 #include <stdbool.h>
 
 void   _libc_init(void) __attribute__((__constructor__, __used__));
 
 void   __guard_setup(void);
 void   __libc_thr_init(void);
 void   __libc_atomic_init(void);
 void   __libc_atexit_init(void);
 void   __libc_env_init(void);
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+__dso_hidden void      __libc_static_tls_setup(void);
+#endif
 
 static bool libc_initialised;
 
 void _libc_init(void);
 
@@ -75,10 +80,15 @@
        /* For -fstack-protector */
        __guard_setup();
 
        /* Atomic operations */
        __libc_atomic_init();
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       /* Initialize TLS for statically linked programs. */
+       __libc_static_tls_setup();
+#endif
 
        /* Threads */
        __libc_thr_init();
 
        /* Initialize the atexit mutexes */

ADDED    src/lib/libc/tls/Makefile.inc
Index: src/lib/libc/tls/Makefile.inc
===================================================================
--- src/lib/libc/tls/Makefile.inc
+++ src/lib/libc/tls/Makefile.inc
@@ -0,0 +1,8 @@
+#      $NetBSD$
+
+.include <bsd.own.mk>
+
+# Our sources
+.PATH: ${.PARSEDIR} ${ARCHDIR}/tls
+
+SRCS+= tls.c

ADDED    src/lib/libc/tls/tls.c
Index: src/lib/libc/tls/tls.c
===================================================================
--- src/lib/libc/tls/tls.c
+++ src/lib/libc/tls/tls.c
@@ -0,0 +1,156 @@
+/*     $NetBSD$        */
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include "namespace.h"
+
+#include <sys/tls.h>
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+
+#define        _rtld_tls_allocate      __libc_rtld_tls_allocate
+#define        _rtld_tls_free          __libc_rtld_tls_free
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <link_elf.h>
+#include <lwp.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+__dso_hidden void      __libc_static_tls_setup(void);
+
+static const void *tls_initaddr;
+static size_t tls_initsize;
+static size_t tls_size;
+static size_t tls_allocation;
+static void *initial_thread_tcb;
+
+__weak_alias(__tls_get_addr, 0)
+#ifdef __i386__
+__weak_alias(___tls_get_addr, 0)
+#endif
+
+__weak_alias(_rtld_tls_allocate, __libc_rtld_tls_allocate)
+
+struct tls_tcb *
+_rtld_tls_allocate(void)
+{
+       struct tls_tcb *tcb;
+       uint8_t *p;
+
+       if (initial_thread_tcb == NULL) {
+#ifdef __HAVE_TLS_VARIANT_II
+               tls_size = roundup2(tls_size, sizeof(void *));
+#endif
+               tls_allocation = tls_size + sizeof(*tcb);
+
+               initial_thread_tcb = p = mmap(NULL, tls_allocation,
+                   PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
+       } else {
+               p = calloc(1, tls_allocation);
+       }
+       if (p == NULL) {
+               static const char msg[] =  "TLS allocation failed, 
terminating\n";
+               write(STDERR_FILENO, msg, sizeof(msg));
+               _exit(127);
+       }
+#ifdef __HAVE_TLS_VARIANT_I
+       /* LINTED */
+       tcb = (struct tls_tcb *)p;
+       p += sizeof(struct tls_tcb);
+#else
+       /* LINTED tls_size is rounded above */
+       tcb = (struct tls_tcb *)(p + tls_size);
+       tcb->tcb_self = tcb;
+#endif
+       memcpy(p, tls_initaddr, tls_initsize);
+
+       return tcb;
+}
+
+__weak_alias(_rtld_tls_free, __libc_rtld_tls_free)
+
+void
+_rtld_tls_free(struct tls_tcb *tcb)
+{
+       uint8_t *p;
+
+#ifdef __HAVE_TLS_VARIANT_I
+       /* LINTED */
+       p = (uint8_t *)tcb;
+#else
+       /* LINTED */
+       p = (uint8_t *)tcb - tls_size;
+#endif
+       if (p == initial_thread_tcb)
+               munmap(p, tls_allocation);
+       else
+               free(p);
+}
+
+__weakref_visible int rtld_DYNAMIC __weak_reference(_DYNAMIC);
+
+static int
+__libc_static_tls_setup_cb(struct dl_phdr_info *data, size_t len, void *cookie)
+{
+       const Elf_Phdr *phdr = data->dlpi_phdr;
+       const Elf_Phdr *phlimit = data->dlpi_phdr + data->dlpi_phnum;
+
+       for (; phdr < phlimit; ++phdr) {
+               if (phdr->p_type != PT_TLS)
+                       continue;
+               tls_initaddr = (void *)(phdr->p_vaddr + data->dlpi_addr);
+               tls_initsize = phdr->p_filesz;
+               tls_size = phdr->p_memsz;
+       }
+       return 0;
+}
+
+void
+__libc_static_tls_setup(void)
+{
+       struct tls_tcb *tcb;
+
+       if (&rtld_DYNAMIC != NULL)
+               return;
+
+       dl_iterate_phdr(__libc_static_tls_setup_cb, NULL);
+
+       tcb = _rtld_tls_allocate();
+       _lwp_setprivate(tcb);
+}
+
+#endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */

Index: src/lib/libpthread/pthread.c
===================================================================
--- src/lib/libpthread/pthread.c
+++ src/lib/libpthread/pthread.c
@@ -36,10 +36,11 @@
 
 #include <sys/param.h>
 #include <sys/mman.h>
 #include <sys/sysctl.h>
 #include <sys/lwpctl.h>
+#include <sys/tls.h>
 
 #include <err.h>
 #include <errno.h>
 #include <lwp.h>
 #include <signal.h>
@@ -192,10 +193,15 @@
        /* Create the thread structure corresponding to main() */
        pthread__initmain(&first);
        pthread__initthread(first);
        pthread__scrubthread(first, NULL, 0);
 
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       first->pt_tls = _lwp_getprivate();
+       first->pt_tls->tcb_pthread = first;
+#endif
+
        first->pt_lid = _lwp_self();
        PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq);
        RB_INSERT(__pthread__alltree, &pthread__alltree, first);
 
        if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &first->pt_lwpctl) != 0) {
@@ -282,10 +288,13 @@
 static void
 pthread__initthread(pthread_t t)
 {
 
        t->pt_self = t;
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       t->pt_tls = NULL;
+#endif
        t->pt_magic = PT_MAGIC;
        t->pt_willpark = 0;
        t->pt_unpark = 0;
        t->pt_nwaiters = 0;
        t->pt_sleepobj = NULL;
@@ -305,10 +314,16 @@
 
 static void
 pthread__scrubthread(pthread_t t, char *name, int flags)
 {
 
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       if (t->pt_tls) {
+               _rtld_tls_free(t->pt_tls);
+               t->pt_tls = NULL;
+       }
+#endif
        t->pt_state = PT_STATE_RUNNING;
        t->pt_exitval = NULL;
        t->pt_flags = flags;
        t->pt_cancel = 0;
        t->pt_errno = 0;
@@ -324,10 +339,11 @@
        pthread_t newthread;
        pthread_attr_t nattr;
        struct pthread_attr_private *p;
        char * volatile name;
        unsigned long flag;
+       void *private_area;
        int ret;
 
        /*
         * It's okay to check this without a lock because there can
         * only be one thread before it becomes true.
@@ -405,12 +421,19 @@
         * Create the new LWP.
         */
        pthread__scrubthread(newthread, name, nattr.pta_flags);
        newthread->pt_func = startfunc;
        newthread->pt_arg = arg;
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       private_area = newthread->pt_tls = _rtld_tls_allocate();
+       newthread->pt_tls->tcb_pthread = newthread;
+#else
+       private_area = newthread;
+#endif
+
        _lwp_makecontext(&newthread->pt_uc, pthread__create_tramp,
-           newthread, newthread, newthread->pt_stack.ss_sp,
+           newthread, private_area, newthread->pt_stack.ss_sp,
            newthread->pt_stack.ss_size);
 
        flag = LWP_DETACHED;
        if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0 ||
            (nattr.pta_flags & PT_FLAG_EXPLICIT_SCHED) != 0)
@@ -1238,13 +1261,13 @@
                /* XXX */
                errx(2, "failed to setup main thread: error=%d", error);
        }
 
        *newt = t;
-
-       /* Set up identity register. */
-       (void)_lwp_setprivate(t);
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+       _lwp_setprivate(t);
+#endif
 }
 
 static int
 /*ARGSUSED*/
 pthread__stackid_setup(void *base, size_t size, pthread_t *tp)

Index: src/lib/libpthread/pthread_int.h
===================================================================
--- src/lib/libpthread/pthread_int.h
+++ src/lib/libpthread/pthread_int.h
@@ -35,10 +35,12 @@
  */
 
 #ifndef _LIB_PTHREAD_INT_H
 #define _LIB_PTHREAD_INT_H
 
+#include <sys/tls.h>
+
 /* #define PTHREAD__DEBUG */
 #define ERRORCHECK
 
 #include "pthread_types.h"
 #include "pthread_queue.h"
@@ -90,10 +92,13 @@
        void    (*plo_lock)(__cpu_simple_lock_t *);
 };
 
 struct __pthread_st {
        pthread_t       pt_self;        /* Must be first. */
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       struct tls_tcb  *pt_tls;        /* Thread Local Storage area */
+#endif
        unsigned int    pt_magic;       /* Magic number */
        int             pt_state;       /* running, blocked, etc. */
        pthread_mutex_t pt_lock;        /* lock on state */
        int             pt_flags;       /* see PT_FLAG_* below */
        int             pt_cancel;      /* Deferred cancellation */
@@ -249,15 +254,24 @@
        _INITCONTEXT_U_MD(ucp)                                          \
        } while (/*CONSTCOND*/0)
 
 
 #if 0 && defined(__HAVE___LWP_GETPRIVATE_FAST)
+#  if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+static inline pthread_t __constfunc
+pthread__self(void)
+{
+       struct tls_tcb *tcb = __lwp_getprivate_fast()
+       return (pthread_t)tcb->tcb_pthread;
+}
+#  else
 static inline pthread_t __constfunc
 pthread__self(void)
 {
        return (pthread_t)__lwp_getprivate_fast();
 }
+#  endif
 #else
 /* Stack location of pointer to a particular thread */
 extern vaddr_t pthread__mainbase;
 extern vaddr_t pthread__mainstruct;
 static inline pthread_t

Index: src/libexec/ld.elf_so/Makefile
===================================================================
--- src/libexec/ld.elf_so/Makefile
+++ src/libexec/ld.elf_so/Makefile
@@ -59,11 +59,12 @@
 .endif
 
 CLIBOBJ!=      cd ${NETBSDSRCDIR}/lib/libc && ${PRINTOBJDIR}
 
 SRCS+=         rtld.c reloc.c symbol.c xmalloc.c xprintf.c debug.c \
-               map_object.c load.c search.c headers.c paths.c expand.c
+               map_object.c load.c search.c headers.c paths.c expand.c \
+               tls.c
 
 .if ${USE_FORT} == "yes"
 .PATH.c: ${NETBSDSRCDIR}/lib/libc/misc
 SRCS+=         stack_protector.c
 .endif

ADDED    src/libexec/ld.elf_so/README.TLS
Index: src/libexec/ld.elf_so/README.TLS
===================================================================
--- src/libexec/ld.elf_so/README.TLS
+++ src/libexec/ld.elf_so/README.TLS
@@ -0,0 +1,81 @@
+Steps for adding TLS support for a new platform:
+
+(1) Declare TLS variant in machine/types.h by defining either
+__HAVE_TLS_VARIANT_I or __HAVE_TLS_VARIANT_II.
+
+(2) crt0.o has to call _rtld_tls_static_setup() if _DYNAMIC == NULL.
+This part is already done if the new src/lib/csu/arch layout is used
+by the architecture.
+
+(3) _lwp_makecontext has to set the reserved register or kernel transfer
+variable in uc_mcontext to the provided value of 'private'.
+
+This is not possible on the VAX as there is no free space in ucontext_t.
+This requires either a special version of _lwp_create or versioning
+everything using ucontext_t. Debug support depends on getting the data from
+ucontext_t, so the second option is possibly required.
+
+(4) _lwp_setprivate(2) has to update the same register as
+_lwp_makecontext. cpu_lwp_setprivate has to call _lwp_setprivate(2) to
+reflect the kernel view. cpu_switch has to update the mapping.
+
+_lwp_setprivate is used for the initial thread, all other threads
+created by libpthread use _lwp_makecontext for this purpose.
+
+(5) Provide __tls_get_addr and possible other MD functions for dynamic
+TLS offset computation. If such alternative entry points exist (currently
+only i386), also add a weak reference to 0 in src/lib/libc/tls/tls.c.
+
+The generic implementation is:
+
+#include <sys/cdefs.h>
+#include <sys/tls.h>
+#include <lwp.h>
+
+/* Weak entry is overriden by ld.elf_so for dynamic linkage */
+weak_alias(__tls_get_addr, __libc__tls_get_addr)
+
+void *
+__libc__tls_get_addr(size_t idx[2])
+{
+       struct tls_tcb *tcb;
+
+       tcb = _lwp_getprivate();
+       return _rtld_tls_get_addr(tcb, idx[0], idx[1]);
+}
+
+XXX Document optimisations based idx[0]
+
+(6) Implement the necessary relocation records in mdreloc.c.  There are
+typically three relocation types found in dynamic binaries:
+
+(a) R_TYPE(TLS_DTPOFF): Offset inside the module.  The common TLS code
+ensures that the DTV vector points to offset 0 inside the module TLS block.
+This is normally def->st_value + rela->r_addend.
+
+(b) R_TYPE(TLS_DTPMOD): Module index.
+
+(c) R_TYPE(TLS_TPOFF): Static TLS offset.  The code has to check whether
+the static TLS offset for this module has been allocated
+(defobj->tls_done) and otherwise call _rtld_tls_offset_allocate().  This
+may fail if no static space is available and the object has been pulled
+in via dlopen(3).
+
+For TLS Variant I, this is typically:
+
+def->st_value + rela->r_addend + defobj->tlsoffset + sizeof(struct tls_tcb)
+
+e.g. the relocation doesn't include the fixed TCB.
+
+For TLS Variant II, this is typically:
+
+def->st_value - defobj->tlsoffset + rela->r_addend
+
+e.g. starting offset is counting down from the TCB.
+
+(7) Implement _lwp_getprivate_fast() in machine/mcontext.h and set
+__HAVE___LWP_GETPRIVATE_FAST.
+
+(8) Test using src/tests/lib/libc/tls.  Make sure with "objdump -R" that
+t_tls_dynamic has two TPOFF relocations and h_tls_dlopen.so.1 and
+libh_tls_dynamic.so.1 have both two DTPMOD and DTPOFF relocations.

Index: src/libexec/ld.elf_so/TODO
===================================================================
--- src/libexec/ld.elf_so/TODO
+++ src/libexec/ld.elf_so/TODO
@@ -1,7 +1,11 @@
 rtld:
 * resolve MIPS binding lossage
+
+TLS:
+* implement proper allocator for static TLS and support for actively
+  freeing DTV entries.
 
 binutils/gcc:
 * alpha: why are there GLOB_DAT relocs in ld.elf_so?
 * alpha: bogus textrels in rtti info
 * mips: why are there global GOT relocs in ld.elf_so?

Index: src/libexec/ld.elf_so/headers.c
===================================================================
--- src/libexec/ld.elf_so/headers.c
+++ src/libexec/ld.elf_so/headers.c
@@ -358,12 +358,22 @@
                        break;
 
                case PT_DYNAMIC:
                        obj->dynamic = (Elf_Dyn *)(uintptr_t)vaddr;
                        break;
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+               case PT_TLS:
+                       obj->tlsindex = 1;
+                       obj->tlssize = ph->p_memsz;
+                       obj->tlsalign = ph->p_align;
+                       obj->tlsinitsize = ph->p_filesz;
+                       obj->tlsinit = (void *)(uintptr_t)ph->p_vaddr;
+                       break;
+#endif
                }
        }
        assert(nsegs == 2);
 
        obj->entry = entry;
        return obj;
 }

Index: src/libexec/ld.elf_so/map_object.c
===================================================================
--- src/libexec/ld.elf_so/map_object.c
+++ src/libexec/ld.elf_so/map_object.c
@@ -64,10 +64,13 @@
 _rtld_map_object(const char *path, int fd, const struct stat *sb)
 {
        Obj_Entry       *obj;
        Elf_Ehdr        *ehdr;
        Elf_Phdr        *phdr;
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       Elf_Phdr        *phtls;
+#endif
        size_t           phsize;
        Elf_Phdr        *phlimit;
        Elf_Phdr        *segs[2];
        int              nsegs;
        caddr_t          mapbase = MAP_FAILED;
@@ -85,10 +88,13 @@
        Elf_Off          data_offset;
        Elf_Addr         data_vaddr;
        Elf_Addr         data_vlimit;
        int              data_flags;
        caddr_t          data_addr;
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       Elf_Addr         tls_vaddr = 0; /* Noise GCC */
+#endif
        Elf_Addr         phdr_vaddr;
        size_t           phdr_memsz;
        caddr_t          gap_addr;
        size_t           gap_size;
        int i;
@@ -157,10 +163,13 @@
          *
          * We rely on there being exactly two load segments, text and data,
          * in that order.
          */
        phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       phtls = NULL;
+#endif
        phsize = ehdr->e_phnum * sizeof(phdr[0]);
        obj->phdr = NULL;
        phdr_vaddr = EA_UNDEF;
        phdr_memsz = 0;
        phlimit = phdr + ehdr->e_phnum;
@@ -188,10 +197,16 @@
                
                case PT_DYNAMIC:
                        obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr;
                        dbg(("%s: PT_DYNAMIC %p", obj->path, obj->dynamic));
                        break;
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+               case PT_TLS:
+                       phtls = phdr;
+                       break;
+#endif
                }
 
                ++phdr;
        }
        phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
@@ -235,10 +250,21 @@
 #endif
 
        obj->textsize = text_vlimit - base_vaddr;
        obj->vaddrbase = base_vaddr;
        obj->isdynamic = ehdr->e_type == ET_DYN;
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       if (phtls != NULL) {
+               ++_rtld_tls_dtv_generation;
+               obj->tlsindex = ++_rtld_tls_max_index;
+               obj->tlssize = phtls->p_memsz;
+               obj->tlsalign = phtls->p_align;
+               obj->tlsinitsize = phtls->p_filesz;
+               tls_vaddr = phtls->p_vaddr;
+       }
+#endif
 
        obj->phdr_loaded = false;
        for (i = 0; i < nsegs; i++) {
                if (phdr_vaddr != EA_UNDEF &&
                    segs[i]->p_vaddr <= phdr_vaddr &&
@@ -337,10 +363,15 @@
                memset(clear_addr, 0, nclear);
 
        /* Non-file portion of BSS mapped above. */
 #endif
 
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       if (phtls != NULL)
+               obj->tlsinit = mapbase + tls_vaddr;
+#endif
+
        obj->mapbase = mapbase;
        obj->mapsize = mapsize;
        obj->relocbase = mapbase - base_vaddr;
 
        if (obj->dynamic)
@@ -366,10 +397,14 @@
 void
 _rtld_obj_free(Obj_Entry *obj)
 {
        Objlist_Entry *elm;
 
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       if (obj->tls_done)
+               _rtld_tls_offset_free(obj);
+#endif
        xfree(obj->path);
        while (obj->needed != NULL) {
                Needed_Entry *needed = obj->needed;
                obj->needed = needed->next;
                xfree(needed);

Index: src/libexec/ld.elf_so/rtld.c
===================================================================
--- src/libexec/ld.elf_so/rtld.c
+++ src/libexec/ld.elf_so/rtld.c
@@ -313,10 +313,13 @@
                       *pAUX_ruid, *pAUX_rgid;
        const AuxInfo  *pAUX_pagesz;
        char          **env, **oenvp;
        const AuxInfo  *aux;
        const AuxInfo  *auxp;
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       Obj_Entry      *obj;
+#endif
        Elf_Addr       *const osp = sp;
        bool            bind_now = 0;
        const char     *ld_bind_now, *ld_preload, *ld_library_path;
        const char    **argv;
        const char     *execname;
@@ -570,10 +573,20 @@
        }
 
        dbg(("loading needed objects"));
        if (_rtld_load_needed_objects(_rtld_objmain, _RTLD_MAIN) == -1)
                _rtld_die();
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       dbg(("initializing initial Thread Local Storage"));
+       /*
+        * All initial objects get the TLS space from the static block.
+        */
+       for (obj = _rtld_objlist; obj != NULL; obj = obj->next)
+               _rtld_tls_offset_allocate(obj);
+       _rtld_tls_initial_allocation();
+#endif
 
        dbg(("relocating objects"));
        if (_rtld_relocate_objects(_rtld_objmain, bind_now) == -1)
                _rtld_die();
 

Index: src/libexec/ld.elf_so/rtld.h
===================================================================
--- src/libexec/ld.elf_so/rtld.h
+++ src/libexec/ld.elf_so/rtld.h
@@ -39,10 +39,11 @@
 #include <stddef.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/exec_elf.h>
+#include <sys/tls.h>
 #include "rtldenv.h"
 #include "link.h"
 
 #if defined(_RTLD_SOURCE)
 
@@ -209,10 +210,14 @@
                                         * priority over others */
                        z_noopen:1,     /* True if object should never be
                                           dlopen'ed */
                        phdr_loaded:1,  /* Phdr is loaded and doesn't need to
                                         * be freed. */
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+                       tls_done:1,     /* True if static TLS offset
+                                        * has been allocated */
+#endif
                        ref_nodel:1;    /* Refcount increased to prevent 
dlclose */
 
        struct link_map linkmap;        /* for GDB */
 
        /* These items are computed by map_object() or by digest_phdr(). */
@@ -229,12 +234,23 @@
        uint8_t         nbuckets_s1;
        uint8_t         nbuckets_s2;
        size_t          pathlen;        /* Pathname length */
        STAILQ_HEAD(, Struct_Name_Entry) names; /* List of names for this 
object we
                                                   know about. */
+
 #ifdef __powerpc__
        Elf_Addr       *gotptr;         /* GOT table (secure-plt only) */
+#endif
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       /* Thread Local Storage support for this module */
+       size_t          tlsindex;       /* Index in DTV */
+       void            *tlsinit;       /* Base address of TLS init block */
+       size_t          tlsinitsize;    /* Size of TLS init block */
+       size_t          tlssize;        /* Size of TLS block */
+       size_t          tlsoffset;      /* Offset in the static TLS block */
+       size_t          tlsalign;       /* Needed alignment for static TLS */
 #endif
 } Obj_Entry;
 
 typedef struct Struct_DoneList {
        const Obj_Entry **objs;         /* Array of object pointers */
@@ -265,10 +281,13 @@
 /* Flags for _rtld_load_object() and friends. */
 #define        _RTLD_GLOBAL    0x01    /* Add object to global DAG. */
 #define        _RTLD_MAIN      0x02
 #define        _RTLD_NOLOAD    0x04    /* dlopen() specified RTLD_NOLOAD. */
 #define        _RTLD_DLOPEN    0x08    /* Load_object() called from dlopen(). 
*/
+
+/* Preallocation for static TLS model */
+#define        RTLD_STATIC_TLS_RESERVATION     64
 
 /* rtld.c */
 
 /* We export these symbols using _rtld_symbol_lookup and is_exported. */
 __dso_public char *dlerror(void);
@@ -340,10 +359,22 @@
 const Elf_Sym *_rtld_symlook_needed(const char *, unsigned long,
     const Needed_Entry *, const Obj_Entry **, bool,
     DoneList *, DoneList *);
 #ifdef COMBRELOC
 void _rtld_combreloc_reset(const Obj_Entry *);
+#endif
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+/* tls.c */
+void *_rtld_tls_get_addr(void *, size_t, size_t);
+void _rtld_tls_initial_allocation(void);
+void *_rtld_tls_module_allocate(size_t index);
+int _rtld_tls_offset_allocate(Obj_Entry *);
+void _rtld_tls_offset_free(Obj_Entry *);
+
+extern size_t _rtld_tls_dtv_generation;
+extern size_t _rtld_tls_max_index;
 #endif
 
 /* map_object.c */
 struct stat;
 Obj_Entry *_rtld_map_object(const char *, int, const struct stat *);

Index: src/libexec/ld.elf_so/symbol.c
===================================================================
--- src/libexec/ld.elf_so/symbol.c
+++ src/libexec/ld.elf_so/symbol.c
@@ -83,18 +83,27 @@
 }
 
 static bool
 _rtld_is_exported(const Elf_Sym *def)
 {
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+       extern void __tls_get_addr(void *);
+#endif
+
        static const fptr_t _rtld_exports[] = {
                (fptr_t)dlopen,
                (fptr_t)dlclose,
                (fptr_t)dlsym,
                (fptr_t)dlerror,
                (fptr_t)dladdr,
                (fptr_t)dlinfo,
                (fptr_t)dl_iterate_phdr,
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+               (fptr_t)_rtld_tls_allocate,
+               (fptr_t)_rtld_tls_free,
+               (fptr_t)__tls_get_addr,
+#endif
                NULL
        };
        int i;
        fptr_t value;
 

ADDED    src/libexec/ld.elf_so/tls.c
Index: src/libexec/ld.elf_so/tls.c
===================================================================
--- src/libexec/ld.elf_so/tls.c
+++ src/libexec/ld.elf_so/tls.c
@@ -0,0 +1,235 @@
+/*     $NetBSD$        */
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <sys/param.h>
+#include <lwp.h>
+#include <string.h>
+#include "rtld.h"
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+
+static size_t _rtld_tls_static_space;  /* Static TLS space allocated */
+static size_t _rtld_tls_static_offset; /* Next offset for static TLS to use */
+size_t _rtld_tls_dtv_generation = 1;
+size_t _rtld_tls_max_index = 1;
+
+#define        DTV_GENERATION(dtv)     ((size_t)((dtv)[0]))
+#define        DTV_MAX_INDEX(dtv)      ((size_t)((dtv)[-1]))
+#define        SET_DTV_GENERATION(dtv, val)    (dtv)[0] = (void *)(size_t)(val)
+#define        SET_DTV_MAX_INDEX(dtv, val)     (dtv)[-1] = (void 
*)(size_t)(val)
+
+void *
+_rtld_tls_get_addr(void *tls, size_t idx, size_t offset)
+{
+       struct tls_tcb *tcb = tls;
+       void **dtv, **new_dtv;
+
+       dtv = tcb->tcb_dtv;
+
+       if (__predict_false(DTV_GENERATION(dtv) != _rtld_tls_dtv_generation)) {
+               size_t to_copy = DTV_MAX_INDEX(dtv);
+
+               new_dtv = xcalloc((2 + _rtld_tls_max_index) * sizeof(*dtv));
+               ++new_dtv;
+               if (to_copy > _rtld_tls_max_index)
+                       to_copy = _rtld_tls_max_index;
+               memcpy(new_dtv + 1, dtv + 1, to_copy * sizeof(*dtv));
+               xfree(dtv - 1);
+               dtv = tcb->tcb_dtv = new_dtv;
+               SET_DTV_MAX_INDEX(dtv, _rtld_tls_max_index);
+               SET_DTV_GENERATION(dtv, _rtld_tls_dtv_generation);
+       }
+
+       if (__predict_false(dtv[idx] == NULL))
+               dtv[idx] = _rtld_tls_module_allocate(idx);
+
+       return (uint8_t *)dtv[idx] + offset;
+}
+
+void
+_rtld_tls_initial_allocation(void)
+{
+       struct tls_tcb *tcb;
+
+       _rtld_tls_static_space = _rtld_tls_static_offset +
+           RTLD_STATIC_TLS_RESERVATION;
+
+#ifndef __HAVE_TLS_VARIANT_I
+       _rtld_tls_static_space = roundup2(_rtld_tls_static_space,
+           sizeof(void *));
+#endif
+
+       tcb = _rtld_tls_allocate();
+       _lwp_setprivate(tcb);
+}
+
+struct tls_tcb *
+_rtld_tls_allocate(void)
+{
+       Obj_Entry *obj;
+       struct tls_tcb *tcb;
+       uint8_t *p, *q;
+
+       p = xcalloc(_rtld_tls_static_space + sizeof(struct tls_tcb));
+#ifdef __HAVE_TLS_VARIANT_I
+       tcb = (struct tls_tcb *)p;
+       p += sizeof(struct tls_tcb);
+#else
+       p += _rtld_tls_static_space;
+       tcb = (struct tls_tcb *)p;
+       tcb->tcb_self = tcb;
+#endif
+       tcb->tcb_dtv = xcalloc(sizeof(*tcb->tcb_dtv) * (2 + 
_rtld_tls_max_index));
+       ++tcb->tcb_dtv;
+       SET_DTV_MAX_INDEX(tcb->tcb_dtv, _rtld_tls_max_index);
+       SET_DTV_GENERATION(tcb->tcb_dtv, _rtld_tls_dtv_generation);
+
+       for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
+               if (obj->tlssize) {
+#ifdef __HAVE_TLS_VARIANT_I
+                       q = p + obj->tlsoffset;
+#else
+                       q = p - obj->tlsoffset;
+#endif
+                       memcpy(q, obj->tlsinit, obj->tlsinitsize);
+                       tcb->tcb_dtv[obj->tlsindex] = q;
+               }
+       }
+
+       return tcb;
+}
+
+void
+_rtld_tls_free(struct tls_tcb *tcb)
+{
+       size_t i, max_index;
+       uint8_t *p;
+
+       max_index = DTV_MAX_INDEX(tcb->tcb_dtv);
+       for (i = 1; i <= max_index; ++i)
+               xfree(tcb->tcb_dtv[i]);
+       xfree(tcb->tcb_dtv - 1);
+
+#ifdef __HAVE_TLS_VARIANT_I
+       p = (uint8_t *)tcb;
+#else
+       p = (uint8_t *)tcb - _rtld_tls_static_space;
+#endif
+       xfree(p);
+}
+
+void *
+_rtld_tls_module_allocate(size_t idx)
+{
+       Obj_Entry *obj;
+       uint8_t *p;
+
+       for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
+               if (obj->tlsindex == idx)
+                       break;
+       }
+       if (obj == NULL) {
+               _rtld_error("Module for TLS index %zu missing", idx);
+               _rtld_die();
+       }
+
+       p = xmalloc(obj->tlssize);
+       memcpy(p, obj->tlsinit, obj->tlsinitsize);
+       memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize);
+
+       return p;
+}
+
+int
+_rtld_tls_offset_allocate(Obj_Entry *obj)
+{
+       size_t offset, next_offset;
+
+       if (obj->tls_done)
+               return 0;
+       if (obj->tlssize == 0) {
+               obj->tlsoffset = 0;
+               obj->tls_done = 1;
+               return 0;
+       }
+
+#ifdef __HAVE_TLS_VARIANT_I
+       offset = roundup2(_rtld_tls_static_offset, obj->tlsalign);
+       next_offset = offset + obj->tlssize;
+#else
+       offset = roundup2(_rtld_tls_static_offset + obj->tlssize,
+           obj->tlsalign);
+       next_offset = offset;
+#endif
+
+       /*
+        * Check if the static allocation was already done.
+        * This happens if dynamically loaded modules want to use
+        * static TLS space.
+        *
+        * XXX Keep an actual free list and callbacks for initialisation.
+        */
+       if (_rtld_tls_static_space) {
+               if (obj->tlsinitsize) {
+                       _rtld_error("%s: Use of initialized "
+                           "Thread Locale Storage with model initial-exec "
+                           "and dlopen is not supported",
+                           obj->path);
+                       return -1;
+               }
+               if (next_offset > _rtld_tls_static_space) {
+                       _rtld_error("%s: No space available "
+                           "for static Thread Local Storage",
+                           obj->path);
+                       return -1;
+               }
+       }
+       obj->tlsoffset = offset;
+       _rtld_tls_static_offset = next_offset;
+       obj->tls_done = 1;
+
+       return 0;
+}
+
+void
+_rtld_tls_offset_free(Obj_Entry *obj)
+{
+
+       /*
+        * XXX See above.
+        */
+       obj->tls_done = 0;
+       return;
+}
+
+#endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */

Index: src/rescue/list.ldd
===================================================================
--- src/rescue/list.ldd
+++ src/rescue/list.ldd
@@ -3,11 +3,11 @@
 PROG   ldd
 
 LIBS   ${LDD_ELF32DIR}/libldd_elf32.a
 LIBS   ${LDD_ELF64DIR}/libldd_elf64.a
 
-SPECIAL ldd    keepsymbols     _rtld_pagesz _rtld_error _rtld_trust
+SPECIAL ldd    keepsymbols     _rtld_pagesz _rtld_die _rtld_error _rtld_trust
 SPECIAL ldd    keepsymbols     _rtld_default_paths _rtld_paths 
 SPECIAL ldd    keepsymbols     _rtld_xforms _rtld_objmain
 SPECIAL ldd    keepsymbols     _rtld_objtail _rtld_objlist
 SPECIAL ldd    keepsymbols     _rtld_objcount _rtld_objloads
 SPECIAL ldd    keepsymbols     print_needed main_local main_progname

Index: src/sys/sys/Makefile
===================================================================
--- src/sys/sys/Makefile
+++ src/sys/sys/Makefile
@@ -34,11 +34,11 @@
        sleepq.h socket.h \
        socketvar.h sockio.h specificdata.h stat.h statvfs.h \
        syscall.h syscallargs.h sysctl.h stdint.h swap.h \
        syncobj.h syslimits.h syslog.h \
        tape.h termios.h time.h timeb.h timepps.h times.h \
-       timex.h trace.h tree.h tty.h ttychars.h ttycom.h \
+       timex.h tls.h trace.h tree.h tty.h ttychars.h ttycom.h \
        ttydefaults.h ttydev.h types.h \
        ucontext.h ucred.h uio.h un.h unistd.h unpcb.h user.h utsname.h uuid.h \
        vadvise.h verified_exec.h videoio.h vmmeter.h vnode.h vnode_if.h \
        wait.h wapbl.h wapbl_replay.h wdog.h
 

ADDED    src/sys/sys/tls.h
Index: src/sys/sys/tls.h
===================================================================
--- src/sys/sys/tls.h
+++ src/sys/sys/tls.h
@@ -0,0 +1,61 @@
+/*     $NetBSD$        */
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_TLS_H_
+#define _SYS_TLS_H_
+
+#include <sys/cdefs.h>
+#include <machine/types.h>
+
+#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
+
+#if defined(__HAVE_TLS_VARIANT_I) && defined(__HAVE_TLS_VARIANT_II)
+#error Only one TLS variant can be supported at a time
+#endif
+
+struct tls_tcb {
+#ifdef __HAVE_TLS_VARIANT_I
+       void    **tcb_dtv;
+       void    *tcb_pthread;
+#else
+       void    *tcb_self;
+       void    **tcb_dtv;
+       void    *tcb_pthread;
+#endif
+};
+
+__BEGIN_PUBLIC_DECLS
+struct tls_tcb *_rtld_tls_allocate(void);
+void            _rtld_tls_free(struct tls_tcb *);
+void            _rtld_tls_static_setup(void);
+__END_PUBLIC_DECLS
+#endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */
+
+#endif /* _SYS_TLS_H_ */

Index: src/tests/lib/libc/Makefile
===================================================================
--- src/tests/lib/libc/Makefile
+++ src/tests/lib/libc/Makefile
@@ -1,12 +1,14 @@
 # $NetBSD: Makefile,v 1.37 2011/01/13 14:32:35 pgoyette Exp $
 
 .include <bsd.own.mk>
 .include <bsd.sys.mk>
 
+SUBDIR+=       tls_dso .WAIT
+
 TESTS_SUBDIRS+=        db gen hash ieeefp inet net regex rpc setjmp stdlib
-TESTS_SUBDIRS+=        stdio string sys time ttyio
+TESTS_SUBDIRS+=        stdio string sys time tls ttyio
 
 .if ${HAS_SSP} == "yes"
 TESTS_SUBDIRS+=        ssp
 .endif
 

ADDED    src/tests/lib/libc/tls/Makefile
Index: src/tests/lib/libc/tls/Makefile
===================================================================
--- src/tests/lib/libc/tls/Makefile
+++ src/tests/lib/libc/tls/Makefile
@@ -0,0 +1,15 @@
+# $NetBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR=      ${TESTSBASE}/lib/libc/tls
+SUBDIR+=       dso
+
+TESTS_C+=      t_tls_static t_tls_dynamic t_tls_dlopen
+SRCS.t_tls_static=     t_tls_static.c t_tls_static_helper.c
+LDADD.t_tls_static+=   -lpthread -static
+LDADD.t_tls_dynamic+=  -lpthread \
+                       -Wl,-rpath,${TESTSDIR} -L../tls_dso -lh_tls_dynamic
+LDADD.t_tls_dlopen+=   -lpthread -Wl,-rpath,${TESTSDIR} -Wl,-export-dynamic
+
+.include <bsd.test.mk>

ADDED    src/tests/lib/libc/tls/dso/Makefile
Index: src/tests/lib/libc/tls/dso/Makefile
===================================================================
--- src/tests/lib/libc/tls/dso/Makefile
+++ src/tests/lib/libc/tls/dso/Makefile
@@ -0,0 +1,18 @@
+# $NetBSD$
+
+NOMAN=         # defined
+NOLINT=                # defined
+
+.include <bsd.own.mk>
+
+LIB=                   h_tls_dlopen
+SRCS=                  h_tls_dlopen.c
+
+LIBDIR=                ${TESTSBASE}/lib/libc/tls
+SHLIBDIR=      ${TESTSBASE}/lib/libc/tls
+SHLIB_MAJOR=   1
+
+LIBISCXX=      yes
+LIBISMODULE=   yes
+
+.include <bsd.lib.mk>

ADDED    src/tests/lib/libc/tls/dso/h_tls_dlopen.c
Index: src/tests/lib/libc/tls/dso/h_tls_dlopen.c
===================================================================
--- src/tests/lib/libc/tls/dso/h_tls_dlopen.c
+++ src/tests/lib/libc/tls/dso/h_tls_dlopen.c
@@ -0,0 +1,53 @@
+/*     $NetBSD$        */
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <sys/tls.h>
+
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+#define        __thread
+#endif
+
+extern __thread int var1;
+extern __thread int var2;
+
+void testf_dso_helper(int x, int y);
+
+void
+testf_dso_helper(int x, int y)
+{
+       var1 = x;
+       var2 = y;
+}

ADDED    src/tests/lib/libc/tls/t_tls_dlopen.c
Index: src/tests/lib/libc/tls/t_tls_dlopen.c
===================================================================
--- src/tests/lib/libc/tls/t_tls_dlopen.c
+++ src/tests/lib/libc/tls/t_tls_dlopen.c
@@ -0,0 +1,106 @@
+/*     $NetBSD$        */
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <atf-c.h>
+#include <dlfcn.h>
+#include <pthread.h>
+
+#include <sys/tls.h>
+
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+#define        __thread
+#endif
+
+ATF_TC(t_tls_dlopen);
+
+ATF_TC_HEAD(t_tls_dlopen, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test (un)initialized TLS variables and dlopen");
+}
+
+void (*testf_helper)(int, int);
+
+__thread int var1 = 1;
+__thread int var2;
+
+static void *
+testf(void *dummy)
+{
+       ATF_CHECK_EQ(var1, 1);
+       ATF_CHECK_EQ(var2, 0);
+       testf_helper(2, 2);
+       ATF_CHECK_EQ(var1, 2);
+       ATF_CHECK_EQ(var2, 2);
+       testf_helper(3, 3);
+       ATF_CHECK_EQ(var1, 3);
+       ATF_CHECK_EQ(var2, 3);
+
+       return NULL;
+}
+
+ATF_TC_BODY(t_tls_dlopen, tc)
+{
+       void *handle;
+       pthread_t t;
+
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+       atf_tc_skip("no TLS support on this platform");
+#endif
+
+       handle = dlopen("h_tls_dlopen.so", RTLD_NOW | RTLD_LOCAL);
+       ATF_REQUIRE(handle != NULL);
+
+       testf_helper = dlsym(handle, "testf_dso_helper");
+       ATF_REQUIRE(testf_helper != NULL);
+
+       testf(NULL);
+
+       pthread_create(&t, 0, testf, 0);
+       pthread_join(t, NULL);
+
+       pthread_create(&t, 0, testf, 0);
+       pthread_join(t, NULL);
+
+       dlclose(handle);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+       ATF_TP_ADD_TC(tp, t_tls_dlopen);
+
+       return atf_no_error();
+}

ADDED    src/tests/lib/libc/tls/t_tls_dynamic.c
Index: src/tests/lib/libc/tls/t_tls_dynamic.c
===================================================================
--- src/tests/lib/libc/tls/t_tls_dynamic.c
+++ src/tests/lib/libc/tls/t_tls_dynamic.c
@@ -0,0 +1,96 @@
+/*     $NetBSD$        */
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <atf-c.h>
+#include <pthread.h>
+
+#include <sys/tls.h>
+
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+#define        __thread
+#endif
+
+ATF_TC(t_tls_dynamic);
+
+ATF_TC_HEAD(t_tls_dynamic, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test (un)initialized TLS variables in dynamic binaries");
+}
+
+void testf_dso_helper(int, int);
+
+extern __thread int var1;
+extern __thread int var2;
+
+static void *
+testf(void *dummy)
+{
+       ATF_CHECK_EQ(var1, 1);
+       ATF_CHECK_EQ(var2, 0);
+       testf_dso_helper(2, 2);
+       ATF_CHECK_EQ(var1, 2);
+       ATF_CHECK_EQ(var2, 2);
+       testf_dso_helper(3, 3);
+       ATF_CHECK_EQ(var1, 3);
+       ATF_CHECK_EQ(var2, 3);
+
+       return NULL;
+}
+
+ATF_TC_BODY(t_tls_dynamic, tc)
+{
+       pthread_t t;
+
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+       atf_tc_skip("no TLS support on this platform");
+#endif
+
+       testf(NULL);
+
+       pthread_create(&t, 0, testf, 0);
+       pthread_join(t, NULL);
+
+       pthread_create(&t, 0, testf, 0);
+       pthread_join(t, NULL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+       ATF_TP_ADD_TC(tp, t_tls_dynamic);
+
+       return atf_no_error();
+}

ADDED    src/tests/lib/libc/tls/t_tls_static.c
Index: src/tests/lib/libc/tls/t_tls_static.c
===================================================================
--- src/tests/lib/libc/tls/t_tls_static.c
+++ src/tests/lib/libc/tls/t_tls_static.c
@@ -0,0 +1,93 @@
+/*     $NetBSD$        */
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <atf-c.h>
+#include <pthread.h>
+
+#include <sys/tls.h>
+
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+#define        __thread
+#endif
+
+ATF_TC(t_tls_static);
+
+ATF_TC_HEAD(t_tls_static, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test (un)initialized TLS variables in static binaries");
+}
+
+void testf_helper(void);
+
+__thread int var1 = 1;
+__thread int var2;
+
+static void *
+testf(void *dummy)
+{
+       ATF_CHECK_EQ(var1, 1);
+       ATF_CHECK_EQ(var2, 0);
+       testf_helper();
+       ATF_CHECK_EQ(var1, -1);
+       ATF_CHECK_EQ(var2, -1);
+
+       return NULL;
+}
+
+ATF_TC_BODY(t_tls_static, tc)
+{
+       pthread_t t;
+
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+       atf_tc_skip("no TLS support on this platform");
+#endif
+
+       testf(NULL);
+
+       pthread_create(&t, 0, testf, 0);
+       pthread_join(t, NULL);
+
+       pthread_create(&t, 0, testf, 0);
+       pthread_join(t, NULL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+       ATF_TP_ADD_TC(tp, t_tls_static);
+
+       return atf_no_error();
+}

ADDED    src/tests/lib/libc/tls/t_tls_static_helper.c
Index: src/tests/lib/libc/tls/t_tls_static_helper.c
===================================================================
--- src/tests/lib/libc/tls/t_tls_static_helper.c
+++ src/tests/lib/libc/tls/t_tls_static_helper.c
@@ -0,0 +1,53 @@
+/*     $NetBSD$        */
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <sys/tls.h>
+
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+#define        __thread
+#endif
+
+extern __thread int var1;
+extern __thread int var2;
+
+void testf_helper(void);
+
+void
+testf_helper(void)
+{
+       var1 = -1;
+       var2 = -1;
+}

ADDED    src/tests/lib/libc/tls_dso/Makefile
Index: src/tests/lib/libc/tls_dso/Makefile
===================================================================
--- src/tests/lib/libc/tls_dso/Makefile
+++ src/tests/lib/libc/tls_dso/Makefile
@@ -0,0 +1,20 @@
+# $NetBSD: Makefile,v 1.1 2010/07/28 13:51:40 joerg Exp $
+
+.include <bsd.own.mk>
+
+LIB=                   h_tls_dynamic
+SRCS=                  h_tls_dynamic.c
+
+LIBDIR=                ${TESTSBASE}/lib/libc/tls
+SHLIBDIR=      ${TESTSBASE}/lib/libc/tls
+SHLIB_MAJOR=   1
+
+LIBISCXX=      yes
+MKSTATICLIB=   no
+MKPROFILE=     no
+MKPICINSTALL=  no
+MKLINT=                no
+
+NOMAN=         # defined
+
+.include <bsd.lib.mk>

ADDED    src/tests/lib/libc/tls_dso/h_tls_dynamic.c
Index: src/tests/lib/libc/tls_dso/h_tls_dynamic.c
===================================================================
--- src/tests/lib/libc/tls_dso/h_tls_dynamic.c
+++ src/tests/lib/libc/tls_dso/h_tls_dynamic.c
@@ -0,0 +1,53 @@
+/*     $NetBSD$        */
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <sys/tls.h>
+
+#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
+#define        __thread
+#endif
+
+__thread int var1 = 1;
+__thread int var2;
+
+void testf_dso_helper(int x, int y);
+
+void
+testf_dso_helper(int x, int y)
+{
+       var1 = x;
+       var2 = y;
+}

Index: src/usr.bin/ldd/Makefile.elf
===================================================================
--- src/usr.bin/ldd/Makefile.elf
+++ src/usr.bin/ldd/Makefile.elf
@@ -3,8 +3,8 @@
 # Makefile fragment to build a (32 or 64 bit) libldd_elfxx.a.
 # Expects CPPFLAGS to have ELFSIZE set, and LIB to be set.
 
 SRCS=  ldd_elfxx.c
 SRCS+= xmalloc.c debug.c expand.c map_object.c load.c search.c \
-       headers.c paths.c
+       headers.c paths.c tls.c
 
 .include "Makefile.common"

Index: src/usr.bin/ldd/elf32/Makefile
===================================================================
--- src/usr.bin/ldd/elf32/Makefile
+++ src/usr.bin/ldd/elf32/Makefile
@@ -1,9 +1,17 @@
 #      $NetBSD: Makefile,v 1.7 2009/12/13 08:50:56 mrg Exp $
 
 .include <bsd.own.mk>
 .include <bsd.init.mk>
+
+RTLD_FUNCS     = \
+       _rtld_tls_allocate \
+       _rtld_tls_free \
+
+.for _d in ${RTLD_FUNCS}
+CPPFLAGS+=     -D${_d}=_elf32_${_d}
+.endfor
 
 CPPFLAGS+=     -DELFSIZE=32
 LIB=   ldd_elf32
 
 # XXX Force one member

Index: src/usr.bin/ldd/elf64/Makefile
===================================================================
--- src/usr.bin/ldd/elf64/Makefile
+++ src/usr.bin/ldd/elf64/Makefile
@@ -28,10 +28,12 @@
        _rtld_obj_free \
        _rtld_obj_new \
        _rtld_add_paths \
        _rtld_process_hints \
        _rtld_sysctl \
+       _rtld_tls_allocate \
+       _rtld_tls_free \
        _rtld_load_library
 
 .for _d in ${RTLD_FUNCS}
 CPPFLAGS+=     -D${_d}=_elf64_${_d}
 .endfor

Index: src/usr.bin/ldd/ldd.c
===================================================================
--- src/usr.bin/ldd/ldd.c
+++ src/usr.bin/ldd/ldd.c
@@ -300,6 +300,16 @@
                        }
                } else {
                        fmtprint(libname, needed->obj, fmt1, fmt2);
                }
        }
+}
+
+void
+_rtld_die(void)
+{
+       const char *msg = dlerror();
+
+       if (msg == NULL)
+               msg = "Fatal error";
+       xerrx(1, "%s", msg);
 }

Index: src/libexec/ld.elf_so/arch/sh3/Makefile.inc
===================================================================
--- src/libexec/ld.elf_so/arch/sh3/Makefile.inc
+++ src/libexec/ld.elf_so/arch/sh3/Makefile.inc
@@ -1,10 +1,10 @@
 #      $NetBSD: Makefile.inc,v 1.7 2005/06/04 16:17:17 lukem Exp $
 
-SRCS+=         rtld_start.S mdreloc.c
+SRCS+=         rtld_start.S mdreloc.c mdtls.c
 
 # XXX Should not be in CPPFLAGS!
 CPPFLAGS+=     -fpic
 
 CPPFLAGS+=     -DELFSIZE=32
 
 LDFLAGS+=      -Wl,-e,.rtld_start

Index: src/libexec/ld.elf_so/arch/sh3/mdreloc.c
===================================================================
--- src/libexec/ld.elf_so/arch/sh3/mdreloc.c
+++ src/libexec/ld.elf_so/arch/sh3/mdreloc.c
@@ -9,10 +9,11 @@
 #ifndef lint
 __RCSID("$NetBSD: mdreloc.c,v 1.28 2010/08/06 16:33:18 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
+#include <sys/tls.h>
 
 #include "debug.h"
 #include "rtld.h"
 
 void _rtld_bind_start(void);
@@ -152,10 +153,53 @@
                                return -1;
                        }
                        rdbg(("COPY (avoid in main)"));
                        break;
 
+               case R_TYPE(TLS_DTPOFF32):
+                       def = _rtld_find_symdef(symnum, obj, &defobj, false);
+                       if (def == NULL)
+                               return -1;
+
+                       *where = (Elf_Addr)(def->st_value);
+
+                       rdbg(("TLS_DTPOFF32 %s in %s --> %p",
+                           obj->strtab + obj->symtab[symnum].st_name,
+                           obj->path, (void *)*where));
+
+                       break;
+               case R_TYPE(TLS_DTPMOD32):
+                       def = _rtld_find_symdef(symnum, obj, &defobj, false);
+                       if (def == NULL)
+                               return -1;
+
+                       *where = (Elf_Addr)(defobj->tlsindex);
+
+                       rdbg(("TLS_DTPMOD32 %s in %s --> %p",
+                           obj->strtab + obj->symtab[symnum].st_name,
+                           obj->path, (void *)*where));
+
+                       break;
+
+               case R_TYPE(TLS_TPOFF32):
+                       def = _rtld_find_symdef(symnum, obj, &defobj, false);
+                       if (def == NULL)
+                               return -1;
+
+                       if (!defobj->tls_done &&
+                           _rtld_tls_offset_allocate(obj))
+                               return -1;
+
+                       *where = (Elf_Addr)def->st_value +
+                           rela->r_addend + defobj->tlsoffset +
+                           sizeof(struct tls_tcb);
+
+                       rdbg(("TLS_TPOFF32 %s in %s --> %p",
+                           obj->strtab + obj->symtab[symnum].st_name,
+                           obj->path, (void *)*where));
+                       break;
+
                default:
                        rdbg(("sym = %lu, type = %lu, offset = %p, "
                            "addend = %p, contents = %p, symbol = %s",
                            symnum, (u_long)ELF_R_TYPE(rela->r_info),
                            (void *)rela->r_offset, (void *)rela->r_addend,
@@ -165,10 +209,11 @@
                            "in non-PLT relocations",
                            obj->path, (u_long) ELF_R_TYPE(rela->r_info));
                        return -1;
                }
        }
+
        return 0;
 }
 
 int
 _rtld_relocate_plt_lazy(const Obj_Entry *obj)

ADDED    src/libexec/ld.elf_so/arch/sh3/mdtls.c
Index: src/libexec/ld.elf_so/arch/sh3/mdtls.c
===================================================================
--- src/libexec/ld.elf_so/arch/sh3/mdtls.c
+++ src/libexec/ld.elf_so/arch/sh3/mdtls.c
@@ -1,0 +1,17 @@
+#include <sys/cdefs.h>
+
+__RCSID("$NetBSD$");
+
+#include <sys/tls.h>
+#include "rtld.h"
+
+__dso_public void *__tls_get_addr(int[2]);
+
+void *
+__tls_get_addr(int idx[2])
+{
+       void *p;
+
+       asm volatile ("stc\tgbr, %0" : "=r" (p));
+       return _rtld_tls_get_addr(p, idx[0], idx[1]);
+}

Index: src/sys/arch/sh3/include/types.h
===================================================================
--- src/sys/arch/sh3/include/types.h
+++ src/sys/arch/sh3/include/types.h
@@ -77,7 +77,8 @@
 #define        __HAVE_RAS
 #endif
 
 #define        __HAVE_CPU_LWP_SETPRIVATE
 #define        __HAVE___LWP_GETPRIVATE_FAST
+#define        __HAVE_TLS_VARIANT_I
 
 #endif /* !_SH3_TYPES_H_ */



Home | Main Index | Thread Index | Old Index