1 /* $NetBSD: tls.c,v 1.11 2017/07/13 14:10:38 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.11 2017/07/13 14:10:38 joerg 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->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 if (obj->tlsinitsize) 146 memcpy(q, obj->tlsinit, obj->tlsinitsize); 147 tcb->tcb_dtv[obj->tlsindex] = q; 148 } 149 } 150 151 return tcb; 152 } 153 154 struct tls_tcb * 155 _rtld_tls_allocate(void) 156 { 157 struct tls_tcb *tcb; 158 sigset_t mask; 159 160 _rtld_exclusive_enter(&mask); 161 tcb = _rtld_tls_allocate_locked(); 162 _rtld_exclusive_exit(&mask); 163 164 return tcb; 165 } 166 167 void 168 _rtld_tls_free(struct tls_tcb *tcb) 169 { 170 size_t i, max_index; 171 uint8_t *p, *p_end; 172 sigset_t mask; 173 174 _rtld_exclusive_enter(&mask); 175 176 #ifdef __HAVE_TLS_VARIANT_I 177 p = (uint8_t *)tcb; 178 #else 179 p = (uint8_t *)tcb - _rtld_tls_static_space; 180 #endif 181 p_end = p + _rtld_tls_static_space; 182 183 max_index = DTV_MAX_INDEX(tcb->tcb_dtv); 184 for (i = 1; i <= max_index; ++i) { 185 if ((uint8_t *)tcb->tcb_dtv[i] < p || 186 (uint8_t *)tcb->tcb_dtv[i] >= p_end) 187 xfree(tcb->tcb_dtv[i]); 188 } 189 xfree(tcb->tcb_dtv - 1); 190 xfree(p); 191 192 _rtld_exclusive_exit(&mask); 193 } 194 195 void * 196 _rtld_tls_module_allocate(size_t idx) 197 { 198 Obj_Entry *obj; 199 uint8_t *p; 200 201 for (obj = _rtld_objlist; obj != NULL; obj = obj->next) { 202 if (obj->tlsindex == idx) 203 break; 204 } 205 if (obj == NULL) { 206 _rtld_error("Module for TLS index %zu missing", idx); 207 _rtld_die(); 208 } 209 210 p = xmalloc(obj->tlssize); 211 memcpy(p, obj->tlsinit, obj->tlsinitsize); 212 memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize); 213 214 return p; 215 } 216 217 int 218 _rtld_tls_offset_allocate(Obj_Entry *obj) 219 { 220 size_t offset, next_offset; 221 222 if (obj->tls_done) 223 return 0; 224 if (obj->tlssize == 0) { 225 obj->tlsoffset = 0; 226 obj->tls_done = 1; 227 return 0; 228 } 229 230 #ifdef __HAVE_TLS_VARIANT_I 231 offset = roundup2(_rtld_tls_static_offset, obj->tlsalign); 232 next_offset = offset + obj->tlssize; 233 #else 234 offset = roundup2(_rtld_tls_static_offset + obj->tlssize, 235 obj->tlsalign); 236 next_offset = offset; 237 #endif 238 239 /* 240 * Check if the static allocation was already done. 241 * This happens if dynamically loaded modules want to use 242 * static TLS space. 243 * 244 * XXX Keep an actual free list and callbacks for initialisation. 245 */ 246 if (_rtld_tls_static_space) { 247 if (obj->tlsinitsize) { 248 _rtld_error("%s: Use of initialized " 249 "Thread Local Storage with model initial-exec " 250 "and dlopen is not supported", 251 obj->path); 252 return -1; 253 } 254 if (next_offset > _rtld_tls_static_space) { 255 _rtld_error("%s: No space available " 256 "for static Thread Local Storage", 257 obj->path); 258 return -1; 259 } 260 } 261 obj->tlsoffset = offset; 262 _rtld_tls_static_offset = next_offset; 263 obj->tls_done = 1; 264 265 return 0; 266 } 267 268 void 269 _rtld_tls_offset_free(Obj_Entry *obj) 270 { 271 272 /* 273 * XXX See above. 274 */ 275 obj->tls_done = 0; 276 return; 277 } 278 279 #ifdef __HAVE_COMMON___TLS_GET_ADDR 280 /* 281 * The fast path is access to an already allocated DTV entry. 282 * This checks the current limit and the entry without needing any 283 * locking. Entries are only freed on dlclose() and it is an application 284 * bug if code of the module is still running at that point. 285 */ 286 void * 287 __tls_get_addr(void *arg_) 288 { 289 size_t *arg = (size_t *)arg_; 290 void **dtv; 291 #ifdef __HAVE___LWP_GETTCB_FAST 292 struct tls_tcb * const tcb = __lwp_gettcb_fast(); 293 #else 294 struct tls_tcb * const tcb = __lwp_getprivate_fast(); 295 #endif 296 size_t idx = arg[0], offset = arg[1] + TLS_DTV_OFFSET; 297 298 dtv = tcb->tcb_dtv; 299 300 if (__predict_true(idx < DTV_MAX_INDEX(dtv) && dtv[idx] != NULL)) 301 return (uint8_t *)dtv[idx] + offset; 302 303 return _rtld_tls_get_addr(tcb, idx, offset); 304 } 305 #endif 306 307 #endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */ 308