10e1c7d0fSDoug Rabson /*- 2d915a14eSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3d915a14eSPedro F. Giffuni * 40e1c7d0fSDoug Rabson * Copyright (c) 2004 Doug Rabson 50e1c7d0fSDoug Rabson * All rights reserved. 60e1c7d0fSDoug Rabson * 70e1c7d0fSDoug Rabson * Redistribution and use in source and binary forms, with or without 80e1c7d0fSDoug Rabson * modification, are permitted provided that the following conditions 90e1c7d0fSDoug Rabson * are met: 100e1c7d0fSDoug Rabson * 1. Redistributions of source code must retain the above copyright 110e1c7d0fSDoug Rabson * notice, this list of conditions and the following disclaimer. 120e1c7d0fSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 130e1c7d0fSDoug Rabson * notice, this list of conditions and the following disclaimer in the 140e1c7d0fSDoug Rabson * documentation and/or other materials provided with the distribution. 150e1c7d0fSDoug Rabson * 160e1c7d0fSDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 170e1c7d0fSDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 180e1c7d0fSDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 190e1c7d0fSDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 200e1c7d0fSDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 210e1c7d0fSDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 220e1c7d0fSDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 230e1c7d0fSDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 240e1c7d0fSDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 250e1c7d0fSDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 260e1c7d0fSDoug Rabson * SUCH DAMAGE. 270e1c7d0fSDoug Rabson * 280e1c7d0fSDoug Rabson * $FreeBSD$ 290e1c7d0fSDoug Rabson */ 300e1c7d0fSDoug Rabson 310e1c7d0fSDoug Rabson /* 320e1c7d0fSDoug Rabson * Define stubs for TLS internals so that programs and libraries can 330e1c7d0fSDoug Rabson * link. These functions will be replaced by functional versions at 340e1c7d0fSDoug Rabson * runtime from ld-elf.so.1. 350e1c7d0fSDoug Rabson */ 360e1c7d0fSDoug Rabson 3726896bdaSDavid Xu #include <sys/cdefs.h> 386b2d5217SPedro F. Giffuni #include <sys/param.h> 39ccd13c49SDoug Rabson #include <stdlib.h> 40ccd13c49SDoug Rabson #include <string.h> 41ccd13c49SDoug Rabson #include <elf.h> 428584ed54SMichal Meloun #include <unistd.h> 4326896bdaSDavid Xu 447f7489ebSKonstantin Belousov #include "rtld.h" 45ccd13c49SDoug Rabson #include "libc_private.h" 46ccd13c49SDoug Rabson 478584ed54SMichal Meloun #define tls_assert(cond) ((cond) ? (void) 0 : \ 488584ed54SMichal Meloun (tls_msg(#cond ": assert failed: " __FILE__ ":" \ 498584ed54SMichal Meloun __XSTRING(__LINE__) "\n"), abort())) 508584ed54SMichal Meloun #define tls_msg(s) write(STDOUT_FILENO, s, strlen(s)) 518584ed54SMichal Meloun 52a4bd5210SJason Evans /* Provided by jemalloc to avoid bootstrapping issues. */ 53d0e79aa3SJason Evans void *__je_bootstrap_malloc(size_t size); 54d0e79aa3SJason Evans void *__je_bootstrap_calloc(size_t num, size_t size); 55d0e79aa3SJason Evans void __je_bootstrap_free(void *ptr); 56a4bd5210SJason Evans 5726896bdaSDavid Xu __weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 5826896bdaSDavid Xu __weak_reference(__libc_free_tls, _rtld_free_tls); 5926896bdaSDavid Xu 6026896bdaSDavid Xu #ifdef __i386__ 6126896bdaSDavid Xu 6226896bdaSDavid Xu __weak_reference(___libc_tls_get_addr, ___tls_get_addr); 6326896bdaSDavid Xu __attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *); 6426896bdaSDavid Xu 6526896bdaSDavid Xu #endif 6626896bdaSDavid Xu 6726896bdaSDavid Xu void * __libc_tls_get_addr(void *); 6826896bdaSDavid Xu __weak_reference(__libc_tls_get_addr, __tls_get_addr); 6926896bdaSDavid Xu 7026896bdaSDavid Xu void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 7126896bdaSDavid Xu void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 7226896bdaSDavid Xu void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 7326896bdaSDavid Xu void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 7426896bdaSDavid Xu 75294246bbSEd Maste #ifndef PIC 76ccd13c49SDoug Rabson 777f7489ebSKonstantin Belousov static size_t libc_tls_static_space; 787f7489ebSKonstantin Belousov static size_t libc_tls_init_size; 797f7489ebSKonstantin Belousov static size_t libc_tls_init_align; 807f7489ebSKonstantin Belousov static void *libc_tls_init; 81ccd13c49SDoug Rabson #endif 820e1c7d0fSDoug Rabson 83ca46b569SKonstantin Belousov void * 84ca46b569SKonstantin Belousov __libc_tls_get_addr(void *vti) 85ca46b569SKonstantin Belousov { 86*8bcdb144SJohn Baldwin uintptr_t *dtv; 87ca46b569SKonstantin Belousov tls_index *ti; 88ca46b569SKonstantin Belousov 89*8bcdb144SJohn Baldwin dtv = _tcb_get()->tcb_dtv; 90ca46b569SKonstantin Belousov ti = vti; 91ca46b569SKonstantin Belousov return ((char *)(dtv[ti->ti_module + 1] + ti->ti_offset) + 92ca46b569SKonstantin Belousov TLS_DTV_OFFSET); 93ca46b569SKonstantin Belousov } 94ca46b569SKonstantin Belousov 950e1c7d0fSDoug Rabson #ifdef __i386__ 960e1c7d0fSDoug Rabson 9726896bdaSDavid Xu /* GNU ABI */ 980e1c7d0fSDoug Rabson 990e1c7d0fSDoug Rabson __attribute__((__regparm__(1))) 1000e1c7d0fSDoug Rabson void * 101ca46b569SKonstantin Belousov ___libc_tls_get_addr(void *vti) 1020e1c7d0fSDoug Rabson { 103ca46b569SKonstantin Belousov return (__libc_tls_get_addr(vti)); 1040e1c7d0fSDoug Rabson } 1050e1c7d0fSDoug Rabson 1060e1c7d0fSDoug Rabson #endif 1070e1c7d0fSDoug Rabson 108294246bbSEd Maste #ifndef PIC 10926896bdaSDavid Xu 1108584ed54SMichal Meloun static void * 1117f7489ebSKonstantin Belousov libc_malloc_aligned(size_t size, size_t align) 1128584ed54SMichal Meloun { 1138584ed54SMichal Meloun void *mem, *res; 1148584ed54SMichal Meloun 1158584ed54SMichal Meloun if (align < sizeof(void *)) 1168584ed54SMichal Meloun align = sizeof(void *); 1178584ed54SMichal Meloun 1188584ed54SMichal Meloun mem = __je_bootstrap_malloc(size + sizeof(void *) + align - 1); 1198584ed54SMichal Meloun res = (void *)roundup2((uintptr_t)mem + sizeof(void *), align); 1208584ed54SMichal Meloun *(void **)((uintptr_t)res - sizeof(void *)) = mem; 1218584ed54SMichal Meloun return (res); 1228584ed54SMichal Meloun } 1238584ed54SMichal Meloun 1248584ed54SMichal Meloun static void 1257f7489ebSKonstantin Belousov libc_free_aligned(void *ptr) 1268584ed54SMichal Meloun { 1278584ed54SMichal Meloun void *mem; 1288584ed54SMichal Meloun uintptr_t x; 1298584ed54SMichal Meloun 1308584ed54SMichal Meloun if (ptr == NULL) 1318584ed54SMichal Meloun return; 1328584ed54SMichal Meloun 1338584ed54SMichal Meloun x = (uintptr_t)ptr; 1348584ed54SMichal Meloun x -= sizeof(void *); 1358584ed54SMichal Meloun mem = *(void **)x; 1368584ed54SMichal Meloun __je_bootstrap_free(mem); 1378584ed54SMichal Meloun } 1388584ed54SMichal Meloun 139ccd13c49SDoug Rabson #ifdef TLS_VARIANT_I 140ccd13c49SDoug Rabson 1416e16d0bcSMichal Meloun /* 1426e16d0bcSMichal Meloun * There are two versions of variant I of TLS 1436e16d0bcSMichal Meloun * 1446e16d0bcSMichal Meloun * - ARM and aarch64 uses original variant I as is described in [1] and [2], 1456e16d0bcSMichal Meloun * where TP points to start of TCB followed by aligned TLS segment. 1466e16d0bcSMichal Meloun * Both TCB and TLS must be aligned to alignment of TLS section. The TCB[0] 1476e16d0bcSMichal Meloun * points to DTV vector and DTV values are real addresses (without bias). 1486e16d0bcSMichal Meloun * Note: for Local Exec TLS Model, the offsets from TP (TCB in this case) to 1496e16d0bcSMichal Meloun * TLS variables are computed by linker, so we cannot overalign TLS section. 1506e16d0bcSMichal Meloun * 1516e16d0bcSMichal Meloun * - MIPS, PowerPC and RISC-V use modified version of variant I, 1526e16d0bcSMichal Meloun * described in [3] where TP points (with bias) to TLS and TCB immediately 1536e16d0bcSMichal Meloun * precedes TLS without any alignment gap[4]. Only TLS should be aligned. 1546e16d0bcSMichal Meloun * The TCB[0] points to DTV vector and DTV values are biased by constant 155*8bcdb144SJohn Baldwin * value (TLS_DTV_OFFSET) from real addresses[5]. 1566e16d0bcSMichal Meloun * 1576e16d0bcSMichal Meloun * [1] Ulrich Drepper: ELF Handling for Thread-Local Storage 1586e16d0bcSMichal Meloun * www.akkadia.org/drepper/tls.pdf 1596e16d0bcSMichal Meloun * 1606e16d0bcSMichal Meloun * [2] ARM IHI 0045E: Addenda to, and Errata in, the ABI for the ARM(r) 1616e16d0bcSMichal Meloun * Architecture 1626e16d0bcSMichal Meloun * infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf 1636e16d0bcSMichal Meloun * 1646e16d0bcSMichal Meloun * [3] OpenPOWER: Power Architecture 64-Bit ELF V2 ABI Specification 1656e16d0bcSMichal Meloun * https://members.openpowerfoundation.org/document/dl/576 1666e16d0bcSMichal Meloun * 1676e16d0bcSMichal Meloun * [4] Its unclear if "without any alignment gap" is hard ABI requirement, 168*8bcdb144SJohn Baldwin * but we must follow this rule due to suboptimal _tcb_set() 1696e16d0bcSMichal Meloun * (aka <ARCH>_SET_TP) implementation. This function doesn't expect TP but 1706e16d0bcSMichal Meloun * TCB as argument. 1716e16d0bcSMichal Meloun * 1726e16d0bcSMichal Meloun * [5] I'm not able to validate "values are biased" assertions. 1736e16d0bcSMichal Meloun */ 1746e16d0bcSMichal Meloun 17517ceb495SDavid Xu /* 1766e16d0bcSMichal Meloun * Return pointer to allocated TLS block 1776e16d0bcSMichal Meloun */ 1786e16d0bcSMichal Meloun static void * 1796e16d0bcSMichal Meloun get_tls_block_ptr(void *tcb, size_t tcbsize) 1806e16d0bcSMichal Meloun { 1816e16d0bcSMichal Meloun size_t extra_size, post_size, pre_size, tls_block_size; 1826e16d0bcSMichal Meloun 1836e16d0bcSMichal Meloun /* Compute fragments sizes. */ 1846e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 1856e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 1867f7489ebSKonstantin Belousov post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; 1876e16d0bcSMichal Meloun #else 1886e16d0bcSMichal Meloun post_size = 0; 1896e16d0bcSMichal Meloun #endif 1906e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 1917f7489ebSKonstantin Belousov pre_size = roundup2(tls_block_size, libc_tls_init_align) - 1927f7489ebSKonstantin Belousov tls_block_size; 1936e16d0bcSMichal Meloun 1946e16d0bcSMichal Meloun return ((char *)tcb - pre_size - extra_size); 1956e16d0bcSMichal Meloun } 1966e16d0bcSMichal Meloun 1976e16d0bcSMichal Meloun /* 1986e16d0bcSMichal Meloun * Free Static TLS using the Variant I method. The tcbsize 1996e16d0bcSMichal Meloun * and tcbalign parameters must be the same as those used to allocate 2006e16d0bcSMichal Meloun * the block. 20117ceb495SDavid Xu */ 202ccd13c49SDoug Rabson void 2036e16d0bcSMichal Meloun __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) 204ccd13c49SDoug Rabson { 205ccd13c49SDoug Rabson Elf_Addr *dtv; 2063614156cSMarcel Moolenaar Elf_Addr **tls; 207ccd13c49SDoug Rabson 2088584ed54SMichal Meloun tls = (Elf_Addr **)tcb; 2093614156cSMarcel Moolenaar dtv = tls[0]; 210d0e79aa3SJason Evans __je_bootstrap_free(dtv); 2117f7489ebSKonstantin Belousov libc_free_aligned(get_tls_block_ptr(tcb, tcbsize)); 212ccd13c49SDoug Rabson } 213ccd13c49SDoug Rabson 214ccd13c49SDoug Rabson /* 215ccd13c49SDoug Rabson * Allocate Static TLS using the Variant I method. 2166e16d0bcSMichal Meloun * 2176e16d0bcSMichal Meloun * To handle all above requirements, we setup the following layout for 2186e16d0bcSMichal Meloun * TLS block: 2196e16d0bcSMichal Meloun * (whole memory block is aligned with MAX(TLS_TCB_ALIGN, tls_init_align)) 2206e16d0bcSMichal Meloun * 2216e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 2226e16d0bcSMichal Meloun * | pre gap | extended TCB | TCB | post gap | TLS segment | 2236e16d0bcSMichal Meloun * | pre_size | extra_size | TLS_TCB_SIZE | post_size | tls_static_space | 2246e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 2256e16d0bcSMichal Meloun * 2266e16d0bcSMichal Meloun * where: 2276e16d0bcSMichal Meloun * extra_size is tcbsize - TLS_TCB_SIZE 228a1581cd7SGordon Bergling * post_size is used to adjust TCB to TLS alignment for first version of TLS 2296e16d0bcSMichal Meloun * layout and is always 0 for second version. 230a1581cd7SGordon Bergling * pre_size is used to adjust TCB alignment for first version and to adjust 2316e16d0bcSMichal Meloun * TLS alignment for second version. 2326e16d0bcSMichal Meloun * 233ccd13c49SDoug Rabson */ 2340e1c7d0fSDoug Rabson void * 2358584ed54SMichal Meloun __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) 2360e1c7d0fSDoug Rabson { 2376e16d0bcSMichal Meloun Elf_Addr *dtv, **tcb; 2386e16d0bcSMichal Meloun char *tls_block, *tls; 2396e16d0bcSMichal Meloun size_t extra_size, maxalign, post_size, pre_size, tls_block_size; 240ccd13c49SDoug Rabson 2413614156cSMarcel Moolenaar if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) 2423614156cSMarcel Moolenaar return (oldtcb); 243ccd13c49SDoug Rabson 2448584ed54SMichal Meloun tls_assert(tcbalign >= TLS_TCB_ALIGN); 2457f7489ebSKonstantin Belousov maxalign = MAX(tcbalign, libc_tls_init_align); 2468584ed54SMichal Meloun 2476e16d0bcSMichal Meloun /* Compute fragmets sizes. */ 2486e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 2496e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 2507f7489ebSKonstantin Belousov post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; 2516e16d0bcSMichal Meloun #else 2526e16d0bcSMichal Meloun post_size = 0; 2536e16d0bcSMichal Meloun #endif 2546e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 2557f7489ebSKonstantin Belousov pre_size = roundup2(tls_block_size, libc_tls_init_align) - 2567f7489ebSKonstantin Belousov tls_block_size; 2577f7489ebSKonstantin Belousov tls_block_size += pre_size + libc_tls_static_space; 2586e16d0bcSMichal Meloun 2596e16d0bcSMichal Meloun /* Allocate whole TLS block */ 2607f7489ebSKonstantin Belousov tls_block = libc_malloc_aligned(tls_block_size, maxalign); 2616e16d0bcSMichal Meloun if (tls_block == NULL) { 2628584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 2638584ed54SMichal Meloun abort(); 2648584ed54SMichal Meloun } 2656e16d0bcSMichal Meloun memset(tls_block, 0, tls_block_size); 2666e16d0bcSMichal Meloun tcb = (Elf_Addr **)(tls_block + pre_size + extra_size); 2676e16d0bcSMichal Meloun tls = (char *)tcb + TLS_TCB_SIZE + post_size; 2683614156cSMarcel Moolenaar 2693614156cSMarcel Moolenaar if (oldtcb != NULL) { 2706e16d0bcSMichal Meloun memcpy(tls_block, get_tls_block_ptr(oldtcb, tcbsize), 2716e16d0bcSMichal Meloun tls_block_size); 2727f7489ebSKonstantin Belousov libc_free_aligned(oldtcb); 2733614156cSMarcel Moolenaar 2743614156cSMarcel Moolenaar /* Adjust the DTV. */ 2756e16d0bcSMichal Meloun dtv = tcb[0]; 276300e0893SKonstantin Belousov dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET); 2773614156cSMarcel Moolenaar } else { 278d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 2798584ed54SMichal Meloun if (dtv == NULL) { 2808584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 2818584ed54SMichal Meloun abort(); 2828584ed54SMichal Meloun } 2836e16d0bcSMichal Meloun /* Build the DTV. */ 2846e16d0bcSMichal Meloun tcb[0] = dtv; 2858584ed54SMichal Meloun dtv[0] = 1; /* Generation. */ 2868584ed54SMichal Meloun dtv[1] = 1; /* Segments count. */ 287300e0893SKonstantin Belousov dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET); 288ccd13c49SDoug Rabson 2897f7489ebSKonstantin Belousov if (libc_tls_init_size > 0) 2907f7489ebSKonstantin Belousov memcpy(tls, libc_tls_init, libc_tls_init_size); 2910e1c7d0fSDoug Rabson } 2920e1c7d0fSDoug Rabson 2936e16d0bcSMichal Meloun return (tcb); 294ccd13c49SDoug Rabson } 295ccd13c49SDoug Rabson 296ccd13c49SDoug Rabson #endif 297ccd13c49SDoug Rabson 298ccd13c49SDoug Rabson #ifdef TLS_VARIANT_II 299ccd13c49SDoug Rabson 300ccd13c49SDoug Rabson /* 301ccd13c49SDoug Rabson * Free Static TLS using the Variant II method. 302ccd13c49SDoug Rabson */ 3030e1c7d0fSDoug Rabson void 30426896bdaSDavid Xu __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 3050e1c7d0fSDoug Rabson { 306ccd13c49SDoug Rabson size_t size; 307ccd13c49SDoug Rabson Elf_Addr* dtv; 308ccd13c49SDoug Rabson Elf_Addr tlsstart, tlsend; 309ccd13c49SDoug Rabson 310ccd13c49SDoug Rabson /* 311ccd13c49SDoug Rabson * Figure out the size of the initial TLS block so that we can 312ccd13c49SDoug Rabson * find stuff which ___tls_get_addr() allocated dynamically. 313ccd13c49SDoug Rabson */ 3147f7489ebSKonstantin Belousov tcbalign = MAX(tcbalign, libc_tls_init_align); 3157f7489ebSKonstantin Belousov size = roundup2(libc_tls_static_space, tcbalign); 316ccd13c49SDoug Rabson 317ccd13c49SDoug Rabson dtv = ((Elf_Addr**)tcb)[1]; 318ccd13c49SDoug Rabson tlsend = (Elf_Addr) tcb; 319ccd13c49SDoug Rabson tlsstart = tlsend - size; 3207f7489ebSKonstantin Belousov libc_free_aligned((void*)tlsstart); 321d0e79aa3SJason Evans __je_bootstrap_free(dtv); 322ccd13c49SDoug Rabson } 323ccd13c49SDoug Rabson 324ccd13c49SDoug Rabson /* 325ccd13c49SDoug Rabson * Allocate Static TLS using the Variant II method. 326ccd13c49SDoug Rabson */ 327ccd13c49SDoug Rabson void * 32826896bdaSDavid Xu __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 329ccd13c49SDoug Rabson { 330ccd13c49SDoug Rabson size_t size; 331ccd13c49SDoug Rabson char *tls; 332ccd13c49SDoug Rabson Elf_Addr *dtv; 333ccd13c49SDoug Rabson Elf_Addr segbase, oldsegbase; 334ccd13c49SDoug Rabson 3357f7489ebSKonstantin Belousov tcbalign = MAX(tcbalign, libc_tls_init_align); 3367f7489ebSKonstantin Belousov size = roundup2(libc_tls_static_space, tcbalign); 337ccd13c49SDoug Rabson 3380031cdf4STim Kientzle if (tcbsize < 2 * sizeof(Elf_Addr)) 3390031cdf4STim Kientzle tcbsize = 2 * sizeof(Elf_Addr); 3407f7489ebSKonstantin Belousov tls = libc_malloc_aligned(size + tcbsize, tcbalign); 3418584ed54SMichal Meloun if (tls == NULL) { 3428584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 3438584ed54SMichal Meloun abort(); 3448584ed54SMichal Meloun } 3458584ed54SMichal Meloun memset(tls, 0, size + tcbsize); 346d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 3478584ed54SMichal Meloun if (dtv == NULL) { 3488584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 3498584ed54SMichal Meloun abort(); 3508584ed54SMichal Meloun } 351ccd13c49SDoug Rabson 352ccd13c49SDoug Rabson segbase = (Elf_Addr)(tls + size); 353ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[0] = segbase; 354ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 355ccd13c49SDoug Rabson 356ccd13c49SDoug Rabson dtv[0] = 1; 357ccd13c49SDoug Rabson dtv[1] = 1; 3587f7489ebSKonstantin Belousov dtv[2] = segbase - libc_tls_static_space; 359ccd13c49SDoug Rabson 360ccd13c49SDoug Rabson if (oldtls) { 361ccd13c49SDoug Rabson /* 362ccd13c49SDoug Rabson * Copy the static TLS block over whole. 363ccd13c49SDoug Rabson */ 364ccd13c49SDoug Rabson oldsegbase = (Elf_Addr) oldtls; 3657f7489ebSKonstantin Belousov memcpy((void *)(segbase - libc_tls_static_space), 3667f7489ebSKonstantin Belousov (const void *)(oldsegbase - libc_tls_static_space), 3677f7489ebSKonstantin Belousov libc_tls_static_space); 368ccd13c49SDoug Rabson 369ccd13c49SDoug Rabson /* 370ccd13c49SDoug Rabson * We assume that this block was the one we created with 371ccd13c49SDoug Rabson * allocate_initial_tls(). 372ccd13c49SDoug Rabson */ 373ccd13c49SDoug Rabson _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 374ccd13c49SDoug Rabson } else { 3757f7489ebSKonstantin Belousov memcpy((void *)(segbase - libc_tls_static_space), 3767f7489ebSKonstantin Belousov libc_tls_init, libc_tls_init_size); 3777f7489ebSKonstantin Belousov memset((void *)(segbase - libc_tls_static_space + 3787f7489ebSKonstantin Belousov libc_tls_init_size), 0, 3797f7489ebSKonstantin Belousov libc_tls_static_space - libc_tls_init_size); 380ccd13c49SDoug Rabson } 381ccd13c49SDoug Rabson 382ccd13c49SDoug Rabson return (void*) segbase; 383ccd13c49SDoug Rabson } 384ccd13c49SDoug Rabson 38526896bdaSDavid Xu #endif /* TLS_VARIANT_II */ 38626896bdaSDavid Xu 38726896bdaSDavid Xu #else 38826896bdaSDavid Xu 38926896bdaSDavid Xu void * 39026896bdaSDavid Xu __libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 39126896bdaSDavid Xu size_t tcbalign __unused) 39226896bdaSDavid Xu { 39326896bdaSDavid Xu return (0); 39426896bdaSDavid Xu } 39526896bdaSDavid Xu 39626896bdaSDavid Xu void 39726896bdaSDavid Xu __libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 39826896bdaSDavid Xu size_t tcbalign __unused) 39926896bdaSDavid Xu { 40026896bdaSDavid Xu } 40126896bdaSDavid Xu 402294246bbSEd Maste #endif /* PIC */ 40326896bdaSDavid Xu 40426896bdaSDavid Xu extern char **environ; 405ccd13c49SDoug Rabson 406ccd13c49SDoug Rabson void 40755b6b759SCraig Rodrigues _init_tls(void) 408ccd13c49SDoug Rabson { 409294246bbSEd Maste #ifndef PIC 410ccd13c49SDoug Rabson Elf_Addr *sp; 411ccd13c49SDoug Rabson Elf_Auxinfo *aux, *auxp; 412ccd13c49SDoug Rabson Elf_Phdr *phdr; 413ccd13c49SDoug Rabson size_t phent, phnum; 414ccd13c49SDoug Rabson int i; 4150e7e4e5fSDoug Rabson void *tls; 416ccd13c49SDoug Rabson 417ccd13c49SDoug Rabson sp = (Elf_Addr *) environ; 418ccd13c49SDoug Rabson while (*sp++ != 0) 419ccd13c49SDoug Rabson ; 420ccd13c49SDoug Rabson aux = (Elf_Auxinfo *) sp; 421513004a2SPedro F. Giffuni phdr = NULL; 422ccd13c49SDoug Rabson phent = phnum = 0; 423ccd13c49SDoug Rabson for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 424ccd13c49SDoug Rabson switch (auxp->a_type) { 425ccd13c49SDoug Rabson case AT_PHDR: 426ccd13c49SDoug Rabson phdr = auxp->a_un.a_ptr; 427ccd13c49SDoug Rabson break; 428ccd13c49SDoug Rabson 429ccd13c49SDoug Rabson case AT_PHENT: 430ccd13c49SDoug Rabson phent = auxp->a_un.a_val; 431ccd13c49SDoug Rabson break; 432ccd13c49SDoug Rabson 433ccd13c49SDoug Rabson case AT_PHNUM: 434ccd13c49SDoug Rabson phnum = auxp->a_un.a_val; 435ccd13c49SDoug Rabson break; 436ccd13c49SDoug Rabson } 437ccd13c49SDoug Rabson } 438513004a2SPedro F. Giffuni if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0) 439ccd13c49SDoug Rabson return; 440ccd13c49SDoug Rabson 44126896bdaSDavid Xu for (i = 0; (unsigned) i < phnum; i++) { 442ccd13c49SDoug Rabson if (phdr[i].p_type == PT_TLS) { 4437f7489ebSKonstantin Belousov libc_tls_static_space = roundup2(phdr[i].p_memsz, 444ccd13c49SDoug Rabson phdr[i].p_align); 4457f7489ebSKonstantin Belousov libc_tls_init_size = phdr[i].p_filesz; 4467f7489ebSKonstantin Belousov libc_tls_init_align = phdr[i].p_align; 4477f7489ebSKonstantin Belousov libc_tls_init = (void *)phdr[i].p_vaddr; 4488584ed54SMichal Meloun break; 449ccd13c49SDoug Rabson } 450ccd13c49SDoug Rabson } 4516e16d0bcSMichal Meloun tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); 452ccd13c49SDoug Rabson 453*8bcdb144SJohn Baldwin _tcb_set(tls); 454ccd13c49SDoug Rabson #endif 4550e1c7d0fSDoug Rabson } 456