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