Skip to content

Commit aad5999

Browse files
committed
Add TLS support infrastructure. For dynamic binaries, ld.elf_so exports
_rtld_tls_allocate and _rtld_tls_free. libpthread uses this functions to setup the thread private area of all new threads. ld.elf_so is responsible for setting up the private area for the initial thread. Similar functions are called from _libc_init for static binaries, using dl_iterate_phdr to access the ELF Program Header. Add test cases to exercise the different TLS storage models. Test cases are compiled and installed on all platforms, but are skipped on platforms not marked for TLS support. This material is based upon work partially supported by The NetBSD Foundation under a contract with Joerg Sonnenberger. It is inspired by the TLS support in FreeBSD by Doug Rabson and the clean ups of the DragonFly port of the original FreeBSD modifications.
1 parent ef6127c commit aad5999

File tree

35 files changed

+1271
-36
lines changed

35 files changed

+1271
-36
lines changed

distrib/sets/lists/comp/mi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $NetBSD: mi,v 1.1594 2011/03/07 15:49:56 njoly Exp $
1+
# $NetBSD: mi,v 1.1595 2011/03/09 23:10:05 joerg Exp $
22
#
33
# Note: don't delete entries from here - mark them as "obsolete" instead.
44
#
@@ -2173,6 +2173,7 @@
21732173
./usr/include/sys/timepps.h comp-c-include
21742174
./usr/include/sys/times.h comp-c-include
21752175
./usr/include/sys/timex.h comp-c-include
2176+
./usr/include/sys/tls.h comp-c-include
21762177
./usr/include/sys/tprintf.h comp-obsolete obsolete
21772178
./usr/include/sys/trace.h comp-c-include
21782179
./usr/include/sys/tree.h comp-c-include

distrib/sets/lists/tests/mi

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $NetBSD: mi,v 1.262 2011/03/09 19:04:57 bouyer Exp $
1+
# $NetBSD: mi,v 1.263 2011/03/09 23:10:05 joerg Exp $
22
#
33
# Note: don't delete entries from here - mark them as "obsolete" instead.
44
#
@@ -420,6 +420,10 @@
420420
./usr/libdata/debug/usr/tests/lib/libc/sys/t_context.debug tests-lib-debug debug,atf
421421
./usr/libdata/debug/usr/tests/lib/libc/sys/t_cerror.debug tests-lib-debug debug,atf
422422
./usr/libdata/debug/usr/tests/lib/libc/sys/t_sigqueue.debug tests-lib-debug debug,atf
423+
./usr/libdata/debug/usr/tests/lib/libc/tls tests-lib-debug
424+
./usr/libdata/debug/usr/tests/lib/libc/tls/t_tls_dlopen.debug tests-lib-debug debug,atf
425+
./usr/libdata/debug/usr/tests/lib/libc/tls/t_tls_dynamic.debug tests-lib-debug debug,atf
426+
./usr/libdata/debug/usr/tests/lib/libc/tls/t_tls_static.debug tests-lib-debug debug,atf
423427
./usr/libdata/debug/usr/tests/lib/libc/ttyio tests-lib-debug
424428
./usr/libdata/debug/usr/tests/lib/libc/ttyio/t_ptm.debug tests-lib-debug debug,atf
425429
./usr/libdata/debug/usr/tests/lib/libc/ttyio/t_ttyio.debug tests-lib-debug debug,atf
@@ -1848,6 +1852,15 @@
18481852
./usr/tests/lib/libc/sys/t_context tests-lib-tests atf
18491853
./usr/tests/lib/libc/sys/t_cerror tests-lib-tests atf
18501854
./usr/tests/lib/libc/sys/t_sigqueue tests-lib-tests atf
1855+
./usr/tests/lib/libc/tls tests-lib-tests
1856+
./usr/tests/lib/libc/tls/Atffile tests-lib-tests atf
1857+
./usr/tests/lib/libc/tls/h_tls_dlopen.so tests-lib-tests atf
1858+
./usr/tests/lib/libc/tls/h_tls_dlopen.so.1 tests-lib-tests atf
1859+
./usr/tests/lib/libc/tls/libh_tls_dynamic.so tests-lib-tests atf
1860+
./usr/tests/lib/libc/tls/libh_tls_dynamic.so.1 tests-lib-tests atf
1861+
./usr/tests/lib/libc/tls/t_tls_dlopen tests-lib-tests atf
1862+
./usr/tests/lib/libc/tls/t_tls_dynamic tests-lib-tests atf
1863+
./usr/tests/lib/libc/tls/t_tls_static tests-lib-tests atf
18511864
./usr/tests/lib/libc/ttyio tests-lib-tests
18521865
./usr/tests/lib/libc/ttyio/Atffile tests-lib-tests atf
18531866
./usr/tests/lib/libc/ttyio/t_ptm tests-lib-tests atf

etc/mtree/NetBSD.dist.tests

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $NetBSD: NetBSD.dist.tests,v 1.30 2011/03/06 17:08:12 bouyer Exp $
1+
# $NetBSD: NetBSD.dist.tests,v 1.31 2011/03/09 23:10:06 joerg Exp $
22

33
./usr/libdata/debug/usr/tests
44
./usr/libdata/debug/usr/tests/atf
@@ -61,6 +61,7 @@
6161
./usr/libdata/debug/usr/tests/lib/libc/stdlib
6262
./usr/libdata/debug/usr/tests/lib/libc/string
6363
./usr/libdata/debug/usr/tests/lib/libc/sys
64+
./usr/libdata/debug/usr/tests/lib/libc/tls
6465
./usr/libdata/debug/usr/tests/lib/libc/ttyio
6566
./usr/libdata/debug/usr/tests/lib/libc/time
6667
./usr/libdata/debug/usr/tests/lib/libdes
@@ -175,6 +176,7 @@
175176
./usr/tests/lib/libc/stdlib
176177
./usr/tests/lib/libc/string
177178
./usr/tests/lib/libc/sys
179+
./usr/tests/lib/libc/tls
178180
./usr/tests/lib/libc/ttyio
179181
./usr/tests/lib/libc/time
180182
./usr/tests/lib/libdes

lib/libc/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $NetBSD: Makefile,v 1.143 2010/09/04 12:17:58 ahoka Exp $
1+
# $NetBSD: Makefile,v 1.144 2011/03/09 23:10:06 joerg Exp $
22
# @(#)Makefile 8.2 (Berkeley) 2/3/94
33
#
44
# All library objects contain sccsid strings by default; they may be
@@ -92,6 +92,7 @@ COMPATDIR=${.CURDIR}/compat
9292
.include "${.CURDIR}/termios/Makefile.inc"
9393
.include "${.CURDIR}/thread-stub/Makefile.inc"
9494
.include "${.CURDIR}/time/Makefile.inc"
95+
.include "${.CURDIR}/tls/Makefile.inc"
9596
.include "${.CURDIR}/sys/Makefile.inc"
9697
.include "${.CURDIR}/uuid/Makefile.inc"
9798
.if (${MKYP} != "no")

lib/libc/misc/initfini.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: initfini.c,v 1.8 2011/03/07 05:09:11 joerg Exp $ */
1+
/* $NetBSD: initfini.c,v 1.9 2011/03/09 23:10:06 joerg Exp $ */
22

33
/*-
44
* Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -30,14 +30,15 @@
3030
*/
3131

3232
#include <sys/cdefs.h>
33-
__RCSID("$NetBSD: initfini.c,v 1.8 2011/03/07 05:09:11 joerg Exp $");
33+
__RCSID("$NetBSD: initfini.c,v 1.9 2011/03/09 23:10:06 joerg Exp $");
3434

3535
#ifdef _LIBC
3636
#include "namespace.h"
3737
#endif
3838

3939
#include <sys/param.h>
4040
#include <sys/exec.h>
41+
#include <sys/tls.h>
4142
#include <stdbool.h>
4243

4344
void _libc_init(void) __attribute__((__constructor__, __used__));
@@ -48,6 +49,10 @@ void __libc_atomic_init(void);
4849
void __libc_atexit_init(void);
4950
void __libc_env_init(void);
5051

52+
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
53+
__dso_hidden void __libc_static_tls_setup(void);
54+
#endif
55+
5156
static bool libc_initialised;
5257

5358
void _libc_init(void);
@@ -78,6 +83,11 @@ _libc_init(void)
7883
/* Atomic operations */
7984
__libc_atomic_init();
8085

86+
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
87+
/* Initialize TLS for statically linked programs. */
88+
__libc_static_tls_setup();
89+
#endif
90+
8191
/* Threads */
8292
__libc_thr_init();
8393

lib/libc/tls/Makefile.inc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# $NetBSD: Makefile.inc,v 1.1 2011/03/09 23:10:06 joerg Exp $
2+
3+
.include <bsd.own.mk>
4+
5+
# Our sources
6+
.PATH: ${.PARSEDIR} ${ARCHDIR}/tls
7+
8+
SRCS+= tls.c

