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.
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.
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.
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
25 /* We don't need any of this if TLS is not supported. */
31 /* Value used for dtv entries for which the allocation is delayed. */
32 # define TLS_DTV_UNALLOCATE ((void *) -1l)
37 _dl_next_tls_modid (void)
41 if (__builtin_expect (GL(dl_tls_dtv_gaps), false))
43 /* XXX If this method proves too costly we can optimize
44 it to use a constant time method. But I don't think
46 struct link_map *runp = GL(dl_initimage_list);
47 bool used[GL(dl_tls_max_dtv_idx)];
49 assert (runp != NULL);
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;
56 while ((runp = runp->l_tls_nextimage) != GL(dl_initimage_list));
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))
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;
70 while (used[result++]);
73 /* No gaps, allocate a new entry. */
74 result = ++GL(dl_tls_max_dtv_idx);
82 _dl_determine_tlsoffset (struct link_map *firstp)
84 struct link_map *runp = firstp;
88 if (GL(dl_initimage_list) == NULL)
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;
99 /* We simply start with zero. */
104 max_align = MAX (max_align, runp->l_tls_align);
106 /* Compute the offset of the next TLS block. */
107 offset = roundup (offset + runp->l_tls_blocksize, runp->l_tls_align);
109 /* XXX For some architectures we perhaps should store the
111 runp->l_tls_offset = offset;
113 while ((runp = runp->l_tls_nextimage) != firstp);
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
123 if (offset % TLS_TCB_ALIGN != 0)
127 GL(dl_tls_static_size) = offset + TLS_TCB_SIZE;
129 struct link_map *lastp;
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;
137 while ((runp = runp->l_tls_nextimage) != firstp)
139 max_align = MAX (max_align, runp->l_tls_align);
141 /* Compute the offset of the next TLS block. */
142 offset = roundup (offset + lastp->l_tls_blocksize, runp->l_tls_align);
144 runp->l_tls_offset = offset;
149 GL(dl_tls_static_size) = offset + lastp->l_tls_blocksize;
151 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
154 /* The alignment requirement for the static TLS block. */
155 GL(dl_tls_static_align) = MAX (TLS_TCB_ALIGN, max_align);
161 _dl_allocate_tls (void)
166 /* Allocate a correctly aligned chunk of memory. */
168 assert (GL(dl_tls_static_align) <= GL(dl_pagesize));
170 # define _dl_zerofd (-1)
172 # define _dl_zerofd GL(dl_zerofd)
173 if ((dl_zerofd) == -1)
174 GL(dl_zerofd) = _dl_sysdep_open_zero_fill ();
177 result = __mmap (0, GL(dl_tls_static_size), PROT_READ|PROT_WRITE,
178 MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0);
180 dtv = (dtv_t *) malloc ((GL(dl_tls_max_dtv_idx) + 1) * sizeof (dtv_t));
181 if (result != MAP_FAILED && dtv != NULL)
183 struct link_map *runp;
186 /* The TCB follows the TLS blocks. */
187 result = (char *) result + GL(dl_tls_static_size) - TLS_TCB_SIZE;
190 /* XXX Fill in an correct generation number. */
193 /* Initialize the memory from the initialization image list and clear
195 if (GL(dl_initimage_list) != NULL)
197 runp = GL(dl_initimage_list)->l_tls_nextimage;
200 assert (runp->l_tls_modid > 0);
201 assert (runp->l_tls_modid <= GL(dl_tls_max_dtv_idx));
203 dtv[runp->l_tls_modid].pointer = result - runp->l_tls_offset;
205 dtv[runp->l_tls_modid].pointer = result + runp->l_tls_offset;
207 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
210 memset (__mempcpy (dtv[runp->l_tls_modid].pointer,
211 runp->l_tls_initimage,
212 runp->l_tls_initimage_size),
214 runp->l_tls_blocksize - runp->l_tls_initimage_size);
216 while ((runp = runp->l_tls_nextimage)
217 != GL(dl_initimage_list)->l_tls_nextimage);
220 /* Add the dtv to the thread data structures. */
221 INSTALL_DTV (result, dtv);
223 else if (result != NULL)
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
243 # ifndef GET_ADDR_MODULE
244 # define GET_ADDR_MODULE ti->ti_module
246 # ifndef GET_ADDR_OFFSET
247 # define GET_ADDR_OFFSET ti->ti_offset
252 __tls_get_addr (GET_ADDR_ARGS)
254 dtv_t *dtv = THREAD_DTV ();
256 if (dtv[GET_ADDR_MODULE].pointer == TLS_DTV_UNALLOCATE)
259 return (char *) dtv[GET_ADDR_MODULE].pointer + GET_ADDR_OFFSET;