1 /* $NetBSD: tls.c,v 1.10 2014/12/14 23:49:17 chs 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.10 2014/12/14 23:49:17 chs Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/ucontext.h> 36 #include <lwp.h> 37 #include <string.h> 38 #include "debug.h" 39 #include "rtld.h" 40 41 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 42 43 static struct tls_tcb *_rtld_tls_allocate_locked(void); 44 45 #ifndef TLS_DTV_OFFSET 46 #define TLS_DTV_OFFSET 0 47 #endif 48 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; 53 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) 58 59 void * 60 _rtld_tls_get_addr(void *tls, size_t idx, size_t offset) 61 { 62 struct tls_tcb *tcb = tls; 63 void **dtv, **new_dtv; 64 sigset_t mask; 65 66 _rtld_exclusive_enter(&mask); 67 68 dtv = tcb->tcb_dtv; 69 70 if (__predict_false(DTV_GENERATION(dtv) != _rtld_tls_dtv_generation)) { 71 size_t to_copy = DTV_MAX_INDEX(dtv); 72 73 new_dtv = xcalloc((2 + _rtld_tls_max_index) * sizeof(*dtv)); 74 ++new_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)); 78 xfree(dtv - 1); 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); 82 } 83 84 if (__predict_false(dtv[idx] == NULL)) 85 dtv[idx] = _rtld_tls_module_allocate(idx); 86 87 _rtld_exclusive_exit(&mask); 88 89 return (uint8_t *)dtv[idx] + offset; 90 } 91 92 void 93 _rtld_tls_initial_allocation(void) 94 { 95 struct tls_tcb *tcb; 96 97 _rtld_tls_static_space = _rtld_tls_static_offset + 98 RTLD_STATIC_TLS_RESERVATION; 99 100 #ifndef __HAVE_TLS_VARIANT_I 101 _rtld_tls_static_space = roundup2(_rtld_tls_static_space, 102 sizeof(void *)); 103 #endif 104 dbg(("_rtld_tls_static_space %zu", _rtld_tls_static_space)); 105 106 tcb = _rtld_tls_allocate_locked(); 107 #ifdef __HAVE___LWP_SETTCB 108 __lwp_settcb(tcb); 109 #else 110 _lwp_setprivate(tcb); 111 #endif 112 } 113 114 static struct tls_tcb * 115 _rtld_tls_allocate_locked(void) 116 { 117 Obj_Entry *obj; 118 struct tls_tcb *tcb; 119 uint8_t *p, *q; 120 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); 125 #else 126 p += _rtld_tls_static_space; 127 tcb = (struct tls_tcb *)p; 128 tcb->tcb_self = tcb; 129 #endif 130 dbg(("tcb %p", tcb)); 131 tcb->tcb_dtv = xcalloc(sizeof(*tcb->tcb_dtv) * (2 + _rtld_tls_max_index)); 132 ++tcb->tcb_dtv; 133 SET_DTV_MAX_INDEX(tcb->tcb_dtv, _rtld_tls_max_index); 134 SET_DTV_GENERATION(tcb->tcb_dtv, _rtld_tls_dtv_generation); 135 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; 140 #else 141 q = p - obj->tlsoffset; 142 #endif 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; 147 } 148 } 149 150 return tcb; 151 } 152 153 struct tls_tcb * 154 _rtld_tls_allocate(void) 155 { 156 struct tls_tcb *tcb; 157 sigset_t mask; 158 159 _rtld_exclusive_enter(&mask); 160 tcb = _rtld_tls_allocate_locked(); 161 _rtld_exclusive_exit(&mask); 162 163 return tcb; 164 } 165 166 void 167 _rtld_tls_free(struct tls_tcb *tcb) 168 { 169 size_t i, max_index; 170 uint8_t *p; 171 sigset_t mask; 172 173 _rtld_exclusive_enter(&mask); 174 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); 179 180 #ifdef __HAVE_TLS_VARIANT_I 181 p = (uint8_t *)tcb; 182 #else 183 p = (uint8_t *)tcb - _rtld_tls_static_space; 184 #endif 185 xfree(p); 186 187 _rtld_exclusive_exit(&mask); 188 } 189 190 void * 191 _rtld_tls_module_allocate(size_t idx) 192 { 193 Obj_Entry *obj; 194 uint8_t *p; 195 196 for (obj = _rtld_objlist; obj != NULL; obj = obj->next) { 197 if (obj->tlsindex == idx) 198 break; 199 } 200 if (obj == NULL) { 201 _rtld_error("Module for TLS index %zu missing", idx); 202 _rtld_die(); 203 } 204 205 p = xmalloc(obj->tlssize); 206 memcpy(p, obj->tlsinit, obj->tlsinitsize); 207 memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize); 208 209 return p; 210 } 211 212 int 213 _rtld_tls_offset_allocate(Obj_Entry *obj) 214 { 215 size_t offset, next_offset; 216 217 if (obj->tls_done) 218 return 0; 219 if (obj->tlssize == 0) { 220 obj->tlsoffset = 0; 221 obj->tls_done = 1; 222 return 0; 223 } 224 225 #ifdef __HAVE_TLS_VARIANT_I 226 offset = roundup2(_rtld_tls_static_offset, obj->tlsalign); 227 next_offset = offset + obj->tlssize; 228 #else 229 offset = roundup2(_rtld_tls_static_offset + obj->tlssize, 230 obj->tlsalign); 231 next_offset = offset; 232 #endif 233 234 /* 235 * Check if the static allocation was already done. 236 * This happens if dynamically loaded modules want to use 237 * static TLS space. 238 * 239 * XXX Keep an actual free list and callbacks for initialisation. 240 */ 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", 246 obj->path); 247 return -1; 248 } 249 if (next_offset > _rtld_tls_static_space) { 250 _rtld_error("%s: No space available " 251 "for static Thread Local Storage", 252 obj->path); 253 return -1; 254 } 255 } 256 obj->tlsoffset = offset; 257 _rtld_tls_static_offset = next_offset; 258 obj->tls_done = 1; 259 260 return 0; 261 } 262 263 void 264 _rtld_tls_offset_free(Obj_Entry *obj) 265 { 266 267 /* 268 * XXX See above. 269 */ 270 obj->tls_done = 0; 271 return; 272 } 273 274 #ifdef __HAVE_COMMON___TLS_GET_ADDR 275 /* 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. 280 */ 281 void * 282 __tls_get_addr(void *arg_) 283 { 284 size_t *arg = (size_t *)arg_; 285 void **dtv; 286 #ifdef __HAVE___LWP_GETTCB_FAST 287 struct tls_tcb * const tcb = __lwp_gettcb_fast(); 288 #else 289 struct tls_tcb * const tcb = __lwp_getprivate_fast(); 290 #endif 291 size_t idx = arg[0], offset = arg[1] + TLS_DTV_OFFSET; 292 293 dtv = tcb->tcb_dtv; 294 295 if (__predict_true(idx < DTV_MAX_INDEX(dtv) && dtv[idx] != NULL)) 296 return (uint8_t *)dtv[idx] + offset; 297 298 return _rtld_tls_get_addr(tcb, idx, offset); 299 } 300 #endif 301 302 #endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */ 303