chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / sysdeps / i386 / dl-tlsdesc.S
1 /* Thread-local storage handling in the ELF dynamic linker.  i386 version.
2    Copyright (C) 2004, 2005, 2008 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <sysdep.h>
21 #include <tls.h>
22 #include "tlsdesc.h"
23
24         .text
25
26      /* This function is used to compute the TP offset for symbols in
27         Static TLS, i.e., whose TP offset is the same for all
28         threads.
29
30         The incoming %eax points to the TLS descriptor, such that
31         0(%eax) points to _dl_tlsdesc_return itself, and 4(%eax) holds
32         the TP offset of the symbol corresponding to the object
33         denoted by the argument.  */
34
35         .hidden _dl_tlsdesc_return
36         .global _dl_tlsdesc_return
37         .type   _dl_tlsdesc_return,@function
38         cfi_startproc
39         .align 16
40 _dl_tlsdesc_return:
41         movl    4(%eax), %eax
42         ret
43         cfi_endproc
44         .size   _dl_tlsdesc_return, .-_dl_tlsdesc_return
45
46      /* This function is used for undefined weak TLS symbols, for
47         which the base address (i.e., disregarding any addend) should
48         resolve to NULL.
49
50         %eax points to the TLS descriptor, such that 0(%eax) points to
51         _dl_tlsdesc_undefweak itself, and 4(%eax) holds the addend.
52         We return the addend minus the TP, such that, when the caller
53         adds TP, it gets the addend back.  If that's zero, as usual,
54         that's most likely a NULL pointer.  */
55
56         .hidden _dl_tlsdesc_undefweak
57         .global _dl_tlsdesc_undefweak
58         .type   _dl_tlsdesc_undefweak,@function
59         cfi_startproc
60         .align 16
61 _dl_tlsdesc_undefweak:
62         movl    4(%eax), %eax
63         subl    %gs:0, %eax
64         ret
65         cfi_endproc
66         .size   _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
67
68 #ifdef SHARED
69         .hidden _dl_tlsdesc_dynamic
70         .global _dl_tlsdesc_dynamic
71         .type   _dl_tlsdesc_dynamic,@function
72
73      /* This function is used for symbols that need dynamic TLS.
74
75         %eax points to the TLS descriptor, such that 0(%eax) points to
76         _dl_tlsdesc_dynamic itself, and 4(%eax) points to a struct
77         tlsdesc_dynamic_arg object.  It must return in %eax the offset
78         between the thread pointer and the object denoted by the
79         argument, without clobbering any registers.
80
81         The assembly code that follows is a rendition of the following
82         C code, hand-optimized a little bit.
83
84 ptrdiff_t
85 __attribute__ ((__regparm__ (1)))
86 _dl_tlsdesc_dynamic (struct tlsdesc *tdp)
87 {
88   struct tlsdesc_dynamic_arg *td = tdp->arg;
89   dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + DTV_OFFSET);
90   if (__builtin_expect (td->gen_count <= dtv[0].counter
91                         && (dtv[td->tlsinfo.ti_module].pointer.val
92                             != TLS_DTV_UNALLOCATED),
93                         1))
94     return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
95       - __thread_pointer;
96
97   return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
98 }
99 */
100         cfi_startproc
101         .align 16
102 _dl_tlsdesc_dynamic:
103         /* Like all TLS resolvers, preserve call-clobbered registers.
104            We need two scratch regs anyway.  */
105         subl    $28, %esp
106         cfi_adjust_cfa_offset (28)
107         movl    %ecx, 20(%esp)
108         movl    %edx, 24(%esp)
109         movl    TLSDESC_ARG(%eax), %eax
110         movl    %gs:DTV_OFFSET, %edx
111         movl    TLSDESC_GEN_COUNT(%eax), %ecx
112         cmpl    (%edx), %ecx
113         ja      .Lslow
114         movl    TLSDESC_MODID(%eax), %ecx
115         movl    (%edx,%ecx,8), %edx
116         cmpl    $-1, %edx
117         je      .Lslow
118         movl    TLSDESC_MODOFF(%eax), %eax
119         addl    %edx, %eax
120 .Lret:
121         movl    20(%esp), %ecx
122         subl    %gs:0, %eax
123         movl    24(%esp), %edx
124         addl    $28, %esp
125         cfi_adjust_cfa_offset (-28)
126         ret
127         .p2align 4,,7
128 .Lslow:
129         cfi_adjust_cfa_offset (28)
130         movl    %ebx, 16(%esp)
131         LOAD_PIC_REG (bx)
132         call    ___tls_get_addr@PLT
133         movl    16(%esp), %ebx
134         jmp     .Lret
135         cfi_endproc
136         .size   _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
137 #endif /* SHARED */
138
139      /* This function is a wrapper for a lazy resolver for TLS_DESC
140         REL relocations that reference the *ABS* segment in their own
141         link maps.  %ebx points to the caller's GOT.  %eax points to a
142         TLS descriptor, such that 0(%eax) holds the address of the
143         resolver wrapper itself (unless some other thread beat us to
144         it) and 4(%eax) holds the addend in the relocation.
145
146         When the actual resolver returns, it will have adjusted the
147         TLS descriptor such that we can tail-call it for it to return
148         the TP offset of the symbol.  */
149
150         .hidden _dl_tlsdesc_resolve_abs_plus_addend
151         .global _dl_tlsdesc_resolve_abs_plus_addend
152         .type   _dl_tlsdesc_resolve_abs_plus_addend,@function
153         cfi_startproc
154         .align 16
155 _dl_tlsdesc_resolve_abs_plus_addend:
156 0:
157         pushl   %eax
158         cfi_adjust_cfa_offset (4)
159         pushl   %ecx
160         cfi_adjust_cfa_offset (4)
161         pushl   %edx
162         cfi_adjust_cfa_offset (4)
163         movl    $1f - 0b, %ecx
164         movl    4(%ebx), %edx
165         call    _dl_tlsdesc_resolve_abs_plus_addend_fixup
166 1:
167         popl    %edx
168         cfi_adjust_cfa_offset (-4)
169         popl    %ecx
170         cfi_adjust_cfa_offset (-4)
171         popl    %eax
172         cfi_adjust_cfa_offset (-4)
173         jmp     *(%eax)
174         cfi_endproc
175         .size   _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
176
177      /* This function is a wrapper for a lazy resolver for TLS_DESC
178         REL relocations that had zero addends.  %ebx points to the
179         caller's GOT.  %eax points to a TLS descriptor, such that
180         0(%eax) holds the address of the resolver wrapper itself
181         (unless some other thread beat us to it) and 4(%eax) holds a
182         pointer to the relocation.
183
184         When the actual resolver returns, it will have adjusted the
185         TLS descriptor such that we can tail-call it for it to return
186         the TP offset of the symbol.  */
187
188         .hidden _dl_tlsdesc_resolve_rel
189         .global _dl_tlsdesc_resolve_rel
190         .type   _dl_tlsdesc_resolve_rel,@function
191         cfi_startproc
192         .align 16
193 _dl_tlsdesc_resolve_rel:
194 0:
195         pushl   %eax
196         cfi_adjust_cfa_offset (4)
197         pushl   %ecx
198         cfi_adjust_cfa_offset (4)
199         pushl   %edx
200         cfi_adjust_cfa_offset (4)
201         movl    $1f - 0b, %ecx
202         movl    4(%ebx), %edx
203         call    _dl_tlsdesc_resolve_rel_fixup
204 1:
205         popl    %edx
206         cfi_adjust_cfa_offset (-4)
207         popl    %ecx
208         cfi_adjust_cfa_offset (-4)
209         popl    %eax
210         cfi_adjust_cfa_offset (-4)
211         jmp     *(%eax)
212         cfi_endproc
213         .size   _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
214
215      /* This function is a wrapper for a lazy resolver for TLS_DESC
216         RELA relocations.  %ebx points to the caller's GOT.  %eax
217         points to a TLS descriptor, such that 0(%eax) holds the
218         address of the resolver wrapper itself (unless some other
219         thread beat us to it) and 4(%eax) holds a pointer to the
220         relocation.
221
222         When the actual resolver returns, it will have adjusted the
223         TLS descriptor such that we can tail-call it for it to return
224         the TP offset of the symbol.  */
225
226         .hidden _dl_tlsdesc_resolve_rela
227         .global _dl_tlsdesc_resolve_rela
228         .type   _dl_tlsdesc_resolve_rela,@function
229         cfi_startproc
230         .align 16
231 _dl_tlsdesc_resolve_rela:
232 0:
233         pushl   %eax
234         cfi_adjust_cfa_offset (4)
235         pushl   %ecx
236         cfi_adjust_cfa_offset (4)
237         pushl   %edx
238         cfi_adjust_cfa_offset (4)
239         movl    $1f - 0b, %ecx
240         movl    4(%ebx), %edx
241         call    _dl_tlsdesc_resolve_rela_fixup
242 1:
243         popl    %edx
244         cfi_adjust_cfa_offset (-4)
245         popl    %ecx
246         cfi_adjust_cfa_offset (-4)
247         popl    %eax
248         cfi_adjust_cfa_offset (-4)
249         jmp     *(%eax)
250         cfi_endproc
251         .size   _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
252
253      /* This function is a placeholder for lazy resolving of TLS
254         relocations.  Once some thread starts resolving a TLS
255         relocation, it sets up the TLS descriptor to use this
256         resolver, such that other threads that would attempt to
257         resolve it concurrently may skip the call to the original lazy
258         resolver and go straight to a condition wait.
259
260         When the actual resolver returns, it will have adjusted the
261         TLS descriptor such that we can tail-call it for it to return
262         the TP offset of the symbol.  */
263
264         .hidden _dl_tlsdesc_resolve_hold
265         .global _dl_tlsdesc_resolve_hold
266         .type   _dl_tlsdesc_resolve_hold,@function
267         cfi_startproc
268         .align 16
269 _dl_tlsdesc_resolve_hold:
270 0:
271         pushl   %eax
272         cfi_adjust_cfa_offset (4)
273         pushl   %ecx
274         cfi_adjust_cfa_offset (4)
275         pushl   %edx
276         cfi_adjust_cfa_offset (4)
277         movl    $1f - 0b, %ecx
278         movl    4(%ebx), %edx
279         call    _dl_tlsdesc_resolve_hold_fixup
280 1:
281         popl    %edx
282         cfi_adjust_cfa_offset (-4)
283         popl    %ecx
284         cfi_adjust_cfa_offset (-4)
285         popl    %eax
286         cfi_adjust_cfa_offset (-4)
287         jmp     *(%eax)
288         cfi_endproc
289         .size   _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold