xref: /netbsd/lib/libc/tls/tls.c (revision ae278da3)
1*ae278da3Sriastradh /*	$NetBSD: tls.c,v 1.14 2020/08/20 15:54:11 riastradh Exp $	*/
21ee66c44Sjoerg 
31ee66c44Sjoerg /*-
41ee66c44Sjoerg  * Copyright (c) 2011 The NetBSD Foundation, Inc.
51ee66c44Sjoerg  * All rights reserved.
61ee66c44Sjoerg  *
71ee66c44Sjoerg  * This code is derived from software contributed to The NetBSD Foundation
81ee66c44Sjoerg  * by Joerg Sonnenberger.
91ee66c44Sjoerg  *
101ee66c44Sjoerg  * Redistribution and use in source and binary forms, with or without
111ee66c44Sjoerg  * modification, are permitted provided that the following conditions
121ee66c44Sjoerg  * are met:
131ee66c44Sjoerg  * 1. Redistributions of source code must retain the above copyright
141ee66c44Sjoerg  *    notice, this list of conditions and the following disclaimer.
151ee66c44Sjoerg  * 2. Redistributions in binary form must reproduce the above copyright
161ee66c44Sjoerg  *    notice, this list of conditions and the following disclaimer in the
171ee66c44Sjoerg  *    documentation and/or other materials provided with the distribution.
181ee66c44Sjoerg  *
191ee66c44Sjoerg  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201ee66c44Sjoerg  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211ee66c44Sjoerg  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221ee66c44Sjoerg  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231ee66c44Sjoerg  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241ee66c44Sjoerg  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251ee66c44Sjoerg  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261ee66c44Sjoerg  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271ee66c44Sjoerg  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281ee66c44Sjoerg  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291ee66c44Sjoerg  * POSSIBILITY OF SUCH DAMAGE.
301ee66c44Sjoerg  */
311ee66c44Sjoerg 
321ee66c44Sjoerg #include <sys/cdefs.h>
33*ae278da3Sriastradh __RCSID("$NetBSD: tls.c,v 1.14 2020/08/20 15:54:11 riastradh Exp $");
341ee66c44Sjoerg 
351ee66c44Sjoerg #include "namespace.h"
361ee66c44Sjoerg 
37834462b9Sjoerg #define	_rtld_tls_allocate	__libc_rtld_tls_allocate
38834462b9Sjoerg #define	_rtld_tls_free		__libc_rtld_tls_free
39834462b9Sjoerg 
401ee66c44Sjoerg #include <sys/tls.h>
411ee66c44Sjoerg 
421ee66c44Sjoerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
431ee66c44Sjoerg 
441ee66c44Sjoerg #include <sys/param.h>
451ee66c44Sjoerg #include <sys/mman.h>
461ee66c44Sjoerg #include <link_elf.h>
471ee66c44Sjoerg #include <lwp.h>
48c57ff63aSjoerg #include <stdbool.h>
49fcc27c2eSjoerg #include <stdalign.h>
501ee66c44Sjoerg #include <stddef.h>
511ee66c44Sjoerg #include <stdlib.h>
521ee66c44Sjoerg #include <string.h>
531ee66c44Sjoerg #include <unistd.h>
541ee66c44Sjoerg 
551ee66c44Sjoerg __dso_hidden void	__libc_static_tls_setup(void);
561ee66c44Sjoerg 
57c57ff63aSjoerg static bool is_dynamic;
581ee66c44Sjoerg static const void *tls_initaddr;
591ee66c44Sjoerg static size_t tls_initsize;
601ee66c44Sjoerg static size_t tls_size;
611ee66c44Sjoerg static size_t tls_allocation;
621ee66c44Sjoerg static void *initial_thread_tcb;
631ee66c44Sjoerg 
64e668b199Sskrll void * __libc_tls_get_addr(void);
65e668b199Sskrll 
__weak_alias(__tls_get_addr,__libc_tls_get_addr)66e668b199Sskrll __weak_alias(__tls_get_addr, __libc_tls_get_addr)
671ee66c44Sjoerg #ifdef __i386__
68e668b199Sskrll __weak_alias(___tls_get_addr, __libc_tls_get_addr)
691ee66c44Sjoerg #endif
701ee66c44Sjoerg 
71e668b199Sskrll void *
72e668b199Sskrll __libc_tls_get_addr(void)
73e668b199Sskrll {
74e668b199Sskrll 
75e668b199Sskrll 	abort();
765d3b2d32She 	/* NOTREACHED */
77e668b199Sskrll }
78e668b199Sskrll 
__weak_alias(_rtld_tls_allocate,__libc_rtld_tls_allocate)791ee66c44Sjoerg __weak_alias(_rtld_tls_allocate, __libc_rtld_tls_allocate)
801ee66c44Sjoerg 
811ee66c44Sjoerg struct tls_tcb *
821ee66c44Sjoerg _rtld_tls_allocate(void)
831ee66c44Sjoerg {
841ee66c44Sjoerg 	struct tls_tcb *tcb;
851ee66c44Sjoerg 	uint8_t *p;
861ee66c44Sjoerg 
871ee66c44Sjoerg 	if (initial_thread_tcb == NULL) {
889c6b6190Snakayama #ifdef __HAVE_TLS_VARIANT_I
89f656b03fSjoerg 		tls_allocation = tls_size;
909c6b6190Snakayama #else
919c6b6190Snakayama 		tls_allocation = roundup2(tls_size, alignof(max_align_t));
921ee66c44Sjoerg #endif
931ee66c44Sjoerg 
94f656b03fSjoerg 		initial_thread_tcb = p = mmap(NULL,
95f656b03fSjoerg 		    tls_allocation + sizeof(*tcb), PROT_READ | PROT_WRITE,
96f656b03fSjoerg 		    MAP_ANON, -1, 0);
97*ae278da3Sriastradh 		if (p == MAP_FAILED)
98*ae278da3Sriastradh 			initial_thread_tcb = p = NULL;
991ee66c44Sjoerg 	} else {
100f656b03fSjoerg 		p = calloc(1, tls_allocation + sizeof(*tcb));
1011ee66c44Sjoerg 	}
1021ee66c44Sjoerg 	if (p == NULL) {
1031ee66c44Sjoerg 		static const char msg[] =  "TLS allocation failed, terminating\n";
1041ee66c44Sjoerg 		write(STDERR_FILENO, msg, sizeof(msg));
1051ee66c44Sjoerg 		_exit(127);
1061ee66c44Sjoerg 	}
1071ee66c44Sjoerg #ifdef __HAVE_TLS_VARIANT_I
1081ee66c44Sjoerg 	/* LINTED */
1091ee66c44Sjoerg 	tcb = (struct tls_tcb *)p;
1101ee66c44Sjoerg 	p += sizeof(struct tls_tcb);
1111ee66c44Sjoerg #else
1121ee66c44Sjoerg 	/* LINTED tls_size is rounded above */
113f656b03fSjoerg 	tcb = (struct tls_tcb *)(p + tls_allocation);
114f656b03fSjoerg 	p = (uint8_t *)tcb - tls_size;
1151ee66c44Sjoerg 	tcb->tcb_self = tcb;
1161ee66c44Sjoerg #endif
1171ee66c44Sjoerg 	memcpy(p, tls_initaddr, tls_initsize);
1181ee66c44Sjoerg 
1191ee66c44Sjoerg 	return tcb;
1201ee66c44Sjoerg }
1211ee66c44Sjoerg 
__weak_alias(_rtld_tls_free,__libc_rtld_tls_free)1221ee66c44Sjoerg __weak_alias(_rtld_tls_free, __libc_rtld_tls_free)
1231ee66c44Sjoerg 
1241ee66c44Sjoerg void
1251ee66c44Sjoerg _rtld_tls_free(struct tls_tcb *tcb)
1261ee66c44Sjoerg {
1271ee66c44Sjoerg 	uint8_t *p;
1281ee66c44Sjoerg 
1291ee66c44Sjoerg #ifdef __HAVE_TLS_VARIANT_I
1301ee66c44Sjoerg 	/* LINTED */
1311ee66c44Sjoerg 	p = (uint8_t *)tcb;
1321ee66c44Sjoerg #else
1331ee66c44Sjoerg 	/* LINTED */
134f656b03fSjoerg 	p = (uint8_t *)tcb - tls_allocation;
1351ee66c44Sjoerg #endif
1361ee66c44Sjoerg 	if (p == initial_thread_tcb)
137f656b03fSjoerg 		munmap(p, tls_allocation + sizeof(*tcb));
1381ee66c44Sjoerg 	else
1391ee66c44Sjoerg 		free(p);
1401ee66c44Sjoerg }
1411ee66c44Sjoerg 
142e4ffad0aSmatt static int __section(".text.startup")
__libc_static_tls_setup_cb(struct dl_phdr_info * data,size_t len,void * cookie)1431ee66c44Sjoerg __libc_static_tls_setup_cb(struct dl_phdr_info *data, size_t len, void *cookie)
1441ee66c44Sjoerg {
1451ee66c44Sjoerg 	const Elf_Phdr *phdr = data->dlpi_phdr;
1461ee66c44Sjoerg 	const Elf_Phdr *phlimit = data->dlpi_phdr + data->dlpi_phnum;
1471ee66c44Sjoerg 
1481ee66c44Sjoerg 	for (; phdr < phlimit; ++phdr) {
149c57ff63aSjoerg 		if (phdr->p_type == PT_INTERP) {
150c57ff63aSjoerg 			is_dynamic = true;
151c57ff63aSjoerg 			return -1;
152c57ff63aSjoerg 		}
1531ee66c44Sjoerg 		if (phdr->p_type != PT_TLS)
1541ee66c44Sjoerg 			continue;
1551ee66c44Sjoerg 		tls_initaddr = (void *)(phdr->p_vaddr + data->dlpi_addr);
1561ee66c44Sjoerg 		tls_initsize = phdr->p_filesz;
1579c6b6190Snakayama #ifdef __HAVE_TLS_VARIANT_I
1581ee66c44Sjoerg 		tls_size = phdr->p_memsz;
1599c6b6190Snakayama #else
1609c6b6190Snakayama 		tls_size = roundup2(phdr->p_memsz, phdr->p_align);
1619c6b6190Snakayama #endif
1621ee66c44Sjoerg 	}
1631ee66c44Sjoerg 	return 0;
1641ee66c44Sjoerg }
1651ee66c44Sjoerg 
1661ee66c44Sjoerg void
__libc_static_tls_setup(void)1671ee66c44Sjoerg __libc_static_tls_setup(void)
1681ee66c44Sjoerg {
1691ee66c44Sjoerg 	struct tls_tcb *tcb;
1701ee66c44Sjoerg 
1711ee66c44Sjoerg 	dl_iterate_phdr(__libc_static_tls_setup_cb, NULL);
172c57ff63aSjoerg 	if (is_dynamic)
173c57ff63aSjoerg 		return;
1741ee66c44Sjoerg 
1751ee66c44Sjoerg 	tcb = _rtld_tls_allocate();
176d9261df9Smatt #ifdef __HAVE___LWP_SETTCB
177d9261df9Smatt 	__lwp_settcb(tcb);
178d9261df9Smatt #else
1791ee66c44Sjoerg 	_lwp_setprivate(tcb);
180d9261df9Smatt #endif
1811ee66c44Sjoerg }
1821ee66c44Sjoerg 
1831ee66c44Sjoerg #endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */
184