1 /* $NetBSD: tls.c,v 1.7 2013/08/19 22:14:37 matt Exp $ */
4 * Copyright (c) 2011 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Joerg Sonnenberger.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: tls.c,v 1.7 2013/08/19 22:14:37 matt Exp $");
35 #include "namespace.h"
37 #define _rtld_tls_allocate __libc_rtld_tls_allocate
38 #define _rtld_tls_free __libc_rtld_tls_free
42 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
44 #include <sys/param.h>
53 __dso_hidden
void __libc_static_tls_setup(void);
55 static const void *tls_initaddr
;
56 static size_t tls_initsize
;
57 static size_t tls_size
;
58 static size_t tls_allocation
;
59 static void *initial_thread_tcb
;
61 void * __libc_tls_get_addr(void);
63 __weak_alias(__tls_get_addr
, __libc_tls_get_addr
)
65 __weak_alias(___tls_get_addr
, __libc_tls_get_addr
)
69 __libc_tls_get_addr(void)
76 __weak_alias(_rtld_tls_allocate
, __libc_rtld_tls_allocate
)
79 _rtld_tls_allocate(void)
84 if (initial_thread_tcb
== NULL
) {
85 #ifdef __HAVE_TLS_VARIANT_II
86 tls_size
= roundup2(tls_size
, sizeof(void *));
88 tls_allocation
= tls_size
+ sizeof(*tcb
);
90 initial_thread_tcb
= p
= mmap(NULL
, tls_allocation
,
91 PROT_READ
| PROT_WRITE
, MAP_ANON
, -1, 0);
93 p
= calloc(1, tls_allocation
);
96 static const char msg
[] = "TLS allocation failed, terminating\n";
97 write(STDERR_FILENO
, msg
, sizeof(msg
));
100 #ifdef __HAVE_TLS_VARIANT_I
102 tcb
= (struct tls_tcb
*)p
;
103 p
+= sizeof(struct tls_tcb
);
105 /* LINTED tls_size is rounded above */
106 tcb
= (struct tls_tcb
*)(p
+ tls_size
);
109 memcpy(p
, tls_initaddr
, tls_initsize
);
114 __weak_alias(_rtld_tls_free
, __libc_rtld_tls_free
)
117 _rtld_tls_free(struct tls_tcb
*tcb
)
121 #ifdef __HAVE_TLS_VARIANT_I
126 p
= (uint8_t *)tcb
- tls_size
;
128 if (p
== initial_thread_tcb
)
129 munmap(p
, tls_allocation
);
134 __weakref_visible
int rtld_DYNAMIC
__weak_reference(_DYNAMIC
);
136 static int __section(".text.startup")
137 __libc_static_tls_setup_cb(struct dl_phdr_info
*data
, size_t len
, void *cookie
)
139 const Elf_Phdr
*phdr
= data
->dlpi_phdr
;
140 const Elf_Phdr
*phlimit
= data
->dlpi_phdr
+ data
->dlpi_phnum
;
142 for (; phdr
< phlimit
; ++phdr
) {
143 if (phdr
->p_type
!= PT_TLS
)
145 tls_initaddr
= (void *)(phdr
->p_vaddr
+ data
->dlpi_addr
);
146 tls_initsize
= phdr
->p_filesz
;
147 tls_size
= phdr
->p_memsz
;
153 __libc_static_tls_setup(void)
157 if (&rtld_DYNAMIC
!= NULL
) {
160 * Old powerpc crt0's are going to overwrite r2 so we need to
161 * restore it but only do so if the saved value isn't NULL (if
162 * it is NULL, ld.elf_so doesn't have the matching change).
164 if ((tcb
= _lwp_getprivate()) != NULL
)
170 dl_iterate_phdr(__libc_static_tls_setup_cb
, NULL
);
172 tcb
= _rtld_tls_allocate();
173 #ifdef __HAVE___LWP_SETTCB
176 _lwp_setprivate(tcb
);
180 #endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */