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 44*7f7489ebSKonstantin 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 100*7f7489ebSKonstantin Belousov static size_t libc_tls_static_space; 101*7f7489ebSKonstantin Belousov static size_t libc_tls_init_size; 102*7f7489ebSKonstantin Belousov static size_t libc_tls_init_align; 103*7f7489ebSKonstantin Belousov static void *libc_tls_init; 104ccd13c49SDoug Rabson #endif 1050e1c7d0fSDoug Rabson 1060e1c7d0fSDoug Rabson #ifdef __i386__ 1070e1c7d0fSDoug Rabson 10826896bdaSDavid Xu /* GNU ABI */ 1090e1c7d0fSDoug Rabson 1100e1c7d0fSDoug Rabson __attribute__((__regparm__(1))) 1110e1c7d0fSDoug Rabson void * 11226896bdaSDavid Xu ___libc_tls_get_addr(void *ti __unused) 1130e1c7d0fSDoug Rabson { 1140e1c7d0fSDoug Rabson return (0); 1150e1c7d0fSDoug Rabson } 1160e1c7d0fSDoug Rabson 1170e1c7d0fSDoug Rabson #endif 1180e1c7d0fSDoug Rabson 1190e1c7d0fSDoug Rabson void * 12026896bdaSDavid Xu __libc_tls_get_addr(void *ti __unused) 1210e1c7d0fSDoug Rabson { 1220e1c7d0fSDoug Rabson return (0); 1230e1c7d0fSDoug Rabson } 1240e1c7d0fSDoug Rabson 125294246bbSEd Maste #ifndef PIC 12626896bdaSDavid Xu 1278584ed54SMichal Meloun static void * 128*7f7489ebSKonstantin Belousov libc_malloc_aligned(size_t size, size_t align) 1298584ed54SMichal Meloun { 1308584ed54SMichal Meloun void *mem, *res; 1318584ed54SMichal Meloun 1328584ed54SMichal Meloun if (align < sizeof(void *)) 1338584ed54SMichal Meloun align = sizeof(void *); 1348584ed54SMichal Meloun 1358584ed54SMichal Meloun mem = __je_bootstrap_malloc(size + sizeof(void *) + align - 1); 1368584ed54SMichal Meloun res = (void *)roundup2((uintptr_t)mem + sizeof(void *), align); 1378584ed54SMichal Meloun *(void **)((uintptr_t)res - sizeof(void *)) = mem; 1388584ed54SMichal Meloun return (res); 1398584ed54SMichal Meloun } 1408584ed54SMichal Meloun 1418584ed54SMichal Meloun static void 142*7f7489ebSKonstantin Belousov libc_free_aligned(void *ptr) 1438584ed54SMichal Meloun { 1448584ed54SMichal Meloun void *mem; 1458584ed54SMichal Meloun uintptr_t x; 1468584ed54SMichal Meloun 1478584ed54SMichal Meloun if (ptr == NULL) 1488584ed54SMichal Meloun return; 1498584ed54SMichal Meloun 1508584ed54SMichal Meloun x = (uintptr_t)ptr; 1518584ed54SMichal Meloun x -= sizeof(void *); 1528584ed54SMichal Meloun mem = *(void **)x; 1538584ed54SMichal Meloun __je_bootstrap_free(mem); 1548584ed54SMichal Meloun } 1558584ed54SMichal Meloun 156ccd13c49SDoug Rabson #ifdef TLS_VARIANT_I 157ccd13c49SDoug Rabson 1586e16d0bcSMichal Meloun /* 1596e16d0bcSMichal Meloun * There are two versions of variant I of TLS 1606e16d0bcSMichal Meloun * 1616e16d0bcSMichal Meloun * - ARM and aarch64 uses original variant I as is described in [1] and [2], 1626e16d0bcSMichal Meloun * where TP points to start of TCB followed by aligned TLS segment. 1636e16d0bcSMichal Meloun * Both TCB and TLS must be aligned to alignment of TLS section. The TCB[0] 1646e16d0bcSMichal Meloun * points to DTV vector and DTV values are real addresses (without bias). 1656e16d0bcSMichal Meloun * Note: for Local Exec TLS Model, the offsets from TP (TCB in this case) to 1666e16d0bcSMichal Meloun * TLS variables are computed by linker, so we cannot overalign TLS section. 1676e16d0bcSMichal Meloun * 1686e16d0bcSMichal Meloun * - MIPS, PowerPC and RISC-V use modified version of variant I, 1696e16d0bcSMichal Meloun * described in [3] where TP points (with bias) to TLS and TCB immediately 1706e16d0bcSMichal Meloun * precedes TLS without any alignment gap[4]. Only TLS should be aligned. 1716e16d0bcSMichal Meloun * The TCB[0] points to DTV vector and DTV values are biased by constant 1726e16d0bcSMichal Meloun * value (0x8000) from real addresses[5]. 1736e16d0bcSMichal Meloun * 1746e16d0bcSMichal Meloun * [1] Ulrich Drepper: ELF Handling for Thread-Local Storage 1756e16d0bcSMichal Meloun * www.akkadia.org/drepper/tls.pdf 1766e16d0bcSMichal Meloun * 1776e16d0bcSMichal Meloun * [2] ARM IHI 0045E: Addenda to, and Errata in, the ABI for the ARM(r) 1786e16d0bcSMichal Meloun * Architecture 1796e16d0bcSMichal Meloun * infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf 1806e16d0bcSMichal Meloun * 1816e16d0bcSMichal Meloun * [3] OpenPOWER: Power Architecture 64-Bit ELF V2 ABI Specification 1826e16d0bcSMichal Meloun * https://members.openpowerfoundation.org/document/dl/576 1836e16d0bcSMichal Meloun * 1846e16d0bcSMichal Meloun * [4] Its unclear if "without any alignment gap" is hard ABI requirement, 1856e16d0bcSMichal Meloun * but we must follow this rule due to suboptimal _set_tp() 1866e16d0bcSMichal Meloun * (aka <ARCH>_SET_TP) implementation. This function doesn't expect TP but 1876e16d0bcSMichal Meloun * TCB as argument. 1886e16d0bcSMichal Meloun * 1896e16d0bcSMichal Meloun * [5] I'm not able to validate "values are biased" assertions. 1906e16d0bcSMichal Meloun */ 1916e16d0bcSMichal Meloun 19217ceb495SDavid Xu /* 1936e16d0bcSMichal Meloun * Return pointer to allocated TLS block 1946e16d0bcSMichal Meloun */ 1956e16d0bcSMichal Meloun static void * 1966e16d0bcSMichal Meloun get_tls_block_ptr(void *tcb, size_t tcbsize) 1976e16d0bcSMichal Meloun { 1986e16d0bcSMichal Meloun size_t extra_size, post_size, pre_size, tls_block_size; 1996e16d0bcSMichal Meloun 2006e16d0bcSMichal Meloun /* Compute fragments sizes. */ 2016e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 2026e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 203*7f7489ebSKonstantin Belousov post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; 2046e16d0bcSMichal Meloun #else 2056e16d0bcSMichal Meloun post_size = 0; 2066e16d0bcSMichal Meloun #endif 2076e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 208*7f7489ebSKonstantin Belousov pre_size = roundup2(tls_block_size, libc_tls_init_align) - 209*7f7489ebSKonstantin Belousov tls_block_size; 2106e16d0bcSMichal Meloun 2116e16d0bcSMichal Meloun return ((char *)tcb - pre_size - extra_size); 2126e16d0bcSMichal Meloun } 2136e16d0bcSMichal Meloun 2146e16d0bcSMichal Meloun /* 2156e16d0bcSMichal Meloun * Free Static TLS using the Variant I method. The tcbsize 2166e16d0bcSMichal Meloun * and tcbalign parameters must be the same as those used to allocate 2176e16d0bcSMichal Meloun * the block. 21817ceb495SDavid Xu */ 219ccd13c49SDoug Rabson void 2206e16d0bcSMichal Meloun __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) 221ccd13c49SDoug Rabson { 222ccd13c49SDoug Rabson Elf_Addr *dtv; 2233614156cSMarcel Moolenaar Elf_Addr **tls; 224ccd13c49SDoug Rabson 2258584ed54SMichal Meloun tls = (Elf_Addr **)tcb; 2263614156cSMarcel Moolenaar dtv = tls[0]; 227d0e79aa3SJason Evans __je_bootstrap_free(dtv); 228*7f7489ebSKonstantin Belousov libc_free_aligned(get_tls_block_ptr(tcb, tcbsize)); 229ccd13c49SDoug Rabson } 230ccd13c49SDoug Rabson 231ccd13c49SDoug Rabson /* 232ccd13c49SDoug Rabson * Allocate Static TLS using the Variant I method. 2336e16d0bcSMichal Meloun * 2346e16d0bcSMichal Meloun * To handle all above requirements, we setup the following layout for 2356e16d0bcSMichal Meloun * TLS block: 2366e16d0bcSMichal Meloun * (whole memory block is aligned with MAX(TLS_TCB_ALIGN, tls_init_align)) 2376e16d0bcSMichal Meloun * 2386e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 2396e16d0bcSMichal Meloun * | pre gap | extended TCB | TCB | post gap | TLS segment | 2406e16d0bcSMichal Meloun * | pre_size | extra_size | TLS_TCB_SIZE | post_size | tls_static_space | 2416e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 2426e16d0bcSMichal Meloun * 2436e16d0bcSMichal Meloun * where: 2446e16d0bcSMichal Meloun * extra_size is tcbsize - TLS_TCB_SIZE 2456e16d0bcSMichal Meloun * post_size is used to adjust TCB to TLS aligment for first version of TLS 2466e16d0bcSMichal Meloun * layout and is always 0 for second version. 2476e16d0bcSMichal Meloun * pre_size is used to adjust TCB aligment for first version and to adjust 2486e16d0bcSMichal Meloun * TLS alignment for second version. 2496e16d0bcSMichal Meloun * 250ccd13c49SDoug Rabson */ 2510e1c7d0fSDoug Rabson void * 2528584ed54SMichal Meloun __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) 2530e1c7d0fSDoug Rabson { 2546e16d0bcSMichal Meloun Elf_Addr *dtv, **tcb; 2556e16d0bcSMichal Meloun char *tls_block, *tls; 2566e16d0bcSMichal Meloun size_t extra_size, maxalign, post_size, pre_size, tls_block_size; 257ccd13c49SDoug Rabson 2583614156cSMarcel Moolenaar if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) 2593614156cSMarcel Moolenaar return (oldtcb); 260ccd13c49SDoug Rabson 2618584ed54SMichal Meloun tls_assert(tcbalign >= TLS_TCB_ALIGN); 262*7f7489ebSKonstantin Belousov maxalign = MAX(tcbalign, libc_tls_init_align); 2638584ed54SMichal Meloun 2646e16d0bcSMichal Meloun /* Compute fragmets sizes. */ 2656e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 2666e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 267*7f7489ebSKonstantin Belousov post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; 2686e16d0bcSMichal Meloun #else 2696e16d0bcSMichal Meloun post_size = 0; 2706e16d0bcSMichal Meloun #endif 2716e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 272*7f7489ebSKonstantin Belousov pre_size = roundup2(tls_block_size, libc_tls_init_align) - 273*7f7489ebSKonstantin Belousov tls_block_size; 274*7f7489ebSKonstantin Belousov tls_block_size += pre_size + libc_tls_static_space; 2756e16d0bcSMichal Meloun 2766e16d0bcSMichal Meloun /* Allocate whole TLS block */ 277*7f7489ebSKonstantin Belousov tls_block = libc_malloc_aligned(tls_block_size, maxalign); 2786e16d0bcSMichal Meloun if (tls_block == NULL) { 2798584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 2808584ed54SMichal Meloun abort(); 2818584ed54SMichal Meloun } 2826e16d0bcSMichal Meloun memset(tls_block, 0, tls_block_size); 2836e16d0bcSMichal Meloun tcb = (Elf_Addr **)(tls_block + pre_size + extra_size); 2846e16d0bcSMichal Meloun tls = (char *)tcb + TLS_TCB_SIZE + post_size; 2853614156cSMarcel Moolenaar 2863614156cSMarcel Moolenaar if (oldtcb != NULL) { 2876e16d0bcSMichal Meloun memcpy(tls_block, get_tls_block_ptr(oldtcb, tcbsize), 2886e16d0bcSMichal Meloun tls_block_size); 289*7f7489ebSKonstantin Belousov libc_free_aligned(oldtcb); 2903614156cSMarcel Moolenaar 2913614156cSMarcel Moolenaar /* Adjust the DTV. */ 2926e16d0bcSMichal Meloun dtv = tcb[0]; 2936e16d0bcSMichal Meloun dtv[2] = (Elf_Addr)(tls + DTV_OFFSET); 2943614156cSMarcel Moolenaar } else { 295d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 2968584ed54SMichal Meloun if (dtv == NULL) { 2978584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 2988584ed54SMichal Meloun abort(); 2998584ed54SMichal Meloun } 3006e16d0bcSMichal Meloun /* Build the DTV. */ 3016e16d0bcSMichal Meloun tcb[0] = dtv; 3028584ed54SMichal Meloun dtv[0] = 1; /* Generation. */ 3038584ed54SMichal Meloun dtv[1] = 1; /* Segments count. */ 3046e16d0bcSMichal Meloun dtv[2] = (Elf_Addr)(tls + DTV_OFFSET); 305ccd13c49SDoug Rabson 306*7f7489ebSKonstantin Belousov if (libc_tls_init_size > 0) 307*7f7489ebSKonstantin Belousov memcpy(tls, libc_tls_init, libc_tls_init_size); 3080e1c7d0fSDoug Rabson } 3090e1c7d0fSDoug Rabson 3106e16d0bcSMichal Meloun return (tcb); 311ccd13c49SDoug Rabson } 312ccd13c49SDoug Rabson 313ccd13c49SDoug Rabson #endif 314ccd13c49SDoug Rabson 315ccd13c49SDoug Rabson #ifdef TLS_VARIANT_II 316ccd13c49SDoug Rabson 3173614156cSMarcel Moolenaar #define TLS_TCB_SIZE (3 * sizeof(Elf_Addr)) 3183614156cSMarcel Moolenaar 319ccd13c49SDoug Rabson /* 320ccd13c49SDoug Rabson * Free Static TLS using the Variant II method. 321ccd13c49SDoug Rabson */ 3220e1c7d0fSDoug Rabson void 32326896bdaSDavid Xu __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 3240e1c7d0fSDoug Rabson { 325ccd13c49SDoug Rabson size_t size; 326ccd13c49SDoug Rabson Elf_Addr* dtv; 327ccd13c49SDoug Rabson Elf_Addr tlsstart, tlsend; 328ccd13c49SDoug Rabson 329ccd13c49SDoug Rabson /* 330ccd13c49SDoug Rabson * Figure out the size of the initial TLS block so that we can 331ccd13c49SDoug Rabson * find stuff which ___tls_get_addr() allocated dynamically. 332ccd13c49SDoug Rabson */ 333*7f7489ebSKonstantin Belousov tcbalign = MAX(tcbalign, libc_tls_init_align); 334*7f7489ebSKonstantin Belousov size = roundup2(libc_tls_static_space, tcbalign); 335ccd13c49SDoug Rabson 336ccd13c49SDoug Rabson dtv = ((Elf_Addr**)tcb)[1]; 337ccd13c49SDoug Rabson tlsend = (Elf_Addr) tcb; 338ccd13c49SDoug Rabson tlsstart = tlsend - size; 339*7f7489ebSKonstantin Belousov libc_free_aligned((void*)tlsstart); 340d0e79aa3SJason Evans __je_bootstrap_free(dtv); 341ccd13c49SDoug Rabson } 342ccd13c49SDoug Rabson 343ccd13c49SDoug Rabson /* 344ccd13c49SDoug Rabson * Allocate Static TLS using the Variant II method. 345ccd13c49SDoug Rabson */ 346ccd13c49SDoug Rabson void * 34726896bdaSDavid Xu __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 348ccd13c49SDoug Rabson { 349ccd13c49SDoug Rabson size_t size; 350ccd13c49SDoug Rabson char *tls; 351ccd13c49SDoug Rabson Elf_Addr *dtv; 352ccd13c49SDoug Rabson Elf_Addr segbase, oldsegbase; 353ccd13c49SDoug Rabson 354*7f7489ebSKonstantin Belousov tcbalign = MAX(tcbalign, libc_tls_init_align); 355*7f7489ebSKonstantin Belousov size = roundup2(libc_tls_static_space, tcbalign); 356ccd13c49SDoug Rabson 3570031cdf4STim Kientzle if (tcbsize < 2 * sizeof(Elf_Addr)) 3580031cdf4STim Kientzle tcbsize = 2 * sizeof(Elf_Addr); 359*7f7489ebSKonstantin Belousov tls = libc_malloc_aligned(size + tcbsize, tcbalign); 3608584ed54SMichal Meloun if (tls == NULL) { 3618584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 3628584ed54SMichal Meloun abort(); 3638584ed54SMichal Meloun } 3648584ed54SMichal Meloun memset(tls, 0, size + tcbsize); 365d0e79aa3SJason Evans dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); 3668584ed54SMichal Meloun if (dtv == NULL) { 3678584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 3688584ed54SMichal Meloun abort(); 3698584ed54SMichal Meloun } 370ccd13c49SDoug Rabson 371ccd13c49SDoug Rabson segbase = (Elf_Addr)(tls + size); 372ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[0] = segbase; 373ccd13c49SDoug Rabson ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 374ccd13c49SDoug Rabson 375ccd13c49SDoug Rabson dtv[0] = 1; 376ccd13c49SDoug Rabson dtv[1] = 1; 377*7f7489ebSKonstantin Belousov dtv[2] = segbase - libc_tls_static_space; 378ccd13c49SDoug Rabson 379ccd13c49SDoug Rabson if (oldtls) { 380ccd13c49SDoug Rabson /* 381ccd13c49SDoug Rabson * Copy the static TLS block over whole. 382ccd13c49SDoug Rabson */ 383ccd13c49SDoug Rabson oldsegbase = (Elf_Addr) oldtls; 384*7f7489ebSKonstantin Belousov memcpy((void *)(segbase - libc_tls_static_space), 385*7f7489ebSKonstantin Belousov (const void *)(oldsegbase - libc_tls_static_space), 386*7f7489ebSKonstantin Belousov libc_tls_static_space); 387ccd13c49SDoug Rabson 388ccd13c49SDoug Rabson /* 389ccd13c49SDoug Rabson * We assume that this block was the one we created with 390ccd13c49SDoug Rabson * allocate_initial_tls(). 391ccd13c49SDoug Rabson */ 392ccd13c49SDoug Rabson _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 393ccd13c49SDoug Rabson } else { 394*7f7489ebSKonstantin Belousov memcpy((void *)(segbase - libc_tls_static_space), 395*7f7489ebSKonstantin Belousov libc_tls_init, libc_tls_init_size); 396*7f7489ebSKonstantin Belousov memset((void *)(segbase - libc_tls_static_space + 397*7f7489ebSKonstantin Belousov libc_tls_init_size), 0, 398*7f7489ebSKonstantin Belousov libc_tls_static_space - libc_tls_init_size); 399ccd13c49SDoug Rabson } 400ccd13c49SDoug Rabson 401ccd13c49SDoug Rabson return (void*) segbase; 402ccd13c49SDoug Rabson } 403ccd13c49SDoug Rabson 40426896bdaSDavid Xu #endif /* TLS_VARIANT_II */ 40526896bdaSDavid Xu 40626896bdaSDavid Xu #else 40726896bdaSDavid Xu 40826896bdaSDavid Xu void * 40926896bdaSDavid Xu __libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 41026896bdaSDavid Xu size_t tcbalign __unused) 41126896bdaSDavid Xu { 41226896bdaSDavid Xu return (0); 41326896bdaSDavid Xu } 41426896bdaSDavid Xu 41526896bdaSDavid Xu void 41626896bdaSDavid Xu __libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 41726896bdaSDavid Xu size_t tcbalign __unused) 41826896bdaSDavid Xu { 41926896bdaSDavid Xu } 42026896bdaSDavid Xu 421294246bbSEd Maste #endif /* PIC */ 42226896bdaSDavid Xu 42326896bdaSDavid Xu extern char **environ; 424ccd13c49SDoug Rabson 425ccd13c49SDoug Rabson void 42655b6b759SCraig Rodrigues _init_tls(void) 427ccd13c49SDoug Rabson { 428294246bbSEd Maste #ifndef PIC 429ccd13c49SDoug Rabson Elf_Addr *sp; 430ccd13c49SDoug Rabson Elf_Auxinfo *aux, *auxp; 431ccd13c49SDoug Rabson Elf_Phdr *phdr; 432ccd13c49SDoug Rabson size_t phent, phnum; 433ccd13c49SDoug Rabson int i; 4340e7e4e5fSDoug Rabson void *tls; 435ccd13c49SDoug Rabson 436ccd13c49SDoug Rabson sp = (Elf_Addr *) environ; 437ccd13c49SDoug Rabson while (*sp++ != 0) 438ccd13c49SDoug Rabson ; 439ccd13c49SDoug Rabson aux = (Elf_Auxinfo *) sp; 440513004a2SPedro F. Giffuni phdr = NULL; 441ccd13c49SDoug Rabson phent = phnum = 0; 442ccd13c49SDoug Rabson for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 443ccd13c49SDoug Rabson switch (auxp->a_type) { 444ccd13c49SDoug Rabson case AT_PHDR: 445ccd13c49SDoug Rabson phdr = auxp->a_un.a_ptr; 446ccd13c49SDoug Rabson break; 447ccd13c49SDoug Rabson 448ccd13c49SDoug Rabson case AT_PHENT: 449ccd13c49SDoug Rabson phent = auxp->a_un.a_val; 450ccd13c49SDoug Rabson break; 451ccd13c49SDoug Rabson 452ccd13c49SDoug Rabson case AT_PHNUM: 453ccd13c49SDoug Rabson phnum = auxp->a_un.a_val; 454ccd13c49SDoug Rabson break; 455ccd13c49SDoug Rabson } 456ccd13c49SDoug Rabson } 457513004a2SPedro F. Giffuni if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0) 458ccd13c49SDoug Rabson return; 459ccd13c49SDoug Rabson 46026896bdaSDavid Xu for (i = 0; (unsigned) i < phnum; i++) { 461ccd13c49SDoug Rabson if (phdr[i].p_type == PT_TLS) { 462*7f7489ebSKonstantin Belousov libc_tls_static_space = roundup2(phdr[i].p_memsz, 463ccd13c49SDoug Rabson phdr[i].p_align); 464*7f7489ebSKonstantin Belousov libc_tls_init_size = phdr[i].p_filesz; 465*7f7489ebSKonstantin Belousov libc_tls_init_align = phdr[i].p_align; 466*7f7489ebSKonstantin Belousov libc_tls_init = (void *)phdr[i].p_vaddr; 4678584ed54SMichal Meloun break; 468ccd13c49SDoug Rabson } 469ccd13c49SDoug Rabson } 4706e16d0bcSMichal Meloun tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); 471ccd13c49SDoug Rabson 472ccd13c49SDoug Rabson _set_tp(tls); 473ccd13c49SDoug Rabson #endif 4740e1c7d0fSDoug Rabson } 475