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$ 27 */ 28 29 /* 30 * Define stubs for TLS internals so that programs and libraries can 31 * link. These functions will be replaced by functional versions at 32 * runtime from ld-elf.so.1. 33 */ 34 35 #include <sys/cdefs.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <elf.h> 39 #include <assert.h> 40 41 #include "libc_private.h" 42 43 /* XXX not sure what variants to use for arm. */ 44 45 __weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 46 __weak_reference(__libc_free_tls, _rtld_free_tls); 47 48 #ifdef __i386__ 49 50 __weak_reference(___libc_tls_get_addr, ___tls_get_addr); 51 __attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *); 52 53 #endif 54 55 void * __libc_tls_get_addr(void *); 56 __weak_reference(__libc_tls_get_addr, __tls_get_addr); 57 58 void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 59 void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 60 void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 61 void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 62 63 #if defined(__ia64__) || defined(__alpha__) || defined(__powerpc__) 64 #define TLS_VARIANT_I 65 #endif 66 #if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \ 67 defined(__arm__) 68 #define TLS_VARIANT_II 69 #endif 70 71 #ifndef PIC 72 73 #define round(size, align) \ 74 (((size) + (align) - 1) & ~((align) - 1)) 75 76 static size_t tls_static_space; 77 static size_t tls_init_size; 78 #ifdef TLS_VARIANT_I 79 static size_t tls_init_offset; 80 #endif 81 static void *tls_init; 82 #endif 83 84 #ifdef __i386__ 85 86 /* GNU ABI */ 87 88 __attribute__((__regparm__(1))) 89 void * 90 ___libc_tls_get_addr(void *ti __unused) 91 { 92 return (0); 93 } 94 95 #endif 96 97 void * 98 __libc_tls_get_addr(void *ti __unused) 99 { 100 return (0); 101 } 102 103 #ifndef PIC 104 105 #ifdef TLS_VARIANT_I 106 107 /* 108 * Free Static TLS using the Variant I method. 109 */ 110 void 111 __libc_free_tls(void *tls, size_t tcbsize __unused, size_t tcbalign __unused) 112 { 113 Elf_Addr* dtv; 114 115 dtv = ((Elf_Addr**)tls)[0]; 116 free(tls); 117 free(dtv); 118 } 119 120 /* 121 * Allocate Static TLS using the Variant I method. 122 */ 123 void * 124 __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign __unused) 125 { 126 size_t size; 127 char *tls; 128 Elf_Addr *dtv; 129 130 size = tls_static_space; 131 if (size < tcbsize) 132 size = tcbsize; 133 134 tls = malloc(size); 135 dtv = malloc(3 * sizeof(Elf_Addr)); 136 137 *(Elf_Addr **) tls = dtv; 138 139 dtv[0] = 1; 140 dtv[1] = 1; 141 dtv[2] = (Elf_Addr)(tls + tls_init_offset); 142 if (oldtls) { 143 /* 144 * Copy the static TLS block over whole. 145 */ 146 memcpy(tls + tls_init_offset, 147 (char *)oldtls + tls_init_offset, 148 tls_static_space - tls_init_offset); 149 150 /* 151 * We assume that this block was the one we created with 152 * allocate_initial_tls(). 153 */ 154 _rtld_free_tls(oldtls, 2 * sizeof(Elf_Addr), sizeof(Elf_Addr)); 155 } else { 156 memcpy(tls + tls_init_offset, tls_init, tls_init_size); 157 memset(tls + tls_init_offset + tls_init_size, 158 0, tls_static_space - tls_init_size); 159 } 160 161 return tls; 162 } 163 164 #endif 165 166 #ifdef TLS_VARIANT_II 167 168 /* 169 * Free Static TLS using the Variant II method. 170 */ 171 void 172 __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 173 { 174 size_t size; 175 Elf_Addr* dtv; 176 Elf_Addr tlsstart, tlsend; 177 178 /* 179 * Figure out the size of the initial TLS block so that we can 180 * find stuff which ___tls_get_addr() allocated dynamically. 181 */ 182 size = round(tls_static_space, tcbalign); 183 184 dtv = ((Elf_Addr**)tcb)[1]; 185 tlsend = (Elf_Addr) tcb; 186 tlsstart = tlsend - size; 187 free((void*) tlsstart); 188 free(dtv); 189 } 190 191 /* 192 * Allocate Static TLS using the Variant II method. 193 */ 194 void * 195 __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 196 { 197 size_t size; 198 char *tls; 199 Elf_Addr *dtv; 200 Elf_Addr segbase, oldsegbase; 201 202 size = round(tls_static_space, tcbalign); 203 204 assert(tcbsize >= 2*sizeof(Elf_Addr)); 205 tls = malloc(size + tcbsize); 206 dtv = malloc(3 * sizeof(Elf_Addr)); 207 208 segbase = (Elf_Addr)(tls + size); 209 ((Elf_Addr*)segbase)[0] = segbase; 210 ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 211 212 dtv[0] = 1; 213 dtv[1] = 1; 214 dtv[2] = segbase - tls_static_space; 215 216 if (oldtls) { 217 /* 218 * Copy the static TLS block over whole. 219 */ 220 oldsegbase = (Elf_Addr) oldtls; 221 memcpy((void *)(segbase - tls_static_space), 222 (const void *)(oldsegbase - tls_static_space), 223 tls_static_space); 224 225 /* 226 * We assume that this block was the one we created with 227 * allocate_initial_tls(). 228 */ 229 _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 230 } else { 231 memcpy((void *)(segbase - tls_static_space), 232 tls_init, tls_init_size); 233 memset((void *)(segbase - tls_static_space + tls_init_size), 234 0, tls_static_space - tls_init_size); 235 } 236 237 return (void*) segbase; 238 } 239 240 #endif /* TLS_VARIANT_II */ 241 242 #else 243 244 void * 245 __libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 246 size_t tcbalign __unused) 247 { 248 return (0); 249 } 250 251 void 252 __libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 253 size_t tcbalign __unused) 254 { 255 } 256 257 #endif /* PIC */ 258 259 extern char **environ; 260 261 void 262 _init_tls() 263 { 264 #ifndef PIC 265 Elf_Addr *sp; 266 Elf_Auxinfo *aux, *auxp; 267 Elf_Phdr *phdr; 268 size_t phent, phnum; 269 int i; 270 void *tls; 271 272 sp = (Elf_Addr *) environ; 273 while (*sp++ != 0) 274 ; 275 aux = (Elf_Auxinfo *) sp; 276 phdr = 0; 277 phent = phnum = 0; 278 for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 279 switch (auxp->a_type) { 280 case AT_PHDR: 281 phdr = auxp->a_un.a_ptr; 282 break; 283 284 case AT_PHENT: 285 phent = auxp->a_un.a_val; 286 break; 287 288 case AT_PHNUM: 289 phnum = auxp->a_un.a_val; 290 break; 291 } 292 } 293 if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0) 294 return; 295 296 for (i = 0; (unsigned) i < phnum; i++) { 297 if (phdr[i].p_type == PT_TLS) { 298 #ifdef TLS_VARIANT_I 299 tls_static_space = round(2*sizeof(Elf_Addr), 300 phdr[i].p_align) + phdr[i].p_memsz; 301 tls_init_offset = round(2*sizeof(Elf_Addr), 302 phdr[i].p_align); 303 #else 304 tls_static_space = round(phdr[i].p_memsz, 305 phdr[i].p_align); 306 #endif 307 tls_init_size = phdr[i].p_filesz; 308 tls_init = (void*) phdr[i].p_vaddr; 309 } 310 } 311 312 tls = _rtld_allocate_tls(NULL, 2*sizeof(Elf_Addr), 313 sizeof(Elf_Addr)); 314 315 _set_tp(tls); 316 #endif 317 } 318