10e1c7d0fSDoug Rabson /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 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 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 356b2d5217SPedro F. Giffuni #include <sys/param.h> 36ccd13c49SDoug Rabson #include <stdlib.h> 37ccd13c49SDoug Rabson #include <string.h> 38ccd13c49SDoug Rabson #include <elf.h> 398584ed54SMichal Meloun #include <unistd.h> 4026896bdaSDavid Xu 417f7489ebSKonstantin Belousov #include "rtld.h" 42ccd13c49SDoug Rabson #include "libc_private.h" 43ccd13c49SDoug Rabson 448584ed54SMichal Meloun #define tls_assert(cond) ((cond) ? (void) 0 : \ 458584ed54SMichal Meloun (tls_msg(#cond ": assert failed: " __FILE__ ":" \ 468584ed54SMichal Meloun __XSTRING(__LINE__) "\n"), abort())) 478584ed54SMichal Meloun #define tls_msg(s) write(STDOUT_FILENO, s, strlen(s)) 488584ed54SMichal Meloun 49a4bd5210SJason Evans /* Provided by jemalloc to avoid bootstrapping issues. */ 50d0e79aa3SJason Evans void *__je_bootstrap_malloc(size_t size); 51d0e79aa3SJason Evans void *__je_bootstrap_calloc(size_t num, size_t size); 52d0e79aa3SJason Evans void __je_bootstrap_free(void *ptr); 53a4bd5210SJason Evans 5426896bdaSDavid Xu __weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 5526896bdaSDavid Xu __weak_reference(__libc_free_tls, _rtld_free_tls); 5626896bdaSDavid Xu 5726896bdaSDavid Xu #ifdef __i386__ 5826896bdaSDavid Xu 5926896bdaSDavid Xu __weak_reference(___libc_tls_get_addr, ___tls_get_addr); 6026896bdaSDavid Xu __attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *); 6126896bdaSDavid Xu 6226896bdaSDavid Xu #endif 6326896bdaSDavid Xu 6426896bdaSDavid Xu void * __libc_tls_get_addr(void *); 6526896bdaSDavid Xu __weak_reference(__libc_tls_get_addr, __tls_get_addr); 6626896bdaSDavid Xu 6726896bdaSDavid Xu void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 6826896bdaSDavid Xu void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 6926896bdaSDavid Xu void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 7026896bdaSDavid Xu void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 7126896bdaSDavid Xu 72294246bbSEd Maste #ifndef PIC 73ccd13c49SDoug Rabson 747f7489ebSKonstantin Belousov static size_t libc_tls_static_space; 757f7489ebSKonstantin Belousov static size_t libc_tls_init_size; 767f7489ebSKonstantin Belousov static size_t libc_tls_init_align; 777f7489ebSKonstantin Belousov static void *libc_tls_init; 78ccd13c49SDoug Rabson #endif 790e1c7d0fSDoug Rabson 80ca46b569SKonstantin Belousov void * 81ca46b569SKonstantin Belousov __libc_tls_get_addr(void *vti) 82ca46b569SKonstantin Belousov { 838bcdb144SJohn Baldwin uintptr_t *dtv; 84ca46b569SKonstantin Belousov tls_index *ti; 85ca46b569SKonstantin Belousov 868bcdb144SJohn Baldwin dtv = _tcb_get()->tcb_dtv; 87ca46b569SKonstantin Belousov ti = vti; 88ca46b569SKonstantin Belousov return ((char *)(dtv[ti->ti_module + 1] + ti->ti_offset) + 89ca46b569SKonstantin Belousov TLS_DTV_OFFSET); 90ca46b569SKonstantin Belousov } 91ca46b569SKonstantin Belousov 920e1c7d0fSDoug Rabson #ifdef __i386__ 930e1c7d0fSDoug Rabson 9426896bdaSDavid Xu /* GNU ABI */ 950e1c7d0fSDoug Rabson 960e1c7d0fSDoug Rabson __attribute__((__regparm__(1))) 970e1c7d0fSDoug Rabson void * 98ca46b569SKonstantin Belousov ___libc_tls_get_addr(void *vti) 990e1c7d0fSDoug Rabson { 100ca46b569SKonstantin Belousov return (__libc_tls_get_addr(vti)); 1010e1c7d0fSDoug Rabson } 1020e1c7d0fSDoug Rabson 1030e1c7d0fSDoug Rabson #endif 1040e1c7d0fSDoug Rabson 105294246bbSEd Maste #ifndef PIC 10626896bdaSDavid Xu 1078584ed54SMichal Meloun static void * 1087f7489ebSKonstantin Belousov libc_malloc_aligned(size_t size, size_t align) 1098584ed54SMichal Meloun { 1108584ed54SMichal Meloun void *mem, *res; 1118584ed54SMichal Meloun 1128584ed54SMichal Meloun if (align < sizeof(void *)) 1138584ed54SMichal Meloun align = sizeof(void *); 1148584ed54SMichal Meloun 1158584ed54SMichal Meloun mem = __je_bootstrap_malloc(size + sizeof(void *) + align - 1); 116*1e99be5dSMaxim Sobolev if (mem == NULL) 117*1e99be5dSMaxim Sobolev return (NULL); 1188584ed54SMichal Meloun res = (void *)roundup2((uintptr_t)mem + sizeof(void *), align); 1198584ed54SMichal Meloun *(void **)((uintptr_t)res - sizeof(void *)) = mem; 1208584ed54SMichal Meloun return (res); 1218584ed54SMichal Meloun } 1228584ed54SMichal Meloun 1238584ed54SMichal Meloun static void 1247f7489ebSKonstantin Belousov libc_free_aligned(void *ptr) 1258584ed54SMichal Meloun { 1268584ed54SMichal Meloun void *mem; 1278584ed54SMichal Meloun uintptr_t x; 1288584ed54SMichal Meloun 1298584ed54SMichal Meloun if (ptr == NULL) 1308584ed54SMichal Meloun return; 1318584ed54SMichal Meloun 1328584ed54SMichal Meloun x = (uintptr_t)ptr; 1338584ed54SMichal Meloun x -= sizeof(void *); 1348584ed54SMichal Meloun mem = *(void **)x; 1358584ed54SMichal Meloun __je_bootstrap_free(mem); 1368584ed54SMichal Meloun } 1378584ed54SMichal Meloun 138ccd13c49SDoug Rabson #ifdef TLS_VARIANT_I 139ccd13c49SDoug Rabson 1406e16d0bcSMichal Meloun /* 1416e16d0bcSMichal Meloun * There are two versions of variant I of TLS 1426e16d0bcSMichal Meloun * 1436e16d0bcSMichal Meloun * - ARM and aarch64 uses original variant I as is described in [1] and [2], 1446e16d0bcSMichal Meloun * where TP points to start of TCB followed by aligned TLS segment. 1456e16d0bcSMichal Meloun * Both TCB and TLS must be aligned to alignment of TLS section. The TCB[0] 1466e16d0bcSMichal Meloun * points to DTV vector and DTV values are real addresses (without bias). 1476e16d0bcSMichal Meloun * Note: for Local Exec TLS Model, the offsets from TP (TCB in this case) to 1486e16d0bcSMichal Meloun * TLS variables are computed by linker, so we cannot overalign TLS section. 1496e16d0bcSMichal Meloun * 150479ef15dSWarner Losh * - PowerPC and RISC-V use modified version of variant I, described in [3] 151479ef15dSWarner Losh * where TP points (with bias) to TLS and TCB immediately precedes TLS without 152479ef15dSWarner Losh * any alignment gap[4]. Only TLS should be aligned. The TCB[0] points to DTV 153479ef15dSWarner Losh * vector and DTV values are biased by constant value (TLS_DTV_OFFSET) from 154479ef15dSWarner Losh * real addresses[5]. 1556e16d0bcSMichal Meloun * 1566e16d0bcSMichal Meloun * [1] Ulrich Drepper: ELF Handling for Thread-Local Storage 1576e16d0bcSMichal Meloun * www.akkadia.org/drepper/tls.pdf 1586e16d0bcSMichal Meloun * 1596e16d0bcSMichal Meloun * [2] ARM IHI 0045E: Addenda to, and Errata in, the ABI for the ARM(r) 1606e16d0bcSMichal Meloun * Architecture 1616e16d0bcSMichal Meloun * infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf 1626e16d0bcSMichal Meloun * 1636e16d0bcSMichal Meloun * [3] OpenPOWER: Power Architecture 64-Bit ELF V2 ABI Specification 1646e16d0bcSMichal Meloun * https://members.openpowerfoundation.org/document/dl/576 1656e16d0bcSMichal Meloun * 1666e16d0bcSMichal Meloun * [4] Its unclear if "without any alignment gap" is hard ABI requirement, 1678bcdb144SJohn Baldwin * but we must follow this rule due to suboptimal _tcb_set() 1686e16d0bcSMichal Meloun * (aka <ARCH>_SET_TP) implementation. This function doesn't expect TP but 1696e16d0bcSMichal Meloun * TCB as argument. 1706e16d0bcSMichal Meloun * 1716e16d0bcSMichal Meloun * [5] I'm not able to validate "values are biased" assertions. 1726e16d0bcSMichal Meloun */ 1736e16d0bcSMichal Meloun 17417ceb495SDavid Xu /* 1756e16d0bcSMichal Meloun * Return pointer to allocated TLS block 1766e16d0bcSMichal Meloun */ 1776e16d0bcSMichal Meloun static void * 1786e16d0bcSMichal Meloun get_tls_block_ptr(void *tcb, size_t tcbsize) 1796e16d0bcSMichal Meloun { 1806e16d0bcSMichal Meloun size_t extra_size, post_size, pre_size, tls_block_size; 1816e16d0bcSMichal Meloun 1826e16d0bcSMichal Meloun /* Compute fragments sizes. */ 1836e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 1846e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 1857f7489ebSKonstantin Belousov post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; 1866e16d0bcSMichal Meloun #else 1876e16d0bcSMichal Meloun post_size = 0; 1886e16d0bcSMichal Meloun #endif 1896e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 1907f7489ebSKonstantin Belousov pre_size = roundup2(tls_block_size, libc_tls_init_align) - 1917f7489ebSKonstantin Belousov tls_block_size; 1926e16d0bcSMichal Meloun 1936e16d0bcSMichal Meloun return ((char *)tcb - pre_size - extra_size); 1946e16d0bcSMichal Meloun } 1956e16d0bcSMichal Meloun 1966e16d0bcSMichal Meloun /* 1976e16d0bcSMichal Meloun * Free Static TLS using the Variant I method. The tcbsize 1986e16d0bcSMichal Meloun * and tcbalign parameters must be the same as those used to allocate 1996e16d0bcSMichal Meloun * the block. 20017ceb495SDavid Xu */ 201ccd13c49SDoug Rabson void 2026e16d0bcSMichal Meloun __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) 203ccd13c49SDoug Rabson { 204ccd13c49SDoug Rabson Elf_Addr *dtv; 2053614156cSMarcel Moolenaar Elf_Addr **tls; 206ccd13c49SDoug Rabson 2078584ed54SMichal Meloun tls = (Elf_Addr **)tcb; 2083614156cSMarcel Moolenaar dtv = tls[0]; 209d0e79aa3SJason Evans __je_bootstrap_free(dtv); 2107f7489ebSKonstantin Belousov libc_free_aligned(get_tls_block_ptr(tcb, tcbsize)); 211ccd13c49SDoug Rabson } 212ccd13c49SDoug Rabson 213ccd13c49SDoug Rabson /* 214ccd13c49SDoug Rabson * Allocate Static TLS using the Variant I method. 2156e16d0bcSMichal Meloun * 2166e16d0bcSMichal Meloun * To handle all above requirements, we setup the following layout for 2176e16d0bcSMichal Meloun * TLS block: 2186e16d0bcSMichal Meloun * (whole memory block is aligned with MAX(TLS_TCB_ALIGN, tls_init_align)) 2196e16d0bcSMichal Meloun * 2206e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 2216e16d0bcSMichal Meloun * | pre gap | extended TCB | TCB | post gap | TLS segment | 2226e16d0bcSMichal Meloun * | pre_size | extra_size | TLS_TCB_SIZE | post_size | tls_static_space | 2236e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 2246e16d0bcSMichal Meloun * 2256e16d0bcSMichal Meloun * where: 2266e16d0bcSMichal Meloun * extra_size is tcbsize - TLS_TCB_SIZE 227a1581cd7SGordon Bergling * post_size is used to adjust TCB to TLS alignment for first version of TLS 2286e16d0bcSMichal Meloun * layout and is always 0 for second version. 229a1581cd7SGordon Bergling * pre_size is used to adjust TCB alignment for first version and to adjust 2306e16d0bcSMichal Meloun * TLS alignment for second version. 2316e16d0bcSMichal Meloun * 232ccd13c49SDoug Rabson */ 2330e1c7d0fSDoug Rabson void * 2348584ed54SMichal Meloun __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) 2350e1c7d0fSDoug Rabson { 2366e16d0bcSMichal Meloun Elf_Addr *dtv, **tcb; 2376e16d0bcSMichal Meloun char *tls_block, *tls; 2386e16d0bcSMichal Meloun size_t extra_size, maxalign, post_size, pre_size, tls_block_size; 239ccd13c49SDoug Rabson 2403614156cSMarcel Moolenaar if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) 2413614156cSMarcel Moolenaar return (oldtcb); 242ccd13c49SDoug Rabson 2438584ed54SMichal Meloun tls_assert(tcbalign >= TLS_TCB_ALIGN); 2447f7489ebSKonstantin Belousov maxalign = MAX(tcbalign, libc_tls_init_align); 2458584ed54SMichal Meloun 2466e16d0bcSMichal Meloun /* Compute fragmets sizes. */ 2476e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 2486e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 2497f7489ebSKonstantin Belousov post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; 2506e16d0bcSMichal Meloun #else 2516e16d0bcSMichal Meloun post_size = 0; 2526e16d0bcSMichal Meloun #endif 2536e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 2547f7489ebSKonstantin Belousov pre_size = roundup2(tls_block_size, libc_tls_init_align) - 2557f7489ebSKonstantin Belousov tls_block_size; 2567f7489ebSKonstantin Belousov tls_block_size += pre_size + libc_tls_static_space; 2576e16d0bcSMichal Meloun 2586e16d0bcSMichal Meloun /* Allocate whole TLS block */ 2597f7489ebSKonstantin Belousov tls_block = libc_malloc_aligned(tls_block_size, maxalign); 2606e16d0bcSMichal Meloun if (tls_block == NULL) { 2618584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 2628584ed54SMichal Meloun abort(); 2638584ed54SMichal Meloun } 2646e16d0bcSMichal Meloun memset(tls_block, 0, tls_block_size); 2656e16d0bcSMichal Meloun tcb = (Elf_Addr **)(tls_block + pre_size + extra_size); 2666e16d0bcSMichal Meloun tls = (char *)tcb + TLS_TCB_SIZE + post_size; 2673614156cSMarcel Moolenaar 2683614156cSMarcel Moolenaar if (oldtcb != NULL) { 2696e16d0bcSMichal Meloun memcpy(tls_block, get_tls_block_ptr(oldtcb, tcbsize), 2706e16d0bcSMichal Meloun tls_block_size); 2717f7489ebSKonstantin Belousov libc_free_aligned(oldtcb); 2723614156cSMarcel Moolenaar 2733614156cSMarcel Moolenaar /* Adjust the DTV. */ 2746e16d0bcSMichal Meloun dtv = tcb[0]; 275300e0893SKonstantin Belousov dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET); 2763614156cSMarcel Moolenaar } else { 277d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 2788584ed54SMichal Meloun if (dtv == NULL) { 2798584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 2808584ed54SMichal Meloun abort(); 2818584ed54SMichal Meloun } 2826e16d0bcSMichal Meloun /* Build the DTV. */ 2836e16d0bcSMichal Meloun tcb[0] = dtv; 2848584ed54SMichal Meloun dtv[0] = 1; /* Generation. */ 2858584ed54SMichal Meloun dtv[1] = 1; /* Segments count. */ 286300e0893SKonstantin Belousov dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET); 287ccd13c49SDoug Rabson 2887f7489ebSKonstantin Belousov if (libc_tls_init_size > 0) 2897f7489ebSKonstantin Belousov memcpy(tls, libc_tls_init, libc_tls_init_size); 2900e1c7d0fSDoug Rabson } 2910e1c7d0fSDoug Rabson 2926e16d0bcSMichal Meloun return (tcb); 293ccd13c49SDoug Rabson } 294ccd13c49SDoug Rabson 295ccd13c49SDoug Rabson #endif 296ccd13c49SDoug Rabson 297ccd13c49SDoug Rabson #ifdef TLS_VARIANT_II 298ccd13c49SDoug Rabson 299ccd13c49SDoug Rabson /* 300ccd13c49SDoug Rabson * Free Static TLS using the Variant II method. 301ccd13c49SDoug Rabson */ 3020e1c7d0fSDoug Rabson void 30326896bdaSDavid Xu __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 3040e1c7d0fSDoug Rabson { 305ccd13c49SDoug Rabson size_t size; 306ccd13c49SDoug Rabson Elf_Addr* dtv; 307ccd13c49SDoug Rabson Elf_Addr tlsstart, tlsend; 308ccd13c49SDoug Rabson 309ccd13c49SDoug Rabson /* 310ccd13c49SDoug Rabson * Figure out the size of the initial TLS block so that we can 311ccd13c49SDoug Rabson * find stuff which ___tls_get_addr() allocated dynamically. 312ccd13c49SDoug Rabson */ 3137f7489ebSKonstantin Belousov tcbalign = MAX(tcbalign, libc_tls_init_align); 3147f7489ebSKonstantin Belousov size = roundup2(libc_tls_static_space, tcbalign); 315ccd13c49SDoug Rabson 316ccd13c49SDoug Rabson dtv = ((Elf_Addr**)tcb)[1]; 317ccd13c49SDoug Rabson tlsend = (Elf_Addr) tcb; 318ccd13c49SDoug Rabson tlsstart = tlsend - size; 3197f7489ebSKonstantin Belousov libc_free_aligned((void*)tlsstart); 320d0e79aa3SJason Evans __je_bootstrap_free(dtv); 321ccd13c49SDoug Rabson } 322ccd13c49SDoug Rabson 323ccd13c49SDoug Rabson /* 324ccd13c49SDoug Rabson * Allocate Static TLS using the Variant II method. 325ccd13c49SDoug Rabson */ 326ccd13c49SDoug Rabson void * 32726896bdaSDavid Xu __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 328ccd13c49SDoug Rabson { 329ccd13c49SDoug Rabson size_t size; 330ccd13c49SDoug Rabson char *tls; 331ccd13c49SDoug Rabson Elf_Addr *dtv; 332ccd13c49SDoug Rabson Elf_Addr segbase, oldsegbase; 333ccd13c49SDoug Rabson 3347f7489ebSKonstantin Belousov tcbalign = MAX(tcbalign, libc_tls_init_align); 3357f7489ebSKonstantin Belousov size = roundup2(libc_tls_static_space, tcbalign); 336ccd13c49SDoug Rabson 3370031cdf4STim Kientzle if (tcbsize < 2 * sizeof(Elf_Addr)) 3380031cdf4STim Kientzle tcbsize = 2 * sizeof(Elf_Addr); 3397f7489ebSKonstantin Belousov tls = libc_malloc_aligned(size + tcbsize, tcbalign); 3408584ed54SMichal Meloun if (tls == NULL) { 3418584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 3428584ed54SMichal Meloun abort(); 3438584ed54SMichal Meloun } 3448584ed54SMichal Meloun memset(tls, 0, size + tcbsize); 345d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 3468584ed54SMichal Meloun if (dtv == NULL) { 3478584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 3488584ed54SMichal Meloun abort(); 3498584ed54SMichal Meloun } 350ccd13c49SDoug Rabson 351ccd13c49SDoug Rabson segbase = (Elf_Addr)(tls + size); 352ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[0] = segbase; 353ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 354ccd13c49SDoug Rabson 355ccd13c49SDoug Rabson dtv[0] = 1; 356ccd13c49SDoug Rabson dtv[1] = 1; 3577f7489ebSKonstantin Belousov dtv[2] = segbase - libc_tls_static_space; 358ccd13c49SDoug Rabson 359ccd13c49SDoug Rabson if (oldtls) { 360ccd13c49SDoug Rabson /* 361ccd13c49SDoug Rabson * Copy the static TLS block over whole. 362ccd13c49SDoug Rabson */ 363ccd13c49SDoug Rabson oldsegbase = (Elf_Addr) oldtls; 3647f7489ebSKonstantin Belousov memcpy((void *)(segbase - libc_tls_static_space), 3657f7489ebSKonstantin Belousov (const void *)(oldsegbase - libc_tls_static_space), 3667f7489ebSKonstantin Belousov libc_tls_static_space); 367ccd13c49SDoug Rabson 368ccd13c49SDoug Rabson /* 369ccd13c49SDoug Rabson * We assume that this block was the one we created with 370ccd13c49SDoug Rabson * allocate_initial_tls(). 371ccd13c49SDoug Rabson */ 372ccd13c49SDoug Rabson _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 373ccd13c49SDoug Rabson } else { 3747f7489ebSKonstantin Belousov memcpy((void *)(segbase - libc_tls_static_space), 3757f7489ebSKonstantin Belousov libc_tls_init, libc_tls_init_size); 3767f7489ebSKonstantin Belousov memset((void *)(segbase - libc_tls_static_space + 3777f7489ebSKonstantin Belousov libc_tls_init_size), 0, 3787f7489ebSKonstantin Belousov libc_tls_static_space - libc_tls_init_size); 379ccd13c49SDoug Rabson } 380ccd13c49SDoug Rabson 381ccd13c49SDoug Rabson return (void*) segbase; 382ccd13c49SDoug Rabson } 383ccd13c49SDoug Rabson 38426896bdaSDavid Xu #endif /* TLS_VARIANT_II */ 38526896bdaSDavid Xu 38626896bdaSDavid Xu #else 38726896bdaSDavid Xu 38826896bdaSDavid Xu void * 38926896bdaSDavid Xu __libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 39026896bdaSDavid Xu size_t tcbalign __unused) 39126896bdaSDavid Xu { 39226896bdaSDavid Xu return (0); 39326896bdaSDavid Xu } 39426896bdaSDavid Xu 39526896bdaSDavid Xu void 39626896bdaSDavid Xu __libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 39726896bdaSDavid Xu size_t tcbalign __unused) 39826896bdaSDavid Xu { 39926896bdaSDavid Xu } 40026896bdaSDavid Xu 401294246bbSEd Maste #endif /* PIC */ 40226896bdaSDavid Xu 403ccd13c49SDoug Rabson void 40455b6b759SCraig Rodrigues _init_tls(void) 405ccd13c49SDoug Rabson { 406294246bbSEd Maste #ifndef PIC 407ccd13c49SDoug Rabson Elf_Addr *sp; 408ccd13c49SDoug Rabson Elf_Auxinfo *aux, *auxp; 409ccd13c49SDoug Rabson Elf_Phdr *phdr; 410ccd13c49SDoug Rabson size_t phent, phnum; 411ccd13c49SDoug Rabson int i; 4120e7e4e5fSDoug Rabson void *tls; 413ccd13c49SDoug Rabson 414ccd13c49SDoug Rabson sp = (Elf_Addr *) environ; 415ccd13c49SDoug Rabson while (*sp++ != 0) 416ccd13c49SDoug Rabson ; 417ccd13c49SDoug Rabson aux = (Elf_Auxinfo *) sp; 418513004a2SPedro F. Giffuni phdr = NULL; 419ccd13c49SDoug Rabson phent = phnum = 0; 420ccd13c49SDoug Rabson for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 421ccd13c49SDoug Rabson switch (auxp->a_type) { 422ccd13c49SDoug Rabson case AT_PHDR: 423ccd13c49SDoug Rabson phdr = auxp->a_un.a_ptr; 424ccd13c49SDoug Rabson break; 425ccd13c49SDoug Rabson 426ccd13c49SDoug Rabson case AT_PHENT: 427ccd13c49SDoug Rabson phent = auxp->a_un.a_val; 428ccd13c49SDoug Rabson break; 429ccd13c49SDoug Rabson 430ccd13c49SDoug Rabson case AT_PHNUM: 431ccd13c49SDoug Rabson phnum = auxp->a_un.a_val; 432ccd13c49SDoug Rabson break; 433ccd13c49SDoug Rabson } 434ccd13c49SDoug Rabson } 435513004a2SPedro F. Giffuni if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0) 436ccd13c49SDoug Rabson return; 437ccd13c49SDoug Rabson 43826896bdaSDavid Xu for (i = 0; (unsigned) i < phnum; i++) { 439ccd13c49SDoug Rabson if (phdr[i].p_type == PT_TLS) { 4407f7489ebSKonstantin Belousov libc_tls_static_space = roundup2(phdr[i].p_memsz, 441ccd13c49SDoug Rabson phdr[i].p_align); 4427f7489ebSKonstantin Belousov libc_tls_init_size = phdr[i].p_filesz; 4437f7489ebSKonstantin Belousov libc_tls_init_align = phdr[i].p_align; 4447f7489ebSKonstantin Belousov libc_tls_init = (void *)phdr[i].p_vaddr; 4458584ed54SMichal Meloun break; 446ccd13c49SDoug Rabson } 447ccd13c49SDoug Rabson } 4486e16d0bcSMichal Meloun tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); 449ccd13c49SDoug Rabson 4508bcdb144SJohn Baldwin _tcb_set(tls); 451ccd13c49SDoug Rabson #endif 4520e1c7d0fSDoug Rabson } 453