2.9
[glibc/nacl-glibc.git] / sysdeps / i386 / dl-tlsdesc.S
blobdb5005d9f4bdcf4593cb1783e5c7f9863f6087ad
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.
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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
20 #include <sysdep.h>
21 #include <tls.h>
22 #include "tlsdesc.h"
24         .text
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.
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.  */
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
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.
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.  */
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
68 #ifdef SHARED
69         .hidden _dl_tlsdesc_dynamic
70         .global _dl_tlsdesc_dynamic
71         .type   _dl_tlsdesc_dynamic,@function
73      /* This function is used for symbols that need dynamic TLS.
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.
81         The assembly code that follows is a rendition of the following
82         C code, hand-optimized a little bit.
84 ptrdiff_t
85 __attribute__ ((__regparm__ (1)))
86 _dl_tlsdesc_dynamic (struct tlsdesc *tdp)
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;
97   return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
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         call    __i686.get_pc_thunk.bx
132         addl    $_GLOBAL_OFFSET_TABLE_, %ebx
133         call    ___tls_get_addr@PLT
134         movl    16(%esp), %ebx
135         jmp     .Lret
136         cfi_endproc
137         .size   _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
138 #endif /* SHARED */
140      /* This function is a wrapper for a lazy resolver for TLS_DESC
141         REL relocations that reference the *ABS* segment in their own
142         link maps.  %ebx points to the caller's GOT.  %eax points to a
143         TLS descriptor, such that 0(%eax) holds the address of the
144         resolver wrapper itself (unless some other thread beat us to
145         it) and 4(%eax) holds the addend in the relocation.
147         When the actual resolver returns, it will have adjusted the
148         TLS descriptor such that we can tail-call it for it to return
149         the TP offset of the symbol.  */
151         .hidden _dl_tlsdesc_resolve_abs_plus_addend
152         .global _dl_tlsdesc_resolve_abs_plus_addend
153         .type   _dl_tlsdesc_resolve_abs_plus_addend,@function
154         cfi_startproc
155         .align 16
156 _dl_tlsdesc_resolve_abs_plus_addend:
158         pushl   %eax
159         cfi_adjust_cfa_offset (4)
160         pushl   %ecx
161         cfi_adjust_cfa_offset (4)
162         pushl   %edx
163         cfi_adjust_cfa_offset (4)
164         movl    $1f - 0b, %ecx
165         movl    4(%ebx), %edx
166         call    _dl_tlsdesc_resolve_abs_plus_addend_fixup
168         popl    %edx
169         cfi_adjust_cfa_offset (-4)
170         popl    %ecx
171         cfi_adjust_cfa_offset (-4)
172         popl    %eax
173         cfi_adjust_cfa_offset (-4)
174         jmp     *(%eax)
175         cfi_endproc
176         .size   _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
178      /* This function is a wrapper for a lazy resolver for TLS_DESC
179         REL relocations that had zero addends.  %ebx points to the
180         caller's GOT.  %eax points to a TLS descriptor, such that
181         0(%eax) holds the address of the resolver wrapper itself
182         (unless some other thread beat us to it) and 4(%eax) holds a
183         pointer to the relocation.
185         When the actual resolver returns, it will have adjusted the
186         TLS descriptor such that we can tail-call it for it to return
187         the TP offset of the symbol.  */
189         .hidden _dl_tlsdesc_resolve_rel
190         .global _dl_tlsdesc_resolve_rel
191         .type   _dl_tlsdesc_resolve_rel,@function
192         cfi_startproc
193         .align 16
194 _dl_tlsdesc_resolve_rel:
196         pushl   %eax
197         cfi_adjust_cfa_offset (4)
198         pushl   %ecx
199         cfi_adjust_cfa_offset (4)
200         pushl   %edx
201         cfi_adjust_cfa_offset (4)
202         movl    $1f - 0b, %ecx
203         movl    4(%ebx), %edx
204         call    _dl_tlsdesc_resolve_rel_fixup
206         popl    %edx
207         cfi_adjust_cfa_offset (-4)
208         popl    %ecx
209         cfi_adjust_cfa_offset (-4)
210         popl    %eax
211         cfi_adjust_cfa_offset (-4)
212         jmp     *(%eax)
213         cfi_endproc
214         .size   _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
216      /* This function is a wrapper for a lazy resolver for TLS_DESC
217         RELA relocations.  %ebx points to the caller's GOT.  %eax
218         points to a TLS descriptor, such that 0(%eax) holds the
219         address of the resolver wrapper itself (unless some other
220         thread beat us to it) and 4(%eax) holds a pointer to the
221         relocation.
223         When the actual resolver returns, it will have adjusted the
224         TLS descriptor such that we can tail-call it for it to return
225         the TP offset of the symbol.  */
227         .hidden _dl_tlsdesc_resolve_rela
228         .global _dl_tlsdesc_resolve_rela
229         .type   _dl_tlsdesc_resolve_rela,@function
230         cfi_startproc
231         .align 16
232 _dl_tlsdesc_resolve_rela:
234         pushl   %eax
235         cfi_adjust_cfa_offset (4)
236         pushl   %ecx
237         cfi_adjust_cfa_offset (4)
238         pushl   %edx
239         cfi_adjust_cfa_offset (4)
240         movl    $1f - 0b, %ecx
241         movl    4(%ebx), %edx
242         call    _dl_tlsdesc_resolve_rela_fixup
244         popl    %edx
245         cfi_adjust_cfa_offset (-4)
246         popl    %ecx
247         cfi_adjust_cfa_offset (-4)
248         popl    %eax
249         cfi_adjust_cfa_offset (-4)
250         jmp     *(%eax)
251         cfi_endproc
252         .size   _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
254      /* This function is a placeholder for lazy resolving of TLS
255         relocations.  Once some thread starts resolving a TLS
256         relocation, it sets up the TLS descriptor to use this
257         resolver, such that other threads that would attempt to
258         resolve it concurrently may skip the call to the original lazy
259         resolver and go straight to a condition wait.
261         When the actual resolver returns, it will have adjusted the
262         TLS descriptor such that we can tail-call it for it to return
263         the TP offset of the symbol.  */
265         .hidden _dl_tlsdesc_resolve_hold
266         .global _dl_tlsdesc_resolve_hold
267         .type   _dl_tlsdesc_resolve_hold,@function
268         cfi_startproc
269         .align 16
270 _dl_tlsdesc_resolve_hold:
272         pushl   %eax
273         cfi_adjust_cfa_offset (4)
274         pushl   %ecx
275         cfi_adjust_cfa_offset (4)
276         pushl   %edx
277         cfi_adjust_cfa_offset (4)
278         movl    $1f - 0b, %ecx
279         movl    4(%ebx), %edx
280         call    _dl_tlsdesc_resolve_hold_fixup
282         popl    %edx
283         cfi_adjust_cfa_offset (-4)
284         popl    %ecx
285         cfi_adjust_cfa_offset (-4)
286         popl    %eax
287         cfi_adjust_cfa_offset (-4)
288         jmp     *(%eax)
289         cfi_endproc
290         .size   _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold