tls.c revision 161800
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: head/lib/libc/gen/tls.c 161800 2006-09-01 06:13:16Z marcel $ 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> 39133754Sdfr#include <assert.h> 40143921Sdavidxu 41133754Sdfr#include "libc_private.h" 42133064Sdfr 43143921Sdavidxu__weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 44143921Sdavidxu__weak_reference(__libc_free_tls, _rtld_free_tls); 45143921Sdavidxu 46143921Sdavidxu#ifdef __i386__ 47143921Sdavidxu 48143921Sdavidxu__weak_reference(___libc_tls_get_addr, ___tls_get_addr); 49143921Sdavidxu__attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *); 50143921Sdavidxu 51143921Sdavidxu#endif 52143921Sdavidxu 53143921Sdavidxuvoid * __libc_tls_get_addr(void *); 54143921Sdavidxu__weak_reference(__libc_tls_get_addr, __tls_get_addr); 55143921Sdavidxu 56143921Sdavidxuvoid *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 57143921Sdavidxuvoid _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 58143921Sdavidxuvoid *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 59143921Sdavidxuvoid __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 60143921Sdavidxu 61161800Smarcel#if defined(__ia64__) || defined(__powerpc__) 62133754Sdfr#define TLS_VARIANT_I 63133754Sdfr#endif 64135686Scognet#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \ 65135686Scognet defined(__arm__) 66133754Sdfr#define TLS_VARIANT_II 67133754Sdfr#endif 68133754Sdfr 69133754Sdfr#ifndef PIC 70133754Sdfr 71133754Sdfr#define round(size, align) \ 72133754Sdfr (((size) + (align) - 1) & ~((align) - 1)) 73133754Sdfr 74133754Sdfrstatic size_t tls_static_space; 75133754Sdfrstatic size_t tls_init_size; 76133754Sdfrstatic void *tls_init; 77133754Sdfr#endif 78133754Sdfr 79133064Sdfr#ifdef __i386__ 80133064Sdfr 81143921Sdavidxu/* GNU ABI */ 82133064Sdfr 83133064Sdfr__attribute__((__regparm__(1))) 84133064Sdfrvoid * 85143921Sdavidxu___libc_tls_get_addr(void *ti __unused) 86133064Sdfr{ 87133064Sdfr return (0); 88133064Sdfr} 89133064Sdfr 90133064Sdfr#endif 91133064Sdfr 92133064Sdfrvoid * 93143921Sdavidxu__libc_tls_get_addr(void *ti __unused) 94133064Sdfr{ 95133064Sdfr return (0); 96133064Sdfr} 97133064Sdfr 98143921Sdavidxu#ifndef PIC 99143921Sdavidxu 100133754Sdfr#ifdef TLS_VARIANT_I 101133754Sdfr 102161800Smarcel#define TLS_TCB_SIZE (2 * sizeof(void *)) 103161800Smarcel 104142560Sdavidxu/* 105142959Sdavidxu * Free Static TLS using the Variant I method. 106142560Sdavidxu */ 107133754Sdfrvoid 108161800Smarcel__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) 109133754Sdfr{ 110161800Smarcel Elf_Addr *dtv; 111161800Smarcel Elf_Addr **tls; 112133754Sdfr 113161800Smarcel tls = (Elf_Addr **)((Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE); 114161800Smarcel dtv = tls[0]; 115133754Sdfr free(dtv); 116161800Smarcel free(tcb); 117133754Sdfr} 118133754Sdfr 119133754Sdfr/* 120133754Sdfr * Allocate Static TLS using the Variant I method. 121133754Sdfr */ 122133064Sdfrvoid * 123161800Smarcel__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused) 124133064Sdfr{ 125133754Sdfr Elf_Addr *dtv; 126161800Smarcel Elf_Addr **tls; 127161800Smarcel char *tcb; 128133754Sdfr 129161800Smarcel if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) 130161800Smarcel return (oldtcb); 131133754Sdfr 132161800Smarcel tcb = calloc(1, tls_static_space + tcbsize); 133161800Smarcel tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE); 134133754Sdfr 135161800Smarcel if (oldtcb != NULL) { 136161800Smarcel memcpy(tls, oldtcb, tls_static_space + TLS_TCB_SIZE); 137161800Smarcel free(oldtcb); 138133754Sdfr 139161800Smarcel /* Adjust the DTV. */ 140161800Smarcel dtv = tls[0]; 141161800Smarcel dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; 142161800Smarcel } else { 143161800Smarcel dtv = malloc(3 * sizeof(Elf_Addr)); 144161800Smarcel tls[0] = dtv; 145161800Smarcel dtv[0] = 1; 146161800Smarcel dtv[1] = 1; 147161800Smarcel dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; 148133754Sdfr 149161800Smarcel if (tls_init_size > 0) 150161800Smarcel memcpy((void*)dtv[2], tls_init, tls_init_size); 151161800Smarcel if (tls_static_space > tls_init_size) 152161800Smarcel memset((void*)(dtv[2] + tls_init_size), 0, 153161800Smarcel tls_static_space - tls_init_size); 154133754Sdfr } 155133754Sdfr 156161800Smarcel return(tcb); 157133064Sdfr} 158133064Sdfr 159133754Sdfr#endif 160133754Sdfr 161133754Sdfr#ifdef TLS_VARIANT_II 162133754Sdfr 163161800Smarcel#define TLS_TCB_SIZE (3 * sizeof(Elf_Addr)) 164161800Smarcel 165133754Sdfr/* 166133754Sdfr * Free Static TLS using the Variant II method. 167133754Sdfr */ 168133064Sdfrvoid 169143921Sdavidxu__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 170133064Sdfr{ 171133754Sdfr size_t size; 172133754Sdfr Elf_Addr* dtv; 173133754Sdfr Elf_Addr tlsstart, tlsend; 174133754Sdfr 175133754Sdfr /* 176133754Sdfr * Figure out the size of the initial TLS block so that we can 177133754Sdfr * find stuff which ___tls_get_addr() allocated dynamically. 178133754Sdfr */ 179133754Sdfr size = round(tls_static_space, tcbalign); 180133754Sdfr 181133754Sdfr dtv = ((Elf_Addr**)tcb)[1]; 182133754Sdfr tlsend = (Elf_Addr) tcb; 183133754Sdfr tlsstart = tlsend - size; 184133754Sdfr free((void*) tlsstart); 185133754Sdfr free(dtv); 186133064Sdfr} 187133754Sdfr 188133754Sdfr/* 189133754Sdfr * Allocate Static TLS using the Variant II method. 190133754Sdfr */ 191133754Sdfrvoid * 192143921Sdavidxu__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 193133754Sdfr{ 194133754Sdfr size_t size; 195133754Sdfr char *tls; 196133754Sdfr Elf_Addr *dtv; 197133754Sdfr Elf_Addr segbase, oldsegbase; 198133754Sdfr 199133754Sdfr size = round(tls_static_space, tcbalign); 200133754Sdfr 201133754Sdfr assert(tcbsize >= 2*sizeof(Elf_Addr)); 202157198Sdavidxu tls = calloc(1, size + tcbsize); 203133754Sdfr dtv = malloc(3 * sizeof(Elf_Addr)); 204133754Sdfr 205133754Sdfr segbase = (Elf_Addr)(tls + size); 206133754Sdfr ((Elf_Addr*)segbase)[0] = segbase; 207133754Sdfr ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 208133754Sdfr 209133754Sdfr dtv[0] = 1; 210133754Sdfr dtv[1] = 1; 211133754Sdfr dtv[2] = segbase - tls_static_space; 212133754Sdfr 213133754Sdfr if (oldtls) { 214133754Sdfr /* 215133754Sdfr * Copy the static TLS block over whole. 216133754Sdfr */ 217133754Sdfr oldsegbase = (Elf_Addr) oldtls; 218133754Sdfr memcpy((void *)(segbase - tls_static_space), 219133754Sdfr (const void *)(oldsegbase - tls_static_space), 220133754Sdfr tls_static_space); 221133754Sdfr 222133754Sdfr /* 223133754Sdfr * We assume that this block was the one we created with 224133754Sdfr * allocate_initial_tls(). 225133754Sdfr */ 226133754Sdfr _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 227133754Sdfr } else { 228133754Sdfr memcpy((void *)(segbase - tls_static_space), 229133754Sdfr tls_init, tls_init_size); 230133754Sdfr memset((void *)(segbase - tls_static_space + tls_init_size), 231133754Sdfr 0, tls_static_space - tls_init_size); 232133754Sdfr } 233133754Sdfr 234133754Sdfr return (void*) segbase; 235143921Sdavidxu} 236143921Sdavidxu 237143921Sdavidxu#endif /* TLS_VARIANT_II */ 238143921Sdavidxu 239133754Sdfr#else 240143921Sdavidxu 241143921Sdavidxuvoid * 242143921Sdavidxu__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 243143921Sdavidxu size_t tcbalign __unused) 244143921Sdavidxu{ 245133754Sdfr return (0); 246133754Sdfr} 247133754Sdfr 248143921Sdavidxuvoid 249143921Sdavidxu__libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 250143921Sdavidxu size_t tcbalign __unused) 251143921Sdavidxu{ 252143921Sdavidxu} 253133754Sdfr 254143921Sdavidxu#endif /* PIC */ 255143921Sdavidxu 256143921Sdavidxuextern char **environ; 257143921Sdavidxu 258133754Sdfrvoid 259133754Sdfr_init_tls() 260133754Sdfr{ 261133754Sdfr#ifndef PIC 262133754Sdfr Elf_Addr *sp; 263133754Sdfr Elf_Auxinfo *aux, *auxp; 264133754Sdfr Elf_Phdr *phdr; 265133754Sdfr size_t phent, phnum; 266133754Sdfr int i; 267133949Sdfr void *tls; 268133754Sdfr 269133754Sdfr sp = (Elf_Addr *) environ; 270133754Sdfr while (*sp++ != 0) 271133754Sdfr ; 272133754Sdfr aux = (Elf_Auxinfo *) sp; 273133754Sdfr phdr = 0; 274133754Sdfr phent = phnum = 0; 275133754Sdfr for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 276133754Sdfr switch (auxp->a_type) { 277133754Sdfr case AT_PHDR: 278133754Sdfr phdr = auxp->a_un.a_ptr; 279133754Sdfr break; 280133754Sdfr 281133754Sdfr case AT_PHENT: 282133754Sdfr phent = auxp->a_un.a_val; 283133754Sdfr break; 284133754Sdfr 285133754Sdfr case AT_PHNUM: 286133754Sdfr phnum = auxp->a_un.a_val; 287133754Sdfr break; 288133754Sdfr } 289133754Sdfr } 290133754Sdfr if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0) 291133754Sdfr return; 292133754Sdfr 293143921Sdavidxu for (i = 0; (unsigned) i < phnum; i++) { 294133754Sdfr if (phdr[i].p_type == PT_TLS) { 295133754Sdfr tls_static_space = round(phdr[i].p_memsz, 296133754Sdfr phdr[i].p_align); 297133754Sdfr tls_init_size = phdr[i].p_filesz; 298133754Sdfr tls_init = (void*) phdr[i].p_vaddr; 299133754Sdfr } 300133754Sdfr } 301133754Sdfr 302161800Smarcel tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, 1); 303133754Sdfr 304133949Sdfr _set_tp(tls); 305133754Sdfr#endif 306133754Sdfr} 307