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