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)
131 call __i686.get_pc_thunk.bx
132 addl $_GLOBAL_OFFSET_TABLE_, %ebx
133 call ___tls_get_addr@PLT
137 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
140 /* This function is a wrapper for a lazy resolver for TLS_DESC
141 REL relocations that reference the *ABS* segment in their own
142 link maps. %ebx points to the caller's GOT. %eax points to a
143 TLS descriptor, such that 0(%eax) holds the address of the
144 resolver wrapper itself (unless some other thread beat us to
145 it) and 4(%eax) holds the addend in the relocation.
147 When the actual resolver returns, it will have adjusted the
148 TLS descriptor such that we can tail-call it for it to return
149 the TP offset of the symbol. */
151 .hidden _dl_tlsdesc_resolve_abs_plus_addend
152 .global _dl_tlsdesc_resolve_abs_plus_addend
153 .type _dl_tlsdesc_resolve_abs_plus_addend,@function
156 _dl_tlsdesc_resolve_abs_plus_addend:
159 cfi_adjust_cfa_offset (4)
161 cfi_adjust_cfa_offset (4)
163 cfi_adjust_cfa_offset (4)
166 call _dl_tlsdesc_resolve_abs_plus_addend_fixup
169 cfi_adjust_cfa_offset (-4)
171 cfi_adjust_cfa_offset (-4)
173 cfi_adjust_cfa_offset (-4)
176 .size _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
178 /* This function is a wrapper for a lazy resolver for TLS_DESC
179 REL relocations that had zero addends. %ebx points to the
180 caller's GOT. %eax points to a TLS descriptor, such that
181 0(%eax) holds the address of the resolver wrapper itself
182 (unless some other thread beat us to it) and 4(%eax) holds a
183 pointer to the relocation.
185 When the actual resolver returns, it will have adjusted the
186 TLS descriptor such that we can tail-call it for it to return
187 the TP offset of the symbol. */
189 .hidden _dl_tlsdesc_resolve_rel
190 .global _dl_tlsdesc_resolve_rel
191 .type _dl_tlsdesc_resolve_rel,@function
194 _dl_tlsdesc_resolve_rel:
197 cfi_adjust_cfa_offset (4)
199 cfi_adjust_cfa_offset (4)
201 cfi_adjust_cfa_offset (4)
204 call _dl_tlsdesc_resolve_rel_fixup
207 cfi_adjust_cfa_offset (-4)
209 cfi_adjust_cfa_offset (-4)
211 cfi_adjust_cfa_offset (-4)
214 .size _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
216 /* This function is a wrapper for a lazy resolver for TLS_DESC
217 RELA relocations. %ebx points to the caller's GOT. %eax
218 points to a TLS descriptor, such that 0(%eax) holds the
219 address of the resolver wrapper itself (unless some other
220 thread beat us to it) and 4(%eax) holds a pointer to the
223 When the actual resolver returns, it will have adjusted the
224 TLS descriptor such that we can tail-call it for it to return
225 the TP offset of the symbol. */
227 .hidden _dl_tlsdesc_resolve_rela
228 .global _dl_tlsdesc_resolve_rela
229 .type _dl_tlsdesc_resolve_rela,@function
232 _dl_tlsdesc_resolve_rela:
235 cfi_adjust_cfa_offset (4)
237 cfi_adjust_cfa_offset (4)
239 cfi_adjust_cfa_offset (4)
242 call _dl_tlsdesc_resolve_rela_fixup
245 cfi_adjust_cfa_offset (-4)
247 cfi_adjust_cfa_offset (-4)
249 cfi_adjust_cfa_offset (-4)
252 .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
254 /* This function is a placeholder for lazy resolving of TLS
255 relocations. Once some thread starts resolving a TLS
256 relocation, it sets up the TLS descriptor to use this
257 resolver, such that other threads that would attempt to
258 resolve it concurrently may skip the call to the original lazy
259 resolver and go straight to a condition wait.
261 When the actual resolver returns, it will have adjusted the
262 TLS descriptor such that we can tail-call it for it to return
263 the TP offset of the symbol. */
265 .hidden _dl_tlsdesc_resolve_hold
266 .global _dl_tlsdesc_resolve_hold
267 .type _dl_tlsdesc_resolve_hold,@function
270 _dl_tlsdesc_resolve_hold:
273 cfi_adjust_cfa_offset (4)
275 cfi_adjust_cfa_offset (4)
277 cfi_adjust_cfa_offset (4)
280 call _dl_tlsdesc_resolve_hold_fixup
283 cfi_adjust_cfa_offset (-4)
285 cfi_adjust_cfa_offset (-4)
287 cfi_adjust_cfa_offset (-4)
290 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold