]> git.ipfire.org Git - thirdparty/glibc.git/blame - csu/libc-tls.c
2.5-18.1
[thirdparty/glibc.git] / csu / libc-tls.c
CommitLineData
8a30f00f 1/* Initialization code for TLS in statically linked application.
0ecb606c 2 Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
8a30f00f
UD
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
7d0b1164 20#include <errno.h>
8a30f00f
UD
21#include <ldsodefs.h>
22#include <tls.h>
23#include <unistd.h>
82412d54 24#include <stdio.h>
99343c05 25#include <sys/param.h>
8a30f00f 26
82412d54 27
b9cb349f
RM
28#ifdef SHARED
29 #error makefile bug, this file is for static only
30#endif
8a30f00f
UD
31
32#ifdef USE_TLS
33extern ElfW(Phdr) *_dl_phdr;
34extern size_t _dl_phnum;
35
36
0ecb606c 37static dtv_t static_dtv[2 + TLS_SLOTINFO_SURPLUS];
8a30f00f
UD
38
39
40static struct
41{
42 struct dtv_slotinfo_list si;
43 /* The dtv_slotinfo_list data structure does not include the actual
8265947d
RM
44 information since it is defined as an array of size zero. We define
45 here the necessary entries. Note that it is not important whether
46 there is padding or not since we will always access the information
47 through the 'si' element. */
8a30f00f
UD
48 struct dtv_slotinfo info[2 + TLS_SLOTINFO_SURPLUS];
49} static_slotinfo;
50
51/* Fake link map for the application. */
52static struct link_map static_map;
53
54
b9cb349f
RM
55/* Highest dtv index currently needed. */
56size_t _dl_tls_max_dtv_idx;
57/* Flag signalling whether there are gaps in the module ID allocation. */
58bool _dl_tls_dtv_gaps;
59/* Information about the dtv slots. */
60struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list;
61/* Number of modules in the static TLS block. */
62size_t _dl_tls_static_nelem;
0ecb606c
JJ
63/* Size of the static TLS block. Giving this initialized value
64 preallocates some surplus bytes in the static TLS area. */
65size_t _dl_tls_static_size = 2048;
80f6f981
UD
66/* Size actually allocated in the static TLS block. */
67size_t _dl_tls_static_used;
b9cb349f
RM
68/* Alignment requirement of the static TLS block. */
69size_t _dl_tls_static_align;
70
71/* Generation counter for the dtv. */
72size_t _dl_tls_generation;
73
74
2a76f7ef
UD
75/* Additional definitions needed by TLS initialization. */
76#ifdef TLS_INIT_HELPER
77TLS_INIT_HELPER
78#endif
79
216455bc
RM
80static inline void
81init_slotinfo (void)
82{
83 /* Create the slotinfo list. */
84 static_slotinfo.si.len = (((char *) (&static_slotinfo + 1)
85 - (char *) &static_slotinfo.si.slotinfo[0])
86 / sizeof static_slotinfo.si.slotinfo[0]);
87 // static_slotinfo.si.next = NULL; already zero
88
89 /* The slotinfo list. Will be extended by the code doing dynamic
90 linking. */
91 GL(dl_tls_max_dtv_idx) = 1;
92 GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo.si;
93}
94
95static inline void
96init_static_tls (size_t memsz, size_t align)
97{
98 /* That is the size of the TLS memory for this object. The initialized
99 value of _dl_tls_static_size is provided by dl-open.c to request some
100 surplus that permits dynamic loading of modules with IE-model TLS. */
101 GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size),
102 TLS_TCB_ALIGN);
103 GL(dl_tls_static_used) = memsz;
104 /* The alignment requirement for the static TLS block. */
105 GL(dl_tls_static_align) = align;
106 /* Number of elements in the static TLS block. */
107 GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
108}
2a76f7ef 109
8a30f00f
UD
110void
111__libc_setup_tls (size_t tcbsize, size_t tcbalign)
112{
113 void *tlsblock;
114 size_t memsz = 0;
115 size_t filesz = 0;
d10c6430 116 void *initimage = NULL;
8a30f00f
UD
117 size_t align = 0;
118 size_t max_align = tcbalign;
8a30f00f 119 size_t tcb_offset;
a162642d 120 ElfW(Phdr) *phdr;
8a30f00f
UD
121
122 /* Look through the TLS segment if there is any. */
123 if (_dl_phdr != NULL)
a162642d 124 for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
d10c6430
RM
125 if (phdr->p_type == PT_TLS)
126 {
127 /* Remember the values we need. */
128 memsz = phdr->p_memsz;
129 filesz = phdr->p_filesz;
130 initimage = (void *) phdr->p_vaddr;
131 align = phdr->p_align;
132 if (phdr->p_align > max_align)
133 max_align = phdr->p_align;
134 break;
135 }
8a30f00f 136
8a30f00f
UD
137 /* We have to set up the TCB block which also (possibly) contains
138 'errno'. Therefore we avoid 'malloc' which might touch 'errno'.
139 Instead we use 'sbrk' which would only uses 'errno' if it fails.
140 In this case we are right away out of memory and the user gets
e7e6e437
RM
141 what she/he deserves.
142
143 The initialized value of _dl_tls_static_size is provided by dl-open.c
144 to request some surplus that permits dynamic loading of modules with
145 IE-model TLS. */
8a30f00f 146# if TLS_TCB_AT_TP
216455bc
RM
147 tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign);
148 tlsblock = __sbrk (tcb_offset + tcbsize + max_align);
8a30f00f 149# elif TLS_DTV_AT_TP
aff4519d
UD
150 tcb_offset = roundup (tcbsize, align ?: 1);
151 tlsblock = __sbrk (tcb_offset + memsz + max_align
152 + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size));
153 tlsblock += TLS_PRE_TCB_SIZE;
8a30f00f
UD
154# else
155 /* In case a model with a different layout for the TCB and DTV
156 is defined add another #elif here and in the following #ifs. */
157# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
158# endif
159
160 /* Align the TLS block. */
161 tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1)
162 & ~(max_align - 1));
163
164 /* Initialize the dtv. [0] is the length, [1] the generation counter. */
0ecb606c 165 static_dtv[0].counter = (sizeof (static_dtv) / sizeof (static_dtv[0])) - 2;
8a30f00f
UD
166 // static_dtv[1].counter = 0; would be needed if not already done
167
168 /* Initialize the TLS block. */
169# if TLS_TCB_AT_TP
0ecb606c
JJ
170 static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset
171 - roundup (memsz, align ?: 1));
82412d54 172 static_map.l_tls_offset = roundup (memsz, align ?: 1);
8a30f00f 173# elif TLS_DTV_AT_TP
0ecb606c 174 static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset;
216455bc 175 static_map.l_tls_offset = tcb_offset;
8a30f00f
UD
176# else
177# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
178# endif
0ecb606c 179 static_dtv[2].pointer.is_static = true;
82412d54 180 /* sbrk gives us zero'd memory, so we don't need to clear the remainder. */
0ecb606c 181 memcpy (static_dtv[2].pointer.val, initimage, filesz);
8a30f00f
UD
182
183 /* Install the pointer to the dtv. */
184
185 /* Initialize the thread pointer. */
186# if TLS_TCB_AT_TP
8a30f00f
UD
187 INSTALL_DTV ((char *) tlsblock + tcb_offset, static_dtv);
188
82412d54 189 const char *lossage = TLS_INIT_TP ((char *) tlsblock + tcb_offset, 0);
8a30f00f
UD
190# elif TLS_DTV_AT_TP
191 INSTALL_DTV (tlsblock, static_dtv);
82412d54 192 const char *lossage = TLS_INIT_TP (tlsblock, 0);
8a30f00f
UD
193# else
194# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
195# endif
82412d54
RM
196 if (__builtin_expect (lossage != NULL, 0))
197 __libc_fatal (lossage);
8a30f00f
UD
198
199 /* We have to create a fake link map which normally would be created
a816b435 200 by the dynamic linker. It just has to have enough information to
8a30f00f
UD
201 make the TLS routines happy. */
202 static_map.l_tls_align = align;
203 static_map.l_tls_blocksize = memsz;
8265947d 204 static_map.l_tls_initimage = initimage;
8a30f00f 205 static_map.l_tls_initimage_size = filesz;
8a30f00f
UD
206 static_map.l_type = lt_executable;
207 static_map.l_tls_modid = 1;
208
216455bc
RM
209 init_slotinfo ();
210 // static_slotinfo.si.slotinfo[1].gen = 0; already zero
8a30f00f
UD
211 static_slotinfo.si.slotinfo[1].map = &static_map;
212
c56baa87 213 memsz = roundup (memsz, align ?: 1);
216455bc 214
8a30f00f 215# if TLS_TCB_AT_TP
c56baa87 216 memsz += tcbsize;
aff4519d
UD
217# elif TLS_DTV_AT_TP
218 memsz += tcb_offset;
f7c1f4dd 219# endif
c56baa87 220
216455bc
RM
221 init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align));
222}
223
224/* This is called only when the data structure setup was skipped at startup,
225 when there was no need for it then. Now we have dynamically loaded
226 something needing TLS, or libpthread needs it. */
227int
228internal_function
229_dl_tls_setup (void)
230{
231 init_slotinfo ();
232 init_static_tls (
233# if TLS_TCB_AT_TP
234 TLS_TCB_SIZE,
235# else
236 0,
237# endif
238 TLS_TCB_ALIGN);
239 return 0;
8a30f00f
UD
240}
241
242
243/* This is the minimal initialization function used when libpthread is
244 not used. */
245void
246__attribute__ ((weak))
247__pthread_initialize_minimal (void)
248{
0f283ffc 249 __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
8a30f00f 250}
131fd126
UD
251
252#elif defined NONTLS_INIT_TP
253
254/* This is the minimal initialization function used when libpthread is
255 not used. */
256void
257__attribute__ ((weak))
258__pthread_initialize_minimal (void)
259{
260 NONTLS_INIT_TP;
261}
262
8a30f00f 263#endif