lib/libc/tls/tls.c

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/* $NetBSD: tls.c,v 1.1 2011/03/09 23:10:06 joerg Exp $ */
2+
3+
/*-
4+
* Copyright (c) 2011 The NetBSD Foundation, Inc.
5+
* All rights reserved.
6+
*
7+
* This code is derived from software contributed to The NetBSD Foundation
8+
* by Joerg Sonnenberger.
9+
*
10+
* Redistribution and use in source and binary forms, with or without
11+
* modification, are permitted provided that the following conditions
12+
* are met:
13+
* 1. Redistributions of source code must retain the above copyright
14+
* notice, this list of conditions and the following disclaimer.
15+
* 2. Redistributions in binary form must reproduce the above copyright
16+
* notice, this list of conditions and the following disclaimer in the
17+
* documentation and/or other materials provided with the distribution.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20+
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21+
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
32+
#include <sys/cdefs.h>
33+
__RCSID("$NetBSD: tls.c,v 1.1 2011/03/09 23:10:06 joerg Exp $");
34+
35+
#include "namespace.h"
36+
37+
#include <sys/tls.h>
38+
39+
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
40+
41+
#define _rtld_tls_allocate __libc_rtld_tls_allocate
42+
#define _rtld_tls_free __libc_rtld_tls_free
43+
44+
#include <sys/param.h>
45+
#include <sys/mman.h>
46+
#include <link_elf.h>
47+
#include <lwp.h>
48+
#include <stddef.h>
49+
#include <stdlib.h>
50+
#include <string.h>
51+
#include <unistd.h>
52+
53+
__dso_hidden void __libc_static_tls_setup(void);
54+
55+
static const void *tls_initaddr;
56+
static size_t tls_initsize;
57+
static size_t tls_size;
58+
static size_t tls_allocation;
59+
static void *initial_thread_tcb;
60+
61+
__weak_alias(__tls_get_addr, 0)
62+
#ifdef __i386__
63+
__weak_alias(___tls_get_addr, 0)
64+
#endif
65+
66+
__weak_alias(_rtld_tls_allocate, __libc_rtld_tls_allocate)
67+
68+
struct tls_tcb *
69+
_rtld_tls_allocate(void)
70+
{
71+
struct tls_tcb *tcb;
72+
uint8_t *p;
73+
74+
if (initial_thread_tcb == NULL) {
75+
#ifdef __HAVE_TLS_VARIANT_II
76+
tls_size = roundup2(tls_size, sizeof(void *));
77+
#endif
78+
tls_allocation = tls_size + sizeof(*tcb);
79+
80+
initial_thread_tcb = p = mmap(NULL, tls_allocation,
81+
PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
82+
} else {
83+
p = calloc(1, tls_allocation);
84+
}
85+
if (p == NULL) {
86+
static const char msg[] = "TLS allocation failed, terminating\n";
87+
write(STDERR_FILENO, msg, sizeof(msg));
88+
_exit(127);
89+
}
90+
#ifdef __HAVE_TLS_VARIANT_I
91+
/* LINTED */
92+
tcb = (struct tls_tcb *)p;
93+
p += sizeof(struct tls_tcb);
94+
#else
95+
/* LINTED tls_size is rounded above */
96+
tcb = (struct tls_tcb *)(p + tls_size);
97+
tcb->tcb_self = tcb;
98+
#endif
99+
memcpy(p, tls_initaddr, tls_initsize);
100+
101+
return tcb;
102+
}
103+
104+
__weak_alias(_rtld_tls_free, __libc_rtld_tls_free)
105+
106+
void
107+
_rtld_tls_free(struct tls_tcb *tcb)
108+
{
109+
uint8_t *p;
110+
111+
#ifdef __HAVE_TLS_VARIANT_I
112+
/* LINTED */
113+
p = (uint8_t *)tcb;
114+
#else
115+
/* LINTED */
116+
p = (uint8_t *)tcb - tls_size;
117+
#endif
118+
if (p == initial_thread_tcb)
119+
munmap(p, tls_allocation);
120+
else
121+
free(p);
122+
}
123+
124+
__weakref_visible int rtld_DYNAMIC __weak_reference(_DYNAMIC);
125+
126+
static int
127+
__libc_static_tls_setup_cb(struct dl_phdr_info *data, size_t len, void *cookie)
128+
{
129+
const Elf_Phdr *phdr = data->dlpi_phdr;
130+
const Elf_Phdr *phlimit = data->dlpi_phdr + data->dlpi_phnum;
131+
132+
for (; phdr < phlimit; ++phdr) {
133+
if (phdr->p_type != PT_TLS)
134+
continue;
135+
tls_initaddr = (void *)(phdr->p_vaddr + data->dlpi_addr);
136+
tls_initsize = phdr->p_filesz;
137+
tls_size = phdr->p_memsz;
138+
}
139+
return 0;
140+
}
141+
142+
void
143+
__libc_static_tls_setup(void)
144+
{
145+
struct tls_tcb *tcb;
146+
147+
if (&rtld_DYNAMIC != NULL)
148+
return;
149+
150+
dl_iterate_phdr(__libc_static_tls_setup_cb, NULL);
151+
152+
tcb = _rtld_tls_allocate();
153+
_lwp_setprivate(tcb);
154+
}
155+
156+
#endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */

lib/libpthread/pthread.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: pthread.c,v 1.120 2010/12/22 22:41:45 christos Exp $ */
1+
/* $NetBSD: pthread.c,v 1.121 2011/03/09 23:10:06 joerg Exp $ */
22

33
/*-
44
* Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -30,14 +30,15 @@
3030
*/
3131

3232
#include <sys/cdefs.h>
33-
__RCSID("$NetBSD: pthread.c,v 1.120 2010/12/22 22:41:45 christos Exp $");
33+
__RCSID("$NetBSD: pthread.c,v 1.121 2011/03/09 23:10:06 joerg Exp $");
3434

3535
#define __EXPOSE_STACK 1
3636

3737
#include <sys/param.h>
3838
#include <sys/mman.h>
3939
#include <sys/sysctl.h>
4040
#include <sys/lwpctl.h>
41+
#include <sys/tls.h>
4142

4243
#include <err.h>
4344
#include <errno.h>
@@ -194,6 +195,11 @@ pthread__init(void)
194195
pthread__initthread(first);
195196
pthread__scrubthread(first, NULL, 0);
196197

198+
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
199+
first->pt_tls = _lwp_getprivate();
200+
first->pt_tls->tcb_pthread = first;
201+
#endif
202+
197203
first->pt_lid = _lwp_self();
198204
PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq);
199205
RB_INSERT(__pthread__alltree, &pthread__alltree, first);
@@ -284,6 +290,9 @@ pthread__initthread(pthread_t t)
284290
{
285291

286292
t->pt_self = t;
293+
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
294+
t->pt_tls = NULL;
295+
#endif
287296
t->pt_magic = PT_MAGIC;
288297
t->pt_willpark = 0;
289298
t->pt_unpark = 0;
@@ -307,6 +316,12 @@ static void
307316
pthread__scrubthread(pthread_t t, char *name, int flags)
308317
{
309318

319+
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
320+
if (t->pt_tls) {
321+
_rtld_tls_free(t->pt_tls);
322+
t->pt_tls = NULL;
323+
}
324+
#endif
310325
t->pt_state = PT_STATE_RUNNING;
311326
t->pt_exitval = NULL;
312327
t->pt_flags = flags;
@@ -326,6 +341,7 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
326341
struct pthread_attr_private *p;
327342
char * volatile name;
328343
unsigned long flag;
344+
void *private_area;
329345
int ret;
330346

331347
/*
@@ -407,8 +423,15 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
407423
pthread__scrubthread(newthread, name, nattr.pta_flags);
408424
newthread->pt_func = startfunc;
409425
newthread->pt_arg = arg;
426+
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
427+
private_area = newthread->pt_tls = _rtld_tls_allocate();
428+
newthread->pt_tls->tcb_pthread = newthread;
429+
#else
430+
private_area = newthread;
431+
#endif
432+
410433
_lwp_makecontext(&newthread->pt_uc, pthread__create_tramp,
411-
newthread, newthread, newthread->pt_stack.ss_sp,
434+
newthread, private_area, newthread->pt_stack.ss_sp,
412435
newthread->pt_stack.ss_size);
413436

414437
flag = LWP_DETACHED;
@@ -1240,9 +1263,9 @@ pthread__initmain(pthread_t *newt)
12401263
}
12411264

12421265
*newt = t;
1243-
1244-
/* Set up identity register. */
1245-
(void)_lwp_setprivate(t);
1266+
#if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II)
1267+
_lwp_setprivate(t);
1268+
#endif
12461269
}
12471270

12481271
static int

0 commit comments

Comments
 (0)