1 /* Thread-local storage handling in the ELF dynamic linker.
3 Copyright (C) 2024 Free Software Foundation, Inc.
5 This file is part of the GNU C Library.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, see
19 <https://www.gnu.org/licenses/>. */
27 /* Compute the thread pointer offset for symbols in the static
28 TLS block. The offset is the same for all threads.
30 _dl_tlsdesc_return (tlsdesc *); */
31 .hidden _dl_tlsdesc_return
32 .global _dl_tlsdesc_return
33 .type _dl_tlsdesc_return,%function
40 .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
42 /* Handler for undefined weak TLS symbols.
44 _dl_tlsdesc_undefweak (tlsdesc *);
46 The second word of the descriptor contains the addend.
47 Return the addend minus the thread pointer. This ensures
48 that when the caller adds on the thread pointer it gets back
50 .hidden _dl_tlsdesc_undefweak
51 .global _dl_tlsdesc_undefweak
52 .type _dl_tlsdesc_undefweak,%function
55 _dl_tlsdesc_undefweak:
60 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
65 #define FRAME_SIZE (-((-14 * SZREG) & ALMASK))
66 #define FRAME_SIZE_LSX (-((-32 * SZVREG) & ALMASK))
67 #define FRAME_SIZE_LASX (-((-32 * SZXREG) & ALMASK))
68 #define FRAME_SIZE_FLOAT (-((-24 * SZFREG) & ALMASK))
70 /* Handler for dynamic TLS symbols.
72 _dl_tlsdesc_dynamic (tlsdesc *) ;
74 The second word of the descriptor points to a
75 tlsdesc_dynamic_arg structure.
77 Returns the offset between the thread pointer and the
78 object referenced by the argument.
81 _dl_tlsdesc_dynamic (struct tlsdesc *tdp)
83 struct tlsdesc_dynamic_arg *td = tdp->arg;
84 dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer - SIZE_OF_TCB);
85 if (__glibc_likely (td->gen_count <= dtv[0].counter
86 && (dtv[td->tlsinfo.ti_module].pointer.val
87 != TLS_DTV_UNALLOCATED),
89 return dtv[td->tlsinfo.ti_module].pointer.val
90 + td->tlsinfo.ti_offset
93 return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
95 .hidden _dl_tlsdesc_dynamic
96 .global _dl_tlsdesc_dynamic
97 .type _dl_tlsdesc_dynamic,%function
101 /* Save just enough registers to support fast path, if we fall
102 into slow path we will save additional registers. */
108 /* Runtime Storage Layout of Thread-Local Storage
109 TP point to the start of TLS block.
112 Low address TCB ----------------> dtv0(counter)
113 TP --> static_block0 <----- dtv1
114 static_block1 <----- dtv2
115 static_block2 <----- dtv3
116 dynamic_block0 <----- dtv4
117 Hign address dynamic_block1 <----- dtv5 */
119 REG_L t0, tp, -SIZE_OF_TCB /* t0 = dtv */
120 REG_L a0, a0, TLSDESC_ARG /* a0(td) = tdp->arg */
121 REG_L t1, a0, TLSDESC_GEN_COUNT /* t1 = td->gen_count */
122 REG_L t2, t0, DTV_COUNTER /* t2 = dtv[0].counter */
123 /* If dtv[0].counter < td->gen_count, goto slow path. */
126 REG_L t1, a0, TLSDESC_MODID /* t1 = td->tlsinfo.ti_module */
127 /* t1 = t1 * sizeof(dtv_t) = t1 * (2 * sizeof(void*)) */
129 add.d t1, t1, t0 /* t1 = dtv[td->tlsinfo.ti_module] */
130 REG_L t1, t1, 0 /* t1 = dtv[td->tlsinfo.ti_module].pointer.val */
131 li.d t2, TLS_DTV_UNALLOCATED
132 /* If dtv[td->tlsinfo.ti_module].pointer.val is TLS_DTV_UNALLOCATED,
136 REG_L t2, a0, TLSDESC_MODOFF /* t2 = td->tlsinfo.ti_offset */
137 /* dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset */
148 /* This is the slow path. We need to call __tls_get_addr() which
149 means we need to save and restore all the register that the
150 callee will trash. */
152 /* Save the remaining registers that we must treat as caller save. */
153 ADDI sp, sp, -FRAME_SIZE
154 REG_S ra, sp, 0 * SZREG
155 REG_S a1, sp, 1 * SZREG
156 REG_S a2, sp, 2 * SZREG
157 REG_S a3, sp, 3 * SZREG
158 REG_S a4, sp, 4 * SZREG
159 REG_S a5, sp, 5 * SZREG
160 REG_S a6, sp, 6 * SZREG
161 REG_S a7, sp, 7 * SZREG
162 REG_S t3, sp, 8 * SZREG
163 REG_S t4, sp, 9 * SZREG
164 REG_S t5, sp, 10 * SZREG
165 REG_S t6, sp, 11 * SZREG
166 REG_S t7, sp, 12 * SZREG
167 REG_S t8, sp, 13 * SZREG
169 #ifndef __loongarch_soft_float
171 /* Save fcsr0 register.
172 Only one physical fcsr0 register, fcsr1-fcsr3 are aliases
173 of some fields in fcsr0. */
175 st.w t0, sp, FRAME_SIZE + 24 /* Use the spare slot above t2 */
177 /* Whether support LASX. */
178 la.global t0, _rtld_global_ro
179 REG_L t0, t0, GLRO_DL_HWCAP_OFFSET
180 andi t1, t0, HWCAP_LOONGARCH_LASX
183 /* Save 256-bit vector registers.
184 FIXME: Without vector ABI, save all vector registers. */
185 ADDI sp, sp, -FRAME_SIZE_LASX
186 xvst xr0, sp, 0*SZXREG
187 xvst xr1, sp, 1*SZXREG
188 xvst xr2, sp, 2*SZXREG
189 xvst xr3, sp, 3*SZXREG
190 xvst xr4, sp, 4*SZXREG
191 xvst xr5, sp, 5*SZXREG
192 xvst xr6, sp, 6*SZXREG
193 xvst xr7, sp, 7*SZXREG
194 xvst xr8, sp, 8*SZXREG
195 xvst xr9, sp, 9*SZXREG
196 xvst xr10, sp, 10*SZXREG
197 xvst xr11, sp, 11*SZXREG
198 xvst xr12, sp, 12*SZXREG
199 xvst xr13, sp, 13*SZXREG
200 xvst xr14, sp, 14*SZXREG
201 xvst xr15, sp, 15*SZXREG
202 xvst xr16, sp, 16*SZXREG
203 xvst xr17, sp, 17*SZXREG
204 xvst xr18, sp, 18*SZXREG
205 xvst xr19, sp, 19*SZXREG
206 xvst xr20, sp, 20*SZXREG
207 xvst xr21, sp, 21*SZXREG
208 xvst xr22, sp, 22*SZXREG
209 xvst xr23, sp, 23*SZXREG
210 xvst xr24, sp, 24*SZXREG
211 xvst xr25, sp, 25*SZXREG
212 xvst xr26, sp, 26*SZXREG
213 xvst xr27, sp, 27*SZXREG
214 xvst xr28, sp, 28*SZXREG
215 xvst xr29, sp, 29*SZXREG
216 xvst xr30, sp, 30*SZXREG
217 xvst xr31, sp, 31*SZXREG
221 /* Whether support LSX. */
222 andi t1, t0, HWCAP_LOONGARCH_LSX
225 /* Save 128-bit vector registers. */
226 ADDI sp, sp, -FRAME_SIZE_LSX
227 vst vr0, sp, 0*SZVREG
228 vst vr1, sp, 1*SZVREG
229 vst vr2, sp, 2*SZVREG
230 vst vr3, sp, 3*SZVREG
231 vst vr4, sp, 4*SZVREG
232 vst vr5, sp, 5*SZVREG
233 vst vr6, sp, 6*SZVREG
234 vst vr7, sp, 7*SZVREG
235 vst vr8, sp, 8*SZVREG
236 vst vr9, sp, 9*SZVREG
237 vst vr10, sp, 10*SZVREG
238 vst vr11, sp, 11*SZVREG
239 vst vr12, sp, 12*SZVREG
240 vst vr13, sp, 13*SZVREG
241 vst vr14, sp, 14*SZVREG
242 vst vr15, sp, 15*SZVREG
243 vst vr16, sp, 16*SZVREG
244 vst vr17, sp, 17*SZVREG
245 vst vr18, sp, 18*SZVREG
246 vst vr19, sp, 19*SZVREG
247 vst vr20, sp, 20*SZVREG
248 vst vr21, sp, 21*SZVREG
249 vst vr22, sp, 22*SZVREG
250 vst vr23, sp, 23*SZVREG
251 vst vr24, sp, 24*SZVREG
252 vst vr25, sp, 25*SZVREG
253 vst vr26, sp, 26*SZVREG
254 vst vr27, sp, 27*SZVREG
255 vst vr28, sp, 28*SZVREG
256 vst vr29, sp, 29*SZVREG
257 vst vr30, sp, 30*SZVREG
258 vst vr31, sp, 31*SZVREG
262 /* Save float registers. */
263 ADDI sp, sp, -FRAME_SIZE_FLOAT
264 FREG_S fa0, sp, 0*SZFREG
265 FREG_S fa1, sp, 1*SZFREG
266 FREG_S fa2, sp, 2*SZFREG
267 FREG_S fa3, sp, 3*SZFREG
268 FREG_S fa4, sp, 4*SZFREG
269 FREG_S fa5, sp, 5*SZFREG
270 FREG_S fa6, sp, 6*SZFREG
271 FREG_S fa7, sp, 7*SZFREG
272 FREG_S ft0, sp, 8*SZFREG
273 FREG_S ft1, sp, 9*SZFREG
274 FREG_S ft2, sp, 10*SZFREG
275 FREG_S ft3, sp, 11*SZFREG
276 FREG_S ft4, sp, 12*SZFREG
277 FREG_S ft5, sp, 13*SZFREG
278 FREG_S ft6, sp, 14*SZFREG
279 FREG_S ft7, sp, 15*SZFREG
280 FREG_S ft8, sp, 16*SZFREG
281 FREG_S ft9, sp, 17*SZFREG
282 FREG_S ft10, sp, 18*SZFREG
283 FREG_S ft11, sp, 19*SZFREG
284 FREG_S ft12, sp, 20*SZFREG
285 FREG_S ft13, sp, 21*SZFREG
286 FREG_S ft14, sp, 22*SZFREG
287 FREG_S ft15, sp, 23*SZFREG
289 #endif /* #ifndef __loongarch_soft_float */
292 bl HIDDEN_JUMPTARGET(__tls_get_addr)
293 ADDI a0, a0, -TLS_DTV_OFFSET
295 #ifndef __loongarch_soft_float
297 la.global t0, _rtld_global_ro
298 REG_L t0, t0, GLRO_DL_HWCAP_OFFSET
299 andi t1, t0, HWCAP_LOONGARCH_LASX
302 /* Restore 256-bit vector registers. */
303 xvld xr0, sp, 0*SZXREG
304 xvld xr1, sp, 1*SZXREG
305 xvld xr2, sp, 2*SZXREG
306 xvld xr3, sp, 3*SZXREG
307 xvld xr4, sp, 4*SZXREG
308 xvld xr5, sp, 5*SZXREG
309 xvld xr6, sp, 6*SZXREG
310 xvld xr7, sp, 7*SZXREG
311 xvld xr8, sp, 8*SZXREG
312 xvld xr9, sp, 9*SZXREG
313 xvld xr10, sp, 10*SZXREG
314 xvld xr11, sp, 11*SZXREG
315 xvld xr12, sp, 12*SZXREG
316 xvld xr13, sp, 13*SZXREG
317 xvld xr14, sp, 14*SZXREG
318 xvld xr15, sp, 15*SZXREG
319 xvld xr16, sp, 16*SZXREG
320 xvld xr17, sp, 17*SZXREG
321 xvld xr18, sp, 18*SZXREG
322 xvld xr19, sp, 19*SZXREG
323 xvld xr20, sp, 20*SZXREG
324 xvld xr21, sp, 21*SZXREG
325 xvld xr22, sp, 22*SZXREG
326 xvld xr23, sp, 23*SZXREG
327 xvld xr24, sp, 24*SZXREG
328 xvld xr25, sp, 25*SZXREG
329 xvld xr26, sp, 26*SZXREG
330 xvld xr27, sp, 27*SZXREG
331 xvld xr28, sp, 28*SZXREG
332 xvld xr29, sp, 29*SZXREG
333 xvld xr30, sp, 30*SZXREG
334 xvld xr31, sp, 31*SZXREG
335 ADDI sp, sp, FRAME_SIZE_LASX
339 andi t1, t0, HWCAP_LOONGARCH_LSX
342 /* Restore 128-bit vector registers. */
343 vld vr0, sp, 0*SZVREG
344 vld vr1, sp, 1*SZVREG
345 vld vr2, sp, 2*SZVREG
346 vld vr3, sp, 3*SZVREG
347 vld vr4, sp, 4*SZVREG
348 vld vr5, sp, 5*SZVREG
349 vld vr6, sp, 6*SZVREG
350 vld vr7, sp, 7*SZVREG
351 vld vr8, sp, 8*SZVREG
352 vld vr9, sp, 9*SZVREG
353 vld vr10, sp, 10*SZVREG
354 vld vr11, sp, 11*SZVREG
355 vld vr12, sp, 12*SZVREG
356 vld vr13, sp, 13*SZVREG
357 vld vr14, sp, 14*SZVREG
358 vld vr15, sp, 15*SZVREG
359 vld vr16, sp, 16*SZVREG
360 vld vr17, sp, 17*SZVREG
361 vld vr18, sp, 18*SZVREG
362 vld vr19, sp, 19*SZVREG
363 vld vr20, sp, 20*SZVREG
364 vld vr21, sp, 21*SZVREG
365 vld vr22, sp, 22*SZVREG
366 vld vr23, sp, 23*SZVREG
367 vld vr24, sp, 24*SZVREG
368 vld vr25, sp, 25*SZVREG
369 vld vr26, sp, 26*SZVREG
370 vld vr27, sp, 27*SZVREG
371 vld vr28, sp, 28*SZVREG
372 vld vr29, sp, 29*SZVREG
373 vld vr30, sp, 30*SZVREG
374 vld vr31, sp, 31*SZVREG
375 ADDI sp, sp, FRAME_SIZE_LSX
379 /* Restore float registers. */
380 FREG_L fa0, sp, 0*SZFREG
381 FREG_L fa1, sp, 1*SZFREG
382 FREG_L fa2, sp, 2*SZFREG
383 FREG_L fa3, sp, 3*SZFREG
384 FREG_L fa4, sp, 4*SZFREG
385 FREG_L fa5, sp, 5*SZFREG
386 FREG_L fa6, sp, 6*SZFREG
387 FREG_L fa7, sp, 7*SZFREG
388 FREG_L ft0, sp, 8*SZFREG
389 FREG_L ft1, sp, 9*SZFREG
390 FREG_L ft2, sp, 10*SZFREG
391 FREG_L ft3, sp, 11*SZFREG
392 FREG_L ft4, sp, 12*SZFREG
393 FREG_L ft5, sp, 13*SZFREG
394 FREG_L ft6, sp, 14*SZFREG
395 FREG_L ft7, sp, 15*SZFREG
396 FREG_L ft8, sp, 16*SZFREG
397 FREG_L ft9, sp, 17*SZFREG
398 FREG_L ft10, sp, 18*SZFREG
399 FREG_L ft11, sp, 19*SZFREG
400 FREG_L ft12, sp, 20*SZFREG
401 FREG_L ft13, sp, 21*SZFREG
402 FREG_L ft14, sp, 22*SZFREG
403 FREG_L ft15, sp, 23*SZFREG
404 ADDI sp, sp, FRAME_SIZE_FLOAT
407 /* Restore fcsr0 register. */
408 ld.w t0, sp, FRAME_SIZE + 24
411 #endif /* #ifndef __loongarch_soft_float */
413 REG_L ra, sp, 0 * SZREG
414 REG_L a1, sp, 1 * SZREG
415 REG_L a2, sp, 2 * SZREG
416 REG_L a3, sp, 3 * SZREG
417 REG_L a4, sp, 4 * SZREG
418 REG_L a5, sp, 5 * SZREG
419 REG_L a6, sp, 6 * SZREG
420 REG_L a7, sp, 7 * SZREG
421 REG_L t3, sp, 8 * SZREG
422 REG_L t4, sp, 9 * SZREG
423 REG_L t5, sp, 10 * SZREG
424 REG_L t6, sp, 11 * SZREG
425 REG_L t7, sp, 12 * SZREG
426 REG_L t8, sp, 13 * SZREG
427 ADDI sp, sp, FRAME_SIZE
431 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
432 .hidden HIDDEN_JUMPTARGET(__tls_get_addr)
434 #endif /* #ifdef SHARED */