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: head/lib/libc/gen/tls.c 160711 2006-07-26 16:56:56Z imp $
|
26 * $FreeBSD: head/lib/libc/gen/tls.c 161800 2006-09-01 06:13:16Z marcel $ |
27 */ 28 29/* 30 * Define stubs for TLS internals so that programs and libraries can 31 * link. These functions will be replaced by functional versions at 32 * runtime from ld-elf.so.1. 33 */ 34 35#include <sys/cdefs.h> 36#include <stdlib.h> 37#include <string.h> 38#include <elf.h> 39#include <assert.h> 40 41#include "libc_private.h" 42 43__weak_reference(__libc_allocate_tls, _rtld_allocate_tls); 44__weak_reference(__libc_free_tls, _rtld_free_tls); 45 46#ifdef __i386__ 47 48__weak_reference(___libc_tls_get_addr, ___tls_get_addr); 49__attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *); 50 51#endif 52 53void * __libc_tls_get_addr(void *); 54__weak_reference(__libc_tls_get_addr, __tls_get_addr); 55 56void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 57void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 58void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); 59void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); 60
|
61#if defined(__ia64__) || defined(__alpha__) || defined(__powerpc__)
|
61#if defined(__ia64__) || defined(__powerpc__) |
62#define TLS_VARIANT_I 63#endif 64#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \ 65 defined(__arm__) 66#define TLS_VARIANT_II 67#endif 68 69#ifndef PIC 70 71#define round(size, align) \ 72 (((size) + (align) - 1) & ~((align) - 1)) 73 74static size_t tls_static_space; 75static size_t tls_init_size;
|
76#ifdef TLS_VARIANT_I
77static size_t tls_init_offset;
78#endif
|
76static void *tls_init; 77#endif 78 79#ifdef __i386__ 80 81/* GNU ABI */ 82 83__attribute__((__regparm__(1))) 84void * 85___libc_tls_get_addr(void *ti __unused) 86{ 87 return (0); 88} 89 90#endif 91 92void * 93__libc_tls_get_addr(void *ti __unused) 94{ 95 return (0); 96} 97 98#ifndef PIC 99 100#ifdef TLS_VARIANT_I 101
|
102#define TLS_TCB_SIZE (2 * sizeof(void *)) 103 |
104/* 105 * Free Static TLS using the Variant I method. 106 */ 107void
|
109__libc_free_tls(void *tls, size_t tcbsize __unused, size_t tcbalign __unused)
|
108__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) |
109{
|
111 Elf_Addr* dtv;
|
110 Elf_Addr *dtv; 111 Elf_Addr **tls; |
112
|
113 dtv = ((Elf_Addr**)tls)[0];
114 free(tls);
|
113 tls = (Elf_Addr **)((Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE); 114 dtv = tls[0]; |
115 free(dtv);
|
116 free(tcb); |
117} 118 119/* 120 * Allocate Static TLS using the Variant I method. 121 */ 122void *
|
122__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign __unused)
|
123__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused) |
124{
|
124 size_t size;
125 char *tls;
|
125 Elf_Addr *dtv;
|
126 Elf_Addr **tls; 127 char *tcb; |
128
|
128 size = tls_static_space;
129 if (size < tcbsize)
130 size = tcbsize;
|
129 if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) 130 return (oldtcb); |
131
|
132 tls = calloc(1, size);
133 dtv = malloc(3 * sizeof(Elf_Addr));
|
132 tcb = calloc(1, tls_static_space + tcbsize); 133 tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE); |
134
|
135 *(Elf_Addr **) tls = dtv;
|
135 if (oldtcb != NULL) { 136 memcpy(tls, oldtcb, tls_static_space + TLS_TCB_SIZE); 137 free(oldtcb); |
138
|
137 dtv[0] = 1;
138 dtv[1] = 1;
139 dtv[2] = (Elf_Addr)(tls + tls_init_offset);
140 if (oldtls) {
141 /*
142 * Copy the static TLS block over whole.
143 */
144 memcpy(tls + tls_init_offset,
145 (char *)oldtls + tls_init_offset,
146 tls_static_space - tls_init_offset);
147
148 /*
149 * We assume that this block was the one we created with
150 * allocate_initial_tls().
151 */
152 _rtld_free_tls(oldtls, 2 * sizeof(Elf_Addr), sizeof(Elf_Addr));
|
139 /* Adjust the DTV. */ 140 dtv = tls[0]; 141 dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; |
142 } else {
|
154 memcpy(tls + tls_init_offset, tls_init, tls_init_size);
155 memset(tls + tls_init_offset + tls_init_size,
156 0, tls_static_space - tls_init_size);
|
143 dtv = malloc(3 * sizeof(Elf_Addr)); 144 tls[0] = dtv; 145 dtv[0] = 1; 146 dtv[1] = 1; 147 dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; 148 149 if (tls_init_size > 0) 150 memcpy((void*)dtv[2], tls_init, tls_init_size); 151 if (tls_static_space > tls_init_size) 152 memset((void*)(dtv[2] + tls_init_size), 0, 153 tls_static_space - tls_init_size); |
154 } 155
|
159 return tls;
|
156 return(tcb); |
157} 158 159#endif 160 161#ifdef TLS_VARIANT_II 162
|
163#define TLS_TCB_SIZE (3 * sizeof(Elf_Addr)) 164 |
165/* 166 * Free Static TLS using the Variant II method. 167 */ 168void 169__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) 170{ 171 size_t size; 172 Elf_Addr* dtv; 173 Elf_Addr tlsstart, tlsend; 174 175 /* 176 * Figure out the size of the initial TLS block so that we can 177 * find stuff which ___tls_get_addr() allocated dynamically. 178 */ 179 size = round(tls_static_space, tcbalign); 180 181 dtv = ((Elf_Addr**)tcb)[1]; 182 tlsend = (Elf_Addr) tcb; 183 tlsstart = tlsend - size; 184 free((void*) tlsstart); 185 free(dtv); 186} 187 188/* 189 * Allocate Static TLS using the Variant II method. 190 */ 191void * 192__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) 193{ 194 size_t size; 195 char *tls; 196 Elf_Addr *dtv; 197 Elf_Addr segbase, oldsegbase; 198 199 size = round(tls_static_space, tcbalign); 200 201 assert(tcbsize >= 2*sizeof(Elf_Addr)); 202 tls = calloc(1, size + tcbsize); 203 dtv = malloc(3 * sizeof(Elf_Addr)); 204 205 segbase = (Elf_Addr)(tls + size); 206 ((Elf_Addr*)segbase)[0] = segbase; 207 ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; 208 209 dtv[0] = 1; 210 dtv[1] = 1; 211 dtv[2] = segbase - tls_static_space; 212 213 if (oldtls) { 214 /* 215 * Copy the static TLS block over whole. 216 */ 217 oldsegbase = (Elf_Addr) oldtls; 218 memcpy((void *)(segbase - tls_static_space), 219 (const void *)(oldsegbase - tls_static_space), 220 tls_static_space); 221 222 /* 223 * We assume that this block was the one we created with 224 * allocate_initial_tls(). 225 */ 226 _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); 227 } else { 228 memcpy((void *)(segbase - tls_static_space), 229 tls_init, tls_init_size); 230 memset((void *)(segbase - tls_static_space + tls_init_size), 231 0, tls_static_space - tls_init_size); 232 } 233 234 return (void*) segbase; 235} 236 237#endif /* TLS_VARIANT_II */ 238 239#else 240 241void * 242__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused, 243 size_t tcbalign __unused) 244{ 245 return (0); 246} 247 248void 249__libc_free_tls(void *tcb __unused, size_t tcbsize __unused, 250 size_t tcbalign __unused) 251{ 252} 253 254#endif /* PIC */ 255 256extern char **environ; 257 258void 259_init_tls() 260{ 261#ifndef PIC 262 Elf_Addr *sp; 263 Elf_Auxinfo *aux, *auxp; 264 Elf_Phdr *phdr; 265 size_t phent, phnum; 266 int i; 267 void *tls; 268 269 sp = (Elf_Addr *) environ; 270 while (*sp++ != 0) 271 ; 272 aux = (Elf_Auxinfo *) sp; 273 phdr = 0; 274 phent = phnum = 0; 275 for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { 276 switch (auxp->a_type) { 277 case AT_PHDR: 278 phdr = auxp->a_un.a_ptr; 279 break; 280 281 case AT_PHENT: 282 phent = auxp->a_un.a_val; 283 break; 284 285 case AT_PHNUM: 286 phnum = auxp->a_un.a_val; 287 break; 288 } 289 } 290 if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0) 291 return; 292 293 for (i = 0; (unsigned) i < phnum; i++) { 294 if (phdr[i].p_type == PT_TLS) {
|
296#ifdef TLS_VARIANT_I
297 tls_static_space = round(2*sizeof(Elf_Addr),
298 phdr[i].p_align) + phdr[i].p_memsz;
299 tls_init_offset = round(2*sizeof(Elf_Addr),
300 phdr[i].p_align);
301#else
|
295 tls_static_space = round(phdr[i].p_memsz, 296 phdr[i].p_align);
|
304#endif
|
297 tls_init_size = phdr[i].p_filesz; 298 tls_init = (void*) phdr[i].p_vaddr; 299 } 300 } 301
|
310 tls = _rtld_allocate_tls(NULL, 3*sizeof(Elf_Addr),
311 sizeof(Elf_Addr));
|
302 tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, 1); |
303 304 _set_tp(tls); 305#endif 306}
|