1133064Sdfr/*- 2133064Sdfr * Copyright (c) 2004 Doug Rabson 3133064Sdfr * All rights reserved. 4133064Sdfr * 5133064Sdfr * Redistribution and use in source and binary forms, with or without 6133064Sdfr * modification, are permitted provided that the following conditions 7133064Sdfr * are met: 8133064Sdfr * 1. Redistributions of source code must retain the above copyright 9133064Sdfr * notice, this list of conditions and the following disclaimer. 10133064Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11133064Sdfr * notice, this list of conditions and the following disclaimer in the 12133064Sdfr * documentation and/or other materials provided with the distribution. 13133064Sdfr * 14133064Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15133064Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16133064Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17133064Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18133064Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19133064Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20133064Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21133064Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22133064Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23133064Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24133064Sdfr * SUCH DAMAGE. 25133064Sdfr * 26133064Sdfr * $FreeBSD: stable/10/lib/libc/gen/tls.c 324617 2017-10-14 16:49:39Z brooks $ 27133064Sdfr */ 28133064Sdfr 29133064Sdfr/* 30133064Sdfr * Define stubs for TLS internals so that programs and libraries can 31133064Sdfr * link. These functions will be replaced by functional versions at 32133064Sdfr * runtime from ld-elf.so.1. 33133064Sdfr */ 34133064Sdfr 35143921Sdavidxu#include <sys/cdefs.h> 36133754Sdfr#include <stdlib.h> 37133754Sdfr#include <string.h> 38133754Sdfr#include <elf.h> 39143921Sdavidxu 40133754Sdfr#include "libc_private.h" 41133064Sdfr 42234370Sjasone/* Provided by jemalloc to avoid bootstrapping issues. */ 43234569Sjasonevoid *__jemalloc_a0malloc(size_t size); 44234569Sjasonevoid *__jemalloc_a0calloc(size_t num, size_t size); 45234569Sjasonevoid __jemalloc_a0free(void *ptr); 46234370Sjasone 47143921Sdavidxu__weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 48143921Sdavidxu__weak_reference(__libc_free_tls, _rtld_free_tls); 49143921Sdavidxu 50143921Sdavidxu#ifdef __i386__ 51143921Sdavidxu 52143921Sdavidxu__weak_reference(___libc_tls_get_addr, ___tls_get_addr); 53143921Sdavidxu__attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *); 54143921Sdavidxu 55143921Sdavidxu#endif 56143921Sdavidxu 57143921Sdavidxuvoid * __libc_tls_get_addr(void *); 58143921Sdavidxu__weak_reference(__libc_tls_get_addr, __tls_get_addr); 59143921Sdavidxu 60143921Sdavidxuvoid *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 61143921Sdavidxuvoid _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 62143921Sdavidxuvoid *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 63143921Sdavidxuvoid __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 64143921Sdavidxu 65163118Skmacy#if defined(__ia64__) || defined(__amd64__) 66163118Skmacy#define TLS_TCB_ALIGN 16 67163118Skmacy#elif defined(__powerpc__) || defined(__i386__) || defined(__arm__) || \ 68178684Sgonzo defined(__sparc64__) || defined(__mips__) 69163118Skmacy#define TLS_TCB_ALIGN sizeof(void *) 70163118Skmacy#else 71163118Skmacy#error TLS_TCB_ALIGN undefined for target architecture 72163118Skmacy#endif 73163118Skmacy 74232582Sgonzo#if defined(__arm__) || defined(__ia64__) || defined(__mips__) || \ 75232582Sgonzo defined(__powerpc__) 76133754Sdfr#define TLS_VARIANT_I 77133754Sdfr#endif 78232582Sgonzo#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) 79133754Sdfr#define TLS_VARIANT_II 80133754Sdfr#endif 81133754Sdfr 82133754Sdfr#ifndef PIC 83133754Sdfr 84133754Sdfr#define round(size, align) \ 85133754Sdfr (((size) + (align) - 1) & ~((align) - 1)) 86133754Sdfr 87133754Sdfrstatic size_t tls_static_space; 88133754Sdfrstatic size_t tls_init_size; 89133754Sdfrstatic void *tls_init; 90133754Sdfr#endif 91133754Sdfr 92133064Sdfr#ifdef __i386__ 93133064Sdfr 94143921Sdavidxu/* GNU ABI */ 95133064Sdfr 96133064Sdfr__attribute__((__regparm__(1))) 97133064Sdfrvoid * 98143921Sdavidxu___libc_tls_get_addr(void *ti __unused) 99133064Sdfr{ 100133064Sdfr return (0); 101133064Sdfr} 102133064Sdfr 103133064Sdfr#endif 104133064Sdfr 105133064Sdfrvoid * 106143921Sdavidxu__libc_tls_get_addr(void *ti __unused) 107133064Sdfr{ 108133064Sdfr return (0); 109133064Sdfr} 110133064Sdfr 111143921Sdavidxu#ifndef PIC 112143921Sdavidxu 113133754Sdfr#ifdef TLS_VARIANT_I 114133754Sdfr 115161800Smarcel#define TLS_TCB_SIZE (2 * sizeof(void *)) 116161800Smarcel 117142560Sdavidxu/* 118142959Sdavidxu * Free Static TLS using the Variant I method. 119142560Sdavidxu */ 120133754Sdfrvoid 121161800Smarcel__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) 122133754Sdfr{ 123161800Smarcel Elf_Addr *dtv; 124161800Smarcel Elf_Addr **tls; 125133754Sdfr 126161800Smarcel tls = (Elf_Addr **)((Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE); 127161800Smarcel dtv = tls[0]; 128234569Sjasone __jemalloc_a0free(dtv); 129234569Sjasone __jemalloc_a0free(tcb); 130133754Sdfr} 131133754Sdfr 132133754Sdfr/* 133133754Sdfr * Allocate Static TLS using the Variant I method. 134133754Sdfr */ 135133064Sdfrvoid * 136161800Smarcel__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused) 137133064Sdfr{ 138133754Sdfr Elf_Addr *dtv; 139161800Smarcel Elf_Addr **tls; 140161800Smarcel char *tcb; 141133754Sdfr 142161800Smarcel if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) 143161800Smarcel return (oldtcb); 144133754Sdfr 145234569Sjasone tcb = __jemalloc_a0calloc(1, tls_static_space + tcbsize - TLS_TCB_SIZE); 146161800Smarcel tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE); 147133754Sdfr 148161800Smarcel if (oldtcb != NULL) { 149203946Smarcel memcpy(tls, oldtcb, tls_static_space); 150234569Sjasone __jemalloc_a0free(oldtcb); 151133754Sdfr 152161800Smarcel /* Adjust the DTV. */ 153161800Smarcel dtv = tls[0]; 154161800Smarcel dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; 155161800Smarcel } else { 156234569Sjasone dtv = __jemalloc_a0malloc(3 * sizeof(Elf_Addr)); 157161800Smarcel tls[0] = dtv; 158161800Smarcel dtv[0] = 1; 159161800Smarcel dtv[1] = 1; 160161800Smarcel dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; 161133754Sdfr 162161800Smarcel if (tls_init_size > 0) 163161827Smarcel memcpy((void*)dtv[2], tls_init, tls_init_size); 164133754Sdfr } 165133754Sdfr 166161800Smarcel return(tcb); 167133064Sdfr} 168133064Sdfr 169133754Sdfr#endif 170133754Sdfr 171133754Sdfr#ifdef TLS_VARIANT_II 172133754Sdfr 173161800Smarcel#define TLS_TCB_SIZE (3 * sizeof(Elf_Addr)) 174161800Smarcel 175133754Sdfr/* 176133754Sdfr * Free Static TLS using the Variant II method. 177133754Sdfr */ 178133064Sdfrvoid 179143921Sdavidxu__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 180133064Sdfr{ 181133754Sdfr size_t size; 182133754Sdfr Elf_Addr* dtv; 183133754Sdfr Elf_Addr tlsstart, tlsend; 184133754Sdfr 185133754Sdfr /* 186133754Sdfr * Figure out the size of the initial TLS block so that we can 187133754Sdfr * find stuff which ___tls_get_addr() allocated dynamically. 188133754Sdfr */ 189133754Sdfr size = round(tls_static_space, tcbalign); 190133754Sdfr 191133754Sdfr dtv = ((Elf_Addr**)tcb)[1]; 192133754Sdfr tlsend = (Elf_Addr) tcb; 193133754Sdfr tlsstart = tlsend - size; 194234569Sjasone __jemalloc_a0free((void*) tlsstart); 195234569Sjasone __jemalloc_a0free(dtv); 196133064Sdfr} 197133754Sdfr 198133754Sdfr/* 199133754Sdfr * Allocate Static TLS using the Variant II method. 200133754Sdfr */ 201133754Sdfrvoid * 202143921Sdavidxu__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 203133754Sdfr{ 204133754Sdfr size_t size; 205133754Sdfr char *tls; 206133754Sdfr Elf_Addr *dtv; 207133754Sdfr Elf_Addr segbase, oldsegbase; 208133754Sdfr 209133754Sdfr size = round(tls_static_space, tcbalign); 210133754Sdfr 211166995Skientzle if (tcbsize < 2 * sizeof(Elf_Addr)) 212166995Skientzle tcbsize = 2 * sizeof(Elf_Addr); 213234569Sjasone tls = __jemalloc_a0calloc(1, size + tcbsize); 214234569Sjasone dtv = __jemalloc_a0malloc(3 * sizeof(Elf_Addr)); 215133754Sdfr 216133754Sdfr segbase = (Elf_Addr)(tls + size); 217133754Sdfr ((Elf_Addr*)segbase)[0] = segbase; 218133754Sdfr ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 219133754Sdfr 220133754Sdfr dtv[0] = 1; 221133754Sdfr dtv[1] = 1; 222133754Sdfr dtv[2] = segbase - tls_static_space; 223133754Sdfr 224133754Sdfr if (oldtls) { 225133754Sdfr /* 226133754Sdfr * Copy the static TLS block over whole. 227133754Sdfr */ 228133754Sdfr oldsegbase = (Elf_Addr) oldtls; 229133754Sdfr memcpy((void *)(segbase - tls_static_space), 230133754Sdfr (const void *)(oldsegbase - tls_static_space), 231133754Sdfr tls_static_space); 232133754Sdfr 233133754Sdfr /* 234133754Sdfr * We assume that this block was the one we created with 235133754Sdfr * allocate_initial_tls(). 236133754Sdfr */ 237133754Sdfr _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 238133754Sdfr } else { 239133754Sdfr memcpy((void *)(segbase - tls_static_space), 240133754Sdfr tls_init, tls_init_size); 241133754Sdfr memset((void *)(segbase - tls_static_space + tls_init_size), 242133754Sdfr 0, tls_static_space - tls_init_size); 243133754Sdfr } 244133754Sdfr 245133754Sdfr return (void*) segbase; 246143921Sdavidxu} 247143921Sdavidxu 248143921Sdavidxu#endif /* TLS_VARIANT_II */ 249143921Sdavidxu 250133754Sdfr#else 251143921Sdavidxu 252143921Sdavidxuvoid * 253143921Sdavidxu__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 254143921Sdavidxu size_t tcbalign __unused) 255143921Sdavidxu{ 256133754Sdfr return (0); 257133754Sdfr} 258133754Sdfr 259143921Sdavidxuvoid 260143921Sdavidxu__libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 261143921Sdavidxu size_t tcbalign __unused) 262143921Sdavidxu{ 263143921Sdavidxu} 264133754Sdfr 265143921Sdavidxu#endif /* PIC */ 266143921Sdavidxu 267143921Sdavidxuextern char **environ; 268143921Sdavidxu 269133754Sdfrvoid 270133754Sdfr_init_tls() 271133754Sdfr{ 272133754Sdfr#ifndef PIC 273133754Sdfr Elf_Addr *sp; 274133754Sdfr Elf_Auxinfo *aux, *auxp; 275133754Sdfr Elf_Phdr *phdr; 276133754Sdfr size_t phent, phnum; 277133754Sdfr int i; 278133949Sdfr void *tls; 279133754Sdfr 280133754Sdfr sp = (Elf_Addr *) environ; 281133754Sdfr while (*sp++ != 0) 282133754Sdfr ; 283133754Sdfr aux = (Elf_Auxinfo *) sp; 284309485Sngie phdr = NULL; 285133754Sdfr phent = phnum = 0; 286133754Sdfr for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 287133754Sdfr switch (auxp->a_type) { 288133754Sdfr case AT_PHDR: 289133754Sdfr phdr = auxp->a_un.a_ptr; 290133754Sdfr break; 291133754Sdfr 292133754Sdfr case AT_PHENT: 293133754Sdfr phent = auxp->a_un.a_val; 294133754Sdfr break; 295133754Sdfr 296133754Sdfr case AT_PHNUM: 297133754Sdfr phnum = auxp->a_un.a_val; 298133754Sdfr break; 299133754Sdfr } 300133754Sdfr } 301309485Sngie if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0) 302133754Sdfr return; 303133754Sdfr 304143921Sdavidxu for (i = 0; (unsigned) i < phnum; i++) { 305133754Sdfr if (phdr[i].p_type == PT_TLS) { 306133754Sdfr tls_static_space = round(phdr[i].p_memsz, 307133754Sdfr phdr[i].p_align); 308133754Sdfr tls_init_size = phdr[i].p_filesz; 309133754Sdfr tls_init = (void*) phdr[i].p_vaddr; 310133754Sdfr } 311133754Sdfr } 312133754Sdfr 313232582Sgonzo#ifdef TLS_VARIANT_I 314232582Sgonzo /* 315232582Sgonzo * tls_static_space should include space for TLS structure 316232582Sgonzo */ 317232582Sgonzo tls_static_space += TLS_TCB_SIZE; 318232582Sgonzo#endif 319232582Sgonzo 320163118Skmacy tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); 321133754Sdfr 322133949Sdfr _set_tp(tls); 323133754Sdfr#endif 324133754Sdfr} 325