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