1 /*- 2 * Copyright (c) 2004 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/lib/libc/gen/tls.c,v 1.7 2005/03/01 23:42:00 davidxu Exp $ 27 * $DragonFly: src/lib/libc/gen/tls.c,v 1.2 2005/03/09 12:06:31 davidxu Exp $ 28 */ 29 30 /* 31 * Define stubs for TLS internals so that programs and libraries can 32 * link. These functions will be replaced by functional versions at 33 * runtime from ld-elf.so.1. 34 */ 35 36 #include <sys/cdefs.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <elf.h> 40 #include <assert.h> 41 42 #include "libc_private.h" 43 44 __weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 45 __weak_reference(__libc_free_tls, _rtld_free_tls); 46 #ifdef __i386__ 47 __weak_reference(___libc_tls_get_addr, ___tls_get_addr); 48 #endif 49 __weak_reference(__libc_tls_get_addr, __tls_get_addr); 50 51 void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 52 void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 53 void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 54 void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 55 56 #if defined(__ia64__) || defined(__powerpc__) 57 #define TLS_VARIANT_I 58 #endif 59 #if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \ 60 defined(__arm__) 61 #define TLS_VARIANT_II 62 #endif 63 64 #ifndef PIC 65 66 #define round(size, align) \ 67 (((size) + (align) - 1) & ~((align) - 1)) 68 69 static size_t tls_static_space; 70 static size_t tls_init_size; 71 #ifdef TLS_VARIANT_I 72 static size_t tls_init_offset; 73 #endif 74 static void *tls_init; 75 #endif 76 77 #ifdef __i386__ 78 79 /* GNU ABI */ 80 81 void *___libc_tls_get_addr(void *ti) __attribute__((__regparm__(1))); 82 83 __attribute__((__regparm__(1))) 84 void * 85 ___libc_tls_get_addr(void *ti __unused) 86 { 87 return (0); 88 } 89 90 #endif 91 92 void *__libc_tls_get_addr(void *ti); 93 void * 94 __libc_tls_get_addr(void *ti __unused) 95 { 96 return (0); 97 } 98 99 #ifndef PIC 100 101 #ifdef TLS_VARIANT_I 102 103 /* 104 * Free Static TLS using the Variant I method. 105 */ 106 void 107 __libc_free_tls(void *tls, size_t tcbsize __unused, size_t tcbalign __unused) 108 { 109 Elf_Addr* dtv; 110 111 dtv = ((Elf_Addr**)tls)[0]; 112 free(tls); 113 free(dtv); 114 } 115 116 /* 117 * Allocate Static TLS using the Variant I method. 118 */ 119 void * 120 __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign __unused) 121 { 122 size_t size; 123 char *tls; 124 Elf_Addr *dtv; 125 126 size = tls_static_space; 127 if (size < tcbsize) 128 size = tcbsize; 129 130 tls = malloc(size); 131 dtv = malloc(3 * sizeof(Elf_Addr)); 132 133 *(Elf_Addr**) tls = dtv; 134 135 dtv[0] = 1; 136 dtv[1] = 1; 137 dtv[2] = (Elf_Addr)(tls + tls_init_offset); 138 if (oldtls) { 139 /* 140 * Copy the static TLS block over whole. 141 */ 142 memcpy(tls + tls_init_offset, 143 (char*) oldtls + tls_init_offset, 144 tls_static_space - tls_init_offset); 145 146 /* 147 * We assume that this block was the one we created with 148 * allocate_initial_tls(). 149 */ 150 _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 151 } else { 152 memcpy(tls + tls_init_offset, tls_init, tls_init_size); 153 memset(tls + tls_init_offset + tls_init_size, 154 0, tls_static_space - tls_init_size); 155 } 156 157 return tls; 158 } 159 160 #endif 161 162 #ifdef TLS_VARIANT_II 163 164 /* 165 * Free Static TLS using the Variant II method. 166 */ 167 void 168 __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 169 { 170 size_t size; 171 Elf_Addr* dtv; 172 Elf_Addr tlsstart, tlsend; 173 174 /* 175 * Figure out the size of the initial TLS block so that we can 176 * find stuff which ___tls_get_addr() allocated dynamically. 177 */ 178 size = round(tls_static_space, tcbalign); 179 180 dtv = ((Elf_Addr**)tcb)[1]; 181 tlsend = (Elf_Addr) tcb; 182 tlsstart = tlsend - size; 183 free((void*) tlsstart); 184 free(dtv); 185 } 186 187 /* 188 * Allocate Static TLS using the Variant II method. 189 */ 190 void * 191 __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 192 { 193 size_t size; 194 char *tls; 195 Elf_Addr *dtv; 196 Elf_Addr segbase, oldsegbase; 197 198 size = round(tls_static_space, tcbalign); 199 200 assert(tcbsize >= 2*sizeof(Elf_Addr)); 201 tls = malloc(size + tcbsize); 202 dtv = malloc(3 * sizeof(Elf_Addr)); 203 204 segbase = (Elf_Addr)(tls + size); 205 ((Elf_Addr*)segbase)[0] = segbase; 206 ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 207 208 dtv[0] = 1; 209 dtv[1] = 1; 210 dtv[2] = segbase - tls_static_space; 211 212 if (oldtls) { 213 /* 214 * Copy the static TLS block over whole. 215 */ 216 oldsegbase = (Elf_Addr) oldtls; 217 memcpy((void *)(segbase - tls_static_space), 218 (const void *)(oldsegbase - tls_static_space), 219 tls_static_space); 220 221 /* 222 * We assume that this block was the one we created with 223 * allocate_initial_tls(). 224 */ 225 _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 226 } else { 227 memcpy((void *)(segbase - tls_static_space), 228 tls_init, tls_init_size); 229 memset((void *)(segbase - tls_static_space + tls_init_size), 230 0, tls_static_space - tls_init_size); 231 } 232 233 return (void*) segbase; 234 } 235 236 #endif /* TLS_VARIANT_II */ 237 238 #else 239 240 void * 241 __libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 242 size_t tcbalign __unused) 243 { 244 return (0); 245 } 246 247 void 248 __libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 249 size_t tcbalign __unused) 250 { 251 } 252 253 #endif /* PIC */ 254 255 extern char **environ; 256 257 void 258 _init_tls() 259 { 260 #ifndef PIC 261 Elf_Addr *sp; 262 Elf_Auxinfo *aux, *auxp; 263 Elf_Phdr *phdr; 264 size_t phent, phnum; 265 int i; 266 void *tls; 267 268 sp = (Elf_Addr *) environ; 269 while (*sp++ != 0) 270 ; 271 aux = (Elf_Auxinfo *) sp; 272 phdr = 0; 273 phent = phnum = 0; 274 for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 275 switch (auxp->a_type) { 276 case AT_PHDR: 277 phdr = auxp->a_un.a_ptr; 278 break; 279 280 case AT_PHENT: 281 phent = auxp->a_un.a_val; 282 break; 283 284 case AT_PHNUM: 285 phnum = auxp->a_un.a_val; 286 break; 287 } 288 } 289 if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0) 290 return; 291 292 for (i = 0; (unsigned)i < phnum; i++) { 293 if (phdr[i].p_type == PT_TLS) { 294 #ifdef TLS_VARIANT_I 295 tls_static_space = round(2*sizeof(Elf_Addr), 296 phdr[i].p_align) + phdr[i].p_memsz; 297 tls_init_offset = round(2*sizeof(Elf_Addr), 298 phdr[i].p_align); 299 #else 300 tls_static_space = round(phdr[i].p_memsz, 301 phdr[i].p_align); 302 #endif 303 tls_init_size = phdr[i].p_filesz; 304 tls_init = (void*) phdr[i].p_vaddr; 305 } 306 } 307 308 tls = _rtld_allocate_tls(NULL, 2*sizeof(Elf_Addr), 309 sizeof(Elf_Addr)); 310 311 _set_tp(tls, 2 * sizeof(Elf_Addr)); 312 #endif 313 } 314