blob: 7c189ab93d6acf2ea630cf8e358d97caf0cca9b4 [file] [log] [blame]
xf.libdd93d52023-05-12 07:10:14 -07001/* Thread-local storage handling in the ELF dynamic linker. i386 version.
2 Copyright (C) 2004-2016 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
83ptrdiff_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 call HIDDEN_JUMPTARGET (___tls_get_addr)
130 jmp .Lret
131 cfi_endproc
132 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
133#endif /* SHARED */
134
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.
141
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. */
145
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
149 cfi_startproc
150 .align 16
151_dl_tlsdesc_resolve_abs_plus_addend:
1520:
153 pushl %eax
154 cfi_adjust_cfa_offset (4)
155 pushl %ecx
156 cfi_adjust_cfa_offset (4)
157 pushl %edx
158 cfi_adjust_cfa_offset (4)
159 movl $1f - 0b, %ecx
160 movl 4(%ebx), %edx
161 call _dl_tlsdesc_resolve_abs_plus_addend_fixup
1621:
163 popl %edx
164 cfi_adjust_cfa_offset (-4)
165 popl %ecx
166 cfi_adjust_cfa_offset (-4)
167 popl %eax
168 cfi_adjust_cfa_offset (-4)
169 jmp *(%eax)
170 cfi_endproc
171 .size _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
172
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.
179
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. */
183
184 .hidden _dl_tlsdesc_resolve_rel
185 .global _dl_tlsdesc_resolve_rel
186 .type _dl_tlsdesc_resolve_rel,@function
187 cfi_startproc
188 .align 16
189_dl_tlsdesc_resolve_rel:
1900:
191 pushl %eax
192 cfi_adjust_cfa_offset (4)
193 pushl %ecx
194 cfi_adjust_cfa_offset (4)
195 pushl %edx
196 cfi_adjust_cfa_offset (4)
197 movl $1f - 0b, %ecx
198 movl 4(%ebx), %edx
199 call _dl_tlsdesc_resolve_rel_fixup
2001:
201 popl %edx
202 cfi_adjust_cfa_offset (-4)
203 popl %ecx
204 cfi_adjust_cfa_offset (-4)
205 popl %eax
206 cfi_adjust_cfa_offset (-4)
207 jmp *(%eax)
208 cfi_endproc
209 .size _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
210
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
216 relocation.
217
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. */
221
222 .hidden _dl_tlsdesc_resolve_rela
223 .global _dl_tlsdesc_resolve_rela
224 .type _dl_tlsdesc_resolve_rela,@function
225 cfi_startproc
226 .align 16
227_dl_tlsdesc_resolve_rela:
2280:
229 pushl %eax
230 cfi_adjust_cfa_offset (4)
231 pushl %ecx
232 cfi_adjust_cfa_offset (4)
233 pushl %edx
234 cfi_adjust_cfa_offset (4)
235 movl $1f - 0b, %ecx
236 movl 4(%ebx), %edx
237 call _dl_tlsdesc_resolve_rela_fixup
2381:
239 popl %edx
240 cfi_adjust_cfa_offset (-4)
241 popl %ecx
242 cfi_adjust_cfa_offset (-4)
243 popl %eax
244 cfi_adjust_cfa_offset (-4)
245 jmp *(%eax)
246 cfi_endproc
247 .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
248
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.
255
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. */
259
260 .hidden _dl_tlsdesc_resolve_hold
261 .global _dl_tlsdesc_resolve_hold
262 .type _dl_tlsdesc_resolve_hold,@function
263 cfi_startproc
264 .align 16
265_dl_tlsdesc_resolve_hold:
2660:
267 pushl %eax
268 cfi_adjust_cfa_offset (4)
269 pushl %ecx
270 cfi_adjust_cfa_offset (4)
271 pushl %edx
272 cfi_adjust_cfa_offset (4)
273 movl $1f - 0b, %ecx
274 movl 4(%ebx), %edx
275 call _dl_tlsdesc_resolve_hold_fixup
2761:
277 popl %edx
278 cfi_adjust_cfa_offset (-4)
279 popl %ecx
280 cfi_adjust_cfa_offset (-4)
281 popl %eax
282 cfi_adjust_cfa_offset (-4)
283 jmp *(%eax)
284 cfi_endproc
285 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold