1 /* Thread-local storage handling in the ELF dynamic linker.
3 Copyright (C) 2011-2015 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 <http://www.gnu.org/licenses/>. */
25 #define NSAVEDQREGPAIRS 16
26 #define SAVE_Q_REGISTERS \
27 stp q0, q1, [sp, #-32*NSAVEDQREGPAIRS]!; \
28 cfi_adjust_cfa_offset (32*NSAVEDQREGPAIRS); \
29 stp q2, q3, [sp, #32*1]; \
30 stp q4, q5, [sp, #32*2]; \
31 stp q6, q7, [sp, #32*3]; \
32 stp q8, q9, [sp, #32*4]; \
33 stp q10, q11, [sp, #32*5]; \
34 stp q12, q13, [sp, #32*6]; \
35 stp q14, q15, [sp, #32*7]; \
36 stp q16, q17, [sp, #32*8]; \
37 stp q18, q19, [sp, #32*9]; \
38 stp q20, q21, [sp, #32*10]; \
39 stp q22, q23, [sp, #32*11]; \
40 stp q24, q25, [sp, #32*12]; \
41 stp q26, q27, [sp, #32*13]; \
42 stp q28, q29, [sp, #32*14]; \
43 stp q30, q31, [sp, #32*15];
45 #define RESTORE_Q_REGISTERS \
46 ldp q2, q3, [sp, #32*1]; \
47 ldp q4, q5, [sp, #32*2]; \
48 ldp q6, q7, [sp, #32*3]; \
49 ldp q8, q9, [sp, #32*4]; \
50 ldp q10, q11, [sp, #32*5]; \
51 ldp q12, q13, [sp, #32*6]; \
52 ldp q14, q15, [sp, #32*7]; \
53 ldp q16, q17, [sp, #32*8]; \
54 ldp q18, q19, [sp, #32*9]; \
55 ldp q20, q21, [sp, #32*10]; \
56 ldp q22, q23, [sp, #32*11]; \
57 ldp q24, q25, [sp, #32*12]; \
58 ldp q26, q27, [sp, #32*13]; \
59 ldp q28, q29, [sp, #32*14]; \
60 ldp q30, q31, [sp, #32*15]; \
61 ldp q0, q1, [sp], #32*NSAVEDQREGPAIRS; \
62 cfi_adjust_cfa_offset (-32*NSAVEDQREGPAIRS);
66 /* Compute the thread pointer offset for symbols in the static
67 TLS block. The offset is the same for all threads.
69 _dl_tlsdesc_return (tlsdesc *) ;
71 .hidden _dl_tlsdesc_return
72 .global _dl_tlsdesc_return
73 .type _dl_tlsdesc_return,%function
80 .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
82 /* Handler for undefined weak TLS symbols.
84 _dl_tlsdesc_undefweak (tlsdesc *);
86 The second word of the descriptor contains the addend.
87 Return the addend minus the thread pointer. This ensures
88 that when the caller adds on the thread pointer it gets back
91 .hidden _dl_tlsdesc_undefweak
92 .global _dl_tlsdesc_undefweak
93 .type _dl_tlsdesc_undefweak,%function
96 _dl_tlsdesc_undefweak:
98 cfi_adjust_cfa_offset(16)
103 cfi_adjust_cfa_offset(16)
106 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
109 /* Handler for dynamic TLS symbols.
111 _dl_tlsdesc_dynamic (tlsdesc *) ;
113 The second word of the descriptor points to a
114 tlsdesc_dynamic_arg structure.
116 Returns the offset between the thread pointer and the
117 object referenced by the argument.
120 __attribute__ ((__regparm__ (1)))
121 _dl_tlsdesc_dynamic (struct tlsdesc *tdp)
123 struct tlsdesc_dynamic_arg *td = tdp->arg;
124 dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + DTV_OFFSET);
125 if (__builtin_expect (td->gen_count <= dtv[0].counter
126 && (dtv[td->tlsinfo.ti_module].pointer.val
127 != TLS_DTV_UNALLOCATED),
129 return dtv[td->tlsinfo.ti_module].pointer.val
130 + td->tlsinfo.ti_offset
133 return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
137 .hidden _dl_tlsdesc_dynamic
138 .global _dl_tlsdesc_dynamic
139 .type _dl_tlsdesc_dynamic,%function
143 # define NSAVEXREGPAIRS 2
144 stp x29, x30, [sp,#-(32+16*NSAVEXREGPAIRS)]!
145 cfi_adjust_cfa_offset (32+16*NSAVEXREGPAIRS)
148 /* Save just enough registers to support fast path, if we fall
149 into slow path we will save additional registers. */
151 stp x1, x2, [sp, #32+16*0]
152 stp x3, x4, [sp, #32+16*1]
162 add x0, x0, x2, lsl #4
170 ldp x1, x2, [sp, #32+16*0]
171 ldp x3, x4, [sp, #32+16*1]
173 ldp x29, x30, [sp], #(32+16*NSAVEXREGPAIRS)
174 cfi_adjust_cfa_offset (32+16*NSAVEXREGPAIRS)
175 # undef NSAVEXREGPAIRS
178 /* This is the slow path. We need to call __tls_get_addr() which
179 means we need to save and restore all the register that the
180 callee will trash. */
182 /* Save the remaining registers that we must treat as caller save. */
183 # define NSAVEXREGPAIRS 7
184 stp x5, x6, [sp, #-16*NSAVEXREGPAIRS]!
185 cfi_adjust_cfa_offset (16*NSAVEXREGPAIRS)
186 stp x7, x8, [sp, #16*1]
187 stp x9, x10, [sp, #16*2]
188 stp x11, x12, [sp, #16*3]
189 stp x13, x14, [sp, #16*4]
190 stp x15, x16, [sp, #16*5]
191 stp x17, x18, [sp, #16*6]
203 ldp x7, x8, [sp, #16*1]
204 ldp x9, x10, [sp, #16*2]
205 ldp x11, x12, [sp, #16*3]
206 ldp x13, x14, [sp, #16*4]
207 ldp x15, x16, [sp, #16*5]
208 ldp x17, x18, [sp, #16*6]
209 ldp x5, x6, [sp], #16*NSAVEXREGPAIRS
210 cfi_adjust_cfa_offset (-16*NSAVEXREGPAIRS)
213 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
214 # undef NSAVEXREGPAIRS
217 /* This function is a wrapper for a lazy resolver for TLS_DESC
219 When the actual resolver returns, it will have adjusted the
220 TLS descriptor such that we can tail-call it for it to return
221 the TP offset of the symbol. */
223 .hidden _dl_tlsdesc_resolve_rela
224 .global _dl_tlsdesc_resolve_rela
225 .type _dl_tlsdesc_resolve_rela,%function
228 _dl_tlsdesc_resolve_rela:
229 #define NSAVEXREGPAIRS 9
230 stp x29, x30, [sp, #-(32+16*NSAVEXREGPAIRS)]!
231 cfi_adjust_cfa_offset (32+16*NSAVEXREGPAIRS)
233 stp x1, x4, [sp, #32+16*0]
234 stp x5, x6, [sp, #32+16*1]
235 stp x7, x8, [sp, #32+16*2]
236 stp x9, x10, [sp, #32+16*3]
237 stp x11, x12, [sp, #32+16*4]
238 stp x13, x14, [sp, #32+16*5]
239 stp x15, x16, [sp, #32+16*6]
240 stp x17, x18, [sp, #32+16*7]
241 str x0, [sp, #32+16*8]
246 bl _dl_tlsdesc_resolve_rela_fixup
250 ldr x0, [sp, #32+16*8]
254 ldp x1, x4, [sp, #32+16*0]
255 ldp x5, x6, [sp, #32+16*1]
256 ldp x7, x8, [sp, #32+16*2]
257 ldp x9, x10, [sp, #32+16*3]
258 ldp x11, x12, [sp, #32+16*4]
259 ldp x13, x14, [sp, #32+16*5]
260 ldp x15, x16, [sp, #32+16*6]
261 ldp x17, x18, [sp, #32+16*7]
262 ldp x29, x30, [sp], #(32+16*NSAVEXREGPAIRS)
263 cfi_adjust_cfa_offset (-32+16*NSAVEXREGPAIRS)
264 ldp x2, x3, [sp], #16
265 cfi_adjust_cfa_offset (-16)
267 #undef NSAVEXREGPAIRS
269 .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
271 /* This function is a placeholder for lazy resolving of TLS
272 relocations. Once some thread starts resolving a TLS
273 relocation, it sets up the TLS descriptor to use this
274 resolver, such that other threads that would attempt to
275 resolve it concurrently may skip the call to the original lazy
276 resolver and go straight to a condition wait.
278 When the actual resolver returns, it will have adjusted the
279 TLS descriptor such that we can tail-call it for it to return
280 the TP offset of the symbol. */
282 .hidden _dl_tlsdesc_resolve_hold
283 .global _dl_tlsdesc_resolve_hold
284 .type _dl_tlsdesc_resolve_hold,%function
287 _dl_tlsdesc_resolve_hold:
288 #define NSAVEXREGPAIRS 10
290 stp x29, x30, [sp, #-(32+16*NSAVEXREGPAIRS)]!
291 cfi_adjust_cfa_offset (32+16*NSAVEXREGPAIRS)
293 stp x1, x2, [sp, #32+16*0]
294 stp x3, x4, [sp, #32+16*1]
295 stp x5, x6, [sp, #32+16*2]
296 stp x7, x8, [sp, #32+16*3]
297 stp x9, x10, [sp, #32+16*4]
298 stp x11, x12, [sp, #32+16*5]
299 stp x13, x14, [sp, #32+16*6]
300 stp x15, x16, [sp, #32+16*7]
301 stp x17, x18, [sp, #32+16*8]
302 str x0, [sp, #32+16*9]
307 bl _dl_tlsdesc_resolve_hold_fixup
311 ldr x0, [sp, #32+16*9]
315 ldp x1, x2, [sp, #32+16*0]
316 ldp x3, x4, [sp, #32+16*1]
317 ldp x5, x6, [sp, #32+16*2]
318 ldp x7, x8, [sp, #32+16*3]
319 ldp x9, x10, [sp, #32+16*4]
320 ldp x11, x12, [sp, #32+16*5]
321 ldp x13, x14, [sp, #32+16*6]
322 ldp x15, x16, [sp, #32+16*7]
323 ldp x17, x18, [sp, #32+16*8]
324 ldp x29, x30, [sp], #(32+16*NSAVEXREGPAIRS)
325 cfi_adjust_cfa_offset (-32+16*NSAVEXREGPAIRS)
328 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold
329 #undef NSAVEXREGPAIRS