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