Merge from vendor branch HEIMDAL:
[dragonfly.git] / lib / libc / gen / tls.c
CommitLineData
b00401f0
DX
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: src/lib/libc/gen/tls.c,v 1.7 2005/03/01 23:42:00 davidxu Exp $
bc633d63 27 * $DragonFly: src/lib/libc/gen/tls.c,v 1.4 2005/03/28 03:33:12 dillon Exp $
b00401f0
DX
28 */
29
30/*
31 * Define stubs for TLS internals so that programs and libraries can
32 * link. These functions will be replaced by functional versions at
33 * runtime from ld-elf.so.1.
34 */
35
92df6c3e 36#include <sys/cdefs.h>
bc633d63 37#include <sys/tls.h>
b00401f0
DX
38#include <stdlib.h>
39#include <string.h>
40#include <elf.h>
41#include <assert.h>
92df6c3e 42
b00401f0
DX
43#include "libc_private.h"
44
92df6c3e
DX
45__weak_reference(__libc_allocate_tls, _rtld_allocate_tls);
46__weak_reference(__libc_free_tls, _rtld_free_tls);
47#ifdef __i386__
48__weak_reference(___libc_tls_get_addr, ___tls_get_addr);
49#endif
50__weak_reference(__libc_tls_get_addr, __tls_get_addr);
51
bc633d63
MD
52struct tls_tcb *_rtld_allocate_tls(struct tls_tcb *, size_t tcbsize, int flags);
53void _rtld_free_tls(struct tls_tcb *tcb, size_t tcb_size);
54struct tls_tcb *__libc_allocate_tls(struct tls_tcb *old_tcb, size_t tcbsize,
55 int flags);
56void __libc_free_tls(struct tls_tcb *tcb, size_t tcb_size);
b00401f0
DX
57
58#if defined(__ia64__) || defined(__powerpc__)
59#define TLS_VARIANT_I
60#endif
61#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \
62 defined(__arm__)
63#define TLS_VARIANT_II
64#endif
65
66#ifndef PIC
67
68#define round(size, align) \
69 (((size) + (align) - 1) & ~((align) - 1))
70
71static size_t tls_static_space;
72static size_t tls_init_size;
b00401f0
DX
73static void *tls_init;
74#endif
75
b00401f0
DX
76#ifdef __i386__
77
92df6c3e
DX
78/* GNU ABI */
79
80void *___libc_tls_get_addr(void *ti) __attribute__((__regparm__(1)));
b00401f0 81
b00401f0
DX
82__attribute__((__regparm__(1)))
83void *
92df6c3e 84___libc_tls_get_addr(void *ti __unused)
b00401f0
DX
85{
86 return (0);
87}
88
89#endif
90
92df6c3e 91void *__libc_tls_get_addr(void *ti);
bc633d63 92
b00401f0 93void *
92df6c3e 94__libc_tls_get_addr(void *ti __unused)
b00401f0
DX
95{
96 return (0);
97}
98
92df6c3e
DX
99#ifndef PIC
100
b00401f0 101/*
bc633d63 102 * Free Static TLS
b00401f0
DX
103 */
104void
bc633d63 105__libc_free_tls(struct tls_tcb *tcb, size_t tcb_size __unused)
b00401f0 106{
bc633d63 107 size_t data_size;
b00401f0 108
bc633d63
MD
109 if (tcb->dtv_base)
110 free(tcb->dtv_base);
111 data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) &
112 ~RTLD_STATIC_TLS_ALIGN_MASK;
113 free((char *)tcb - data_size);
b00401f0
DX
114}
115
b00401f0 116/*
bc633d63 117 * Allocate Static TLS.
b00401f0 118 */
bc633d63
MD
119struct tls_tcb *
120__libc_allocate_tls(struct tls_tcb *old_tcb, size_t tcb_size, int flags)
b00401f0 121{
bc633d63
MD
122 size_t data_size;
123 struct tls_tcb *tcb;
b00401f0
DX
124 Elf_Addr *dtv;
125
bc633d63
MD
126 data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) &
127 ~RTLD_STATIC_TLS_ALIGN_MASK;
128 tcb = malloc(data_size + tcb_size);
129 tcb = (struct tls_tcb *)((char *)tcb + data_size);
130 bzero(tcb, tcb_size);
b00401f0 131 dtv = malloc(3 * sizeof(Elf_Addr));
bc633d63
MD
132 tcb->tcb_base = tcb;
133 tcb->dtv_base = dtv;
b00401f0
DX
134
135 dtv[0] = 1;
136 dtv[1] = 1;
bc633d63 137 dtv[2] = (Elf_Addr)((char *)tcb - tls_static_space);
b00401f0 138
bc633d63 139 if (old_tcb) {
b00401f0
DX
140 /*
141 * Copy the static TLS block over whole.
142 */
bc633d63
MD
143 memcpy((char *)tcb - tls_static_space,
144 (char *)old_tcb - tls_static_space,
145 tls_static_space);
b00401f0
DX
146
147 /*
148 * We assume that this block was the one we created with
149 * allocate_initial_tls().
150 */
bc633d63 151 _rtld_free_tls(old_tcb, sizeof(struct tls_tcb));
b00401f0 152 } else {
bc633d63
MD
153 memcpy((char *)tcb - tls_static_space,
154 tls_init, tls_init_size);
155 memset((char *)tcb - tls_static_space + tls_init_size,
156 0, tls_static_space - tls_init_size);
b00401f0 157 }
bc633d63 158 return (tcb);
92df6c3e
DX
159}
160
b00401f0 161#else
92df6c3e 162
bc633d63
MD
163struct tls_tcb *
164__libc_allocate_tls(struct tls_tcb *old_tls __unused, size_t tcb_size __unused,
165 int flags __unused)
92df6c3e 166{
b00401f0 167 return (0);
b00401f0
DX
168}
169
92df6c3e 170void
bc633d63 171__libc_free_tls(struct tls_tcb *tcb __unused, size_t tcb_size __unused)
92df6c3e
DX
172{
173}
174
175#endif /* PIC */
b00401f0
DX
176
177extern char **environ;
178
179void
180_init_tls()
181{
182#ifndef PIC
183 Elf_Addr *sp;
184 Elf_Auxinfo *aux, *auxp;
185 Elf_Phdr *phdr;
186 size_t phent, phnum;
187 int i;
bc633d63 188 struct tls_tcb *tcb;
b00401f0
DX
189
190 sp = (Elf_Addr *) environ;
191 while (*sp++ != 0)
192 ;
193 aux = (Elf_Auxinfo *) sp;
194 phdr = 0;
195 phent = phnum = 0;
196 for (auxp = aux; auxp->a_type != AT_NULL; auxp++) {
197 switch (auxp->a_type) {
198 case AT_PHDR:
199 phdr = auxp->a_un.a_ptr;
200 break;
201
202 case AT_PHENT:
203 phent = auxp->a_un.a_val;
204 break;
205
206 case AT_PHNUM:
207 phnum = auxp->a_un.a_val;
208 break;
209 }
210 }
211 if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0)
212 return;
213
214 for (i = 0; (unsigned)i < phnum; i++) {
215 if (phdr[i].p_type == PT_TLS) {
b00401f0
DX
216 tls_static_space = round(phdr[i].p_memsz,
217 phdr[i].p_align);
b00401f0
DX
218 tls_init_size = phdr[i].p_filesz;
219 tls_init = (void*) phdr[i].p_vaddr;
220 }
221 }
222
bc633d63
MD
223 if (tls_static_space) {
224 tcb = _rtld_allocate_tls(NULL, sizeof(struct tls_tcb), 0);
225 _set_tp(tcb, (size_t)-1);
226 }
b00401f0
DX
227#endif
228}