1 /* $NetBSD: tls.c,v 1.10 2014/12/14 23:49:17 chs 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.10 2014/12/14 23:49:17 chs 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
110 _lwp_setprivate(tcb
);
114 static struct tls_tcb
*
115 _rtld_tls_allocate_locked(void)
121 p
= xcalloc(_rtld_tls_static_space
+ sizeof(struct tls_tcb
));
122 #ifdef __HAVE_TLS_VARIANT_I
123 tcb
= (struct tls_tcb
*)p
;
124 p
+= sizeof(struct tls_tcb
);
126 p
+= _rtld_tls_static_space
;
127 tcb
= (struct tls_tcb
*)p
;
130 dbg(("tcb %p", tcb
));
131 tcb
->tcb_dtv
= xcalloc(sizeof(*tcb
->tcb_dtv
) * (2 + _rtld_tls_max_index
));
133 SET_DTV_MAX_INDEX(tcb
->tcb_dtv
, _rtld_tls_max_index
);
134 SET_DTV_GENERATION(tcb
->tcb_dtv
, _rtld_tls_dtv_generation
);
136 for (obj
= _rtld_objlist
; obj
!= NULL
; obj
= obj
->next
) {
137 if (obj
->tlsinitsize
&& obj
->tls_done
) {
138 #ifdef __HAVE_TLS_VARIANT_I
139 q
= p
+ obj
->tlsoffset
;
141 q
= p
- obj
->tlsoffset
;
143 dbg(("obj %p dtv %p tlsoffset %zu",
144 obj
, q
, obj
->tlsoffset
));
145 memcpy(q
, obj
->tlsinit
, obj
->tlsinitsize
);
146 tcb
->tcb_dtv
[obj
->tlsindex
] = q
;
154 _rtld_tls_allocate(void)
159 _rtld_exclusive_enter(&mask
);
160 tcb
= _rtld_tls_allocate_locked();
161 _rtld_exclusive_exit(&mask
);
167 _rtld_tls_free(struct tls_tcb
*tcb
)
173 _rtld_exclusive_enter(&mask
);
175 max_index
= DTV_MAX_INDEX(tcb
->tcb_dtv
);
176 for (i
= 1; i
<= max_index
; ++i
)
177 xfree(tcb
->tcb_dtv
[i
]);
178 xfree(tcb
->tcb_dtv
- 1);
180 #ifdef __HAVE_TLS_VARIANT_I
183 p
= (uint8_t *)tcb
- _rtld_tls_static_space
;
187 _rtld_exclusive_exit(&mask
);
191 _rtld_tls_module_allocate(size_t idx
)
196 for (obj
= _rtld_objlist
; obj
!= NULL
; obj
= obj
->next
) {
197 if (obj
->tlsindex
== idx
)
201 _rtld_error("Module for TLS index %zu missing", idx
);
205 p
= xmalloc(obj
->tlssize
);
206 memcpy(p
, obj
->tlsinit
, obj
->tlsinitsize
);
207 memset(p
+ obj
->tlsinitsize
, 0, obj
->tlssize
- obj
->tlsinitsize
);
213 _rtld_tls_offset_allocate(Obj_Entry
*obj
)
215 size_t offset
, next_offset
;
219 if (obj
->tlssize
== 0) {
225 #ifdef __HAVE_TLS_VARIANT_I
226 offset
= roundup2(_rtld_tls_static_offset
, obj
->tlsalign
);
227 next_offset
= offset
+ obj
->tlssize
;
229 offset
= roundup2(_rtld_tls_static_offset
+ obj
->tlssize
,
231 next_offset
= offset
;
235 * Check if the static allocation was already done.
236 * This happens if dynamically loaded modules want to use
239 * XXX Keep an actual free list and callbacks for initialisation.
241 if (_rtld_tls_static_space
) {
242 if (obj
->tlsinitsize
) {
243 _rtld_error("%s: Use of initialized "
244 "Thread Local Storage with model initial-exec "
245 "and dlopen is not supported",
249 if (next_offset
> _rtld_tls_static_space
) {
250 _rtld_error("%s: No space available "
251 "for static Thread Local Storage",
256 obj
->tlsoffset
= offset
;
257 _rtld_tls_static_offset
= next_offset
;
264 _rtld_tls_offset_free(Obj_Entry
*obj
)
274 #ifdef __HAVE_COMMON___TLS_GET_ADDR
276 * The fast path is access to an already allocated DTV entry.
277 * This checks the current limit and the entry without needing any
278 * locking. Entries are only freed on dlclose() and it is an application
279 * bug if code of the module is still running at that point.
282 __tls_get_addr(void *arg_
)
284 size_t *arg
= (size_t *)arg_
;
286 #ifdef __HAVE___LWP_GETTCB_FAST
287 struct tls_tcb
* const tcb
= __lwp_gettcb_fast();
289 struct tls_tcb
* const tcb
= __lwp_getprivate_fast();
291 size_t idx
= arg
[0], offset
= arg
[1] + TLS_DTV_OFFSET
;
295 if (__predict_true(idx
< DTV_MAX_INDEX(dtv
) && dtv
[idx
] != NULL
))
296 return (uint8_t *)dtv
[idx
] + offset
;
298 return _rtld_tls_get_addr(tcb
, idx
, offset
);
302 #endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */