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