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*9e2ee207SJoerg Sonnenberger * $DragonFly: src/lib/libc/gen/tls.c,v 1.5 2005/03/29 19:26:19 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> 38*9e2ee207SJoerg Sonnenberger 39*9e2ee207SJoerg Sonnenberger #include <machine/tls.h> 40*9e2ee207SJoerg 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 55bc633d63SMatthew Dillon struct tls_tcb *__libc_allocate_tls(struct tls_tcb *old_tcb, size_t tcbsize, 56bc633d63SMatthew Dillon int flags); 57bc633d63SMatthew Dillon void __libc_free_tls(struct tls_tcb *tcb, size_t tcb_size); 58b00401f0SDavid Xu 59*9e2ee207SJoerg Sonnenberger #if !defined(RTLD_STATIC_TLS_VARIANT_II) 60*9e2ee207SJoerg Sonnenberger #error "Unsupported TLS layout" 61b00401f0SDavid Xu #endif 62b00401f0SDavid Xu 63b00401f0SDavid Xu #ifndef PIC 64b00401f0SDavid Xu 65b00401f0SDavid Xu #define round(size, align) \ 66b00401f0SDavid Xu (((size) + (align) - 1) & ~((align) - 1)) 67b00401f0SDavid Xu 68b00401f0SDavid Xu static size_t tls_static_space; 69b00401f0SDavid Xu static size_t tls_init_size; 70b00401f0SDavid Xu static void *tls_init; 71b00401f0SDavid Xu #endif 72b00401f0SDavid Xu 73b00401f0SDavid Xu #ifdef __i386__ 74b00401f0SDavid Xu 7592df6c3eSDavid Xu /* GNU ABI */ 76b00401f0SDavid Xu 7792df6c3eSDavid Xu void *___libc_tls_get_addr(void *ti) __attribute__((__regparm__(1))); 7892df6c3eSDavid Xu 79b00401f0SDavid Xu __attribute__((__regparm__(1))) 80b00401f0SDavid Xu void * 8192df6c3eSDavid Xu ___libc_tls_get_addr(void *ti __unused) 82b00401f0SDavid Xu { 83b00401f0SDavid Xu return (0); 84b00401f0SDavid Xu } 85b00401f0SDavid Xu 86b00401f0SDavid Xu #endif 87b00401f0SDavid Xu 8892df6c3eSDavid Xu void *__libc_tls_get_addr(void *ti); 89bc633d63SMatthew Dillon 90b00401f0SDavid Xu void * 9192df6c3eSDavid Xu __libc_tls_get_addr(void *ti __unused) 92b00401f0SDavid Xu { 93b00401f0SDavid Xu return (0); 94b00401f0SDavid Xu } 95b00401f0SDavid Xu 9692df6c3eSDavid Xu #ifndef PIC 9792df6c3eSDavid Xu 98b00401f0SDavid Xu /* 99bc633d63SMatthew Dillon * Free Static TLS 100b00401f0SDavid Xu */ 101b00401f0SDavid Xu void 102bc633d63SMatthew Dillon __libc_free_tls(struct tls_tcb *tcb, size_t tcb_size __unused) 103b00401f0SDavid Xu { 104bc633d63SMatthew Dillon size_t data_size; 105b00401f0SDavid Xu 106*9e2ee207SJoerg Sonnenberger if (tcb->tcb_dtv) 107*9e2ee207SJoerg Sonnenberger free(tcb->tcb_dtv); 108bc633d63SMatthew Dillon data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) & 109bc633d63SMatthew Dillon ~RTLD_STATIC_TLS_ALIGN_MASK; 110bc633d63SMatthew Dillon free((char *)tcb - data_size); 111b00401f0SDavid Xu } 112b00401f0SDavid Xu 113b00401f0SDavid Xu /* 114bc633d63SMatthew Dillon * Allocate Static TLS. 115b00401f0SDavid Xu */ 116bc633d63SMatthew Dillon struct tls_tcb * 117bc633d63SMatthew Dillon __libc_allocate_tls(struct tls_tcb *old_tcb, size_t tcb_size, int flags) 118b00401f0SDavid Xu { 119bc633d63SMatthew Dillon size_t data_size; 120bc633d63SMatthew Dillon struct tls_tcb *tcb; 121b00401f0SDavid Xu Elf_Addr *dtv; 122b00401f0SDavid Xu 123bc633d63SMatthew Dillon data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) & 124bc633d63SMatthew Dillon ~RTLD_STATIC_TLS_ALIGN_MASK; 125bc633d63SMatthew Dillon tcb = malloc(data_size + tcb_size); 126bc633d63SMatthew Dillon tcb = (struct tls_tcb *)((char *)tcb + data_size); 127b00401f0SDavid Xu dtv = malloc(3 * sizeof(Elf_Addr)); 128*9e2ee207SJoerg Sonnenberger 129*9e2ee207SJoerg Sonnenberger #ifdef RTLD_TCB_HAS_SELF_POINTER 130*9e2ee207SJoerg Sonnenberger tcb->tcb_self = tcb; 131*9e2ee207SJoerg Sonnenberger #endif 132*9e2ee207SJoerg Sonnenberger tcb->tcb_dtv = dtv; 133*9e2ee207SJoerg Sonnenberger tcb->tcb_pthread = NULL; 134b00401f0SDavid Xu 135b00401f0SDavid Xu dtv[0] = 1; 136b00401f0SDavid Xu dtv[1] = 1; 137bc633d63SMatthew Dillon dtv[2] = (Elf_Addr)((char *)tcb - tls_static_space); 138bc633d63SMatthew Dillon 139bc633d63SMatthew Dillon if (old_tcb) { 140b00401f0SDavid Xu /* 141b00401f0SDavid Xu * Copy the static TLS block over whole. 142b00401f0SDavid Xu */ 143bc633d63SMatthew Dillon memcpy((char *)tcb - tls_static_space, 144bc633d63SMatthew Dillon (char *)old_tcb - tls_static_space, 145b00401f0SDavid Xu tls_static_space); 146b00401f0SDavid Xu 147b00401f0SDavid Xu /* 148b00401f0SDavid Xu * We assume that this block was the one we created with 149b00401f0SDavid Xu * allocate_initial_tls(). 150b00401f0SDavid Xu */ 151bc633d63SMatthew Dillon _rtld_free_tls(old_tcb, sizeof(struct tls_tcb)); 152b00401f0SDavid Xu } else { 153bc633d63SMatthew Dillon memcpy((char *)tcb - tls_static_space, 154b00401f0SDavid Xu tls_init, tls_init_size); 155bc633d63SMatthew Dillon memset((char *)tcb - tls_static_space + tls_init_size, 156b00401f0SDavid Xu 0, tls_static_space - tls_init_size); 157b00401f0SDavid Xu } 158bc633d63SMatthew Dillon return (tcb); 159b00401f0SDavid Xu } 160b00401f0SDavid Xu 16192df6c3eSDavid Xu #else 16292df6c3eSDavid Xu 163bc633d63SMatthew Dillon struct tls_tcb * 164bc633d63SMatthew Dillon __libc_allocate_tls(struct tls_tcb *old_tls __unused, size_t tcb_size __unused, 165bc633d63SMatthew Dillon int flags __unused) 16692df6c3eSDavid Xu { 16792df6c3eSDavid Xu return (0); 16892df6c3eSDavid Xu } 16992df6c3eSDavid Xu 17092df6c3eSDavid Xu void 171bc633d63SMatthew Dillon __libc_free_tls(struct tls_tcb *tcb __unused, size_t tcb_size __unused) 17292df6c3eSDavid Xu { 17392df6c3eSDavid Xu } 17492df6c3eSDavid Xu 17592df6c3eSDavid Xu #endif /* PIC */ 17692df6c3eSDavid Xu 177b00401f0SDavid Xu extern char **environ; 178b00401f0SDavid Xu 179b00401f0SDavid Xu void 180b00401f0SDavid Xu _init_tls() 181b00401f0SDavid Xu { 182b00401f0SDavid Xu #ifndef PIC 183b00401f0SDavid Xu Elf_Addr *sp; 184b00401f0SDavid Xu Elf_Auxinfo *aux, *auxp; 185b00401f0SDavid Xu Elf_Phdr *phdr; 186b00401f0SDavid Xu size_t phent, phnum; 187b00401f0SDavid Xu int i; 188bc633d63SMatthew Dillon struct tls_tcb *tcb; 189b00401f0SDavid Xu 190b00401f0SDavid Xu sp = (Elf_Addr *) environ; 191b00401f0SDavid Xu while (*sp++ != 0) 192b00401f0SDavid Xu ; 193b00401f0SDavid Xu aux = (Elf_Auxinfo *) sp; 194b00401f0SDavid Xu phdr = 0; 195b00401f0SDavid Xu phent = phnum = 0; 196b00401f0SDavid Xu for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 197b00401f0SDavid Xu switch (auxp->a_type) { 198b00401f0SDavid Xu case AT_PHDR: 199b00401f0SDavid Xu phdr = auxp->a_un.a_ptr; 200b00401f0SDavid Xu break; 201b00401f0SDavid Xu 202b00401f0SDavid Xu case AT_PHENT: 203b00401f0SDavid Xu phent = auxp->a_un.a_val; 204b00401f0SDavid Xu break; 205b00401f0SDavid Xu 206b00401f0SDavid Xu case AT_PHNUM: 207b00401f0SDavid Xu phnum = auxp->a_un.a_val; 208b00401f0SDavid Xu break; 209b00401f0SDavid Xu } 210b00401f0SDavid Xu } 211b00401f0SDavid Xu if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0) 212b00401f0SDavid Xu return; 213b00401f0SDavid Xu 214b00401f0SDavid Xu for (i = 0; (unsigned)i < phnum; i++) { 215b00401f0SDavid Xu if (phdr[i].p_type == PT_TLS) { 216b00401f0SDavid Xu tls_static_space = round(phdr[i].p_memsz, 217b00401f0SDavid Xu phdr[i].p_align); 218b00401f0SDavid Xu tls_init_size = phdr[i].p_filesz; 219b00401f0SDavid Xu tls_init = (void*) phdr[i].p_vaddr; 220b00401f0SDavid Xu } 221b00401f0SDavid Xu } 222b00401f0SDavid Xu 223bc633d63SMatthew Dillon if (tls_static_space) { 224bc633d63SMatthew Dillon tcb = _rtld_allocate_tls(NULL, sizeof(struct tls_tcb), 0); 225*9e2ee207SJoerg Sonnenberger tls_set_tcb(tcb); 226bc633d63SMatthew Dillon } 227b00401f0SDavid Xu #endif 228b00401f0SDavid Xu } 229