1 /* $NetBSD: tls.c,v 1.7 2011/04/23 16:40:08 joerg Exp $ */ 2 /*- 3 * Copyright (c) 2011 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Joerg Sonnenberger. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 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. 17 * 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. 29 */ 30 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: tls.c,v 1.7 2011/04/23 16:40:08 joerg Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/ucontext.h> 36 #include <lwp.h> 37 #include <string.h> 38 #include "rtld.h" 39 40 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 41 42 static struct tls_tcb *_rtld_tls_allocate_locked(void); 43 44 #ifndef TLS_DTV_OFFSET 45 #define TLS_DTV_OFFSET 0 46 #endif 47 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; 52 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) 57 58 void * 59 _rtld_tls_get_addr(void *tls, size_t idx, size_t offset) 60 { 61 struct tls_tcb *tcb = tls; 62 void **dtv, **new_dtv; 63 sigset_t mask; 64 65 _rtld_exclusive_enter(&mask); 66 67 dtv = tcb->tcb_dtv; 68 69 if (__predict_false(DTV_GENERATION(dtv) != _rtld_tls_dtv_generation)) { 70 size_t to_copy = DTV_MAX_INDEX(dtv); 71 72 new_dtv = xcalloc((2 + _rtld_tls_max_index) * sizeof(*dtv)); 73 ++new_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)); 77 xfree(dtv - 1); 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); 81 } 82 83 if (__predict_false(dtv[idx] == NULL)) 84 dtv[idx] = _rtld_tls_module_allocate(idx); 85 86 _rtld_exclusive_exit(&mask); 87 88 return (uint8_t *)dtv[idx] + offset; 89 } 90 91 void 92 _rtld_tls_initial_allocation(void) 93 { 94 struct tls_tcb *tcb; 95 96 _rtld_tls_static_space = _rtld_tls_static_offset + 97 RTLD_STATIC_TLS_RESERVATION; 98 99 #ifndef __HAVE_TLS_VARIANT_I 100 _rtld_tls_static_space = roundup2(_rtld_tls_static_space, 101 sizeof(void *)); 102 #endif 103 104 tcb = _rtld_tls_allocate_locked(); 105 #ifdef __HAVE___LWP_SETTCB 106 __lwp_settcb(tcb); 107 #ifdef __powerpc__ 108 /* 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. 111 */ 112 _lwp_setprivate(tcb); 113 #endif 114 #else 115 _lwp_setprivate(tcb); 116 #endif 117 } 118 119 static struct tls_tcb * 120 _rtld_tls_allocate_locked(void) 121 { 122 Obj_Entry *obj; 123 struct tls_tcb *tcb; 124 uint8_t *p, *q; 125 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); 130 #else 131 p += _rtld_tls_static_space; 132 tcb = (struct tls_tcb *)p; 133 tcb->tcb_self = tcb; 134 #endif 135 tcb->tcb_dtv = xcalloc(sizeof(*tcb->tcb_dtv) * (2 + _rtld_tls_max_index)); 136 ++tcb->tcb_dtv; 137 SET_DTV_MAX_INDEX(tcb->tcb_dtv, _rtld_tls_max_index); 138 SET_DTV_GENERATION(tcb->tcb_dtv, _rtld_tls_dtv_generation); 139 140 for (obj = _rtld_objlist; obj != NULL; obj = obj->next) { 141 if (obj->tlssize) { 142 #ifdef __HAVE_TLS_VARIANT_I 143 q = p + obj->tlsoffset; 144 #else 145 q = p - obj->tlsoffset; 146 #endif 147 memcpy(q, obj->tlsinit, obj->tlsinitsize); 148 tcb->tcb_dtv[obj->tlsindex] = q; 149 } 150 } 151 152 return tcb; 153 } 154 155 struct tls_tcb * 156 _rtld_tls_allocate(void) 157 { 158 struct tls_tcb *tcb; 159 sigset_t mask; 160 161 _rtld_exclusive_enter(&mask); 162 tcb = _rtld_tls_allocate_locked(); 163 _rtld_exclusive_exit(&mask); 164 165 return tcb; 166 } 167 168 void 169 _rtld_tls_free(struct tls_tcb *tcb) 170 { 171 size_t i, max_index; 172 uint8_t *p; 173 sigset_t mask; 174 175 _rtld_exclusive_enter(&mask); 176 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); 181 182 #ifdef __HAVE_TLS_VARIANT_I 183 p = (uint8_t *)tcb; 184 #else 185 p = (uint8_t *)tcb - _rtld_tls_static_space; 186 #endif 187 xfree(p); 188 189 _rtld_exclusive_exit(&mask); 190 } 191 192 void * 193 _rtld_tls_module_allocate(size_t idx) 194 { 195 Obj_Entry *obj; 196 uint8_t *p; 197 198 for (obj = _rtld_objlist; obj != NULL; obj = obj->next) { 199 if (obj->tlsindex == idx) 200 break; 201 } 202 if (obj == NULL) { 203 _rtld_error("Module for TLS index %zu missing", idx); 204 _rtld_die(); 205 } 206 207 p = xmalloc(obj->tlssize); 208 memcpy(p, obj->tlsinit, obj->tlsinitsize); 209 memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize); 210 211 return p; 212 } 213 214 int 215 _rtld_tls_offset_allocate(Obj_Entry *obj) 216 { 217 size_t offset, next_offset; 218 219 if (obj->tls_done) 220 return 0; 221 if (obj->tlssize == 0) { 222 obj->tlsoffset = 0; 223 obj->tls_done = 1; 224 return 0; 225 } 226 227 #ifdef __HAVE_TLS_VARIANT_I 228 offset = roundup2(_rtld_tls_static_offset, obj->tlsalign); 229 next_offset = offset + obj->tlssize; 230 #else 231 offset = roundup2(_rtld_tls_static_offset + obj->tlssize, 232 obj->tlsalign); 233 next_offset = offset; 234 #endif 235 236 /* 237 * Check if the static allocation was already done. 238 * This happens if dynamically loaded modules want to use 239 * static TLS space. 240 * 241 * XXX Keep an actual free list and callbacks for initialisation. 242 */ 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", 248 obj->path); 249 return -1; 250 } 251 if (next_offset > _rtld_tls_static_space) { 252 _rtld_error("%s: No space available " 253 "for static Thread Local Storage", 254 obj->path); 255 return -1; 256 } 257 } 258 obj->tlsoffset = offset; 259 _rtld_tls_static_offset = next_offset; 260 obj->tls_done = 1; 261 262 return 0; 263 } 264 265 void 266 _rtld_tls_offset_free(Obj_Entry *obj) 267 { 268 269 /* 270 * XXX See above. 271 */ 272 obj->tls_done = 0; 273 return; 274 } 275 276 #ifdef __HAVE_COMMON___TLS_GET_ADDR 277 /* 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. 282 */ 283 void * 284 __tls_get_addr(void *arg_) 285 { 286 size_t *arg = (size_t *)arg_; 287 void **dtv; 288 #ifdef __HAVE___LWP_GETTCB_FAST 289 struct tls_tcb * const tcb = __lwp_gettcb_fast(); 290 #else 291 struct tls_tcb * const tcb = __lwp_getprivate_fast(); 292 #endif 293 size_t idx = arg[0], offset = arg[1] + TLS_DTV_OFFSET; 294 295 dtv = tcb->tcb_dtv; 296 297 if (__predict_true(idx < DTV_MAX_INDEX(dtv) && dtv[idx] != NULL)) 298 return (uint8_t *)dtv[idx] + offset; 299 300 return _rtld_tls_get_addr(tcb, idx, offset); 301 } 302 #endif 303 304 #endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */ 305