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
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
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
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
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
61 _dl_tlsdesc_undefweak:
66 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
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.
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),
91 return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
94 return __tls_get_addr_internal (&td->tlsinfo) - __thread_pointer;
100 /* Preserve call-clobbered registers that we modify.
101 We need two scratch regs anyway. */
103 movq %fs:DTV_OFFSET, %rsi
105 movq TLSDESC_ARG(%rax), %rdi
107 cmpq %rax, TLSDESC_GEN_COUNT(%rdi)
109 movq TLSDESC_MODID(%rdi), %rax
111 movq (%rax,%rsi), %rax
114 addq TLSDESC_MODOFF(%rdi), %rax
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. */
124 cfi_adjust_cfa_offset (72)
131 /* %rdi already points to the tlsinfo data structure. */
132 call __tls_get_addr@PLT
140 cfi_adjust_cfa_offset (-72)
143 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
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
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. */
169 cfi_adjust_cfa_offset (72)
172 movq %rax, %rdi /* Pass tlsdesc* in %rdi. */
174 movq 72(%rsp), %rsi /* Pass link_map* in %rsi. */
181 call _dl_tlsdesc_resolve_rela_fixup
192 cfi_adjust_cfa_offset (-80)
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
213 _dl_tlsdesc_resolve_hold:
215 /* Save all call-clobbered registers. */
217 cfi_adjust_cfa_offset (72)
220 movq %rax, %rdi /* Pass tlsdesc* in %rdi. */
222 /* Pass _dl_tlsdesc_resolve_hold's address in %rsi. */
223 leaq . - _dl_tlsdesc_resolve_hold(%rip), %rsi
230 call _dl_tlsdesc_resolve_hold_fixup
242 cfi_adjust_cfa_offset (-72)
245 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold