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, see
17 <http://www.gnu.org/licenses/>. */
25 /* This function is used to compute the TP offset for symbols in
26 Static TLS, i.e., whose TP offset is the same for all
29 The incoming %eax points to the TLS descriptor, such that
30 0(%eax) points to _dl_tlsdesc_return itself, and 4(%eax) holds
31 the TP offset of the symbol corresponding to the object
32 denoted by the argument. */
34 .hidden _dl_tlsdesc_return
35 .global _dl_tlsdesc_return
36 .type _dl_tlsdesc_return,@function
43 .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
45 /* This function is used for undefined weak TLS symbols, for
46 which the base address (i.e., disregarding any addend) should
49 %eax points to the TLS descriptor, such that 0(%eax) points to
50 _dl_tlsdesc_undefweak itself, and 4(%eax) holds the addend.
51 We return the addend minus the TP, such that, when the caller
52 adds TP, it gets the addend back. If that's zero, as usual,
53 that's most likely a NULL pointer. */
55 .hidden _dl_tlsdesc_undefweak
56 .global _dl_tlsdesc_undefweak
57 .type _dl_tlsdesc_undefweak,@function
60 _dl_tlsdesc_undefweak:
65 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
68 .hidden _dl_tlsdesc_dynamic
69 .global _dl_tlsdesc_dynamic
70 .type _dl_tlsdesc_dynamic,@function
72 /* This function is used for symbols that need dynamic TLS.
74 %eax points to the TLS descriptor, such that 0(%eax) points to
75 _dl_tlsdesc_dynamic itself, and 4(%eax) points to a struct
76 tlsdesc_dynamic_arg object. It must return in %eax the offset
77 between the thread pointer and the object denoted by the
78 argument, without clobbering any registers.
80 The assembly code that follows is a rendition of the following
81 C code, hand-optimized a little bit.
84 __attribute__ ((__regparm__ (1)))
85 _dl_tlsdesc_dynamic (struct tlsdesc *tdp)
87 struct tlsdesc_dynamic_arg *td = tdp->arg;
88 dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + DTV_OFFSET);
89 if (__builtin_expect (td->gen_count <= dtv[0].counter
90 && (dtv[td->tlsinfo.ti_module].pointer.val
91 != TLS_DTV_UNALLOCATED),
93 return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
96 return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
102 /* Like all TLS resolvers, preserve call-clobbered registers.
103 We need two scratch regs anyway. */
105 cfi_adjust_cfa_offset (28)
108 movl TLSDESC_ARG(%eax), %eax
109 movl %gs:DTV_OFFSET, %edx
110 movl TLSDESC_GEN_COUNT(%eax), %ecx
113 movl TLSDESC_MODID(%eax), %ecx
114 movl (%edx,%ecx,8), %edx
117 movl TLSDESC_MODOFF(%eax), %eax
124 cfi_adjust_cfa_offset (-28)
128 cfi_adjust_cfa_offset (28)
131 call ___tls_get_addr@PLT
135 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
138 /* This function is a wrapper for a lazy resolver for TLS_DESC
139 REL relocations that reference the *ABS* segment in their own
140 link maps. %ebx points to the caller's GOT. %eax points to a
141 TLS descriptor, such that 0(%eax) holds the address of the
142 resolver wrapper itself (unless some other thread beat us to
143 it) and 4(%eax) holds the addend in the relocation.
145 When the actual resolver returns, it will have adjusted the
146 TLS descriptor such that we can tail-call it for it to return
147 the TP offset of the symbol. */
149 .hidden _dl_tlsdesc_resolve_abs_plus_addend
150 .global _dl_tlsdesc_resolve_abs_plus_addend
151 .type _dl_tlsdesc_resolve_abs_plus_addend,@function
154 _dl_tlsdesc_resolve_abs_plus_addend:
157 cfi_adjust_cfa_offset (4)
159 cfi_adjust_cfa_offset (4)
161 cfi_adjust_cfa_offset (4)
164 call _dl_tlsdesc_resolve_abs_plus_addend_fixup
167 cfi_adjust_cfa_offset (-4)
169 cfi_adjust_cfa_offset (-4)
171 cfi_adjust_cfa_offset (-4)
174 .size _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
176 /* This function is a wrapper for a lazy resolver for TLS_DESC
177 REL relocations that had zero addends. %ebx points to the
178 caller's GOT. %eax points to a TLS descriptor, such that
179 0(%eax) holds the address of the resolver wrapper itself
180 (unless some other thread beat us to it) and 4(%eax) holds a
181 pointer to the relocation.
183 When the actual resolver returns, it will have adjusted the
184 TLS descriptor such that we can tail-call it for it to return
185 the TP offset of the symbol. */
187 .hidden _dl_tlsdesc_resolve_rel
188 .global _dl_tlsdesc_resolve_rel
189 .type _dl_tlsdesc_resolve_rel,@function
192 _dl_tlsdesc_resolve_rel:
195 cfi_adjust_cfa_offset (4)
197 cfi_adjust_cfa_offset (4)
199 cfi_adjust_cfa_offset (4)
202 call _dl_tlsdesc_resolve_rel_fixup
205 cfi_adjust_cfa_offset (-4)
207 cfi_adjust_cfa_offset (-4)
209 cfi_adjust_cfa_offset (-4)
212 .size _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
214 /* This function is a wrapper for a lazy resolver for TLS_DESC
215 RELA relocations. %ebx points to the caller's GOT. %eax
216 points to a TLS descriptor, such that 0(%eax) holds the
217 address of the resolver wrapper itself (unless some other
218 thread beat us to it) and 4(%eax) holds a pointer to the
221 When the actual resolver returns, it will have adjusted the
222 TLS descriptor such that we can tail-call it for it to return
223 the TP offset of the symbol. */
225 .hidden _dl_tlsdesc_resolve_rela
226 .global _dl_tlsdesc_resolve_rela
227 .type _dl_tlsdesc_resolve_rela,@function
230 _dl_tlsdesc_resolve_rela:
233 cfi_adjust_cfa_offset (4)
235 cfi_adjust_cfa_offset (4)
237 cfi_adjust_cfa_offset (4)
240 call _dl_tlsdesc_resolve_rela_fixup
243 cfi_adjust_cfa_offset (-4)
245 cfi_adjust_cfa_offset (-4)
247 cfi_adjust_cfa_offset (-4)
250 .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
252 /* This function is a placeholder for lazy resolving of TLS
253 relocations. Once some thread starts resolving a TLS
254 relocation, it sets up the TLS descriptor to use this
255 resolver, such that other threads that would attempt to
256 resolve it concurrently may skip the call to the original lazy
257 resolver and go straight to a condition wait.
259 When the actual resolver returns, it will have adjusted the
260 TLS descriptor such that we can tail-call it for it to return
261 the TP offset of the symbol. */
263 .hidden _dl_tlsdesc_resolve_hold
264 .global _dl_tlsdesc_resolve_hold
265 .type _dl_tlsdesc_resolve_hold,@function
268 _dl_tlsdesc_resolve_hold:
271 cfi_adjust_cfa_offset (4)
273 cfi_adjust_cfa_offset (4)
275 cfi_adjust_cfa_offset (4)
278 call _dl_tlsdesc_resolve_hold_fixup
281 cfi_adjust_cfa_offset (-4)
283 cfi_adjust_cfa_offset (-4)
285 cfi_adjust_cfa_offset (-4)
288 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold