1 /* $NetBSD: tls.c,v 1.9 2013/10/21 19:14:15 joerg Exp $ */
3 * Copyright (c) 2011 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Joerg Sonnenberger.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: tls.c,v 1.9 2013/10/21 19:14:15 joerg Exp $");
34 #include <sys/param.h>
35 #include <sys/ucontext.h>
41 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
43 static struct tls_tcb
*_rtld_tls_allocate_locked(void);
45 #ifndef TLS_DTV_OFFSET
46 #define TLS_DTV_OFFSET 0
49 static size_t _rtld_tls_static_space
; /* Static TLS space allocated */
50 static size_t _rtld_tls_static_offset
; /* Next offset for static TLS to use */
51 size_t _rtld_tls_dtv_generation
= 1;
52 size_t _rtld_tls_max_index
= 1;
54 #define DTV_GENERATION(dtv) ((size_t)((dtv)[0]))
55 #define DTV_MAX_INDEX(dtv) ((size_t)((dtv)[-1]))
56 #define SET_DTV_GENERATION(dtv, val) (dtv)[0] = (void *)(size_t)(val)
57 #define SET_DTV_MAX_INDEX(dtv, val) (dtv)[-1] = (void *)(size_t)(val)
60 _rtld_tls_get_addr(void *tls
, size_t idx
, size_t offset
)
62 struct tls_tcb
*tcb
= tls
;
63 void **dtv
, **new_dtv
;
66 _rtld_exclusive_enter(&mask
);
70 if (__predict_false(DTV_GENERATION(dtv
) != _rtld_tls_dtv_generation
)) {
71 size_t to_copy
= DTV_MAX_INDEX(dtv
);
73 new_dtv
= xcalloc((2 + _rtld_tls_max_index
) * sizeof(*dtv
));
75 if (to_copy
> _rtld_tls_max_index
)
76 to_copy
= _rtld_tls_max_index
;
77 memcpy(new_dtv
+ 1, dtv
+ 1, to_copy
* sizeof(*dtv
));
79 dtv
= tcb
->tcb_dtv
= new_dtv
;
80 SET_DTV_MAX_INDEX(dtv
, _rtld_tls_max_index
);
81 SET_DTV_GENERATION(dtv
, _rtld_tls_dtv_generation
);
84 if (__predict_false(dtv
[idx
] == NULL
))
85 dtv
[idx
] = _rtld_tls_module_allocate(idx
);
87 _rtld_exclusive_exit(&mask
);
89 return (uint8_t *)dtv
[idx
] + offset
;
93 _rtld_tls_initial_allocation(void)
97 _rtld_tls_static_space
= _rtld_tls_static_offset
+
98 RTLD_STATIC_TLS_RESERVATION
;
100 #ifndef __HAVE_TLS_VARIANT_I
101 _rtld_tls_static_space
= roundup2(_rtld_tls_static_space
,
104 dbg(("_rtld_tls_static_space %zu", _rtld_tls_static_space
));
106 tcb
= _rtld_tls_allocate_locked();
107 #ifdef __HAVE___LWP_SETTCB
111 * Save the tcb pointer so that libc can retrieve it. Older
112 * crt0 will obliterate r2 so there is code in libc to restore it.
114 _lwp_setprivate(tcb
);
117 _lwp_setprivate(tcb
);
121 static struct tls_tcb
*
122 _rtld_tls_allocate_locked(void)
128 p
= xcalloc(_rtld_tls_static_space
+ sizeof(struct tls_tcb
));
129 #ifdef __HAVE_TLS_VARIANT_I
130 tcb
= (struct tls_tcb
*)p
;
131 p
+= sizeof(struct tls_tcb
);
133 p
+= _rtld_tls_static_space
;
134 tcb
= (struct tls_tcb
*)p
;
137 dbg(("tcb %p", tcb
));
138 tcb
->tcb_dtv
= xcalloc(sizeof(*tcb
->tcb_dtv
) * (2 + _rtld_tls_max_index
));
140 SET_DTV_MAX_INDEX(tcb
->tcb_dtv
, _rtld_tls_max_index
);
141 SET_DTV_GENERATION(tcb
->tcb_dtv
, _rtld_tls_dtv_generation
);
143 for (obj
= _rtld_objlist
; obj
!= NULL
; obj
= obj
->next
) {
144 if (obj
->tlsinitsize
&& obj
->tls_done
) {
145 #ifdef __HAVE_TLS_VARIANT_I
146 q
= p
+ obj
->tlsoffset
;
148 q
= p
- obj
->tlsoffset
;
150 dbg(("obj %p dtv %p tlsoffset %zu",
151 obj
, q
, obj
->tlsoffset
));
152 memcpy(q
, obj
->tlsinit
, obj
->tlsinitsize
);
153 tcb
->tcb_dtv
[obj
->tlsindex
] = q
;
161 _rtld_tls_allocate(void)
166 _rtld_exclusive_enter(&mask
);
167 tcb
= _rtld_tls_allocate_locked();
168 _rtld_exclusive_exit(&mask
);
174 _rtld_tls_free(struct tls_tcb
*tcb
)
180 _rtld_exclusive_enter(&mask
);
182 max_index
= DTV_MAX_INDEX(tcb
->tcb_dtv
);
183 for (i
= 1; i
<= max_index
; ++i
)
184 xfree(tcb
->tcb_dtv
[i
]);
185 xfree(tcb
->tcb_dtv
- 1);
187 #ifdef __HAVE_TLS_VARIANT_I
190 p
= (uint8_t *)tcb
- _rtld_tls_static_space
;
194 _rtld_exclusive_exit(&mask
);
198 _rtld_tls_module_allocate(size_t idx
)
203 for (obj
= _rtld_objlist
; obj
!= NULL
; obj
= obj
->next
) {
204 if (obj
->tlsindex
== idx
)
208 _rtld_error("Module for TLS index %zu missing", idx
);
212 p
= xmalloc(obj
->tlssize
);
213 memcpy(p
, obj
->tlsinit
, obj
->tlsinitsize
);
214 memset(p
+ obj
->tlsinitsize
, 0, obj
->tlssize
- obj
->tlsinitsize
);
220 _rtld_tls_offset_allocate(Obj_Entry
*obj
)
222 size_t offset
, next_offset
;
226 if (obj
->tlssize
== 0) {
232 #ifdef __HAVE_TLS_VARIANT_I
233 offset
= roundup2(_rtld_tls_static_offset
, obj
->tlsalign
);
234 next_offset
= offset
+ obj
->tlssize
;
236 offset
= roundup2(_rtld_tls_static_offset
+ obj
->tlssize
,
238 next_offset
= offset
;
242 * Check if the static allocation was already done.
243 * This happens if dynamically loaded modules want to use
246 * XXX Keep an actual free list and callbacks for initialisation.
248 if (_rtld_tls_static_space
) {
249 if (obj
->tlsinitsize
) {
250 _rtld_error("%s: Use of initialized "
251 "Thread Local Storage with model initial-exec "
252 "and dlopen is not supported",
256 if (next_offset
> _rtld_tls_static_space
) {
257 _rtld_error("%s: No space available "
258 "for static Thread Local Storage",
263 obj
->tlsoffset
= offset
;
264 _rtld_tls_static_offset
= next_offset
;
271 _rtld_tls_offset_free(Obj_Entry
*obj
)
281 #ifdef __HAVE_COMMON___TLS_GET_ADDR
283 * The fast path is access to an already allocated DTV entry.
284 * This checks the current limit and the entry without needing any
285 * locking. Entries are only freed on dlclose() and it is an application
286 * bug if code of the module is still running at that point.
289 __tls_get_addr(void *arg_
)
291 size_t *arg
= (size_t *)arg_
;
293 #ifdef __HAVE___LWP_GETTCB_FAST
294 struct tls_tcb
* const tcb
= __lwp_gettcb_fast();
296 struct tls_tcb
* const tcb
= __lwp_getprivate_fast();
298 size_t idx
= arg
[0], offset
= arg
[1] + TLS_DTV_OFFSET
;
302 if (__predict_true(idx
< DTV_MAX_INDEX(dtv
) && dtv
[idx
] != NULL
))
303 return (uint8_t *)dtv
[idx
] + offset
;
305 return _rtld_tls_get_addr(tcb
, idx
, offset
);
309 #endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */