]> git.ipfire.org Git - thirdparty/glibc.git/blame - ports/sysdeps/aarch64/dl-tlsdesc.S
Update copyright notices with scripts/update-copyrights
[thirdparty/glibc.git] / ports / sysdeps / aarch64 / dl-tlsdesc.S
CommitLineData
554066b8
MS
1/* Thread-local storage handling in the ELF dynamic linker.
2 AArch64 version.
d4697bc9 3 Copyright (C) 2011-2014 Free Software Foundation, Inc.
554066b8
MS
4
5 This file is part of the GNU C Library.
6
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.
11
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.
16
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/>. */
20
21#include <sysdep.h>
22#include <tls.h>
23#include "tlsdesc.h"
24
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];
44
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);
63
64 .text
65
66 /* Compute the thread pointer offset for symbols in the static
67 TLS block. The offset is the same for all threads.
68 Prototype:
69 _dl_tlsdesc_return (tlsdesc *) ;
70 */
71 .hidden _dl_tlsdesc_return
72 .global _dl_tlsdesc_return
73 .type _dl_tlsdesc_return,%function
74 cfi_startproc
75 .align 2
76_dl_tlsdesc_return:
77 ldr x0, [x0, #8]
78 RET
79 cfi_endproc
80 .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
81
82 /* Handler for undefined weak TLS symbols.
83 Prototype:
84 _dl_tlsdesc_undefweak (tlsdesc *);
85
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
89 the addend. */
90
91 .hidden _dl_tlsdesc_undefweak
92 .global _dl_tlsdesc_undefweak
93 .type _dl_tlsdesc_undefweak,%function
94 cfi_startproc
95 .align 2
96_dl_tlsdesc_undefweak:
97 str x1, [sp, #-16]!
98 cfi_adjust_cfa_offset(16)
99 ldr x0, [x0, #8]
100 mrs x1, tpidr_el0
101 sub x0, x0, x1
102 ldr x1, [sp], #16
103 cfi_adjust_cfa_offset(16)
104 RET
105 cfi_endproc
106 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
107
108#ifdef SHARED
109 /* Handler for dynamic TLS symbols.
110 Prototype:
111 _dl_tlsdesc_dynamic (tlsdesc *) ;
112
113 The second word of the descriptor points to a
114 tlsdesc_dynamic_arg structure.
115
116 Returns the offset between the thread pointer and the
117 object referenced by the argument.
118
119 ptrdiff_t
120 __attribute__ ((__regparm__ (1)))
121 _dl_tlsdesc_dynamic (struct tlsdesc *tdp)
122 {
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),
128 1))
129 return dtv[td->tlsinfo.ti_module].pointer.val
130 + td->tlsinfo.ti_offset
131 - __thread_pointer;
132
133 return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
134 }
135 */
136
137 .hidden _dl_tlsdesc_dynamic
138 .global _dl_tlsdesc_dynamic
139 .type _dl_tlsdesc_dynamic,%function
140 cfi_startproc
141 .align 2
142_dl_tlsdesc_dynamic:
143# define NSAVEXREGPAIRS 2
144 stp x29, x30, [sp,#-(32+16*NSAVEXREGPAIRS)]!
145 cfi_adjust_cfa_offset (32+16*NSAVEXREGPAIRS)
146 mov x29, sp
147
148 /* Save just enough registers to support fast path, if we fall
149 into slow path we will save additional registers. */
150
151 stp x1, x2, [sp, #32+16*0]
152 stp x3, x4, [sp, #32+16*1]
153
154 mrs x4, tpidr_el0
155 ldr x1, [x0,#8]
156 ldr x0, [x4]
157 ldr x3, [x1,#16]
158 ldr x2, [x0]
159 cmp x3, x2
160 b.hi 2f
161 ldr x2, [x1]
162 add x0, x0, x2, lsl #4
163 ldr x0, [x0]
164 cmn x0, #0x1
165 b.eq 2f
166 ldr x1, [x1,#8]
167 add x0, x0, x1
168 sub x0, x0, x4
1691:
170 ldp x1, x2, [sp, #32+16*0]
171 ldp x3, x4, [sp, #32+16*1]
172
173 ldp x29, x30, [sp], #(32+16*NSAVEXREGPAIRS)
174 cfi_adjust_cfa_offset (32+16*NSAVEXREGPAIRS)
175# undef NSAVEXREGPAIRS
176 RET
1772:
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. */
181
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]
192
193 SAVE_Q_REGISTERS
194
195 mov x0, x1
196 bl __tls_get_addr
197
198 mrs x1, tpidr_el0
199 sub x0, x0, x1
200
201 RESTORE_Q_REGISTERS
202
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)
211 b 1b
212 cfi_endproc
213 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
214# undef NSAVEXREGPAIRS
215#endif
216
217 /* This function is a wrapper for a lazy resolver for TLS_DESC
218 RELA relocations.
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. */
222
223 .hidden _dl_tlsdesc_resolve_rela
224 .global _dl_tlsdesc_resolve_rela
225 .type _dl_tlsdesc_resolve_rela,%function
226 cfi_startproc
227 .align 2
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)
232 mov x29, sp
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]
242
243 SAVE_Q_REGISTERS
244
245 ldr x1, [x3, #8]
246 bl _dl_tlsdesc_resolve_rela_fixup
247
248 RESTORE_Q_REGISTERS
249
250 ldr x0, [sp, #32+16*8]
251 ldr x1, [x0]
252 blr x1
253
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)
266 RET
267#undef NSAVEXREGPAIRS
268 cfi_endproc
269 .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
270
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.
277
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. */
281
282 .hidden _dl_tlsdesc_resolve_hold
283 .global _dl_tlsdesc_resolve_hold
284 .type _dl_tlsdesc_resolve_hold,%function
285 cfi_startproc
286 .align 2
287_dl_tlsdesc_resolve_hold:
288#define NSAVEXREGPAIRS 10
2891:
290 stp x29, x30, [sp, #-(32+16*NSAVEXREGPAIRS)]!
291 cfi_adjust_cfa_offset (32+16*NSAVEXREGPAIRS)
292 mov x29, sp
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]
303
304 SAVE_Q_REGISTERS
305
306 adr x1, 1b
307 bl _dl_tlsdesc_resolve_hold_fixup
308
309 RESTORE_Q_REGISTERS
310
311 ldr x0, [sp, #32+16*9]
312 ldr x1, [x0]
313 blr x1
314
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)
326 RET
327 cfi_endproc
328 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold
329#undef NSAVEXREGPAIRS