1/* Thread-local storage handling in the ELF dynamic linker.  i386 version.
2   Copyright (C) 2004-2022 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 %eax points to the TLS descriptor, such that
30	0(%eax) points to _dl_tlsdesc_return itself, and 4(%eax) 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	movl	4(%eax), %eax
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	%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.  */
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	movl	4(%eax), %eax
64	subl	%gs:0, %eax
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     /* This function is used for symbols that need dynamic TLS.
75
76	%eax points to the TLS descriptor, such that 0(%eax) points to
77	_dl_tlsdesc_dynamic itself, and 4(%eax) points to a struct
78	tlsdesc_dynamic_arg object.  It must return in %eax the offset
79	between the thread pointer and the object denoted by the
80	argument, without clobbering any registers.
81
82	The assembly code that follows is a rendition of the following
83	C code, hand-optimized a little bit.
84
85ptrdiff_t
86__attribute__ ((__regparm__ (1)))
87_dl_tlsdesc_dynamic (struct tlsdesc *tdp)
88{
89  struct tlsdesc_dynamic_arg *td = tdp->arg;
90  dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + DTV_OFFSET);
91  if (__builtin_expect (td->gen_count <= dtv[0].counter
92			&& (dtv[td->tlsinfo.ti_module].pointer.val
93			    != TLS_DTV_UNALLOCATED),
94			1))
95    return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
96      - __thread_pointer;
97
98  return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
99}
100*/
101	cfi_startproc
102	.align 16
103_dl_tlsdesc_dynamic:
104	_CET_ENDBR
105	/* Like all TLS resolvers, preserve call-clobbered registers.
106	   We need two scratch regs anyway.  */
107	subl	$28, %esp
108	cfi_adjust_cfa_offset (28)
109	movl	%ecx, 20(%esp)
110	movl	%edx, 24(%esp)
111	movl	TLSDESC_ARG(%eax), %eax
112	movl	%gs:DTV_OFFSET, %edx
113	movl	TLSDESC_GEN_COUNT(%eax), %ecx
114	cmpl	(%edx), %ecx
115	ja	.Lslow
116	movl	TLSDESC_MODID(%eax), %ecx
117	movl	(%edx,%ecx,8), %edx
118	cmpl	$-1, %edx
119	je	.Lslow
120	movl	TLSDESC_MODOFF(%eax), %eax
121	addl	%edx, %eax
122.Lret:
123	movl	20(%esp), %ecx
124	subl	%gs:0, %eax
125	movl	24(%esp), %edx
126	addl	$28, %esp
127	cfi_adjust_cfa_offset (-28)
128	ret
129	.p2align 4,,7
130.Lslow:
131	cfi_adjust_cfa_offset (28)
132	call	HIDDEN_JUMPTARGET (___tls_get_addr)
133	jmp	.Lret
134	cfi_endproc
135	.size	_dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
136#endif /* SHARED */
137