foo
[glibc.git] / sysdeps / i386 / dl-tlsdesc.S
blobe6753e9e1990559919245781c5c1f5697a461311
1 /* Thread-local storage handling in the ELF dynamic linker.  i386 version.
2    Copyright (C) 2004-2014 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         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 */
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
152         cfi_startproc
153         .align 16
154 _dl_tlsdesc_resolve_abs_plus_addend:
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
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
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
190         cfi_startproc
191         .align 16
192 _dl_tlsdesc_resolve_rel:
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
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
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.
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
228         cfi_startproc
229         .align 16
230 _dl_tlsdesc_resolve_rela:
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
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
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
266         cfi_startproc
267         .align 16
268 _dl_tlsdesc_resolve_hold:
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
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