1/* Thread-local storage handling in the ELF dynamic linker. x86_64 version. 2 Copyright (C) 2004-2021 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, see 17 <https://www.gnu.org/licenses/>. */ 18 19#include <sysdep.h> 20#include <tls.h> 21#include "tlsdesc.h" 22 23 .text 24 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. 28 29 The incoming %rax points to the TLS descriptor, such that 30 0(%rax) points to _dl_tlsdesc_return itself, and 8(%rax) holds 31 the TP offset of the symbol corresponding to the object 32 denoted by the argument. */ 33 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 _CET_ENDBR 41 movq 8(%rax), %rax 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 %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. */ 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 _CET_ENDBR 63 movq 8(%rax), %rax 64 subq %fs:0, %rax 65 ret 66 cfi_endproc 67 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak 68 69#ifdef SHARED 70 .hidden _dl_tlsdesc_dynamic 71 .global _dl_tlsdesc_dynamic 72 .type _dl_tlsdesc_dynamic,@function 73 74 /* %rax points to the TLS descriptor, such that 0(%rax) points to 75 _dl_tlsdesc_dynamic itself, and 8(%rax) points to a struct 76 tlsdesc_dynamic_arg object. It must return in %rax the offset 77 between the thread pointer and the object denoted by the 78 argument, without clobbering any registers. 79 80 The assembly code that follows is a rendition of the following 81 C code, hand-optimized a little bit. 82 83ptrdiff_t 84_dl_tlsdesc_dynamic (register struct tlsdesc *tdp asm ("%rax")) 85{ 86 struct tlsdesc_dynamic_arg *td = tdp->arg; 87 dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + DTV_OFFSET); 88 if (__builtin_expect (td->gen_count <= dtv[0].counter 89 && (dtv[td->tlsinfo.ti_module].pointer.val 90 != TLS_DTV_UNALLOCATED), 91 1)) 92 return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset 93 - __thread_pointer; 94 95 return __tls_get_addr_internal (&td->tlsinfo) - __thread_pointer; 96} 97*/ 98 cfi_startproc 99 .align 16 100_dl_tlsdesc_dynamic: 101 _CET_ENDBR 102 /* Preserve call-clobbered registers that we modify. 103 We need two scratch regs anyway. */ 104 movq %rsi, -16(%rsp) 105 movq %fs:DTV_OFFSET, %rsi 106 movq %rdi, -8(%rsp) 107 movq TLSDESC_ARG(%rax), %rdi 108 movq (%rsi), %rax 109 cmpq %rax, TLSDESC_GEN_COUNT(%rdi) 110 ja .Lslow 111 movq TLSDESC_MODID(%rdi), %rax 112 salq $4, %rax 113 movq (%rax,%rsi), %rax 114 cmpq $-1, %rax 115 je .Lslow 116 addq TLSDESC_MODOFF(%rdi), %rax 117.Lret: 118 movq -16(%rsp), %rsi 119 subq %fs:0, %rax 120 movq -8(%rsp), %rdi 121 ret 122.Lslow: 123 /* Besides rdi and rsi, saved above, save rdx, rcx, r8, r9, 124 r10 and r11. Also, align the stack, that's off by 8 bytes. */ 125 subq $72, %rsp 126 cfi_adjust_cfa_offset (72) 127 movq %rdx, 8(%rsp) 128 movq %rcx, 16(%rsp) 129 movq %r8, 24(%rsp) 130 movq %r9, 32(%rsp) 131 movq %r10, 40(%rsp) 132 movq %r11, 48(%rsp) 133 /* %rdi already points to the tlsinfo data structure. */ 134 call HIDDEN_JUMPTARGET (__tls_get_addr) 135 movq 8(%rsp), %rdx 136 movq 16(%rsp), %rcx 137 movq 24(%rsp), %r8 138 movq 32(%rsp), %r9 139 movq 40(%rsp), %r10 140 movq 48(%rsp), %r11 141 addq $72, %rsp 142 cfi_adjust_cfa_offset (-72) 143 jmp .Lret 144 cfi_endproc 145 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic 146#endif /* SHARED */ 147