1 /* Thread-local storage handling in the ELF dynamic linker. i386 version.
2 Copyright (C) 2004-2017 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)
129 call HIDDEN_JUMPTARGET (___tls_get_addr)
132 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
135 /* This function is a wrapper for a lazy resolver for TLS_DESC
136 REL relocations that reference the *ABS* segment in their own
137 link maps. %ebx points to the caller's GOT. %eax points to a
138 TLS descriptor, such that 0(%eax) holds the address of the
139 resolver wrapper itself (unless some other thread beat us to
140 it) and 4(%eax) holds the addend in the relocation.
142 When the actual resolver returns, it will have adjusted the
143 TLS descriptor such that we can tail-call it for it to return
144 the TP offset of the symbol. */
146 .hidden _dl_tlsdesc_resolve_abs_plus_addend
147 .global _dl_tlsdesc_resolve_abs_plus_addend
148 .type _dl_tlsdesc_resolve_abs_plus_addend,@function
151 _dl_tlsdesc_resolve_abs_plus_addend:
154 cfi_adjust_cfa_offset (4)
156 cfi_adjust_cfa_offset (4)
158 cfi_adjust_cfa_offset (4)
161 call _dl_tlsdesc_resolve_abs_plus_addend_fixup
164 cfi_adjust_cfa_offset (-4)
166 cfi_adjust_cfa_offset (-4)
168 cfi_adjust_cfa_offset (-4)
171 .size _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
173 /* This function is a wrapper for a lazy resolver for TLS_DESC
174 REL relocations that had zero addends. %ebx points to the
175 caller's GOT. %eax points to a TLS descriptor, such that
176 0(%eax) holds the address of the resolver wrapper itself
177 (unless some other thread beat us to it) and 4(%eax) holds a
178 pointer to the relocation.
180 When the actual resolver returns, it will have adjusted the
181 TLS descriptor such that we can tail-call it for it to return
182 the TP offset of the symbol. */
184 .hidden _dl_tlsdesc_resolve_rel
185 .global _dl_tlsdesc_resolve_rel
186 .type _dl_tlsdesc_resolve_rel,@function
189 _dl_tlsdesc_resolve_rel:
192 cfi_adjust_cfa_offset (4)
194 cfi_adjust_cfa_offset (4)
196 cfi_adjust_cfa_offset (4)
199 call _dl_tlsdesc_resolve_rel_fixup
202 cfi_adjust_cfa_offset (-4)
204 cfi_adjust_cfa_offset (-4)
206 cfi_adjust_cfa_offset (-4)
209 .size _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
211 /* This function is a wrapper for a lazy resolver for TLS_DESC
212 RELA relocations. %ebx points to the caller's GOT. %eax
213 points to a TLS descriptor, such that 0(%eax) holds the
214 address of the resolver wrapper itself (unless some other
215 thread beat us to it) and 4(%eax) holds a pointer to the
218 When the actual resolver returns, it will have adjusted the
219 TLS descriptor such that we can tail-call it for it to return
220 the TP offset of the symbol. */
222 .hidden _dl_tlsdesc_resolve_rela
223 .global _dl_tlsdesc_resolve_rela
224 .type _dl_tlsdesc_resolve_rela,@function
227 _dl_tlsdesc_resolve_rela:
230 cfi_adjust_cfa_offset (4)
232 cfi_adjust_cfa_offset (4)
234 cfi_adjust_cfa_offset (4)
237 call _dl_tlsdesc_resolve_rela_fixup
240 cfi_adjust_cfa_offset (-4)
242 cfi_adjust_cfa_offset (-4)
244 cfi_adjust_cfa_offset (-4)
247 .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
249 /* This function is a placeholder for lazy resolving of TLS
250 relocations. Once some thread starts resolving a TLS
251 relocation, it sets up the TLS descriptor to use this
252 resolver, such that other threads that would attempt to
253 resolve it concurrently may skip the call to the original lazy
254 resolver and go straight to a condition wait.
256 When the actual resolver returns, it will have adjusted the
257 TLS descriptor such that we can tail-call it for it to return
258 the TP offset of the symbol. */
260 .hidden _dl_tlsdesc_resolve_hold
261 .global _dl_tlsdesc_resolve_hold
262 .type _dl_tlsdesc_resolve_hold,@function
265 _dl_tlsdesc_resolve_hold:
268 cfi_adjust_cfa_offset (4)
270 cfi_adjust_cfa_offset (4)
272 cfi_adjust_cfa_offset (4)
275 call _dl_tlsdesc_resolve_hold_fixup
278 cfi_adjust_cfa_offset (-4)
280 cfi_adjust_cfa_offset (-4)
282 cfi_adjust_cfa_offset (-4)
285 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold