Deleted Added
sdiff udiff text old ( 160711 ) new ( 161800 )
full compact
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 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(__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;
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
108__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused)
109{
110 Elf_Addr *dtv;
111 Elf_Addr **tls;
112
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 *
123__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused)
124{
125 Elf_Addr *dtv;
126 Elf_Addr **tls;
127 char *tcb;
128
129 if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE)
130 return (oldtcb);
131
132 tcb = calloc(1, tls_static_space + tcbsize);
133 tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE);
134
135 if (oldtcb != NULL) {
136 memcpy(tls, oldtcb, tls_static_space + TLS_TCB_SIZE);
137 free(oldtcb);
138
139 /* Adjust the DTV. */
140 dtv = tls[0];
141 dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE;
142 } else {
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
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) {
295 tls_static_space = round(phdr[i].p_memsz,
296 phdr[i].p_align);
297 tls_init_size = phdr[i].p_filesz;
298 tls_init = (void*) phdr[i].p_vaddr;
299 }
300 }
301
302 tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, 1);
303
304 _set_tp(tls);
305#endif
306}