Update.
[platform/upstream/glibc.git] / sysdeps / generic / dl-tls.c
1 /* Thread-local storage handling in the ELF dynamic linker.  Generic version.
2    Copyright (C) 2002 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <assert.h>
21 #include <stdlib.h>
22
23 #include <tls.h>
24
25 /* We don't need any of this if TLS is not supported.  */
26 #ifdef USE_TLS
27
28 #include <dl-tls.h>
29 #include <ldsodefs.h>
30
31 /* Value used for dtv entries for which the allocation is delayed.  */
32 # define TLS_DTV_UNALLOCATE     ((void *) -1l)
33
34
35 size_t
36 internal_function
37 _dl_next_tls_modid (void)
38 {
39   size_t result;
40
41   if (__builtin_expect (GL(dl_tls_dtv_gaps), false))
42     {
43       /* XXX If this method proves too costly we can optimize
44          it to use a constant time method.  But I don't think
45          it's a problem.  */
46       struct link_map *runp = GL(dl_initimage_list);
47       bool used[GL(dl_tls_max_dtv_idx)];
48
49       assert (runp != NULL);
50       do
51         {
52           assert (runp->l_tls_modid > 0
53                   && runp->l_tls_modid <= GL(dl_tls_max_dtv_idx));
54           used[runp->l_tls_modid - 1] = true;
55         }
56       while ((runp = runp->l_tls_nextimage) != GL(dl_initimage_list));
57
58       result = 0;
59       do
60         /* The information about the gaps is pessimistic.  It might be
61            there are actually none.  */
62         if (result >= GL(dl_tls_max_dtv_idx))
63           {
64             /* Now we know there is actually no gap.  Bump the maximum
65                ID number and remember that there are no gaps.  */
66             result = ++GL(dl_tls_max_dtv_idx);
67             GL(dl_tls_dtv_gaps) = false;
68             break;
69           }
70       while (used[result++]);
71     }
72   else
73     /* No gaps, allocate a new entry.  */
74     result = ++GL(dl_tls_max_dtv_idx);
75
76   return result;
77 }
78
79
80 void
81 internal_function
82 _dl_determine_tlsoffset (struct link_map *firstp)
83 {
84   struct link_map *runp = firstp;
85   size_t max_align = 0;
86   size_t offset;
87
88   if (GL(dl_initimage_list) == NULL)
89     {
90       /* None of the objects used at startup time uses TLS.  We still
91          have to allocate the TCB adn dtv.  */
92       GL(dl_tls_static_size) = TLS_TCB_SIZE;
93       GL(dl_tls_static_align) = TLS_TCB_ALIGN;
94
95       return;
96     }
97
98 # if TLS_TCB_AT_TP
99   /* We simply start with zero.  */
100   offset = 0;
101
102   do
103     {
104       max_align = MAX (max_align, runp->l_tls_align);
105
106       /* Compute the offset of the next TLS block.  */
107       offset = roundup (offset + runp->l_tls_blocksize, runp->l_tls_align);
108
109       /* XXX For some architectures we perhaps should store the
110          negative offset.  */
111       runp->l_tls_offset = offset;
112     }
113   while ((runp = runp->l_tls_nextimage) != firstp);
114
115 #if 0
116   /* The thread descriptor (pointed to by the thread pointer) has its
117      own alignment requirement.  Adjust the static TLS size
118      and TLS offsets appropriately.  */
119   // XXX How to deal with this.  We cannot simply add zero bytes
120   // XXX after the first (closest to the TCB) TLS block since this
121   // XXX would invalidate the offsets the linker creates for the LE
122   // XXX model.
123   if (offset % TLS_TCB_ALIGN != 0)
124     abort ();
125 #endif
126
127   GL(dl_tls_static_size) = offset + TLS_TCB_SIZE;
128 # elif TLS_DTV_AT_TP
129   struct link_map *lastp;
130
131   /* The first block starts right after the TCB.  */
132   offset = TLS_TCB_SIZE;
133   max_align = runp->l_tls_align;
134   runp->l_tls_offset = offset;
135   lastp = runp;
136
137   while ((runp = runp->l_tls_nextimage) != firstp)
138     {
139       max_align = MAX (max_align, runp->l_tls_align);
140
141       /* Compute the offset of the next TLS block.  */
142       offset = roundup (offset + lastp->l_tls_blocksize, runp->l_tls_align);
143
144       runp->l_tls_offset = offset;
145
146       lastp = runp;
147     }
148
149   GL(dl_tls_static_size) = offset + lastp->l_tls_blocksize;
150 # else
151 #  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
152 # endif
153
154   /* The alignment requirement for the static TLS block.  */
155   GL(dl_tls_static_align) = MAX (TLS_TCB_ALIGN, max_align);
156 }
157
158
159 void *
160 internal_function
161 _dl_allocate_tls (void)
162 {
163   void *result;
164   dtv_t *dtv;
165
166   /* Allocate a correctly aligned chunk of memory.  */
167   /* XXX For now */
168   assert (GL(dl_tls_static_align) <= GL(dl_pagesize));
169 #ifdef MAP_ANON
170 # define _dl_zerofd (-1)
171 #else
172 # define _dl_zerofd GL(dl_zerofd)
173   if ((dl_zerofd) == -1)
174     GL(dl_zerofd) = _dl_sysdep_open_zero_fill ();
175 # define MAP_ANON 0
176 #endif
177   result = __mmap (0, GL(dl_tls_static_size), PROT_READ|PROT_WRITE,
178                    MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0);
179
180   dtv = (dtv_t *) malloc ((GL(dl_tls_max_dtv_idx) + 1) * sizeof (dtv_t));
181   if (result != MAP_FAILED && dtv != NULL)
182     {
183       struct link_map *runp;
184
185 # if TLS_TCB_AT_TP
186       /* The TCB follows the TLS blocks.  */
187       result = (char *) result + GL(dl_tls_static_size) - TLS_TCB_SIZE;
188 # endif
189
190       /* XXX Fill in an correct generation number.  */
191       dtv[0].counter = 0;
192
193       /* Initialize the memory from the initialization image list and clear
194          the BSS parts.  */
195       if (GL(dl_initimage_list) != NULL)
196         {
197           runp = GL(dl_initimage_list)->l_tls_nextimage;
198           do
199             {
200               assert (runp->l_tls_modid > 0);
201               assert (runp->l_tls_modid <= GL(dl_tls_max_dtv_idx));
202 # if TLS_TCB_AT_TP
203               dtv[runp->l_tls_modid].pointer = result - runp->l_tls_offset;
204 # elif TLS_DTV_AT_TP
205               dtv[runp->l_tls_modid].pointer = result + runp->l_tls_offset;
206 # else
207 #  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
208 # endif
209
210               memset (__mempcpy (dtv[runp->l_tls_modid].pointer,
211                                  runp->l_tls_initimage,
212                                  runp->l_tls_initimage_size),
213                       '\0',
214                       runp->l_tls_blocksize - runp->l_tls_initimage_size);
215             }
216           while ((runp = runp->l_tls_nextimage)
217                  !=  GL(dl_initimage_list)->l_tls_nextimage);
218         }
219
220       /* Add the dtv to the thread data structures.  */
221       INSTALL_DTV (result, dtv);
222     }
223   else if (result != NULL)
224     {
225       free (result);
226       result = NULL;
227     }
228
229   return result;
230 }
231
232
233 /* The __tls_get_addr function has two basic forms which differ in the
234    arguments.  The IA-64 form takes two parameters, the module ID and
235    offset.  The form used, among others, on IA-32 takes a reference to
236    a special structure which contain the same information.  The second
237    form seems to be more often used (in the moment) so we default to
238    it.  Users of the IA-64 form have to provide adequate definitions
239    of the following macros.  */
240 # ifndef GET_ADDR_ARGS
241 #  define GET_ADDR_ARGS tls_index *ti
242 # endif
243 # ifndef GET_ADDR_MODULE
244 #  define GET_ADDR_MODULE ti->ti_module
245 # endif
246 # ifndef GET_ADDR_OFFSET
247 #  define GET_ADDR_OFFSET ti->ti_offset
248 # endif
249
250
251 void *
252 __tls_get_addr (GET_ADDR_ARGS)
253 {
254   dtv_t *dtv = THREAD_DTV ();
255
256   if (dtv[GET_ADDR_MODULE].pointer == TLS_DTV_UNALLOCATE)
257     /* XXX */;
258
259   return (char *) dtv[GET_ADDR_MODULE].pointer + GET_ADDR_OFFSET;
260 }
261
262 #endif  /* use TLS */