]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/i386/dl-tlsdesc.S
5a749b6d8e093d578e0346f334aaef8e391060bf
[thirdparty/glibc.git] / sysdeps / i386 / dl-tlsdesc.S
1 /* Thread-local storage handling in the ELF dynamic linker. i386 version.
2 Copyright (C) 2004-2013 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
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.
9
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.
14
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/>. */
18
19 #include <sysdep.h>
20 #include <tls.h>
21 #include "tlsdesc.h"
22
23 .text
24
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
27 threads.
28
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. */
33
34 .hidden _dl_tlsdesc_return
35 .global _dl_tlsdesc_return
36 .type _dl_tlsdesc_return,@function
37 cfi_startproc
38 .align 16
39 _dl_tlsdesc_return:
40 movl 4(%eax), %eax
41 ret
42 cfi_endproc
43 .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
44
45 /* This function is used for undefined weak TLS symbols, for
46 which the base address (i.e., disregarding any addend) should
47 resolve to NULL.
48
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. */
54
55 .hidden _dl_tlsdesc_undefweak
56 .global _dl_tlsdesc_undefweak
57 .type _dl_tlsdesc_undefweak,@function
58 cfi_startproc
59 .align 16
60 _dl_tlsdesc_undefweak:
61 movl 4(%eax), %eax
62 subl %gs:0, %eax
63 ret
64 cfi_endproc
65 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
66
67 #ifdef SHARED
68 .hidden _dl_tlsdesc_dynamic
69 .global _dl_tlsdesc_dynamic
70 .type _dl_tlsdesc_dynamic,@function
71
72 /* This function is used for symbols that need dynamic TLS.
73
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.
79
80 The assembly code that follows is a rendition of the following
81 C code, hand-optimized a little bit.
82
83 ptrdiff_t
84 __attribute__ ((__regparm__ (1)))
85 _dl_tlsdesc_dynamic (struct tlsdesc *tdp)
86 {
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),
92 1))
93 return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
94 - __thread_pointer;
95
96 return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
97 }
98 */
99 cfi_startproc
100 .align 16
101 _dl_tlsdesc_dynamic:
102 /* Like all TLS resolvers, preserve call-clobbered registers.
103 We need two scratch regs anyway. */
104 subl $28, %esp
105 cfi_adjust_cfa_offset (28)
106 movl %ecx, 20(%esp)
107 movl %edx, 24(%esp)
108 movl TLSDESC_ARG(%eax), %eax
109 movl %gs:DTV_OFFSET, %edx
110 movl TLSDESC_GEN_COUNT(%eax), %ecx
111 cmpl (%edx), %ecx
112 ja .Lslow
113 movl TLSDESC_MODID(%eax), %ecx
114 movl (%edx,%ecx,8), %edx
115 cmpl $-1, %edx
116 je .Lslow
117 movl TLSDESC_MODOFF(%eax), %eax
118 addl %edx, %eax
119 .Lret:
120 movl 20(%esp), %ecx
121 subl %gs:0, %eax
122 movl 24(%esp), %edx
123 addl $28, %esp
124 cfi_adjust_cfa_offset (-28)
125 ret
126 .p2align 4,,7
127 .Lslow:
128 cfi_adjust_cfa_offset (28)
129 movl %ebx, 16(%esp)
130 LOAD_PIC_REG (bx)
131 call ___tls_get_addr@PLT
132 movl 16(%esp), %ebx
133 jmp .Lret
134 cfi_endproc
135 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
136 #endif /* SHARED */
137
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.
144
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. */
148
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
152 cfi_startproc
153 .align 16
154 _dl_tlsdesc_resolve_abs_plus_addend:
155 0:
156 pushl %eax
157 cfi_adjust_cfa_offset (4)
158 pushl %ecx
159 cfi_adjust_cfa_offset (4)
160 pushl %edx
161 cfi_adjust_cfa_offset (4)
162 movl $1f - 0b, %ecx
163 movl 4(%ebx), %edx
164 call _dl_tlsdesc_resolve_abs_plus_addend_fixup
165 1:
166 popl %edx
167 cfi_adjust_cfa_offset (-4)
168 popl %ecx
169 cfi_adjust_cfa_offset (-4)
170 popl %eax
171 cfi_adjust_cfa_offset (-4)
172 jmp *(%eax)
173 cfi_endproc
174 .size _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
175
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.
182
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. */
186
187 .hidden _dl_tlsdesc_resolve_rel
188 .global _dl_tlsdesc_resolve_rel
189 .type _dl_tlsdesc_resolve_rel,@function
190 cfi_startproc
191 .align 16
192 _dl_tlsdesc_resolve_rel:
193 0:
194 pushl %eax
195 cfi_adjust_cfa_offset (4)
196 pushl %ecx
197 cfi_adjust_cfa_offset (4)
198 pushl %edx
199 cfi_adjust_cfa_offset (4)
200 movl $1f - 0b, %ecx
201 movl 4(%ebx), %edx
202 call _dl_tlsdesc_resolve_rel_fixup
203 1:
204 popl %edx
205 cfi_adjust_cfa_offset (-4)
206 popl %ecx
207 cfi_adjust_cfa_offset (-4)
208 popl %eax
209 cfi_adjust_cfa_offset (-4)
210 jmp *(%eax)
211 cfi_endproc
212 .size _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
213
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
219 relocation.
220
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. */
224
225 .hidden _dl_tlsdesc_resolve_rela
226 .global _dl_tlsdesc_resolve_rela
227 .type _dl_tlsdesc_resolve_rela,@function
228 cfi_startproc
229 .align 16
230 _dl_tlsdesc_resolve_rela:
231 0:
232 pushl %eax
233 cfi_adjust_cfa_offset (4)
234 pushl %ecx
235 cfi_adjust_cfa_offset (4)
236 pushl %edx
237 cfi_adjust_cfa_offset (4)
238 movl $1f - 0b, %ecx
239 movl 4(%ebx), %edx
240 call _dl_tlsdesc_resolve_rela_fixup
241 1:
242 popl %edx
243 cfi_adjust_cfa_offset (-4)
244 popl %ecx
245 cfi_adjust_cfa_offset (-4)
246 popl %eax
247 cfi_adjust_cfa_offset (-4)
248 jmp *(%eax)
249 cfi_endproc
250 .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
251
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.
258
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. */
262
263 .hidden _dl_tlsdesc_resolve_hold
264 .global _dl_tlsdesc_resolve_hold
265 .type _dl_tlsdesc_resolve_hold,@function
266 cfi_startproc
267 .align 16
268 _dl_tlsdesc_resolve_hold:
269 0:
270 pushl %eax
271 cfi_adjust_cfa_offset (4)
272 pushl %ecx
273 cfi_adjust_cfa_offset (4)
274 pushl %edx
275 cfi_adjust_cfa_offset (4)
276 movl $1f - 0b, %ecx
277 movl 4(%ebx), %edx
278 call _dl_tlsdesc_resolve_hold_fixup
279 1:
280 popl %edx
281 cfi_adjust_cfa_offset (-4)
282 popl %ecx
283 cfi_adjust_cfa_offset (-4)
284 popl %eax
285 cfi_adjust_cfa_offset (-4)
286 jmp *(%eax)
287 cfi_endproc
288 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold