10e1c7d0fSDoug Rabson /*- 20e1c7d0fSDoug Rabson * Copyright (c) 2004 Doug Rabson 30e1c7d0fSDoug Rabson * All rights reserved. 40e1c7d0fSDoug Rabson * 50e1c7d0fSDoug Rabson * Redistribution and use in source and binary forms, with or without 60e1c7d0fSDoug Rabson * modification, are permitted provided that the following conditions 70e1c7d0fSDoug Rabson * are met: 80e1c7d0fSDoug Rabson * 1. Redistributions of source code must retain the above copyright 90e1c7d0fSDoug Rabson * notice, this list of conditions and the following disclaimer. 100e1c7d0fSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 110e1c7d0fSDoug Rabson * notice, this list of conditions and the following disclaimer in the 120e1c7d0fSDoug Rabson * documentation and/or other materials provided with the distribution. 130e1c7d0fSDoug Rabson * 140e1c7d0fSDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 150e1c7d0fSDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 160e1c7d0fSDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 170e1c7d0fSDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 180e1c7d0fSDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 190e1c7d0fSDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 200e1c7d0fSDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 210e1c7d0fSDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 220e1c7d0fSDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 230e1c7d0fSDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 240e1c7d0fSDoug Rabson * SUCH DAMAGE. 250e1c7d0fSDoug Rabson * 260e1c7d0fSDoug Rabson * $FreeBSD$ 270e1c7d0fSDoug Rabson */ 280e1c7d0fSDoug Rabson 290e1c7d0fSDoug Rabson /* 300e1c7d0fSDoug Rabson * Define stubs for TLS internals so that programs and libraries can 310e1c7d0fSDoug Rabson * link. These functions will be replaced by functional versions at 320e1c7d0fSDoug Rabson * runtime from ld-elf.so.1. 330e1c7d0fSDoug Rabson */ 340e1c7d0fSDoug Rabson 3526896bdaSDavid Xu #include <sys/cdefs.h> 36ccd13c49SDoug Rabson #include <stdlib.h> 37ccd13c49SDoug Rabson #include <string.h> 38ccd13c49SDoug Rabson #include <elf.h> 3926896bdaSDavid Xu 40ccd13c49SDoug Rabson #include "libc_private.h" 41ccd13c49SDoug Rabson 42a4bd5210SJason Evans /* Provided by jemalloc to avoid bootstrapping issues. */ 43*d0e79aa3SJason Evans void *__je_bootstrap_malloc(size_t size); 44*d0e79aa3SJason Evans void *__je_bootstrap_calloc(size_t num, size_t size); 45*d0e79aa3SJason Evans void __je_bootstrap_free(void *ptr); 46a4bd5210SJason Evans 4726896bdaSDavid Xu __weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 4826896bdaSDavid Xu __weak_reference(__libc_free_tls, _rtld_free_tls); 4926896bdaSDavid Xu 5026896bdaSDavid Xu #ifdef __i386__ 5126896bdaSDavid Xu 5226896bdaSDavid Xu __weak_reference(___libc_tls_get_addr, ___tls_get_addr); 5326896bdaSDavid Xu __attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *); 5426896bdaSDavid Xu 5526896bdaSDavid Xu #endif 5626896bdaSDavid Xu 5726896bdaSDavid Xu void * __libc_tls_get_addr(void *); 5826896bdaSDavid Xu __weak_reference(__libc_tls_get_addr, __tls_get_addr); 5926896bdaSDavid Xu 6026896bdaSDavid Xu void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 6126896bdaSDavid Xu void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 6226896bdaSDavid Xu void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 6326896bdaSDavid Xu void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 6426896bdaSDavid Xu 65e7d939bdSMarcel Moolenaar #if defined(__amd64__) 66b84c7a79SKip Macy #define TLS_TCB_ALIGN 16 67b84c7a79SKip Macy #elif defined(__powerpc__) || defined(__i386__) || defined(__arm__) || \ 68d422e6f9SAndrew Turner defined(__sparc64__) || defined(__mips__) || defined(__aarch64__) 69b84c7a79SKip Macy #define TLS_TCB_ALIGN sizeof(void *) 70b84c7a79SKip Macy #else 71b84c7a79SKip Macy #error TLS_TCB_ALIGN undefined for target architecture 72b84c7a79SKip Macy #endif 73b84c7a79SKip Macy 74d422e6f9SAndrew Turner #if defined(__arm__) || defined(__mips__) || defined(__powerpc__) || \ 75d422e6f9SAndrew Turner defined(__aarch64__) 76ccd13c49SDoug Rabson #define TLS_VARIANT_I 77ccd13c49SDoug Rabson #endif 7854da2fb8SOleksandr Tymoshenko #if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) 79ccd13c49SDoug Rabson #define TLS_VARIANT_II 80ccd13c49SDoug Rabson #endif 81ccd13c49SDoug Rabson 82294246bbSEd Maste #ifndef PIC 83ccd13c49SDoug Rabson 84ccd13c49SDoug Rabson #define round(size, align) \ 85ccd13c49SDoug Rabson (((size) + (align) - 1) & ~((align) - 1)) 86ccd13c49SDoug Rabson 87ccd13c49SDoug Rabson static size_t tls_static_space; 88ccd13c49SDoug Rabson static size_t tls_init_size; 89ccd13c49SDoug Rabson static void *tls_init; 90ccd13c49SDoug Rabson #endif 910e1c7d0fSDoug Rabson 920e1c7d0fSDoug Rabson #ifdef __i386__ 930e1c7d0fSDoug Rabson 9426896bdaSDavid Xu /* GNU ABI */ 950e1c7d0fSDoug Rabson 960e1c7d0fSDoug Rabson __attribute__((__regparm__(1))) 970e1c7d0fSDoug Rabson void * 9826896bdaSDavid Xu ___libc_tls_get_addr(void *ti __unused) 990e1c7d0fSDoug Rabson { 1000e1c7d0fSDoug Rabson return (0); 1010e1c7d0fSDoug Rabson } 1020e1c7d0fSDoug Rabson 1030e1c7d0fSDoug Rabson #endif 1040e1c7d0fSDoug Rabson 1050e1c7d0fSDoug Rabson void * 10626896bdaSDavid Xu __libc_tls_get_addr(void *ti __unused) 1070e1c7d0fSDoug Rabson { 1080e1c7d0fSDoug Rabson return (0); 1090e1c7d0fSDoug Rabson } 1100e1c7d0fSDoug Rabson 111294246bbSEd Maste #ifndef PIC 11226896bdaSDavid Xu 113ccd13c49SDoug Rabson #ifdef TLS_VARIANT_I 114ccd13c49SDoug Rabson 1153614156cSMarcel Moolenaar #define TLS_TCB_SIZE (2 * sizeof(void *)) 1163614156cSMarcel Moolenaar 11717ceb495SDavid Xu /* 11896a93293SDavid Xu * Free Static TLS using the Variant I method. 11917ceb495SDavid Xu */ 120ccd13c49SDoug Rabson void 1213614156cSMarcel Moolenaar __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) 122ccd13c49SDoug Rabson { 123ccd13c49SDoug Rabson Elf_Addr *dtv; 1243614156cSMarcel Moolenaar Elf_Addr **tls; 125ccd13c49SDoug Rabson 1263614156cSMarcel Moolenaar tls = (Elf_Addr **)((Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE); 1273614156cSMarcel Moolenaar dtv = tls[0]; 128*d0e79aa3SJason Evans __je_bootstrap_free(dtv); 129*d0e79aa3SJason Evans __je_bootstrap_free(tcb); 130ccd13c49SDoug Rabson } 131ccd13c49SDoug Rabson 132ccd13c49SDoug Rabson /* 133ccd13c49SDoug Rabson * Allocate Static TLS using the Variant I method. 134ccd13c49SDoug Rabson */ 1350e1c7d0fSDoug Rabson void * 1363614156cSMarcel Moolenaar __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused) 1370e1c7d0fSDoug Rabson { 138ccd13c49SDoug Rabson Elf_Addr *dtv; 1393614156cSMarcel Moolenaar Elf_Addr **tls; 1403614156cSMarcel Moolenaar char *tcb; 141ccd13c49SDoug Rabson 1423614156cSMarcel Moolenaar if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) 1433614156cSMarcel Moolenaar return (oldtcb); 144ccd13c49SDoug Rabson 145*d0e79aa3SJason Evans tcb = __je_bootstrap_calloc(1, tls_static_space + tcbsize - TLS_TCB_SIZE); 1463614156cSMarcel Moolenaar tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE); 1473614156cSMarcel Moolenaar 1483614156cSMarcel Moolenaar if (oldtcb != NULL) { 14994368521SMarcel Moolenaar memcpy(tls, oldtcb, tls_static_space); 150*d0e79aa3SJason Evans __je_bootstrap_free(oldtcb); 1513614156cSMarcel Moolenaar 1523614156cSMarcel Moolenaar /* Adjust the DTV. */ 1533614156cSMarcel Moolenaar dtv = tls[0]; 1543614156cSMarcel Moolenaar dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; 1553614156cSMarcel Moolenaar } else { 156*d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 1573614156cSMarcel Moolenaar tls[0] = dtv; 158ccd13c49SDoug Rabson dtv[0] = 1; 159ccd13c49SDoug Rabson dtv[1] = 1; 1603614156cSMarcel Moolenaar dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; 161ccd13c49SDoug Rabson 1623614156cSMarcel Moolenaar if (tls_init_size > 0) 1633614156cSMarcel Moolenaar memcpy((void*)dtv[2], tls_init, tls_init_size); 1643614156cSMarcel Moolenaar if (tls_static_space > tls_init_size) 1653614156cSMarcel Moolenaar memset((void*)(dtv[2] + tls_init_size), 0, 1663614156cSMarcel Moolenaar tls_static_space - tls_init_size); 1670e1c7d0fSDoug Rabson } 1680e1c7d0fSDoug Rabson 1693614156cSMarcel Moolenaar return(tcb); 170ccd13c49SDoug Rabson } 171ccd13c49SDoug Rabson 172ccd13c49SDoug Rabson #endif 173ccd13c49SDoug Rabson 174ccd13c49SDoug Rabson #ifdef TLS_VARIANT_II 175ccd13c49SDoug Rabson 1763614156cSMarcel Moolenaar #define TLS_TCB_SIZE (3 * sizeof(Elf_Addr)) 1773614156cSMarcel Moolenaar 178ccd13c49SDoug Rabson /* 179ccd13c49SDoug Rabson * Free Static TLS using the Variant II method. 180ccd13c49SDoug Rabson */ 1810e1c7d0fSDoug Rabson void 18226896bdaSDavid Xu __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 1830e1c7d0fSDoug Rabson { 184ccd13c49SDoug Rabson size_t size; 185ccd13c49SDoug Rabson Elf_Addr* dtv; 186ccd13c49SDoug Rabson Elf_Addr tlsstart, tlsend; 187ccd13c49SDoug Rabson 188ccd13c49SDoug Rabson /* 189ccd13c49SDoug Rabson * Figure out the size of the initial TLS block so that we can 190ccd13c49SDoug Rabson * find stuff which ___tls_get_addr() allocated dynamically. 191ccd13c49SDoug Rabson */ 192ccd13c49SDoug Rabson size = round(tls_static_space, tcbalign); 193ccd13c49SDoug Rabson 194ccd13c49SDoug Rabson dtv = ((Elf_Addr**)tcb)[1]; 195ccd13c49SDoug Rabson tlsend = (Elf_Addr) tcb; 196ccd13c49SDoug Rabson tlsstart = tlsend - size; 197*d0e79aa3SJason Evans __je_bootstrap_free((void*) tlsstart); 198*d0e79aa3SJason Evans __je_bootstrap_free(dtv); 199ccd13c49SDoug Rabson } 200ccd13c49SDoug Rabson 201ccd13c49SDoug Rabson /* 202ccd13c49SDoug Rabson * Allocate Static TLS using the Variant II method. 203ccd13c49SDoug Rabson */ 204ccd13c49SDoug Rabson void * 20526896bdaSDavid Xu __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 206ccd13c49SDoug Rabson { 207ccd13c49SDoug Rabson size_t size; 208ccd13c49SDoug Rabson char *tls; 209ccd13c49SDoug Rabson Elf_Addr *dtv; 210ccd13c49SDoug Rabson Elf_Addr segbase, oldsegbase; 211ccd13c49SDoug Rabson 212ccd13c49SDoug Rabson size = round(tls_static_space, tcbalign); 213ccd13c49SDoug Rabson 2140031cdf4STim Kientzle if (tcbsize < 2 * sizeof(Elf_Addr)) 2150031cdf4STim Kientzle tcbsize = 2 * sizeof(Elf_Addr); 216*d0e79aa3SJason Evans tls = __je_bootstrap_calloc(1, size + tcbsize); 217*d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 218ccd13c49SDoug Rabson 219ccd13c49SDoug Rabson segbase = (Elf_Addr)(tls + size); 220ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[0] = segbase; 221ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 222ccd13c49SDoug Rabson 223ccd13c49SDoug Rabson dtv[0] = 1; 224ccd13c49SDoug Rabson dtv[1] = 1; 225ccd13c49SDoug Rabson dtv[2] = segbase - tls_static_space; 226ccd13c49SDoug Rabson 227ccd13c49SDoug Rabson if (oldtls) { 228ccd13c49SDoug Rabson /* 229ccd13c49SDoug Rabson * Copy the static TLS block over whole. 230ccd13c49SDoug Rabson */ 231ccd13c49SDoug Rabson oldsegbase = (Elf_Addr) oldtls; 232ccd13c49SDoug Rabson memcpy((void *)(segbase - tls_static_space), 233ccd13c49SDoug Rabson (const void *)(oldsegbase - tls_static_space), 234ccd13c49SDoug Rabson tls_static_space); 235ccd13c49SDoug Rabson 236ccd13c49SDoug Rabson /* 237ccd13c49SDoug Rabson * We assume that this block was the one we created with 238ccd13c49SDoug Rabson * allocate_initial_tls(). 239ccd13c49SDoug Rabson */ 240ccd13c49SDoug Rabson _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 241ccd13c49SDoug Rabson } else { 242ccd13c49SDoug Rabson memcpy((void *)(segbase - tls_static_space), 243ccd13c49SDoug Rabson tls_init, tls_init_size); 244ccd13c49SDoug Rabson memset((void *)(segbase - tls_static_space + tls_init_size), 245ccd13c49SDoug Rabson 0, tls_static_space - tls_init_size); 246ccd13c49SDoug Rabson } 247ccd13c49SDoug Rabson 248ccd13c49SDoug Rabson return (void*) segbase; 249ccd13c49SDoug Rabson } 250ccd13c49SDoug Rabson 25126896bdaSDavid Xu #endif /* TLS_VARIANT_II */ 25226896bdaSDavid Xu 25326896bdaSDavid Xu #else 25426896bdaSDavid Xu 25526896bdaSDavid Xu void * 25626896bdaSDavid Xu __libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 25726896bdaSDavid Xu size_t tcbalign __unused) 25826896bdaSDavid Xu { 25926896bdaSDavid Xu return (0); 26026896bdaSDavid Xu } 26126896bdaSDavid Xu 26226896bdaSDavid Xu void 26326896bdaSDavid Xu __libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 26426896bdaSDavid Xu size_t tcbalign __unused) 26526896bdaSDavid Xu { 26626896bdaSDavid Xu } 26726896bdaSDavid Xu 268294246bbSEd Maste #endif /* PIC */ 26926896bdaSDavid Xu 27026896bdaSDavid Xu extern char **environ; 271ccd13c49SDoug Rabson 272ccd13c49SDoug Rabson void 273ccd13c49SDoug Rabson _init_tls() 274ccd13c49SDoug Rabson { 275294246bbSEd Maste #ifndef PIC 276ccd13c49SDoug Rabson Elf_Addr *sp; 277ccd13c49SDoug Rabson Elf_Auxinfo *aux, *auxp; 278ccd13c49SDoug Rabson Elf_Phdr *phdr; 279ccd13c49SDoug Rabson size_t phent, phnum; 280ccd13c49SDoug Rabson int i; 2810e7e4e5fSDoug Rabson void *tls; 282ccd13c49SDoug Rabson 283ccd13c49SDoug Rabson sp = (Elf_Addr *) environ; 284ccd13c49SDoug Rabson while (*sp++ != 0) 285ccd13c49SDoug Rabson ; 286ccd13c49SDoug Rabson aux = (Elf_Auxinfo *) sp; 287ccd13c49SDoug Rabson phdr = 0; 288ccd13c49SDoug Rabson phent = phnum = 0; 289ccd13c49SDoug Rabson for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 290ccd13c49SDoug Rabson switch (auxp->a_type) { 291ccd13c49SDoug Rabson case AT_PHDR: 292ccd13c49SDoug Rabson phdr = auxp->a_un.a_ptr; 293ccd13c49SDoug Rabson break; 294ccd13c49SDoug Rabson 295ccd13c49SDoug Rabson case AT_PHENT: 296ccd13c49SDoug Rabson phent = auxp->a_un.a_val; 297ccd13c49SDoug Rabson break; 298ccd13c49SDoug Rabson 299ccd13c49SDoug Rabson case AT_PHNUM: 300ccd13c49SDoug Rabson phnum = auxp->a_un.a_val; 301ccd13c49SDoug Rabson break; 302ccd13c49SDoug Rabson } 303ccd13c49SDoug Rabson } 304ccd13c49SDoug Rabson if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0) 305ccd13c49SDoug Rabson return; 306ccd13c49SDoug Rabson 30726896bdaSDavid Xu for (i = 0; (unsigned) i < phnum; i++) { 308ccd13c49SDoug Rabson if (phdr[i].p_type == PT_TLS) { 309ccd13c49SDoug Rabson tls_static_space = round(phdr[i].p_memsz, 310ccd13c49SDoug Rabson phdr[i].p_align); 311ccd13c49SDoug Rabson tls_init_size = phdr[i].p_filesz; 312ccd13c49SDoug Rabson tls_init = (void*) phdr[i].p_vaddr; 313ccd13c49SDoug Rabson } 314ccd13c49SDoug Rabson } 315ccd13c49SDoug Rabson 31654da2fb8SOleksandr Tymoshenko #ifdef TLS_VARIANT_I 31754da2fb8SOleksandr Tymoshenko /* 31854da2fb8SOleksandr Tymoshenko * tls_static_space should include space for TLS structure 31954da2fb8SOleksandr Tymoshenko */ 32054da2fb8SOleksandr Tymoshenko tls_static_space += TLS_TCB_SIZE; 32154da2fb8SOleksandr Tymoshenko #endif 32254da2fb8SOleksandr Tymoshenko 323b84c7a79SKip Macy tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); 324ccd13c49SDoug Rabson 325ccd13c49SDoug Rabson _set_tp(tls); 326ccd13c49SDoug Rabson #endif 3270e1c7d0fSDoug Rabson } 328