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 75e7d939bdSMarcel Moolenaar #if defined(__amd64__) 76b84c7a79SKip Macy #define TLS_TCB_ALIGN 16 770bfee928SRuslan Bukin #elif defined(__aarch64__) || defined(__arm__) || defined(__i386__) || \ 78a5b6c296SWarner Losh defined(__mips__) || defined(__powerpc__) || defined(__riscv) 79b84c7a79SKip Macy #define TLS_TCB_ALIGN sizeof(void *) 80b84c7a79SKip Macy #else 81b84c7a79SKip Macy #error TLS_TCB_ALIGN undefined for target architecture 82b84c7a79SKip Macy #endif 83b84c7a79SKip Macy 840bfee928SRuslan Bukin #if defined(__aarch64__) || defined(__arm__) || defined(__mips__) || \ 85ca20f8ecSRuslan Bukin defined(__powerpc__) || defined(__riscv) 86ccd13c49SDoug Rabson #define TLS_VARIANT_I 87ccd13c49SDoug Rabson #endif 88a5b6c296SWarner Losh #if defined(__i386__) || defined(__amd64__) 89ccd13c49SDoug Rabson #define TLS_VARIANT_II 90ccd13c49SDoug Rabson #endif 91ccd13c49SDoug Rabson 926e16d0bcSMichal Meloun #if defined(__mips__) || defined(__powerpc__) || defined(__riscv) 936e16d0bcSMichal Meloun #define DTV_OFFSET 0x8000 946e16d0bcSMichal Meloun #else 956e16d0bcSMichal Meloun #define DTV_OFFSET 0 966e16d0bcSMichal Meloun #endif 976e16d0bcSMichal Meloun 98294246bbSEd Maste #ifndef PIC 99ccd13c49SDoug Rabson 1007f7489ebSKonstantin Belousov static size_t libc_tls_static_space; 1017f7489ebSKonstantin Belousov static size_t libc_tls_init_size; 1027f7489ebSKonstantin Belousov static size_t libc_tls_init_align; 1037f7489ebSKonstantin Belousov static void *libc_tls_init; 104ccd13c49SDoug Rabson #endif 1050e1c7d0fSDoug Rabson 106*ca46b569SKonstantin Belousov void * 107*ca46b569SKonstantin Belousov __libc_tls_get_addr(void *vti) 108*ca46b569SKonstantin Belousov { 109*ca46b569SKonstantin Belousov Elf_Addr **dtvp, *dtv; 110*ca46b569SKonstantin Belousov tls_index *ti; 111*ca46b569SKonstantin Belousov 112*ca46b569SKonstantin Belousov dtvp = _get_tp(); 113*ca46b569SKonstantin Belousov dtv = *dtvp; 114*ca46b569SKonstantin Belousov ti = vti; 115*ca46b569SKonstantin Belousov return ((char *)(dtv[ti->ti_module + 1] + ti->ti_offset) + 116*ca46b569SKonstantin Belousov TLS_DTV_OFFSET); 117*ca46b569SKonstantin Belousov } 118*ca46b569SKonstantin Belousov 1190e1c7d0fSDoug Rabson #ifdef __i386__ 1200e1c7d0fSDoug Rabson 12126896bdaSDavid Xu /* GNU ABI */ 1220e1c7d0fSDoug Rabson 1230e1c7d0fSDoug Rabson __attribute__((__regparm__(1))) 1240e1c7d0fSDoug Rabson void * 125*ca46b569SKonstantin Belousov ___libc_tls_get_addr(void *vti) 1260e1c7d0fSDoug Rabson { 127*ca46b569SKonstantin Belousov return (__libc_tls_get_addr(vti)); 1280e1c7d0fSDoug Rabson } 1290e1c7d0fSDoug Rabson 1300e1c7d0fSDoug Rabson #endif 1310e1c7d0fSDoug Rabson 132294246bbSEd Maste #ifndef PIC 13326896bdaSDavid Xu 1348584ed54SMichal Meloun static void * 1357f7489ebSKonstantin Belousov libc_malloc_aligned(size_t size, size_t align) 1368584ed54SMichal Meloun { 1378584ed54SMichal Meloun void *mem, *res; 1388584ed54SMichal Meloun 1398584ed54SMichal Meloun if (align < sizeof(void *)) 1408584ed54SMichal Meloun align = sizeof(void *); 1418584ed54SMichal Meloun 1428584ed54SMichal Meloun mem = __je_bootstrap_malloc(size + sizeof(void *) + align - 1); 1438584ed54SMichal Meloun res = (void *)roundup2((uintptr_t)mem + sizeof(void *), align); 1448584ed54SMichal Meloun *(void **)((uintptr_t)res - sizeof(void *)) = mem; 1458584ed54SMichal Meloun return (res); 1468584ed54SMichal Meloun } 1478584ed54SMichal Meloun 1488584ed54SMichal Meloun static void 1497f7489ebSKonstantin Belousov libc_free_aligned(void *ptr) 1508584ed54SMichal Meloun { 1518584ed54SMichal Meloun void *mem; 1528584ed54SMichal Meloun uintptr_t x; 1538584ed54SMichal Meloun 1548584ed54SMichal Meloun if (ptr == NULL) 1558584ed54SMichal Meloun return; 1568584ed54SMichal Meloun 1578584ed54SMichal Meloun x = (uintptr_t)ptr; 1588584ed54SMichal Meloun x -= sizeof(void *); 1598584ed54SMichal Meloun mem = *(void **)x; 1608584ed54SMichal Meloun __je_bootstrap_free(mem); 1618584ed54SMichal Meloun } 1628584ed54SMichal Meloun 163ccd13c49SDoug Rabson #ifdef TLS_VARIANT_I 164ccd13c49SDoug Rabson 1656e16d0bcSMichal Meloun /* 1666e16d0bcSMichal Meloun * There are two versions of variant I of TLS 1676e16d0bcSMichal Meloun * 1686e16d0bcSMichal Meloun * - ARM and aarch64 uses original variant I as is described in [1] and [2], 1696e16d0bcSMichal Meloun * where TP points to start of TCB followed by aligned TLS segment. 1706e16d0bcSMichal Meloun * Both TCB and TLS must be aligned to alignment of TLS section. The TCB[0] 1716e16d0bcSMichal Meloun * points to DTV vector and DTV values are real addresses (without bias). 1726e16d0bcSMichal Meloun * Note: for Local Exec TLS Model, the offsets from TP (TCB in this case) to 1736e16d0bcSMichal Meloun * TLS variables are computed by linker, so we cannot overalign TLS section. 1746e16d0bcSMichal Meloun * 1756e16d0bcSMichal Meloun * - MIPS, PowerPC and RISC-V use modified version of variant I, 1766e16d0bcSMichal Meloun * described in [3] where TP points (with bias) to TLS and TCB immediately 1776e16d0bcSMichal Meloun * precedes TLS without any alignment gap[4]. Only TLS should be aligned. 1786e16d0bcSMichal Meloun * The TCB[0] points to DTV vector and DTV values are biased by constant 1796e16d0bcSMichal Meloun * value (0x8000) from real addresses[5]. 1806e16d0bcSMichal Meloun * 1816e16d0bcSMichal Meloun * [1] Ulrich Drepper: ELF Handling for Thread-Local Storage 1826e16d0bcSMichal Meloun * www.akkadia.org/drepper/tls.pdf 1836e16d0bcSMichal Meloun * 1846e16d0bcSMichal Meloun * [2] ARM IHI 0045E: Addenda to, and Errata in, the ABI for the ARM(r) 1856e16d0bcSMichal Meloun * Architecture 1866e16d0bcSMichal Meloun * infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf 1876e16d0bcSMichal Meloun * 1886e16d0bcSMichal Meloun * [3] OpenPOWER: Power Architecture 64-Bit ELF V2 ABI Specification 1896e16d0bcSMichal Meloun * https://members.openpowerfoundation.org/document/dl/576 1906e16d0bcSMichal Meloun * 1916e16d0bcSMichal Meloun * [4] Its unclear if "without any alignment gap" is hard ABI requirement, 1926e16d0bcSMichal Meloun * but we must follow this rule due to suboptimal _set_tp() 1936e16d0bcSMichal Meloun * (aka <ARCH>_SET_TP) implementation. This function doesn't expect TP but 1946e16d0bcSMichal Meloun * TCB as argument. 1956e16d0bcSMichal Meloun * 1966e16d0bcSMichal Meloun * [5] I'm not able to validate "values are biased" assertions. 1976e16d0bcSMichal Meloun */ 1986e16d0bcSMichal Meloun 19917ceb495SDavid Xu /* 2006e16d0bcSMichal Meloun * Return pointer to allocated TLS block 2016e16d0bcSMichal Meloun */ 2026e16d0bcSMichal Meloun static void * 2036e16d0bcSMichal Meloun get_tls_block_ptr(void *tcb, size_t tcbsize) 2046e16d0bcSMichal Meloun { 2056e16d0bcSMichal Meloun size_t extra_size, post_size, pre_size, tls_block_size; 2066e16d0bcSMichal Meloun 2076e16d0bcSMichal Meloun /* Compute fragments sizes. */ 2086e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 2096e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 2107f7489ebSKonstantin Belousov post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; 2116e16d0bcSMichal Meloun #else 2126e16d0bcSMichal Meloun post_size = 0; 2136e16d0bcSMichal Meloun #endif 2146e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 2157f7489ebSKonstantin Belousov pre_size = roundup2(tls_block_size, libc_tls_init_align) - 2167f7489ebSKonstantin Belousov tls_block_size; 2176e16d0bcSMichal Meloun 2186e16d0bcSMichal Meloun return ((char *)tcb - pre_size - extra_size); 2196e16d0bcSMichal Meloun } 2206e16d0bcSMichal Meloun 2216e16d0bcSMichal Meloun /* 2226e16d0bcSMichal Meloun * Free Static TLS using the Variant I method. The tcbsize 2236e16d0bcSMichal Meloun * and tcbalign parameters must be the same as those used to allocate 2246e16d0bcSMichal Meloun * the block. 22517ceb495SDavid Xu */ 226ccd13c49SDoug Rabson void 2276e16d0bcSMichal Meloun __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) 228ccd13c49SDoug Rabson { 229ccd13c49SDoug Rabson Elf_Addr *dtv; 2303614156cSMarcel Moolenaar Elf_Addr **tls; 231ccd13c49SDoug Rabson 2328584ed54SMichal Meloun tls = (Elf_Addr **)tcb; 2333614156cSMarcel Moolenaar dtv = tls[0]; 234d0e79aa3SJason Evans __je_bootstrap_free(dtv); 2357f7489ebSKonstantin Belousov libc_free_aligned(get_tls_block_ptr(tcb, tcbsize)); 236ccd13c49SDoug Rabson } 237ccd13c49SDoug Rabson 238ccd13c49SDoug Rabson /* 239ccd13c49SDoug Rabson * Allocate Static TLS using the Variant I method. 2406e16d0bcSMichal Meloun * 2416e16d0bcSMichal Meloun * To handle all above requirements, we setup the following layout for 2426e16d0bcSMichal Meloun * TLS block: 2436e16d0bcSMichal Meloun * (whole memory block is aligned with MAX(TLS_TCB_ALIGN, tls_init_align)) 2446e16d0bcSMichal Meloun * 2456e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 2466e16d0bcSMichal Meloun * | pre gap | extended TCB | TCB | post gap | TLS segment | 2476e16d0bcSMichal Meloun * | pre_size | extra_size | TLS_TCB_SIZE | post_size | tls_static_space | 2486e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 2496e16d0bcSMichal Meloun * 2506e16d0bcSMichal Meloun * where: 2516e16d0bcSMichal Meloun * extra_size is tcbsize - TLS_TCB_SIZE 2526e16d0bcSMichal Meloun * post_size is used to adjust TCB to TLS aligment for first version of TLS 2536e16d0bcSMichal Meloun * layout and is always 0 for second version. 2546e16d0bcSMichal Meloun * pre_size is used to adjust TCB aligment for first version and to adjust 2556e16d0bcSMichal Meloun * TLS alignment for second version. 2566e16d0bcSMichal Meloun * 257ccd13c49SDoug Rabson */ 2580e1c7d0fSDoug Rabson void * 2598584ed54SMichal Meloun __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) 2600e1c7d0fSDoug Rabson { 2616e16d0bcSMichal Meloun Elf_Addr *dtv, **tcb; 2626e16d0bcSMichal Meloun char *tls_block, *tls; 2636e16d0bcSMichal Meloun size_t extra_size, maxalign, post_size, pre_size, tls_block_size; 264ccd13c49SDoug Rabson 2653614156cSMarcel Moolenaar if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) 2663614156cSMarcel Moolenaar return (oldtcb); 267ccd13c49SDoug Rabson 2688584ed54SMichal Meloun tls_assert(tcbalign >= TLS_TCB_ALIGN); 2697f7489ebSKonstantin Belousov maxalign = MAX(tcbalign, libc_tls_init_align); 2708584ed54SMichal Meloun 2716e16d0bcSMichal Meloun /* Compute fragmets sizes. */ 2726e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 2736e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 2747f7489ebSKonstantin Belousov post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; 2756e16d0bcSMichal Meloun #else 2766e16d0bcSMichal Meloun post_size = 0; 2776e16d0bcSMichal Meloun #endif 2786e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 2797f7489ebSKonstantin Belousov pre_size = roundup2(tls_block_size, libc_tls_init_align) - 2807f7489ebSKonstantin Belousov tls_block_size; 2817f7489ebSKonstantin Belousov tls_block_size += pre_size + libc_tls_static_space; 2826e16d0bcSMichal Meloun 2836e16d0bcSMichal Meloun /* Allocate whole TLS block */ 2847f7489ebSKonstantin Belousov tls_block = libc_malloc_aligned(tls_block_size, maxalign); 2856e16d0bcSMichal Meloun if (tls_block == NULL) { 2868584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 2878584ed54SMichal Meloun abort(); 2888584ed54SMichal Meloun } 2896e16d0bcSMichal Meloun memset(tls_block, 0, tls_block_size); 2906e16d0bcSMichal Meloun tcb = (Elf_Addr **)(tls_block + pre_size + extra_size); 2916e16d0bcSMichal Meloun tls = (char *)tcb + TLS_TCB_SIZE + post_size; 2923614156cSMarcel Moolenaar 2933614156cSMarcel Moolenaar if (oldtcb != NULL) { 2946e16d0bcSMichal Meloun memcpy(tls_block, get_tls_block_ptr(oldtcb, tcbsize), 2956e16d0bcSMichal Meloun tls_block_size); 2967f7489ebSKonstantin Belousov libc_free_aligned(oldtcb); 2973614156cSMarcel Moolenaar 2983614156cSMarcel Moolenaar /* Adjust the DTV. */ 2996e16d0bcSMichal Meloun dtv = tcb[0]; 3006e16d0bcSMichal Meloun dtv[2] = (Elf_Addr)(tls + DTV_OFFSET); 3013614156cSMarcel Moolenaar } else { 302d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 3038584ed54SMichal Meloun if (dtv == NULL) { 3048584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 3058584ed54SMichal Meloun abort(); 3068584ed54SMichal Meloun } 3076e16d0bcSMichal Meloun /* Build the DTV. */ 3086e16d0bcSMichal Meloun tcb[0] = dtv; 3098584ed54SMichal Meloun dtv[0] = 1; /* Generation. */ 3108584ed54SMichal Meloun dtv[1] = 1; /* Segments count. */ 3116e16d0bcSMichal Meloun dtv[2] = (Elf_Addr)(tls + DTV_OFFSET); 312ccd13c49SDoug Rabson 3137f7489ebSKonstantin Belousov if (libc_tls_init_size > 0) 3147f7489ebSKonstantin Belousov memcpy(tls, libc_tls_init, libc_tls_init_size); 3150e1c7d0fSDoug Rabson } 3160e1c7d0fSDoug Rabson 3176e16d0bcSMichal Meloun return (tcb); 318ccd13c49SDoug Rabson } 319ccd13c49SDoug Rabson 320ccd13c49SDoug Rabson #endif 321ccd13c49SDoug Rabson 322ccd13c49SDoug Rabson #ifdef TLS_VARIANT_II 323ccd13c49SDoug Rabson 3243614156cSMarcel Moolenaar #define TLS_TCB_SIZE (3 * sizeof(Elf_Addr)) 3253614156cSMarcel Moolenaar 326ccd13c49SDoug Rabson /* 327ccd13c49SDoug Rabson * Free Static TLS using the Variant II method. 328ccd13c49SDoug Rabson */ 3290e1c7d0fSDoug Rabson void 33026896bdaSDavid Xu __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 3310e1c7d0fSDoug Rabson { 332ccd13c49SDoug Rabson size_t size; 333ccd13c49SDoug Rabson Elf_Addr* dtv; 334ccd13c49SDoug Rabson Elf_Addr tlsstart, tlsend; 335ccd13c49SDoug Rabson 336ccd13c49SDoug Rabson /* 337ccd13c49SDoug Rabson * Figure out the size of the initial TLS block so that we can 338ccd13c49SDoug Rabson * find stuff which ___tls_get_addr() allocated dynamically. 339ccd13c49SDoug Rabson */ 3407f7489ebSKonstantin Belousov tcbalign = MAX(tcbalign, libc_tls_init_align); 3417f7489ebSKonstantin Belousov size = roundup2(libc_tls_static_space, tcbalign); 342ccd13c49SDoug Rabson 343ccd13c49SDoug Rabson dtv = ((Elf_Addr**)tcb)[1]; 344ccd13c49SDoug Rabson tlsend = (Elf_Addr) tcb; 345ccd13c49SDoug Rabson tlsstart = tlsend - size; 3467f7489ebSKonstantin Belousov libc_free_aligned((void*)tlsstart); 347d0e79aa3SJason Evans __je_bootstrap_free(dtv); 348ccd13c49SDoug Rabson } 349ccd13c49SDoug Rabson 350ccd13c49SDoug Rabson /* 351ccd13c49SDoug Rabson * Allocate Static TLS using the Variant II method. 352ccd13c49SDoug Rabson */ 353ccd13c49SDoug Rabson void * 35426896bdaSDavid Xu __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 355ccd13c49SDoug Rabson { 356ccd13c49SDoug Rabson size_t size; 357ccd13c49SDoug Rabson char *tls; 358ccd13c49SDoug Rabson Elf_Addr *dtv; 359ccd13c49SDoug Rabson Elf_Addr segbase, oldsegbase; 360ccd13c49SDoug Rabson 3617f7489ebSKonstantin Belousov tcbalign = MAX(tcbalign, libc_tls_init_align); 3627f7489ebSKonstantin Belousov size = roundup2(libc_tls_static_space, tcbalign); 363ccd13c49SDoug Rabson 3640031cdf4STim Kientzle if (tcbsize < 2 * sizeof(Elf_Addr)) 3650031cdf4STim Kientzle tcbsize = 2 * sizeof(Elf_Addr); 3667f7489ebSKonstantin Belousov tls = libc_malloc_aligned(size + tcbsize, tcbalign); 3678584ed54SMichal Meloun if (tls == NULL) { 3688584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 3698584ed54SMichal Meloun abort(); 3708584ed54SMichal Meloun } 3718584ed54SMichal Meloun memset(tls, 0, size + tcbsize); 372d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 3738584ed54SMichal Meloun if (dtv == NULL) { 3748584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 3758584ed54SMichal Meloun abort(); 3768584ed54SMichal Meloun } 377ccd13c49SDoug Rabson 378ccd13c49SDoug Rabson segbase = (Elf_Addr)(tls + size); 379ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[0] = segbase; 380ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 381ccd13c49SDoug Rabson 382ccd13c49SDoug Rabson dtv[0] = 1; 383ccd13c49SDoug Rabson dtv[1] = 1; 3847f7489ebSKonstantin Belousov dtv[2] = segbase - libc_tls_static_space; 385ccd13c49SDoug Rabson 386ccd13c49SDoug Rabson if (oldtls) { 387ccd13c49SDoug Rabson /* 388ccd13c49SDoug Rabson * Copy the static TLS block over whole. 389ccd13c49SDoug Rabson */ 390ccd13c49SDoug Rabson oldsegbase = (Elf_Addr) oldtls; 3917f7489ebSKonstantin Belousov memcpy((void *)(segbase - libc_tls_static_space), 3927f7489ebSKonstantin Belousov (const void *)(oldsegbase - libc_tls_static_space), 3937f7489ebSKonstantin Belousov libc_tls_static_space); 394ccd13c49SDoug Rabson 395ccd13c49SDoug Rabson /* 396ccd13c49SDoug Rabson * We assume that this block was the one we created with 397ccd13c49SDoug Rabson * allocate_initial_tls(). 398ccd13c49SDoug Rabson */ 399ccd13c49SDoug Rabson _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 400ccd13c49SDoug Rabson } else { 4017f7489ebSKonstantin Belousov memcpy((void *)(segbase - libc_tls_static_space), 4027f7489ebSKonstantin Belousov libc_tls_init, libc_tls_init_size); 4037f7489ebSKonstantin Belousov memset((void *)(segbase - libc_tls_static_space + 4047f7489ebSKonstantin Belousov libc_tls_init_size), 0, 4057f7489ebSKonstantin Belousov libc_tls_static_space - libc_tls_init_size); 406ccd13c49SDoug Rabson } 407ccd13c49SDoug Rabson 408ccd13c49SDoug Rabson return (void*) segbase; 409ccd13c49SDoug Rabson } 410ccd13c49SDoug Rabson 41126896bdaSDavid Xu #endif /* TLS_VARIANT_II */ 41226896bdaSDavid Xu 41326896bdaSDavid Xu #else 41426896bdaSDavid Xu 41526896bdaSDavid Xu void * 41626896bdaSDavid Xu __libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 41726896bdaSDavid Xu size_t tcbalign __unused) 41826896bdaSDavid Xu { 41926896bdaSDavid Xu return (0); 42026896bdaSDavid Xu } 42126896bdaSDavid Xu 42226896bdaSDavid Xu void 42326896bdaSDavid Xu __libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 42426896bdaSDavid Xu size_t tcbalign __unused) 42526896bdaSDavid Xu { 42626896bdaSDavid Xu } 42726896bdaSDavid Xu 428294246bbSEd Maste #endif /* PIC */ 42926896bdaSDavid Xu 43026896bdaSDavid Xu extern char **environ; 431ccd13c49SDoug Rabson 432ccd13c49SDoug Rabson void 43355b6b759SCraig Rodrigues _init_tls(void) 434ccd13c49SDoug Rabson { 435294246bbSEd Maste #ifndef PIC 436ccd13c49SDoug Rabson Elf_Addr *sp; 437ccd13c49SDoug Rabson Elf_Auxinfo *aux, *auxp; 438ccd13c49SDoug Rabson Elf_Phdr *phdr; 439ccd13c49SDoug Rabson size_t phent, phnum; 440ccd13c49SDoug Rabson int i; 4410e7e4e5fSDoug Rabson void *tls; 442ccd13c49SDoug Rabson 443ccd13c49SDoug Rabson sp = (Elf_Addr *) environ; 444ccd13c49SDoug Rabson while (*sp++ != 0) 445ccd13c49SDoug Rabson ; 446ccd13c49SDoug Rabson aux = (Elf_Auxinfo *) sp; 447513004a2SPedro F. Giffuni phdr = NULL; 448ccd13c49SDoug Rabson phent = phnum = 0; 449ccd13c49SDoug Rabson for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 450ccd13c49SDoug Rabson switch (auxp->a_type) { 451ccd13c49SDoug Rabson case AT_PHDR: 452ccd13c49SDoug Rabson phdr = auxp->a_un.a_ptr; 453ccd13c49SDoug Rabson break; 454ccd13c49SDoug Rabson 455ccd13c49SDoug Rabson case AT_PHENT: 456ccd13c49SDoug Rabson phent = auxp->a_un.a_val; 457ccd13c49SDoug Rabson break; 458ccd13c49SDoug Rabson 459ccd13c49SDoug Rabson case AT_PHNUM: 460ccd13c49SDoug Rabson phnum = auxp->a_un.a_val; 461ccd13c49SDoug Rabson break; 462ccd13c49SDoug Rabson } 463ccd13c49SDoug Rabson } 464513004a2SPedro F. Giffuni if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0) 465ccd13c49SDoug Rabson return; 466ccd13c49SDoug Rabson 46726896bdaSDavid Xu for (i = 0; (unsigned) i < phnum; i++) { 468ccd13c49SDoug Rabson if (phdr[i].p_type == PT_TLS) { 4697f7489ebSKonstantin Belousov libc_tls_static_space = roundup2(phdr[i].p_memsz, 470ccd13c49SDoug Rabson phdr[i].p_align); 4717f7489ebSKonstantin Belousov libc_tls_init_size = phdr[i].p_filesz; 4727f7489ebSKonstantin Belousov libc_tls_init_align = phdr[i].p_align; 4737f7489ebSKonstantin Belousov libc_tls_init = (void *)phdr[i].p_vaddr; 4748584ed54SMichal Meloun break; 475ccd13c49SDoug Rabson } 476ccd13c49SDoug Rabson } 4776e16d0bcSMichal Meloun tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); 478ccd13c49SDoug Rabson 479ccd13c49SDoug Rabson _set_tp(tls); 480ccd13c49SDoug Rabson #endif 4810e1c7d0fSDoug Rabson } 482