Add test case for bug 18287
[glibc.git] / sysdeps / i386 / dl-tlsdesc.S
blobdb02274c168c3b82992a643665c5fae5abd94d55
1 /* Thread-local storage handling in the ELF dynamic linker.  i386 version.
2    Copyright (C) 2004-2015 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/>.  */
19 #include <sysdep.h>
20 #include <tls.h>
21 #include "tlsdesc.h"
23         .text
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.
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
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
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.
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
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
67 #ifdef SHARED
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.
83 ptrdiff_t
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),
92                         1))
93     return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
94       - __thread_pointer;
96   return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
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 */
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
149         cfi_startproc
150         .align 16
151 _dl_tlsdesc_resolve_abs_plus_addend:
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
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
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
187         cfi_startproc
188         .align 16
189 _dl_tlsdesc_resolve_rel:
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
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
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.
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
225         cfi_startproc
226         .align 16
227 _dl_tlsdesc_resolve_rela:
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
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
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
263         cfi_startproc
264         .align 16
265 _dl_tlsdesc_resolve_hold:
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
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