1 /* $NetBSD: tls.c,v 1.7 2011/04/23 16:40:08 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.7 2011/04/23 16:40:08 joerg Exp $");
34 #include <sys/param.h>
35 #include <sys/ucontext.h>
40 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
42 static struct tls_tcb
*_rtld_tls_allocate_locked(void);
44 #ifndef TLS_DTV_OFFSET
45 #define TLS_DTV_OFFSET 0
48 static size_t _rtld_tls_static_space
; /* Static TLS space allocated */
49 static size_t _rtld_tls_static_offset
; /* Next offset for static TLS to use */
50 size_t _rtld_tls_dtv_generation
= 1;
51 size_t _rtld_tls_max_index
= 1;
53 #define DTV_GENERATION(dtv) ((size_t)((dtv)[0]))
54 #define DTV_MAX_INDEX(dtv) ((size_t)((dtv)[-1]))
55 #define SET_DTV_GENERATION(dtv, val) (dtv)[0] = (void *)(size_t)(val)
56 #define SET_DTV_MAX_INDEX(dtv, val) (dtv)[-1] = (void *)(size_t)(val)
59 _rtld_tls_get_addr(void *tls
, size_t idx
, size_t offset
)
61 struct tls_tcb
*tcb
= tls
;
62 void **dtv
, **new_dtv
;
65 _rtld_exclusive_enter(&mask
);
69 if (__predict_false(DTV_GENERATION(dtv
) != _rtld_tls_dtv_generation
)) {
70 size_t to_copy
= DTV_MAX_INDEX(dtv
);
72 new_dtv
= xcalloc((2 + _rtld_tls_max_index
) * sizeof(*dtv
));
74 if (to_copy
> _rtld_tls_max_index
)
75 to_copy
= _rtld_tls_max_index
;
76 memcpy(new_dtv
+ 1, dtv
+ 1, to_copy
* sizeof(*dtv
));
78 dtv
= tcb
->tcb_dtv
= new_dtv
;
79 SET_DTV_MAX_INDEX(dtv
, _rtld_tls_max_index
);
80 SET_DTV_GENERATION(dtv
, _rtld_tls_dtv_generation
);
83 if (__predict_false(dtv
[idx
] == NULL
))
84 dtv
[idx
] = _rtld_tls_module_allocate(idx
);
86 _rtld_exclusive_exit(&mask
);
88 return (uint8_t *)dtv
[idx
] + offset
;
92 _rtld_tls_initial_allocation(void)
96 _rtld_tls_static_space
= _rtld_tls_static_offset
+
97 RTLD_STATIC_TLS_RESERVATION
;
99 #ifndef __HAVE_TLS_VARIANT_I
100 _rtld_tls_static_space
= roundup2(_rtld_tls_static_space
,
104 tcb
= _rtld_tls_allocate_locked();
105 #ifdef __HAVE___LWP_SETTCB
109 * Save the tcb pointer so that libc can retrieve it. Older
110 * crt0 will obliterate r2 so there is code in libc to restore it.
112 _lwp_setprivate(tcb
);
115 _lwp_setprivate(tcb
);
119 static struct tls_tcb
*
120 _rtld_tls_allocate_locked(void)
126 p
= xcalloc(_rtld_tls_static_space
+ sizeof(struct tls_tcb
));
127 #ifdef __HAVE_TLS_VARIANT_I
128 tcb
= (struct tls_tcb
*)p
;
129 p
+= sizeof(struct tls_tcb
);
131 p
+= _rtld_tls_static_space
;
132 tcb
= (struct tls_tcb
*)p
;
135 tcb
->tcb_dtv
= xcalloc(sizeof(*tcb
->tcb_dtv
) * (2 + _rtld_tls_max_index
));
137 SET_DTV_MAX_INDEX(tcb
->tcb_dtv
, _rtld_tls_max_index
);
138 SET_DTV_GENERATION(tcb
->tcb_dtv
, _rtld_tls_dtv_generation
);
140 for (obj
= _rtld_objlist
; obj
!= NULL
; obj
= obj
->next
) {
142 #ifdef __HAVE_TLS_VARIANT_I
143 q
= p
+ obj
->tlsoffset
;
145 q
= p
- obj
->tlsoffset
;
147 memcpy(q
, obj
->tlsinit
, obj
->tlsinitsize
);
148 tcb
->tcb_dtv
[obj
->tlsindex
] = q
;
156 _rtld_tls_allocate(void)
161 _rtld_exclusive_enter(&mask
);
162 tcb
= _rtld_tls_allocate_locked();
163 _rtld_exclusive_exit(&mask
);
169 _rtld_tls_free(struct tls_tcb
*tcb
)
175 _rtld_exclusive_enter(&mask
);
177 max_index
= DTV_MAX_INDEX(tcb
->tcb_dtv
);
178 for (i
= 1; i
<= max_index
; ++i
)
179 xfree(tcb
->tcb_dtv
[i
]);
180 xfree(tcb
->tcb_dtv
- 1);
182 #ifdef __HAVE_TLS_VARIANT_I
185 p
= (uint8_t *)tcb
- _rtld_tls_static_space
;
189 _rtld_exclusive_exit(&mask
);
193 _rtld_tls_module_allocate(size_t idx
)
198 for (obj
= _rtld_objlist
; obj
!= NULL
; obj
= obj
->next
) {
199 if (obj
->tlsindex
== idx
)
203 _rtld_error("Module for TLS index %zu missing", idx
);
207 p
= xmalloc(obj
->tlssize
);
208 memcpy(p
, obj
->tlsinit
, obj
->tlsinitsize
);
209 memset(p
+ obj
->tlsinitsize
, 0, obj
->tlssize
- obj
->tlsinitsize
);
215 _rtld_tls_offset_allocate(Obj_Entry
*obj
)
217 size_t offset
, next_offset
;
221 if (obj
->tlssize
== 0) {
227 #ifdef __HAVE_TLS_VARIANT_I
228 offset
= roundup2(_rtld_tls_static_offset
, obj
->tlsalign
);
229 next_offset
= offset
+ obj
->tlssize
;
231 offset
= roundup2(_rtld_tls_static_offset
+ obj
->tlssize
,
233 next_offset
= offset
;
237 * Check if the static allocation was already done.
238 * This happens if dynamically loaded modules want to use
241 * XXX Keep an actual free list and callbacks for initialisation.
243 if (_rtld_tls_static_space
) {
244 if (obj
->tlsinitsize
) {
245 _rtld_error("%s: Use of initialized "
246 "Thread Local Storage with model initial-exec "
247 "and dlopen is not supported",
251 if (next_offset
> _rtld_tls_static_space
) {
252 _rtld_error("%s: No space available "
253 "for static Thread Local Storage",
258 obj
->tlsoffset
= offset
;
259 _rtld_tls_static_offset
= next_offset
;
266 _rtld_tls_offset_free(Obj_Entry
*obj
)
276 #ifdef __HAVE_COMMON___TLS_GET_ADDR
278 * The fast path is access to an already allocated DTV entry.
279 * This checks the current limit and the entry without needing any
280 * locking. Entries are only freed on dlclose() and it is an application
281 * bug if code of the module is still running at that point.
284 __tls_get_addr(void *arg_
)
286 size_t *arg
= (size_t *)arg_
;
288 #ifdef __HAVE___LWP_GETTCB_FAST
289 struct tls_tcb
* const tcb
= __lwp_gettcb_fast();
291 struct tls_tcb
* const tcb
= __lwp_getprivate_fast();
293 size_t idx
= arg
[0], offset
= arg
[1] + TLS_DTV_OFFSET
;
297 if (__predict_true(idx
< DTV_MAX_INDEX(dtv
) && dtv
[idx
] != NULL
))
298 return (uint8_t *)dtv
[idx
] + offset
;
300 return _rtld_tls_get_addr(tcb
, idx
, offset
);
304 #endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */