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 $
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__)
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
79static void *tls_init;
80#endif
81
82#ifdef __i386__
83
84/* GNU ABI */
85
86__attribute__((__regparm__(1)))
87void *
88___libc_tls_get_addr(void *ti __unused)
89{
90 return (0);
91}
92
93#endif
94
95void *
96__libc_tls_get_addr(void *ti __unused)
97{
98 return (0);
99}
100
101#ifndef PIC
102
103#ifdef TLS_VARIANT_I
104
105/*
106 * Free Static TLS using the Variant I method.
107 */
108void
109__libc_free_tls(void *tls, size_t tcbsize __unused, size_t tcbalign __unused)
110{
111 Elf_Addr* dtv;
112
113 dtv = ((Elf_Addr**)tls)[0];
114 free(tls);
115 free(dtv);
116}
117
118/*
119 * Allocate Static TLS using the Variant I method.
120 */
121void *
122__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign __unused)
123{
124 size_t size;
125 char *tls;
126 Elf_Addr *dtv;
127
128 size = tls_static_space;
129 if (size < tcbsize)
130 size = tcbsize;
131
132 tls = calloc(1, size);
133 dtv = malloc(3 * sizeof(Elf_Addr));
134
135 *(Elf_Addr **) tls = dtv;
136
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));
153 } 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);
157 }
158
159 return tls;
160}
161
162#endif
163
164#ifdef TLS_VARIANT_II
165
166/*
167 * Free Static TLS using the Variant II method.
168 */
169void
170__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
171{
172 size_t size;
173 Elf_Addr* dtv;
174 Elf_Addr tlsstart, tlsend;
175
176 /*
177 * Figure out the size of the initial TLS block so that we can
178 * find stuff which ___tls_get_addr() allocated dynamically.
179 */
180 size = round(tls_static_space, tcbalign);
181
182 dtv = ((Elf_Addr**)tcb)[1];
183 tlsend = (Elf_Addr) tcb;
184 tlsstart = tlsend - size;
185 free((void*) tlsstart);
186 free(dtv);
187}
188
189/*
190 * Allocate Static TLS using the Variant II method.
191 */
192void *
193__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
194{
195 size_t size;
196 char *tls;
197 Elf_Addr *dtv;
198 Elf_Addr segbase, oldsegbase;
199
200 size = round(tls_static_space, tcbalign);
201
202 assert(tcbsize >= 2*sizeof(Elf_Addr));
203 tls = calloc(1, size + tcbsize);
204 dtv = malloc(3 * sizeof(Elf_Addr));
205
206 segbase = (Elf_Addr)(tls + size);
207 ((Elf_Addr*)segbase)[0] = segbase;
208 ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv;
209
210 dtv[0] = 1;
211 dtv[1] = 1;
212 dtv[2] = segbase - tls_static_space;
213
214 if (oldtls) {
215 /*
216 * Copy the static TLS block over whole.
217 */
218 oldsegbase = (Elf_Addr) oldtls;
219 memcpy((void *)(segbase - tls_static_space),
220 (const void *)(oldsegbase - tls_static_space),
221 tls_static_space);
222
223 /*
224 * We assume that this block was the one we created with
225 * allocate_initial_tls().
226 */
227 _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr));
228 } else {
229 memcpy((void *)(segbase - tls_static_space),
230 tls_init, tls_init_size);
231 memset((void *)(segbase - tls_static_space + tls_init_size),
232 0, tls_static_space - tls_init_size);
233 }
234
235 return (void*) segbase;
236}
237
238#endif /* TLS_VARIANT_II */
239
240#else
241
242void *
243__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused,
244 size_t tcbalign __unused)
245{
246 return (0);
247}
248
249void
250__libc_free_tls(void *tcb __unused, size_t tcbsize __unused,
251 size_t tcbalign __unused)
252{
253}
254
255#endif /* PIC */
256
257extern char **environ;
258
259void
260_init_tls()
261{
262#ifndef PIC
263 Elf_Addr *sp;
264 Elf_Auxinfo *aux, *auxp;
265 Elf_Phdr *phdr;
266 size_t phent, phnum;
267 int i;
268 void *tls;
269
270 sp = (Elf_Addr *) environ;
271 while (*sp++ != 0)
272 ;
273 aux = (Elf_Auxinfo *) sp;
274 phdr = 0;
275 phent = phnum = 0;
276 for (auxp = aux; auxp->a_type != AT_NULL; auxp++) {
277 switch (auxp->a_type) {
278 case AT_PHDR:
279 phdr = auxp->a_un.a_ptr;
280 break;
281
282 case AT_PHENT:
283 phent = auxp->a_un.a_val;
284 break;
285
286 case AT_PHNUM:
287 phnum = auxp->a_un.a_val;
288 break;
289 }
290 }
291 if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0)
292 return;
293
294 for (i = 0; (unsigned) i < phnum; i++) {
295 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
302 tls_static_space = round(phdr[i].p_memsz,
303 phdr[i].p_align);
304#endif
305 tls_init_size = phdr[i].p_filesz;
306 tls_init = (void*) phdr[i].p_vaddr;
307 }
308 }
309
310 tls = _rtld_allocate_tls(NULL, 3*sizeof(Elf_Addr),
311 sizeof(Elf_Addr));
312
313 _set_tp(tls);
314#endif
315}
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 $
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__)
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
79static void *tls_init;
80#endif
81
82#ifdef __i386__
83
84/* GNU ABI */
85
86__attribute__((__regparm__(1)))
87void *
88___libc_tls_get_addr(void *ti __unused)
89{
90 return (0);
91}
92
93#endif
94
95void *
96__libc_tls_get_addr(void *ti __unused)
97{
98 return (0);
99}
100
101#ifndef PIC
102
103#ifdef TLS_VARIANT_I
104
105/*
106 * Free Static TLS using the Variant I method.
107 */
108void
109__libc_free_tls(void *tls, size_t tcbsize __unused, size_t tcbalign __unused)
110{
111 Elf_Addr* dtv;
112
113 dtv = ((Elf_Addr**)tls)[0];
114 free(tls);
115 free(dtv);
116}
117
118/*
119 * Allocate Static TLS using the Variant I method.
120 */
121void *
122__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign __unused)
123{
124 size_t size;
125 char *tls;
126 Elf_Addr *dtv;
127
128 size = tls_static_space;
129 if (size < tcbsize)
130 size = tcbsize;
131
132 tls = calloc(1, size);
133 dtv = malloc(3 * sizeof(Elf_Addr));
134
135 *(Elf_Addr **) tls = dtv;
136
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));
153 } 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);
157 }
158
159 return tls;
160}
161
162#endif
163
164#ifdef TLS_VARIANT_II
165
166/*
167 * Free Static TLS using the Variant II method.
168 */
169void
170__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
171{
172 size_t size;
173 Elf_Addr* dtv;
174 Elf_Addr tlsstart, tlsend;
175
176 /*
177 * Figure out the size of the initial TLS block so that we can
178 * find stuff which ___tls_get_addr() allocated dynamically.
179 */
180 size = round(tls_static_space, tcbalign);
181
182 dtv = ((Elf_Addr**)tcb)[1];
183 tlsend = (Elf_Addr) tcb;
184 tlsstart = tlsend - size;
185 free((void*) tlsstart);
186 free(dtv);
187}
188
189/*
190 * Allocate Static TLS using the Variant II method.
191 */
192void *
193__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
194{
195 size_t size;
196 char *tls;
197 Elf_Addr *dtv;
198 Elf_Addr segbase, oldsegbase;
199
200 size = round(tls_static_space, tcbalign);
201
202 assert(tcbsize >= 2*sizeof(Elf_Addr));
203 tls = calloc(1, size + tcbsize);
204 dtv = malloc(3 * sizeof(Elf_Addr));
205
206 segbase = (Elf_Addr)(tls + size);
207 ((Elf_Addr*)segbase)[0] = segbase;
208 ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv;
209
210 dtv[0] = 1;
211 dtv[1] = 1;
212 dtv[2] = segbase - tls_static_space;
213
214 if (oldtls) {
215 /*
216 * Copy the static TLS block over whole.
217 */
218 oldsegbase = (Elf_Addr) oldtls;
219 memcpy((void *)(segbase - tls_static_space),
220 (const void *)(oldsegbase - tls_static_space),
221 tls_static_space);
222
223 /*
224 * We assume that this block was the one we created with
225 * allocate_initial_tls().
226 */
227 _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr));
228 } else {
229 memcpy((void *)(segbase - tls_static_space),
230 tls_init, tls_init_size);
231 memset((void *)(segbase - tls_static_space + tls_init_size),
232 0, tls_static_space - tls_init_size);
233 }
234
235 return (void*) segbase;
236}
237
238#endif /* TLS_VARIANT_II */
239
240#else
241
242void *
243__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused,
244 size_t tcbalign __unused)
245{
246 return (0);
247}
248
249void
250__libc_free_tls(void *tcb __unused, size_t tcbsize __unused,
251 size_t tcbalign __unused)
252{
253}
254
255#endif /* PIC */
256
257extern char **environ;
258
259void
260_init_tls()
261{
262#ifndef PIC
263 Elf_Addr *sp;
264 Elf_Auxinfo *aux, *auxp;
265 Elf_Phdr *phdr;
266 size_t phent, phnum;
267 int i;
268 void *tls;
269
270 sp = (Elf_Addr *) environ;
271 while (*sp++ != 0)
272 ;
273 aux = (Elf_Auxinfo *) sp;
274 phdr = 0;
275 phent = phnum = 0;
276 for (auxp = aux; auxp->a_type != AT_NULL; auxp++) {
277 switch (auxp->a_type) {
278 case AT_PHDR:
279 phdr = auxp->a_un.a_ptr;
280 break;
281
282 case AT_PHENT:
283 phent = auxp->a_un.a_val;
284 break;
285
286 case AT_PHNUM:
287 phnum = auxp->a_un.a_val;
288 break;
289 }
290 }
291 if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0)
292 return;
293
294 for (i = 0; (unsigned) i < phnum; i++) {
295 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
302 tls_static_space = round(phdr[i].p_memsz,
303 phdr[i].p_align);
304#endif
305 tls_init_size = phdr[i].p_filesz;
306 tls_init = (void*) phdr[i].p_vaddr;
307 }
308 }
309
310 tls = _rtld_allocate_tls(NULL, 3*sizeof(Elf_Addr),
311 sizeof(Elf_Addr));
312
313 _set_tp(tls);
314#endif
315}