1133064Sdfr/*-
2133064Sdfr * Copyright (c) 2004 Doug Rabson
3133064Sdfr * All rights reserved.
4133064Sdfr *
5133064Sdfr * Redistribution and use in source and binary forms, with or without
6133064Sdfr * modification, are permitted provided that the following conditions
7133064Sdfr * are met:
8133064Sdfr * 1. Redistributions of source code must retain the above copyright
9133064Sdfr *    notice, this list of conditions and the following disclaimer.
10133064Sdfr * 2. Redistributions in binary form must reproduce the above copyright
11133064Sdfr *    notice, this list of conditions and the following disclaimer in the
12133064Sdfr *    documentation and/or other materials provided with the distribution.
13133064Sdfr *
14133064Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15133064Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133064Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17133064Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18133064Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133064Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133064Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133064Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133064Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133064Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133064Sdfr * SUCH DAMAGE.
25133064Sdfr *
26133064Sdfr *	$FreeBSD: stable/10/lib/libc/gen/tls.c 324617 2017-10-14 16:49:39Z brooks $
27133064Sdfr */
28133064Sdfr
29133064Sdfr/*
30133064Sdfr * Define stubs for TLS internals so that programs and libraries can
31133064Sdfr * link. These functions will be replaced by functional versions at
32133064Sdfr * runtime from ld-elf.so.1.
33133064Sdfr */
34133064Sdfr
35143921Sdavidxu#include <sys/cdefs.h>
36133754Sdfr#include <stdlib.h>
37133754Sdfr#include <string.h>
38133754Sdfr#include <elf.h>
39143921Sdavidxu
40133754Sdfr#include "libc_private.h"
41133064Sdfr
42234370Sjasone/* Provided by jemalloc to avoid bootstrapping issues. */
43234569Sjasonevoid	*__jemalloc_a0malloc(size_t size);
44234569Sjasonevoid	*__jemalloc_a0calloc(size_t num, size_t size);
45234569Sjasonevoid	__jemalloc_a0free(void *ptr);
46234370Sjasone
47143921Sdavidxu__weak_reference(__libc_allocate_tls, _rtld_allocate_tls);
48143921Sdavidxu__weak_reference(__libc_free_tls, _rtld_free_tls);
49143921Sdavidxu
50143921Sdavidxu#ifdef __i386__
51143921Sdavidxu
52143921Sdavidxu__weak_reference(___libc_tls_get_addr, ___tls_get_addr);
53143921Sdavidxu__attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *);
54143921Sdavidxu
55143921Sdavidxu#endif
56143921Sdavidxu
57143921Sdavidxuvoid * __libc_tls_get_addr(void *);
58143921Sdavidxu__weak_reference(__libc_tls_get_addr, __tls_get_addr);
59143921Sdavidxu
60143921Sdavidxuvoid *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign);
61143921Sdavidxuvoid _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign);
62143921Sdavidxuvoid *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign);
63143921Sdavidxuvoid __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign);
64143921Sdavidxu
65163118Skmacy#if defined(__ia64__) || defined(__amd64__)
66163118Skmacy#define TLS_TCB_ALIGN 16
67163118Skmacy#elif defined(__powerpc__) || defined(__i386__) || defined(__arm__) || \
68178684Sgonzo    defined(__sparc64__) || defined(__mips__)
69163118Skmacy#define TLS_TCB_ALIGN sizeof(void *)
70163118Skmacy#else
71163118Skmacy#error TLS_TCB_ALIGN undefined for target architecture
72163118Skmacy#endif
73163118Skmacy
74232582Sgonzo#if defined(__arm__) || defined(__ia64__) || defined(__mips__) || \
75232582Sgonzo    defined(__powerpc__)
76133754Sdfr#define TLS_VARIANT_I
77133754Sdfr#endif
78232582Sgonzo#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__)
79133754Sdfr#define TLS_VARIANT_II
80133754Sdfr#endif
81133754Sdfr
82133754Sdfr#ifndef PIC
83133754Sdfr
84133754Sdfr#define round(size, align) \
85133754Sdfr	(((size) + (align) - 1) & ~((align) - 1))
86133754Sdfr
87133754Sdfrstatic size_t tls_static_space;
88133754Sdfrstatic size_t tls_init_size;
89133754Sdfrstatic void *tls_init;
90133754Sdfr#endif
91133754Sdfr
92133064Sdfr#ifdef __i386__
93133064Sdfr
94143921Sdavidxu/* GNU ABI */
95133064Sdfr
96133064Sdfr__attribute__((__regparm__(1)))
97133064Sdfrvoid *
98143921Sdavidxu___libc_tls_get_addr(void *ti __unused)
99133064Sdfr{
100133064Sdfr	return (0);
101133064Sdfr}
102133064Sdfr
103133064Sdfr#endif
104133064Sdfr
105133064Sdfrvoid *
106143921Sdavidxu__libc_tls_get_addr(void *ti __unused)
107133064Sdfr{
108133064Sdfr	return (0);
109133064Sdfr}
110133064Sdfr
111143921Sdavidxu#ifndef PIC
112143921Sdavidxu
113133754Sdfr#ifdef TLS_VARIANT_I
114133754Sdfr
115161800Smarcel#define	TLS_TCB_SIZE	(2 * sizeof(void *))
116161800Smarcel
117142560Sdavidxu/*
118142959Sdavidxu * Free Static TLS using the Variant I method.
119142560Sdavidxu */
120133754Sdfrvoid
121161800Smarcel__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused)
122133754Sdfr{
123161800Smarcel	Elf_Addr *dtv;
124161800Smarcel	Elf_Addr **tls;
125133754Sdfr
126161800Smarcel	tls = (Elf_Addr **)((Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE);
127161800Smarcel	dtv = tls[0];
128234569Sjasone	__jemalloc_a0free(dtv);
129234569Sjasone	__jemalloc_a0free(tcb);
130133754Sdfr}
131133754Sdfr
132133754Sdfr/*
133133754Sdfr * Allocate Static TLS using the Variant I method.
134133754Sdfr */
135133064Sdfrvoid *
136161800Smarcel__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused)
137133064Sdfr{
138133754Sdfr	Elf_Addr *dtv;
139161800Smarcel	Elf_Addr **tls;
140161800Smarcel	char *tcb;
141133754Sdfr
142161800Smarcel	if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE)
143161800Smarcel		return (oldtcb);
144133754Sdfr
145234569Sjasone	tcb = __jemalloc_a0calloc(1, tls_static_space + tcbsize - TLS_TCB_SIZE);
146161800Smarcel	tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE);
147133754Sdfr
148161800Smarcel	if (oldtcb != NULL) {
149203946Smarcel		memcpy(tls, oldtcb, tls_static_space);
150234569Sjasone		__jemalloc_a0free(oldtcb);
151133754Sdfr
152161800Smarcel		/* Adjust the DTV. */
153161800Smarcel		dtv = tls[0];
154161800Smarcel		dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE;
155161800Smarcel	} else {
156234569Sjasone		dtv = __jemalloc_a0malloc(3 * sizeof(Elf_Addr));
157161800Smarcel		tls[0] = dtv;
158161800Smarcel		dtv[0] = 1;
159161800Smarcel		dtv[1] = 1;
160161800Smarcel		dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE;
161133754Sdfr
162161800Smarcel		if (tls_init_size > 0)
163161827Smarcel			memcpy((void*)dtv[2], tls_init, tls_init_size);
164133754Sdfr	}
165133754Sdfr
166161800Smarcel	return(tcb);
167133064Sdfr}
168133064Sdfr
169133754Sdfr#endif
170133754Sdfr
171133754Sdfr#ifdef TLS_VARIANT_II
172133754Sdfr
173161800Smarcel#define	TLS_TCB_SIZE	(3 * sizeof(Elf_Addr))
174161800Smarcel
175133754Sdfr/*
176133754Sdfr * Free Static TLS using the Variant II method.
177133754Sdfr */
178133064Sdfrvoid
179143921Sdavidxu__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
180133064Sdfr{
181133754Sdfr	size_t size;
182133754Sdfr	Elf_Addr* dtv;
183133754Sdfr	Elf_Addr tlsstart, tlsend;
184133754Sdfr
185133754Sdfr	/*
186133754Sdfr	 * Figure out the size of the initial TLS block so that we can
187133754Sdfr	 * find stuff which ___tls_get_addr() allocated dynamically.
188133754Sdfr	 */
189133754Sdfr	size = round(tls_static_space, tcbalign);
190133754Sdfr
191133754Sdfr	dtv = ((Elf_Addr**)tcb)[1];
192133754Sdfr	tlsend = (Elf_Addr) tcb;
193133754Sdfr	tlsstart = tlsend - size;
194234569Sjasone	__jemalloc_a0free((void*) tlsstart);
195234569Sjasone	__jemalloc_a0free(dtv);
196133064Sdfr}
197133754Sdfr
198133754Sdfr/*
199133754Sdfr * Allocate Static TLS using the Variant II method.
200133754Sdfr */
201133754Sdfrvoid *
202143921Sdavidxu__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
203133754Sdfr{
204133754Sdfr	size_t size;
205133754Sdfr	char *tls;
206133754Sdfr	Elf_Addr *dtv;
207133754Sdfr	Elf_Addr segbase, oldsegbase;
208133754Sdfr
209133754Sdfr	size = round(tls_static_space, tcbalign);
210133754Sdfr
211166995Skientzle	if (tcbsize < 2 * sizeof(Elf_Addr))
212166995Skientzle		tcbsize = 2 * sizeof(Elf_Addr);
213234569Sjasone	tls = __jemalloc_a0calloc(1, size + tcbsize);
214234569Sjasone	dtv = __jemalloc_a0malloc(3 * sizeof(Elf_Addr));
215133754Sdfr
216133754Sdfr	segbase = (Elf_Addr)(tls + size);
217133754Sdfr	((Elf_Addr*)segbase)[0] = segbase;
218133754Sdfr	((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv;
219133754Sdfr
220133754Sdfr	dtv[0] = 1;
221133754Sdfr	dtv[1] = 1;
222133754Sdfr	dtv[2] = segbase - tls_static_space;
223133754Sdfr
224133754Sdfr	if (oldtls) {
225133754Sdfr		/*
226133754Sdfr		 * Copy the static TLS block over whole.
227133754Sdfr		 */
228133754Sdfr		oldsegbase = (Elf_Addr) oldtls;
229133754Sdfr		memcpy((void *)(segbase - tls_static_space),
230133754Sdfr		    (const void *)(oldsegbase - tls_static_space),
231133754Sdfr		    tls_static_space);
232133754Sdfr
233133754Sdfr		/*
234133754Sdfr		 * We assume that this block was the one we created with
235133754Sdfr		 * allocate_initial_tls().
236133754Sdfr		 */
237133754Sdfr		_rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr));
238133754Sdfr	} else {
239133754Sdfr		memcpy((void *)(segbase - tls_static_space),
240133754Sdfr		    tls_init, tls_init_size);
241133754Sdfr		memset((void *)(segbase - tls_static_space + tls_init_size),
242133754Sdfr		    0, tls_static_space - tls_init_size);
243133754Sdfr	}
244133754Sdfr
245133754Sdfr	return (void*) segbase;
246143921Sdavidxu}
247143921Sdavidxu
248143921Sdavidxu#endif /* TLS_VARIANT_II */
249143921Sdavidxu
250133754Sdfr#else
251143921Sdavidxu
252143921Sdavidxuvoid *
253143921Sdavidxu__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused,
254143921Sdavidxu	size_t tcbalign __unused)
255143921Sdavidxu{
256133754Sdfr	return (0);
257133754Sdfr}
258133754Sdfr
259143921Sdavidxuvoid
260143921Sdavidxu__libc_free_tls(void *tcb __unused, size_t tcbsize __unused,
261143921Sdavidxu	size_t tcbalign __unused)
262143921Sdavidxu{
263143921Sdavidxu}
264133754Sdfr
265143921Sdavidxu#endif /* PIC */
266143921Sdavidxu
267143921Sdavidxuextern char **environ;
268143921Sdavidxu
269133754Sdfrvoid
270133754Sdfr_init_tls()
271133754Sdfr{
272133754Sdfr#ifndef PIC
273133754Sdfr	Elf_Addr *sp;
274133754Sdfr	Elf_Auxinfo *aux, *auxp;
275133754Sdfr	Elf_Phdr *phdr;
276133754Sdfr	size_t phent, phnum;
277133754Sdfr	int i;
278133949Sdfr	void *tls;
279133754Sdfr
280133754Sdfr	sp = (Elf_Addr *) environ;
281133754Sdfr	while (*sp++ != 0)
282133754Sdfr		;
283133754Sdfr	aux = (Elf_Auxinfo *) sp;
284309485Sngie	phdr = NULL;
285133754Sdfr	phent = phnum = 0;
286133754Sdfr	for (auxp = aux; auxp->a_type != AT_NULL; auxp++) {
287133754Sdfr		switch (auxp->a_type) {
288133754Sdfr		case AT_PHDR:
289133754Sdfr			phdr = auxp->a_un.a_ptr;
290133754Sdfr			break;
291133754Sdfr
292133754Sdfr		case AT_PHENT:
293133754Sdfr			phent = auxp->a_un.a_val;
294133754Sdfr			break;
295133754Sdfr
296133754Sdfr		case AT_PHNUM:
297133754Sdfr			phnum = auxp->a_un.a_val;
298133754Sdfr			break;
299133754Sdfr		}
300133754Sdfr	}
301309485Sngie	if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0)
302133754Sdfr		return;
303133754Sdfr
304143921Sdavidxu	for (i = 0; (unsigned) i < phnum; i++) {
305133754Sdfr		if (phdr[i].p_type == PT_TLS) {
306133754Sdfr			tls_static_space = round(phdr[i].p_memsz,
307133754Sdfr			    phdr[i].p_align);
308133754Sdfr			tls_init_size = phdr[i].p_filesz;
309133754Sdfr			tls_init = (void*) phdr[i].p_vaddr;
310133754Sdfr		}
311133754Sdfr	}
312133754Sdfr
313232582Sgonzo#ifdef TLS_VARIANT_I
314232582Sgonzo	/*
315232582Sgonzo	 * tls_static_space should include space for TLS structure
316232582Sgonzo	 */
317232582Sgonzo	tls_static_space += TLS_TCB_SIZE;
318232582Sgonzo#endif
319232582Sgonzo
320163118Skmacy	tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN);
321133754Sdfr
322133949Sdfr	_set_tp(tls);
323133754Sdfr#endif
324133754Sdfr}
325