2.9
[glibc/nacl-glibc.git] / sysdeps / x86_64 / dl-tlsdesc.S
blob5eac1f2a5b872e6e28d61dc3331c8480decac689
1 /* Thread-local storage handling in the ELF dynamic linker.  x86_64 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 %rax points to the TLS descriptor, such that
31         0(%rax) points to _dl_tlsdesc_return itself, and 8(%rax) 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         movq    8(%rax), %rax
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         %rax points to the TLS descriptor, such that 0(%rax) points to
51         _dl_tlsdesc_undefweak itself, and 8(%rax) 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         movq    8(%rax), %rax
63         subq    %fs:0, %rax
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      /* %rax points to the TLS descriptor, such that 0(%rax) points to
74         _dl_tlsdesc_dynamic itself, and 8(%rax) points to a struct
75         tlsdesc_dynamic_arg object.  It must return in %rax the offset
76         between the thread pointer and the object denoted by the
77         argument, without clobbering any registers.
79         The assembly code that follows is a rendition of the following
80         C code, hand-optimized a little bit.
82 ptrdiff_t
83 _dl_tlsdesc_dynamic (register struct tlsdesc *tdp asm ("%rax"))
85   struct tlsdesc_dynamic_arg *td = tdp->arg;
86   dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + DTV_OFFSET);
87   if (__builtin_expect (td->gen_count <= dtv[0].counter
88                         && (dtv[td->tlsinfo.ti_module].pointer.val
89                             != TLS_DTV_UNALLOCATED),
90                         1))
91     return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
92       - __thread_pointer;
94   return __tls_get_addr_internal (&td->tlsinfo) - __thread_pointer;
97         cfi_startproc
98         .align 16
99 _dl_tlsdesc_dynamic:
100         /* Preserve call-clobbered registers that we modify.
101            We need two scratch regs anyway.  */
102         movq    %rsi, -16(%rsp)
103         movq    %fs:DTV_OFFSET, %rsi
104         movq    %rdi, -8(%rsp)
105         movq    TLSDESC_ARG(%rax), %rdi
106         movq    (%rsi), %rax
107         cmpq    %rax, TLSDESC_GEN_COUNT(%rdi)
108         ja      .Lslow
109         movq    TLSDESC_MODID(%rdi), %rax
110         salq    $4, %rax
111         movq    (%rax,%rsi), %rax
112         cmpq    $-1, %rax
113         je      .Lslow
114         addq    TLSDESC_MODOFF(%rdi), %rax
115 .Lret:
116         movq    -16(%rsp), %rsi
117         subq    %fs:0, %rax
118         movq    -8(%rsp), %rdi
119         ret
120 .Lslow:
121         /* Besides rdi and rsi, saved above, save rdx, rcx, r8, r9,
122            r10 and r11.  Also, align the stack, that's off by 8 bytes.  */
123         subq    $72, %rsp
124         cfi_adjust_cfa_offset (72)
125         movq    %rdx, 8(%rsp)
126         movq    %rcx, 16(%rsp)
127         movq    %r8, 24(%rsp)
128         movq    %r9, 32(%rsp)
129         movq    %r10, 40(%rsp)
130         movq    %r11, 48(%rsp)
131         /* %rdi already points to the tlsinfo data structure.  */
132         call    __tls_get_addr@PLT
133         movq    8(%rsp), %rdx
134         movq    16(%rsp), %rcx
135         movq    24(%rsp), %r8
136         movq    32(%rsp), %r9
137         movq    40(%rsp), %r10
138         movq    48(%rsp), %r11
139         addq    $72, %rsp
140         cfi_adjust_cfa_offset (-72)
141         jmp     .Lret
142         cfi_endproc
143         .size   _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
144 #endif /* SHARED */
146      /* This function is a wrapper for a lazy resolver for TLS_DESC
147         RELA relocations.  The incoming 0(%rsp) points to the caller's
148         link map, pushed by the dynamic object's internal lazy TLS
149         resolver front-end before tail-calling us.  We need to pop it
150         ourselves.  %rax points to a TLS descriptor, such that 0(%rax)
151         holds the address of the internal resolver front-end (unless
152         some other thread beat us to resolving it) and 8(%rax) holds a
153         pointer to the relocation.
155         When the actual resolver returns, it will have adjusted the
156         TLS descriptor such that we can tail-call it for it to return
157         the TP offset of the symbol.  */
159         .hidden _dl_tlsdesc_resolve_rela
160         .global _dl_tlsdesc_resolve_rela
161         .type   _dl_tlsdesc_resolve_rela,@function
162         cfi_startproc
163         .align 16
164         /* The PLT entry will have pushed the link_map pointer.  */
165 _dl_tlsdesc_resolve_rela:
166         cfi_adjust_cfa_offset (8)
167         /* Save all call-clobbered registers.  */
168         subq    $72, %rsp
169         cfi_adjust_cfa_offset (72)
170         movq    %rax, (%rsp)
171         movq    %rdi, 8(%rsp)
172         movq    %rax, %rdi      /* Pass tlsdesc* in %rdi.  */
173         movq    %rsi, 16(%rsp)
174         movq    72(%rsp), %rsi  /* Pass link_map* in %rsi.  */
175         movq    %r8, 24(%rsp)
176         movq    %r9, 32(%rsp)
177         movq    %r10, 40(%rsp)
178         movq    %r11, 48(%rsp)
179         movq    %rdx, 56(%rsp)
180         movq    %rcx, 64(%rsp)
181         call    _dl_tlsdesc_resolve_rela_fixup
182         movq    (%rsp), %rax
183         movq    8(%rsp), %rdi
184         movq    16(%rsp), %rsi
185         movq    24(%rsp), %r8
186         movq    32(%rsp), %r9
187         movq    40(%rsp), %r10
188         movq    48(%rsp), %r11
189         movq    56(%rsp), %rdx
190         movq    64(%rsp), %rcx
191         addq    $80, %rsp
192         cfi_adjust_cfa_offset (-80)
193         jmp     *(%rax)
194         cfi_endproc
195         .size   _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
197      /* This function is a placeholder for lazy resolving of TLS
198         relocations.  Once some thread starts resolving a TLS
199         relocation, it sets up the TLS descriptor to use this
200         resolver, such that other threads that would attempt to
201         resolve it concurrently may skip the call to the original lazy
202         resolver and go straight to a condition wait.
204         When the actual resolver returns, it will have adjusted the
205         TLS descriptor such that we can tail-call it for it to return
206         the TP offset of the symbol.  */
208         .hidden _dl_tlsdesc_resolve_hold
209         .global _dl_tlsdesc_resolve_hold
210         .type   _dl_tlsdesc_resolve_hold,@function
211         cfi_startproc
212         .align 16
213 _dl_tlsdesc_resolve_hold:
215         /* Save all call-clobbered registers.  */
216         subq    $72, %rsp
217         cfi_adjust_cfa_offset (72)
218         movq    %rax, (%rsp)
219         movq    %rdi, 8(%rsp)
220         movq    %rax, %rdi      /* Pass tlsdesc* in %rdi.  */
221         movq    %rsi, 16(%rsp)
222         /* Pass _dl_tlsdesc_resolve_hold's address in %rsi.  */
223         leaq    . - _dl_tlsdesc_resolve_hold(%rip), %rsi
224         movq    %r8, 24(%rsp)
225         movq    %r9, 32(%rsp)
226         movq    %r10, 40(%rsp)
227         movq    %r11, 48(%rsp)
228         movq    %rdx, 56(%rsp)
229         movq    %rcx, 64(%rsp)
230         call    _dl_tlsdesc_resolve_hold_fixup
232         movq    (%rsp), %rax
233         movq    8(%rsp), %rdi
234         movq    16(%rsp), %rsi
235         movq    24(%rsp), %r8
236         movq    32(%rsp), %r9
237         movq    40(%rsp), %r10
238         movq    48(%rsp), %r11
239         movq    56(%rsp), %rdx
240         movq    64(%rsp), %rcx
241         addq    $72, %rsp
242         cfi_adjust_cfa_offset (-72)
243         jmp     *(%eax)
244         cfi_endproc
245         .size   _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold