1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
/* Thread-local storage handling in the ELF dynamic linker.
LoongArch version.
Copyright (C) 2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#define FRAME_SIZE (-((-14 * SZREG) & ALMASK))
/* Handler for dynamic TLS symbols.
Prototype:
_dl_tlsdesc_dynamic (tlsdesc *) ;
The second word of the descriptor points to a
tlsdesc_dynamic_arg structure.
Returns the offset between the thread pointer and the
object referenced by the argument.
ptrdiff_t
_dl_tlsdesc_dynamic (struct tlsdesc *tdp)
{
struct tlsdesc_dynamic_arg *td = tdp->arg;
dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer - SIZE_OF_TCB);
if (__glibc_likely (td->gen_count <= dtv[0].counter
&& (dtv[td->tlsinfo.ti_module].pointer.val
!= TLS_DTV_UNALLOCATED),
1))
return dtv[td->tlsinfo.ti_module].pointer.val
+ td->tlsinfo.ti_offset
- __thread_pointer;
return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
} */
.hidden _dl_tlsdesc_dynamic
.global _dl_tlsdesc_dynamic
.type _dl_tlsdesc_dynamic,%function
cfi_startproc
.align 2
_dl_tlsdesc_dynamic:
/* Save just enough registers to support fast path, if we fall
into slow path we will save additional registers. */
ADDI sp, sp, -32
cfi_adjust_cfa_offset (32)
REG_S t0, sp, 0
REG_S t1, sp, 8
REG_S t2, sp, 16
cfi_rel_offset (12, 0)
cfi_rel_offset (13, 8)
cfi_rel_offset (14, 16)
/* Runtime Storage Layout of Thread-Local Storage
TP point to the start of TLS block.
dtv
Low address TCB ----------------> dtv0(counter)
TP --> static_block0 <----- dtv1
static_block1 <----- dtv2
static_block2 <----- dtv3
dynamic_block0 <----- dtv4
Hign address dynamic_block1 <----- dtv5 */
REG_L t0, tp, -SIZE_OF_TCB /* t0 = dtv */
REG_L a0, a0, TLSDESC_ARG /* a0(td) = tdp->arg */
REG_L t1, a0, TLSDESC_GEN_COUNT /* t1 = td->gen_count */
REG_L t2, t0, DTV_COUNTER /* t2 = dtv[0].counter */
/* If dtv[0].counter < td->gen_count, goto slow path. */
bltu t2, t1, .Lslow
REG_L t1, a0, TLSDESC_MODID /* t1 = td->tlsinfo.ti_module */
/* t1 = t1 * sizeof(dtv_t) = t1 * (2 * sizeof(void*)) */
slli.d t1, t1, 4
add.d t1, t1, t0 /* t1 = dtv[td->tlsinfo.ti_module] */
REG_L t1, t1, 0 /* t1 = dtv[td->tlsinfo.ti_module].pointer.val */
li.d t2, TLS_DTV_UNALLOCATED
/* If dtv[td->tlsinfo.ti_module].pointer.val is TLS_DTV_UNALLOCATED,
goto slow path. */
beq t1, t2, .Lslow
cfi_remember_state
REG_L t2, a0, TLSDESC_MODOFF /* t2 = td->tlsinfo.ti_offset */
/* dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset */
add.d a0, t1, t2
.Lret:
sub.d a0, a0, tp
REG_L t0, sp, 0
REG_L t1, sp, 8
REG_L t2, sp, 16
ADDI sp, sp, 32
cfi_adjust_cfa_offset (-32)
RET
.Lslow:
/* This is the slow path. We need to call __tls_get_addr() which
means we need to save and restore all the register that the
callee will trash. */
/* Save the remaining registers that we must treat as caller save. */
cfi_restore_state
ADDI sp, sp, -FRAME_SIZE
cfi_adjust_cfa_offset (FRAME_SIZE)
REG_S ra, sp, 0 * SZREG
REG_S a1, sp, 1 * SZREG
REG_S a2, sp, 2 * SZREG
REG_S a3, sp, 3 * SZREG
REG_S a4, sp, 4 * SZREG
REG_S a5, sp, 5 * SZREG
REG_S a6, sp, 6 * SZREG
REG_S a7, sp, 7 * SZREG
REG_S t3, sp, 8 * SZREG
REG_S t4, sp, 9 * SZREG
REG_S t5, sp, 10 * SZREG
REG_S t6, sp, 11 * SZREG
REG_S t7, sp, 12 * SZREG
REG_S t8, sp, 13 * SZREG
cfi_rel_offset (1, 0 * SZREG)
cfi_rel_offset (5, 1 * SZREG)
cfi_rel_offset (6, 2 * SZREG)
cfi_rel_offset (7, 3 * SZREG)
cfi_rel_offset (8, 4 * SZREG)
cfi_rel_offset (9, 5 * SZREG)
cfi_rel_offset (10, 6 * SZREG)
cfi_rel_offset (11, 7 * SZREG)
cfi_rel_offset (15, 8 * SZREG)
cfi_rel_offset (16, 9 * SZREG)
cfi_rel_offset (17, 10 * SZREG)
cfi_rel_offset (18, 11 * SZREG)
cfi_rel_offset (19, 12 * SZREG)
cfi_rel_offset (20, 13 * SZREG)
#ifndef __loongarch_soft_float
/* Save fcsr0 register.
Only one physical fcsr0 register, fcsr1-fcsr3 are aliases
of some fields in fcsr0. */
movfcsr2gr t0, fcsr0
st.w t0, sp, FRAME_SIZE + 24 /* Use the spare slot above t2. */
#ifdef USE_LASX
#define V_REG_S xvst
#define V_REG_L xvld
#define V_SPACE (-((-32 * SZXREG) & ALMASK)) /* Space for LASX registers. */
#define V_REG(n) $xr##n
#define V_REGS 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
#define V_REGSZ SZXREG
#elif defined USE_LSX
#define V_REG_S vst
#define V_REG_L vld
#define V_SPACE (-((-32 * SZVREG) & ALMASK)) /* Space for LSX registers. */
#define V_REG(n) $vr##n
#define V_REGS 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
#define V_REGSZ SZVREG
#else
#define V_REG_S fst.d
#define V_REG_L fld.d
#define V_SPACE (-((-24 * SZFREG) & ALMASK)) /* Space for FLOAT registers. */
#define V_REG(n) $f##n
#define V_REGS 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
#define V_REGSZ SZFREG
#endif
ADDI sp, sp, -V_SPACE
cfi_adjust_cfa_offset (V_SPACE)
.irp i,V_REGS
V_REG_S V_REG(\i), sp, \i * V_REGSZ
.endr
#endif /* #ifndef __loongarch_soft_float */
bl HIDDEN_JUMPTARGET(__tls_get_addr)
ADDI a0, a0, -TLS_DTV_OFFSET
#ifndef __loongarch_soft_float
.irp i,V_REGS
V_REG_L V_REG(\i), sp, \i * V_REGSZ
.endr
ADDI sp, sp, V_SPACE
cfi_adjust_cfa_offset (-V_SPACE)
/* Restore fcsr0 register. */
ld.w t0, sp, FRAME_SIZE + 24
movgr2fcsr fcsr0, t0
#endif /* #ifndef __loongarch_soft_float */
REG_L ra, sp, 0 * SZREG
REG_L a1, sp, 1 * SZREG
REG_L a2, sp, 2 * SZREG
REG_L a3, sp, 3 * SZREG
REG_L a4, sp, 4 * SZREG
REG_L a5, sp, 5 * SZREG
REG_L a6, sp, 6 * SZREG
REG_L a7, sp, 7 * SZREG
REG_L t3, sp, 8 * SZREG
REG_L t4, sp, 9 * SZREG
REG_L t5, sp, 10 * SZREG
REG_L t6, sp, 11 * SZREG
REG_L t7, sp, 12 * SZREG
REG_L t8, sp, 13 * SZREG
ADDI sp, sp, FRAME_SIZE
cfi_adjust_cfa_offset (-FRAME_SIZE)
b .Lret
cfi_endproc
.size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
.hidden HIDDEN_JUMPTARGET(__tls_get_addr)
|