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 44ccd13c49SDoug Rabson #include "libc_private.h" 45ccd13c49SDoug Rabson 468584ed54SMichal Meloun #define tls_assert(cond) ((cond) ? (void) 0 : \ 478584ed54SMichal Meloun (tls_msg(#cond ": assert failed: " __FILE__ ":" \ 488584ed54SMichal Meloun __XSTRING(__LINE__) "\n"), abort())) 498584ed54SMichal Meloun #define tls_msg(s) write(STDOUT_FILENO, s, strlen(s)) 508584ed54SMichal Meloun 51a4bd5210SJason Evans /* Provided by jemalloc to avoid bootstrapping issues. */ 52d0e79aa3SJason Evans void *__je_bootstrap_malloc(size_t size); 53d0e79aa3SJason Evans void *__je_bootstrap_calloc(size_t num, size_t size); 54d0e79aa3SJason Evans void __je_bootstrap_free(void *ptr); 55a4bd5210SJason Evans 5626896bdaSDavid Xu __weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 5726896bdaSDavid Xu __weak_reference(__libc_free_tls, _rtld_free_tls); 5826896bdaSDavid Xu 5926896bdaSDavid Xu #ifdef __i386__ 6026896bdaSDavid Xu 6126896bdaSDavid Xu __weak_reference(___libc_tls_get_addr, ___tls_get_addr); 6226896bdaSDavid Xu __attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *); 6326896bdaSDavid Xu 6426896bdaSDavid Xu #endif 6526896bdaSDavid Xu 6626896bdaSDavid Xu void * __libc_tls_get_addr(void *); 6726896bdaSDavid Xu __weak_reference(__libc_tls_get_addr, __tls_get_addr); 6826896bdaSDavid Xu 6926896bdaSDavid Xu void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 7026896bdaSDavid Xu void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 7126896bdaSDavid Xu void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 7226896bdaSDavid Xu void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 7326896bdaSDavid Xu 74e7d939bdSMarcel Moolenaar #if defined(__amd64__) 75b84c7a79SKip Macy #define TLS_TCB_ALIGN 16 760bfee928SRuslan Bukin #elif defined(__aarch64__) || defined(__arm__) || defined(__i386__) || \ 77ca20f8ecSRuslan Bukin defined(__mips__) || defined(__powerpc__) || defined(__riscv) || \ 780bfee928SRuslan Bukin defined(__sparc64__) 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 8854da2fb8SOleksandr Tymoshenko #if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) 89ccd13c49SDoug Rabson #define TLS_VARIANT_II 90ccd13c49SDoug Rabson #endif 91ccd13c49SDoug Rabson 92*6e16d0bcSMichal Meloun #if defined(__mips__) || defined(__powerpc__) || defined(__riscv) 93*6e16d0bcSMichal Meloun #define DTV_OFFSET 0x8000 94*6e16d0bcSMichal Meloun #else 95*6e16d0bcSMichal Meloun #define DTV_OFFSET 0 96*6e16d0bcSMichal Meloun #endif 97*6e16d0bcSMichal Meloun 98294246bbSEd Maste #ifndef PIC 99ccd13c49SDoug Rabson 100ccd13c49SDoug Rabson static size_t tls_static_space; 101ccd13c49SDoug Rabson static size_t tls_init_size; 1028584ed54SMichal Meloun static size_t tls_init_align; 103ccd13c49SDoug Rabson static void *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 * 1288584ed54SMichal Meloun 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 1428584ed54SMichal Meloun 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 158*6e16d0bcSMichal Meloun /* 159*6e16d0bcSMichal Meloun * There are two versions of variant I of TLS 160*6e16d0bcSMichal Meloun * 161*6e16d0bcSMichal Meloun * - ARM and aarch64 uses original variant I as is described in [1] and [2], 162*6e16d0bcSMichal Meloun * where TP points to start of TCB followed by aligned TLS segment. 163*6e16d0bcSMichal Meloun * Both TCB and TLS must be aligned to alignment of TLS section. The TCB[0] 164*6e16d0bcSMichal Meloun * points to DTV vector and DTV values are real addresses (without bias). 165*6e16d0bcSMichal Meloun * Note: for Local Exec TLS Model, the offsets from TP (TCB in this case) to 166*6e16d0bcSMichal Meloun * TLS variables are computed by linker, so we cannot overalign TLS section. 167*6e16d0bcSMichal Meloun * 168*6e16d0bcSMichal Meloun * - MIPS, PowerPC and RISC-V use modified version of variant I, 169*6e16d0bcSMichal Meloun * described in [3] where TP points (with bias) to TLS and TCB immediately 170*6e16d0bcSMichal Meloun * precedes TLS without any alignment gap[4]. Only TLS should be aligned. 171*6e16d0bcSMichal Meloun * The TCB[0] points to DTV vector and DTV values are biased by constant 172*6e16d0bcSMichal Meloun * value (0x8000) from real addresses[5]. 173*6e16d0bcSMichal Meloun * 174*6e16d0bcSMichal Meloun * [1] Ulrich Drepper: ELF Handling for Thread-Local Storage 175*6e16d0bcSMichal Meloun * www.akkadia.org/drepper/tls.pdf 176*6e16d0bcSMichal Meloun * 177*6e16d0bcSMichal Meloun * [2] ARM IHI 0045E: Addenda to, and Errata in, the ABI for the ARM(r) 178*6e16d0bcSMichal Meloun * Architecture 179*6e16d0bcSMichal Meloun * infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf 180*6e16d0bcSMichal Meloun * 181*6e16d0bcSMichal Meloun * [3] OpenPOWER: Power Architecture 64-Bit ELF V2 ABI Specification 182*6e16d0bcSMichal Meloun * https://members.openpowerfoundation.org/document/dl/576 183*6e16d0bcSMichal Meloun * 184*6e16d0bcSMichal Meloun * [4] Its unclear if "without any alignment gap" is hard ABI requirement, 185*6e16d0bcSMichal Meloun * but we must follow this rule due to suboptimal _set_tp() 186*6e16d0bcSMichal Meloun * (aka <ARCH>_SET_TP) implementation. This function doesn't expect TP but 187*6e16d0bcSMichal Meloun * TCB as argument. 188*6e16d0bcSMichal Meloun * 189*6e16d0bcSMichal Meloun * [5] I'm not able to validate "values are biased" assertions. 190*6e16d0bcSMichal Meloun */ 191*6e16d0bcSMichal Meloun 1923614156cSMarcel Moolenaar #define TLS_TCB_SIZE (2 * sizeof(void *)) 1933614156cSMarcel Moolenaar 19417ceb495SDavid Xu /* 195*6e16d0bcSMichal Meloun * Return pointer to allocated TLS block 196*6e16d0bcSMichal Meloun */ 197*6e16d0bcSMichal Meloun static void * 198*6e16d0bcSMichal Meloun get_tls_block_ptr(void *tcb, size_t tcbsize) 199*6e16d0bcSMichal Meloun { 200*6e16d0bcSMichal Meloun size_t extra_size, post_size, pre_size, tls_block_size; 201*6e16d0bcSMichal Meloun 202*6e16d0bcSMichal Meloun /* Compute fragments sizes. */ 203*6e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 204*6e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 205*6e16d0bcSMichal Meloun post_size = roundup2(TLS_TCB_SIZE, tls_init_align) - TLS_TCB_SIZE; 206*6e16d0bcSMichal Meloun #else 207*6e16d0bcSMichal Meloun post_size = 0; 208*6e16d0bcSMichal Meloun #endif 209*6e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 210*6e16d0bcSMichal Meloun pre_size = roundup2(tls_block_size, tls_init_align) - tls_block_size; 211*6e16d0bcSMichal Meloun 212*6e16d0bcSMichal Meloun return ((char *)tcb - pre_size - extra_size); 213*6e16d0bcSMichal Meloun } 214*6e16d0bcSMichal Meloun 215*6e16d0bcSMichal Meloun /* 216*6e16d0bcSMichal Meloun * Free Static TLS using the Variant I method. The tcbsize 217*6e16d0bcSMichal Meloun * and tcbalign parameters must be the same as those used to allocate 218*6e16d0bcSMichal Meloun * the block. 21917ceb495SDavid Xu */ 220ccd13c49SDoug Rabson void 221*6e16d0bcSMichal Meloun __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) 222ccd13c49SDoug Rabson { 223ccd13c49SDoug Rabson Elf_Addr *dtv; 2243614156cSMarcel Moolenaar Elf_Addr **tls; 225ccd13c49SDoug Rabson 2268584ed54SMichal Meloun tls = (Elf_Addr **)tcb; 2273614156cSMarcel Moolenaar dtv = tls[0]; 228d0e79aa3SJason Evans __je_bootstrap_free(dtv); 229*6e16d0bcSMichal Meloun free_aligned(get_tls_block_ptr(tcb, tcbsize)); 230ccd13c49SDoug Rabson } 231ccd13c49SDoug Rabson 232ccd13c49SDoug Rabson /* 233ccd13c49SDoug Rabson * Allocate Static TLS using the Variant I method. 234*6e16d0bcSMichal Meloun * 235*6e16d0bcSMichal Meloun * To handle all above requirements, we setup the following layout for 236*6e16d0bcSMichal Meloun * TLS block: 237*6e16d0bcSMichal Meloun * (whole memory block is aligned with MAX(TLS_TCB_ALIGN, tls_init_align)) 238*6e16d0bcSMichal Meloun * 239*6e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 240*6e16d0bcSMichal Meloun * | pre gap | extended TCB | TCB | post gap | TLS segment | 241*6e16d0bcSMichal Meloun * | pre_size | extra_size | TLS_TCB_SIZE | post_size | tls_static_space | 242*6e16d0bcSMichal Meloun * +----------+--------------+--------------+-----------+------------------+ 243*6e16d0bcSMichal Meloun * 244*6e16d0bcSMichal Meloun * where: 245*6e16d0bcSMichal Meloun * extra_size is tcbsize - TLS_TCB_SIZE 246*6e16d0bcSMichal Meloun * post_size is used to adjust TCB to TLS aligment for first version of TLS 247*6e16d0bcSMichal Meloun * layout and is always 0 for second version. 248*6e16d0bcSMichal Meloun * pre_size is used to adjust TCB aligment for first version and to adjust 249*6e16d0bcSMichal Meloun * TLS alignment for second version. 250*6e16d0bcSMichal Meloun * 251ccd13c49SDoug Rabson */ 2520e1c7d0fSDoug Rabson void * 2538584ed54SMichal Meloun __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) 2540e1c7d0fSDoug Rabson { 255*6e16d0bcSMichal Meloun Elf_Addr *dtv, **tcb; 256*6e16d0bcSMichal Meloun char *tls_block, *tls; 257*6e16d0bcSMichal Meloun size_t extra_size, maxalign, post_size, pre_size, tls_block_size; 258ccd13c49SDoug Rabson 2593614156cSMarcel Moolenaar if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) 2603614156cSMarcel Moolenaar return (oldtcb); 261ccd13c49SDoug Rabson 2628584ed54SMichal Meloun tls_assert(tcbalign >= TLS_TCB_ALIGN); 263*6e16d0bcSMichal Meloun maxalign = MAX(tcbalign, tls_init_align); 2648584ed54SMichal Meloun 265*6e16d0bcSMichal Meloun /* Compute fragmets sizes. */ 266*6e16d0bcSMichal Meloun extra_size = tcbsize - TLS_TCB_SIZE; 267*6e16d0bcSMichal Meloun #if defined(__aarch64__) || defined(__arm__) 268*6e16d0bcSMichal Meloun post_size = roundup2(TLS_TCB_SIZE, tls_init_align) - TLS_TCB_SIZE; 269*6e16d0bcSMichal Meloun #else 270*6e16d0bcSMichal Meloun post_size = 0; 271*6e16d0bcSMichal Meloun #endif 272*6e16d0bcSMichal Meloun tls_block_size = tcbsize + post_size; 273*6e16d0bcSMichal Meloun pre_size = roundup2(tls_block_size, tls_init_align) - tls_block_size; 274*6e16d0bcSMichal Meloun tls_block_size += pre_size + tls_static_space; 275*6e16d0bcSMichal Meloun 276*6e16d0bcSMichal Meloun /* Allocate whole TLS block */ 277*6e16d0bcSMichal Meloun tls_block = malloc_aligned(tls_block_size, maxalign); 278*6e16d0bcSMichal Meloun if (tls_block == NULL) { 2798584ed54SMichal Meloun tls_msg("__libc_allocate_tls: Out of memory.\n"); 2808584ed54SMichal Meloun abort(); 2818584ed54SMichal Meloun } 282*6e16d0bcSMichal Meloun memset(tls_block, 0, tls_block_size); 283*6e16d0bcSMichal Meloun tcb = (Elf_Addr **)(tls_block + pre_size + extra_size); 284*6e16d0bcSMichal Meloun tls = (char *)tcb + TLS_TCB_SIZE + post_size; 2853614156cSMarcel Moolenaar 2863614156cSMarcel Moolenaar if (oldtcb != NULL) { 287*6e16d0bcSMichal Meloun memcpy(tls_block, get_tls_block_ptr(oldtcb, tcbsize), 288*6e16d0bcSMichal Meloun tls_block_size); 289*6e16d0bcSMichal Meloun free_aligned(oldtcb); 2903614156cSMarcel Moolenaar 2913614156cSMarcel Moolenaar /* Adjust the DTV. */ 292*6e16d0bcSMichal Meloun dtv = tcb[0]; 293*6e16d0bcSMichal 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 } 300*6e16d0bcSMichal Meloun /* Build the DTV. */ 301*6e16d0bcSMichal Meloun tcb[0] = dtv; 3028584ed54SMichal Meloun dtv[0] = 1; /* Generation. */ 3038584ed54SMichal Meloun dtv[1] = 1; /* Segments count. */ 304*6e16d0bcSMichal Meloun dtv[2] = (Elf_Addr)(tls + DTV_OFFSET); 305ccd13c49SDoug Rabson 3063614156cSMarcel Moolenaar if (tls_init_size > 0) 307*6e16d0bcSMichal Meloun memcpy(tls, tls_init, tls_init_size); 3080e1c7d0fSDoug Rabson } 3090e1c7d0fSDoug Rabson 310*6e16d0bcSMichal 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*6e16d0bcSMichal Meloun tcbalign = MAX(tcbalign, tls_init_align); 3346b2d5217SPedro F. Giffuni size = roundup2(tls_static_space, tcbalign); 335ccd13c49SDoug Rabson 336ccd13c49SDoug Rabson dtv = ((Elf_Addr**)tcb)[1]; 337ccd13c49SDoug Rabson tlsend = (Elf_Addr) tcb; 338ccd13c49SDoug Rabson tlsstart = tlsend - size; 3398584ed54SMichal Meloun 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*6e16d0bcSMichal Meloun tcbalign = MAX(tcbalign, tls_init_align); 3556b2d5217SPedro F. Giffuni size = roundup2(tls_static_space, tcbalign); 356ccd13c49SDoug Rabson 3570031cdf4STim Kientzle if (tcbsize < 2 * sizeof(Elf_Addr)) 3580031cdf4STim Kientzle tcbsize = 2 * sizeof(Elf_Addr); 3598584ed54SMichal Meloun tls = 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; 377ccd13c49SDoug Rabson dtv[2] = segbase - 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; 384ccd13c49SDoug Rabson memcpy((void *)(segbase - tls_static_space), 385ccd13c49SDoug Rabson (const void *)(oldsegbase - tls_static_space), 386ccd13c49SDoug Rabson 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 { 394ccd13c49SDoug Rabson memcpy((void *)(segbase - tls_static_space), 395ccd13c49SDoug Rabson tls_init, tls_init_size); 396ccd13c49SDoug Rabson memset((void *)(segbase - tls_static_space + tls_init_size), 397ccd13c49SDoug Rabson 0, tls_static_space - tls_init_size); 398ccd13c49SDoug Rabson } 399ccd13c49SDoug Rabson 400ccd13c49SDoug Rabson return (void*) segbase; 401ccd13c49SDoug Rabson } 402ccd13c49SDoug Rabson 40326896bdaSDavid Xu #endif /* TLS_VARIANT_II */ 40426896bdaSDavid Xu 40526896bdaSDavid Xu #else 40626896bdaSDavid Xu 40726896bdaSDavid Xu void * 40826896bdaSDavid Xu __libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 40926896bdaSDavid Xu size_t tcbalign __unused) 41026896bdaSDavid Xu { 41126896bdaSDavid Xu return (0); 41226896bdaSDavid Xu } 41326896bdaSDavid Xu 41426896bdaSDavid Xu void 41526896bdaSDavid Xu __libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 41626896bdaSDavid Xu size_t tcbalign __unused) 41726896bdaSDavid Xu { 41826896bdaSDavid Xu } 41926896bdaSDavid Xu 420294246bbSEd Maste #endif /* PIC */ 42126896bdaSDavid Xu 42226896bdaSDavid Xu extern char **environ; 423ccd13c49SDoug Rabson 424ccd13c49SDoug Rabson void 42555b6b759SCraig Rodrigues _init_tls(void) 426ccd13c49SDoug Rabson { 427294246bbSEd Maste #ifndef PIC 428ccd13c49SDoug Rabson Elf_Addr *sp; 429ccd13c49SDoug Rabson Elf_Auxinfo *aux, *auxp; 430ccd13c49SDoug Rabson Elf_Phdr *phdr; 431ccd13c49SDoug Rabson size_t phent, phnum; 432ccd13c49SDoug Rabson int i; 4330e7e4e5fSDoug Rabson void *tls; 434ccd13c49SDoug Rabson 435ccd13c49SDoug Rabson sp = (Elf_Addr *) environ; 436ccd13c49SDoug Rabson while (*sp++ != 0) 437ccd13c49SDoug Rabson ; 438ccd13c49SDoug Rabson aux = (Elf_Auxinfo *) sp; 439513004a2SPedro F. Giffuni phdr = NULL; 440ccd13c49SDoug Rabson phent = phnum = 0; 441ccd13c49SDoug Rabson for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 442ccd13c49SDoug Rabson switch (auxp->a_type) { 443ccd13c49SDoug Rabson case AT_PHDR: 444ccd13c49SDoug Rabson phdr = auxp->a_un.a_ptr; 445ccd13c49SDoug Rabson break; 446ccd13c49SDoug Rabson 447ccd13c49SDoug Rabson case AT_PHENT: 448ccd13c49SDoug Rabson phent = auxp->a_un.a_val; 449ccd13c49SDoug Rabson break; 450ccd13c49SDoug Rabson 451ccd13c49SDoug Rabson case AT_PHNUM: 452ccd13c49SDoug Rabson phnum = auxp->a_un.a_val; 453ccd13c49SDoug Rabson break; 454ccd13c49SDoug Rabson } 455ccd13c49SDoug Rabson } 456513004a2SPedro F. Giffuni if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0) 457ccd13c49SDoug Rabson return; 458ccd13c49SDoug Rabson 45926896bdaSDavid Xu for (i = 0; (unsigned) i < phnum; i++) { 460ccd13c49SDoug Rabson if (phdr[i].p_type == PT_TLS) { 4616b2d5217SPedro F. Giffuni tls_static_space = roundup2(phdr[i].p_memsz, 462ccd13c49SDoug Rabson phdr[i].p_align); 463ccd13c49SDoug Rabson tls_init_size = phdr[i].p_filesz; 4648584ed54SMichal Meloun tls_init_align = phdr[i].p_align; 465ccd13c49SDoug Rabson tls_init = (void*) phdr[i].p_vaddr; 4668584ed54SMichal Meloun break; 467ccd13c49SDoug Rabson } 468ccd13c49SDoug Rabson } 469*6e16d0bcSMichal Meloun tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); 470ccd13c49SDoug Rabson 471ccd13c49SDoug Rabson _set_tp(tls); 472ccd13c49SDoug Rabson #endif 4730e1c7d0fSDoug Rabson } 474