1b00401f0SDavid Xu /*- 2b00401f0SDavid Xu * Copyright (c) 2004 Doug Rabson 3b00401f0SDavid Xu * All rights reserved. 4b00401f0SDavid Xu * 5b00401f0SDavid Xu * Redistribution and use in source and binary forms, with or without 6b00401f0SDavid Xu * modification, are permitted provided that the following conditions 7b00401f0SDavid Xu * are met: 8b00401f0SDavid Xu * 1. Redistributions of source code must retain the above copyright 9b00401f0SDavid Xu * notice, this list of conditions and the following disclaimer. 10b00401f0SDavid Xu * 2. Redistributions in binary form must reproduce the above copyright 11b00401f0SDavid Xu * notice, this list of conditions and the following disclaimer in the 12b00401f0SDavid Xu * documentation and/or other materials provided with the distribution. 13b00401f0SDavid Xu * 14b00401f0SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15b00401f0SDavid Xu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16b00401f0SDavid Xu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17b00401f0SDavid Xu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18b00401f0SDavid Xu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19b00401f0SDavid Xu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20b00401f0SDavid Xu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21b00401f0SDavid Xu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22b00401f0SDavid Xu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23b00401f0SDavid Xu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24b00401f0SDavid Xu * SUCH DAMAGE. 25b00401f0SDavid Xu * 26b00401f0SDavid Xu * $FreeBSD: src/lib/libc/gen/tls.c,v 1.7 2005/03/01 23:42:00 davidxu Exp $ 27*a378ce7dSJoerg Sonnenberger * $DragonFly: src/lib/libc/gen/tls.c,v 1.8 2005/04/29 22:00:20 joerg Exp $ 28b00401f0SDavid Xu */ 29b00401f0SDavid Xu 30b00401f0SDavid Xu /* 31b00401f0SDavid Xu * Define stubs for TLS internals so that programs and libraries can 32b00401f0SDavid Xu * link. These functions will be replaced by functional versions at 33b00401f0SDavid Xu * runtime from ld-elf.so.1. 34b00401f0SDavid Xu */ 35b00401f0SDavid Xu 3692df6c3eSDavid Xu #include <sys/cdefs.h> 37bc633d63SMatthew Dillon #include <sys/tls.h> 389e2ee207SJoerg Sonnenberger 399e2ee207SJoerg Sonnenberger #include <machine/tls.h> 409e2ee207SJoerg Sonnenberger 41b00401f0SDavid Xu #include <stdlib.h> 42b00401f0SDavid Xu #include <string.h> 43b00401f0SDavid Xu #include <elf.h> 44b00401f0SDavid Xu #include <assert.h> 4592df6c3eSDavid Xu 46b00401f0SDavid Xu #include "libc_private.h" 47b00401f0SDavid Xu 4892df6c3eSDavid Xu __weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 4992df6c3eSDavid Xu __weak_reference(__libc_free_tls, _rtld_free_tls); 5092df6c3eSDavid Xu #ifdef __i386__ 5192df6c3eSDavid Xu __weak_reference(___libc_tls_get_addr, ___tls_get_addr); 5292df6c3eSDavid Xu #endif 5392df6c3eSDavid Xu __weak_reference(__libc_tls_get_addr, __tls_get_addr); 5492df6c3eSDavid Xu 55f20fd431SJoerg Sonnenberger struct tls_tcb *__libc_allocate_tls(struct tls_tcb *old_tcb); 56f20fd431SJoerg Sonnenberger void __libc_free_tls(struct tls_tcb *tcb); 57b00401f0SDavid Xu 589e2ee207SJoerg Sonnenberger #if !defined(RTLD_STATIC_TLS_VARIANT_II) 599e2ee207SJoerg Sonnenberger #error "Unsupported TLS layout" 60b00401f0SDavid Xu #endif 61b00401f0SDavid Xu 62b00401f0SDavid Xu #ifndef PIC 63b00401f0SDavid Xu 64b00401f0SDavid Xu #define round(size, align) \ 65b00401f0SDavid Xu (((size) + (align) - 1) & ~((align) - 1)) 66b00401f0SDavid Xu 67b00401f0SDavid Xu static size_t tls_static_space; 68b00401f0SDavid Xu static size_t tls_init_size; 69b00401f0SDavid Xu static void *tls_init; 70b00401f0SDavid Xu #endif 71b00401f0SDavid Xu 72b00401f0SDavid Xu #ifdef __i386__ 73b00401f0SDavid Xu 7492df6c3eSDavid Xu /* GNU ABI */ 75b00401f0SDavid Xu 7692df6c3eSDavid Xu void *___libc_tls_get_addr(void *ti) __attribute__((__regparm__(1))); 7792df6c3eSDavid Xu 78b00401f0SDavid Xu __attribute__((__regparm__(1))) 79b00401f0SDavid Xu void * 8092df6c3eSDavid Xu ___libc_tls_get_addr(void *ti __unused) 81b00401f0SDavid Xu { 82b00401f0SDavid Xu return (0); 83b00401f0SDavid Xu } 84b00401f0SDavid Xu 85b00401f0SDavid Xu #endif 86b00401f0SDavid Xu 8792df6c3eSDavid Xu void *__libc_tls_get_addr(void *ti); 88bc633d63SMatthew Dillon 89b00401f0SDavid Xu void * 9092df6c3eSDavid Xu __libc_tls_get_addr(void *ti __unused) 91b00401f0SDavid Xu { 92b00401f0SDavid Xu return (0); 93b00401f0SDavid Xu } 94b00401f0SDavid Xu 9592df6c3eSDavid Xu #ifndef PIC 9692df6c3eSDavid Xu 97b00401f0SDavid Xu /* 98bc633d63SMatthew Dillon * Free Static TLS 99b00401f0SDavid Xu */ 100b00401f0SDavid Xu void 101f20fd431SJoerg Sonnenberger __libc_free_tls(struct tls_tcb *tcb) 102b00401f0SDavid Xu { 103bc633d63SMatthew Dillon size_t data_size; 104b00401f0SDavid Xu 1059e2ee207SJoerg Sonnenberger if (tcb->tcb_dtv) 1069e2ee207SJoerg Sonnenberger free(tcb->tcb_dtv); 107bc633d63SMatthew Dillon data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) & 108bc633d63SMatthew Dillon ~RTLD_STATIC_TLS_ALIGN_MASK; 109bc633d63SMatthew Dillon free((char *)tcb - data_size); 110b00401f0SDavid Xu } 111b00401f0SDavid Xu 112b00401f0SDavid Xu /* 113bc633d63SMatthew Dillon * Allocate Static TLS. 114*a378ce7dSJoerg Sonnenberger * 115*a378ce7dSJoerg Sonnenberger * !!!WARNING!!! The first run for a static binary is done without valid 116*a378ce7dSJoerg Sonnenberger * TLS storage. It must not call any system calls which want to change 117*a378ce7dSJoerg Sonnenberger * errno. 118b00401f0SDavid Xu */ 119bc633d63SMatthew Dillon struct tls_tcb * 120f20fd431SJoerg Sonnenberger __libc_allocate_tls(struct tls_tcb *old_tcb) 121b00401f0SDavid Xu { 122*a378ce7dSJoerg Sonnenberger static int first_run = 0; 123bc633d63SMatthew Dillon size_t data_size; 124bc633d63SMatthew Dillon struct tls_tcb *tcb; 125b00401f0SDavid Xu Elf_Addr *dtv; 126b00401f0SDavid Xu 127*a378ce7dSJoerg Sonnenberger retry: 128bc633d63SMatthew Dillon data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) & 129bc633d63SMatthew Dillon ~RTLD_STATIC_TLS_ALIGN_MASK; 130*a378ce7dSJoerg Sonnenberger 131*a378ce7dSJoerg Sonnenberger if (first_run) 132f20fd431SJoerg Sonnenberger tcb = malloc(data_size + sizeof(*tcb)); 133*a378ce7dSJoerg Sonnenberger else 134*a378ce7dSJoerg Sonnenberger tcb = alloca(data_size + sizeof(*tcb)); 135bc633d63SMatthew Dillon tcb = (struct tls_tcb *)((char *)tcb + data_size); 136*a378ce7dSJoerg Sonnenberger if (first_run) 137b00401f0SDavid Xu dtv = malloc(3 * sizeof(Elf_Addr)); 138*a378ce7dSJoerg Sonnenberger else 139*a378ce7dSJoerg Sonnenberger dtv = alloca(3 * sizeof(Elf_Addr)); 1409e2ee207SJoerg Sonnenberger 1419e2ee207SJoerg Sonnenberger #ifdef RTLD_TCB_HAS_SELF_POINTER 1429e2ee207SJoerg Sonnenberger tcb->tcb_self = tcb; 1439e2ee207SJoerg Sonnenberger #endif 1449e2ee207SJoerg Sonnenberger tcb->tcb_dtv = dtv; 1459e2ee207SJoerg Sonnenberger tcb->tcb_pthread = NULL; 146b00401f0SDavid Xu 147b00401f0SDavid Xu dtv[0] = 1; 148b00401f0SDavid Xu dtv[1] = 1; 149bc633d63SMatthew Dillon dtv[2] = (Elf_Addr)((char *)tcb - tls_static_space); 150bc633d63SMatthew Dillon 151bc633d63SMatthew Dillon if (old_tcb) { 152b00401f0SDavid Xu /* 153b00401f0SDavid Xu * Copy the static TLS block over whole. 154b00401f0SDavid Xu */ 155bc633d63SMatthew Dillon memcpy((char *)tcb - tls_static_space, 156bc633d63SMatthew Dillon (char *)old_tcb - tls_static_space, 157b00401f0SDavid Xu tls_static_space); 158b00401f0SDavid Xu 159b00401f0SDavid Xu /* 160b00401f0SDavid Xu * We assume that this block was the one we created with 161b00401f0SDavid Xu * allocate_initial_tls(). 162b00401f0SDavid Xu */ 163f20fd431SJoerg Sonnenberger _rtld_free_tls(old_tcb); 164b00401f0SDavid Xu } else { 165bc633d63SMatthew Dillon memcpy((char *)tcb - tls_static_space, 166b00401f0SDavid Xu tls_init, tls_init_size); 167bc633d63SMatthew Dillon memset((char *)tcb - tls_static_space + tls_init_size, 168b00401f0SDavid Xu 0, tls_static_space - tls_init_size); 169b00401f0SDavid Xu } 170*a378ce7dSJoerg Sonnenberger 171*a378ce7dSJoerg Sonnenberger if (first_run) 172bc633d63SMatthew Dillon return (tcb); 173*a378ce7dSJoerg Sonnenberger 174*a378ce7dSJoerg Sonnenberger tls_set_tcb(tcb); 175*a378ce7dSJoerg Sonnenberger first_run = 1; 176*a378ce7dSJoerg Sonnenberger goto retry; 177b00401f0SDavid Xu } 178b00401f0SDavid Xu 17992df6c3eSDavid Xu #else 18092df6c3eSDavid Xu 181bc633d63SMatthew Dillon struct tls_tcb * 182f20fd431SJoerg Sonnenberger __libc_allocate_tls(struct tls_tcb *old_tls __unused) 18392df6c3eSDavid Xu { 18492df6c3eSDavid Xu return (0); 18592df6c3eSDavid Xu } 18692df6c3eSDavid Xu 18792df6c3eSDavid Xu void 188f20fd431SJoerg Sonnenberger __libc_free_tls(struct tls_tcb *tcb __unused) 18992df6c3eSDavid Xu { 19092df6c3eSDavid Xu } 19192df6c3eSDavid Xu 19292df6c3eSDavid Xu #endif /* PIC */ 19392df6c3eSDavid Xu 194b00401f0SDavid Xu extern char **environ; 195b00401f0SDavid Xu 196b00401f0SDavid Xu void 197b00401f0SDavid Xu _init_tls() 198b00401f0SDavid Xu { 199b00401f0SDavid Xu #ifndef PIC 200b00401f0SDavid Xu Elf_Addr *sp; 201b00401f0SDavid Xu Elf_Auxinfo *aux, *auxp; 202b00401f0SDavid Xu Elf_Phdr *phdr; 203b00401f0SDavid Xu size_t phent, phnum; 204b00401f0SDavid Xu int i; 205bc633d63SMatthew Dillon struct tls_tcb *tcb; 206b00401f0SDavid Xu 207b00401f0SDavid Xu sp = (Elf_Addr *) environ; 208b00401f0SDavid Xu while (*sp++ != 0) 209b00401f0SDavid Xu ; 210b00401f0SDavid Xu aux = (Elf_Auxinfo *) sp; 211b00401f0SDavid Xu phdr = 0; 212b00401f0SDavid Xu phent = phnum = 0; 213b00401f0SDavid Xu for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 214b00401f0SDavid Xu switch (auxp->a_type) { 215b00401f0SDavid Xu case AT_PHDR: 216b00401f0SDavid Xu phdr = auxp->a_un.a_ptr; 217b00401f0SDavid Xu break; 218b00401f0SDavid Xu 219b00401f0SDavid Xu case AT_PHENT: 220b00401f0SDavid Xu phent = auxp->a_un.a_val; 221b00401f0SDavid Xu break; 222b00401f0SDavid Xu 223b00401f0SDavid Xu case AT_PHNUM: 224b00401f0SDavid Xu phnum = auxp->a_un.a_val; 225b00401f0SDavid Xu break; 226b00401f0SDavid Xu } 227b00401f0SDavid Xu } 228b00401f0SDavid Xu if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0) 229b00401f0SDavid Xu return; 230b00401f0SDavid Xu 231b00401f0SDavid Xu for (i = 0; (unsigned)i < phnum; i++) { 232b00401f0SDavid Xu if (phdr[i].p_type == PT_TLS) { 233b00401f0SDavid Xu tls_static_space = round(phdr[i].p_memsz, 234b00401f0SDavid Xu phdr[i].p_align); 235b00401f0SDavid Xu tls_init_size = phdr[i].p_filesz; 236b00401f0SDavid Xu tls_init = (void*) phdr[i].p_vaddr; 237b00401f0SDavid Xu } 238b00401f0SDavid Xu } 239b00401f0SDavid Xu 240f20fd431SJoerg Sonnenberger tcb = _rtld_allocate_tls(NULL); 2419e2ee207SJoerg Sonnenberger tls_set_tcb(tcb); 242b00401f0SDavid Xu #endif 243b00401f0SDavid Xu } 244