1 /* Thread-local storage handling in the ELF dynamic linker. i386 version.
2 Copyright (C) 2004, 2005, 2008 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
26 /* This function is used to compute the TP offset for symbols in
27 Static TLS, i.e., whose TP offset is the same for all
30 The incoming %eax points to the TLS descriptor, such that
31 0(%eax) points to _dl_tlsdesc_return itself, and 4(%eax) holds
32 the TP offset of the symbol corresponding to the object
33 denoted by the argument. */
35 .hidden _dl_tlsdesc_return
36 .global _dl_tlsdesc_return
37 .type _dl_tlsdesc_return,@function
44 .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
46 /* This function is used for undefined weak TLS symbols, for
47 which the base address (i.e., disregarding any addend) should
50 %eax points to the TLS descriptor, such that 0(%eax) points to
51 _dl_tlsdesc_undefweak itself, and 4(%eax) holds the addend.
52 We return the addend minus the TP, such that, when the caller
53 adds TP, it gets the addend back. If that's zero, as usual,
54 that's most likely a NULL pointer. */
56 .hidden _dl_tlsdesc_undefweak
57 .global _dl_tlsdesc_undefweak
58 .type _dl_tlsdesc_undefweak,@function
61 _dl_tlsdesc_undefweak:
66 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
69 .hidden _dl_tlsdesc_dynamic
70 .global _dl_tlsdesc_dynamic
71 .type _dl_tlsdesc_dynamic,@function
73 /* This function is used for symbols that need dynamic TLS.
75 %eax points to the TLS descriptor, such that 0(%eax) points to
76 _dl_tlsdesc_dynamic itself, and 4(%eax) points to a struct
77 tlsdesc_dynamic_arg object. It must return in %eax the offset
78 between the thread pointer and the object denoted by the
79 argument, without clobbering any registers.
81 The assembly code that follows is a rendition of the following
82 C code, hand-optimized a little bit.
85 __attribute__ ((__regparm__ (1)))
86 _dl_tlsdesc_dynamic (struct tlsdesc *tdp)
88 struct tlsdesc_dynamic_arg *td = tdp->arg;
89 dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + DTV_OFFSET);
90 if (__builtin_expect (td->gen_count <= dtv[0].counter
91 && (dtv[td->tlsinfo.ti_module].pointer.val
92 != TLS_DTV_UNALLOCATED),
94 return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
97 return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
103 /* Like all TLS resolvers, preserve call-clobbered registers.
104 We need two scratch regs anyway. */
106 cfi_adjust_cfa_offset (28)
109 movl TLSDESC_ARG(%eax), %eax
110 movl %gs:DTV_OFFSET, %edx
111 movl TLSDESC_GEN_COUNT(%eax), %ecx
114 movl TLSDESC_MODID(%eax), %ecx
115 movl (%edx,%ecx,8), %edx
118 movl TLSDESC_MODOFF(%eax), %eax
125 cfi_adjust_cfa_offset (-28)
129 cfi_adjust_cfa_offset (28)
132 call ___tls_get_addr@PLT
136 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
139 /* This function is a wrapper for a lazy resolver for TLS_DESC
140 REL relocations that reference the *ABS* segment in their own
141 link maps. %ebx points to the caller's GOT. %eax points to a
142 TLS descriptor, such that 0(%eax) holds the address of the
143 resolver wrapper itself (unless some other thread beat us to
144 it) and 4(%eax) holds the addend in the relocation.
146 When the actual resolver returns, it will have adjusted the
147 TLS descriptor such that we can tail-call it for it to return
148 the TP offset of the symbol. */
150 .hidden _dl_tlsdesc_resolve_abs_plus_addend
151 .global _dl_tlsdesc_resolve_abs_plus_addend
152 .type _dl_tlsdesc_resolve_abs_plus_addend,@function
155 _dl_tlsdesc_resolve_abs_plus_addend:
158 cfi_adjust_cfa_offset (4)
160 cfi_adjust_cfa_offset (4)
162 cfi_adjust_cfa_offset (4)
165 call _dl_tlsdesc_resolve_abs_plus_addend_fixup
168 cfi_adjust_cfa_offset (-4)
170 cfi_adjust_cfa_offset (-4)
172 cfi_adjust_cfa_offset (-4)
175 .size _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
177 /* This function is a wrapper for a lazy resolver for TLS_DESC
178 REL relocations that had zero addends. %ebx points to the
179 caller's GOT. %eax points to a TLS descriptor, such that
180 0(%eax) holds the address of the resolver wrapper itself
181 (unless some other thread beat us to it) and 4(%eax) holds a
182 pointer to the relocation.
184 When the actual resolver returns, it will have adjusted the
185 TLS descriptor such that we can tail-call it for it to return
186 the TP offset of the symbol. */
188 .hidden _dl_tlsdesc_resolve_rel
189 .global _dl_tlsdesc_resolve_rel
190 .type _dl_tlsdesc_resolve_rel,@function
193 _dl_tlsdesc_resolve_rel:
196 cfi_adjust_cfa_offset (4)
198 cfi_adjust_cfa_offset (4)
200 cfi_adjust_cfa_offset (4)
203 call _dl_tlsdesc_resolve_rel_fixup
206 cfi_adjust_cfa_offset (-4)
208 cfi_adjust_cfa_offset (-4)
210 cfi_adjust_cfa_offset (-4)
213 .size _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
215 /* This function is a wrapper for a lazy resolver for TLS_DESC
216 RELA relocations. %ebx points to the caller's GOT. %eax
217 points to a TLS descriptor, such that 0(%eax) holds the
218 address of the resolver wrapper itself (unless some other
219 thread beat us to it) and 4(%eax) holds a pointer to the
222 When the actual resolver returns, it will have adjusted the
223 TLS descriptor such that we can tail-call it for it to return
224 the TP offset of the symbol. */
226 .hidden _dl_tlsdesc_resolve_rela
227 .global _dl_tlsdesc_resolve_rela
228 .type _dl_tlsdesc_resolve_rela,@function
231 _dl_tlsdesc_resolve_rela:
234 cfi_adjust_cfa_offset (4)
236 cfi_adjust_cfa_offset (4)
238 cfi_adjust_cfa_offset (4)
241 call _dl_tlsdesc_resolve_rela_fixup
244 cfi_adjust_cfa_offset (-4)
246 cfi_adjust_cfa_offset (-4)
248 cfi_adjust_cfa_offset (-4)
251 .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
253 /* This function is a placeholder for lazy resolving of TLS
254 relocations. Once some thread starts resolving a TLS
255 relocation, it sets up the TLS descriptor to use this
256 resolver, such that other threads that would attempt to
257 resolve it concurrently may skip the call to the original lazy
258 resolver and go straight to a condition wait.
260 When the actual resolver returns, it will have adjusted the
261 TLS descriptor such that we can tail-call it for it to return
262 the TP offset of the symbol. */
264 .hidden _dl_tlsdesc_resolve_hold
265 .global _dl_tlsdesc_resolve_hold
266 .type _dl_tlsdesc_resolve_hold,@function
269 _dl_tlsdesc_resolve_hold:
272 cfi_adjust_cfa_offset (4)
274 cfi_adjust_cfa_offset (4)
276 cfi_adjust_cfa_offset (4)
279 call _dl_tlsdesc_resolve_hold_fixup
282 cfi_adjust_cfa_offset (-4)
284 cfi_adjust_cfa_offset (-4)
286 cfi_adjust_cfa_offset (-4)
289 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold