]>
Commit | Line | Data |
---|---|---|
554066b8 MS |
1 | /* Thread-local storage handling in the ELF dynamic linker. |
2 | AArch64 version. | |
04277e02 | 3 | Copyright (C) 2011-2019 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: | |
389d1f1b SE |
77 | DELOUSE (0) |
78 | ldr PTR_REG (0), [x0, #PTR_SIZE] | |
554066b8 MS |
79 | RET |
80 | cfi_endproc | |
81 | .size _dl_tlsdesc_return, .-_dl_tlsdesc_return | |
82 | ||
83 | /* Handler for undefined weak TLS symbols. | |
84 | Prototype: | |
85 | _dl_tlsdesc_undefweak (tlsdesc *); | |
86 | ||
87 | The second word of the descriptor contains the addend. | |
88 | Return the addend minus the thread pointer. This ensures | |
89 | that when the caller adds on the thread pointer it gets back | |
90 | the addend. */ | |
91 | ||
92 | .hidden _dl_tlsdesc_undefweak | |
93 | .global _dl_tlsdesc_undefweak | |
94 | .type _dl_tlsdesc_undefweak,%function | |
95 | cfi_startproc | |
96 | .align 2 | |
97 | _dl_tlsdesc_undefweak: | |
98 | str x1, [sp, #-16]! | |
c71c89e5 | 99 | cfi_adjust_cfa_offset (16) |
389d1f1b | 100 | DELOUSE (0) |
389d1f1b | 101 | ldr PTR_REG (0), [x0, #PTR_SIZE] |
554066b8 | 102 | mrs x1, tpidr_el0 |
389d1f1b | 103 | sub PTR_REG (0), PTR_REG (0), PTR_REG (1) |
554066b8 | 104 | ldr x1, [sp], #16 |
c71c89e5 | 105 | cfi_adjust_cfa_offset (-16) |
554066b8 MS |
106 | RET |
107 | cfi_endproc | |
108 | .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak | |
109 | ||
110 | #ifdef SHARED | |
111 | /* Handler for dynamic TLS symbols. | |
112 | Prototype: | |
113 | _dl_tlsdesc_dynamic (tlsdesc *) ; | |
114 | ||
115 | The second word of the descriptor points to a | |
116 | tlsdesc_dynamic_arg structure. | |
117 | ||
118 | Returns the offset between the thread pointer and the | |
119 | object referenced by the argument. | |
120 | ||
121 | ptrdiff_t | |
122 | __attribute__ ((__regparm__ (1))) | |
123 | _dl_tlsdesc_dynamic (struct tlsdesc *tdp) | |
124 | { | |
125 | struct tlsdesc_dynamic_arg *td = tdp->arg; | |
67aae645 | 126 | dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + TCBHEAD_DTV); |
554066b8 MS |
127 | if (__builtin_expect (td->gen_count <= dtv[0].counter |
128 | && (dtv[td->tlsinfo.ti_module].pointer.val | |
129 | != TLS_DTV_UNALLOCATED), | |
130 | 1)) | |
131 | return dtv[td->tlsinfo.ti_module].pointer.val | |
132 | + td->tlsinfo.ti_offset | |
133 | - __thread_pointer; | |
134 | ||
135 | return ___tls_get_addr (&td->tlsinfo) - __thread_pointer; | |
136 | } | |
137 | */ | |
138 | ||
139 | .hidden _dl_tlsdesc_dynamic | |
140 | .global _dl_tlsdesc_dynamic | |
141 | .type _dl_tlsdesc_dynamic,%function | |
142 | cfi_startproc | |
143 | .align 2 | |
144 | _dl_tlsdesc_dynamic: | |
389d1f1b | 145 | DELOUSE (0) |
554066b8 MS |
146 | |
147 | /* Save just enough registers to support fast path, if we fall | |
148 | into slow path we will save additional registers. */ | |
659ca267 SN |
149 | stp x1, x2, [sp, #-32]! |
150 | stp x3, x4, [sp, #16] | |
151 | cfi_adjust_cfa_offset (32) | |
152 | cfi_rel_offset (x1, 0) | |
153 | cfi_rel_offset (x2, 8) | |
154 | cfi_rel_offset (x3, 16) | |
155 | cfi_rel_offset (x4, 24) | |
554066b8 MS |
156 | |
157 | mrs x4, tpidr_el0 | |
67aae645 FW |
158 | ldr PTR_REG (1), [x0,#TLSDESC_ARG] |
159 | ldr PTR_REG (0), [x4,#TCBHEAD_DTV] | |
160 | ldr PTR_REG (3), [x1,#TLSDESC_GEN_COUNT] | |
161 | ldr PTR_REG (2), [x0,#DTV_COUNTER] | |
389d1f1b | 162 | cmp PTR_REG (3), PTR_REG (2) |
554066b8 | 163 | b.hi 2f |
659ca267 SN |
164 | /* Load r2 = td->tlsinfo.ti_module and r3 = td->tlsinfo.ti_offset. */ |
165 | ldp PTR_REG (2), PTR_REG (3), [x1,#TLSDESC_MODID] | |
389d1f1b | 166 | add PTR_REG (0), PTR_REG (0), PTR_REG (2), lsl #(PTR_LOG_SIZE + 1) |
67aae645 | 167 | ldr PTR_REG (0), [x0] /* Load val member of DTV entry. */ |
5a706f64 | 168 | cmp PTR_REG (0), #TLS_DTV_UNALLOCATED |
554066b8 | 169 | b.eq 2f |
659ca267 SN |
170 | sub PTR_REG (3), PTR_REG (3), PTR_REG (4) |
171 | add PTR_REG (0), PTR_REG (0), PTR_REG (3) | |
554066b8 | 172 | 1: |
659ca267 SN |
173 | ldp x3, x4, [sp, #16] |
174 | ldp x1, x2, [sp], #32 | |
175 | cfi_adjust_cfa_offset (-32) | |
554066b8 MS |
176 | RET |
177 | 2: | |
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. */ | |
659ca267 SN |
183 | # define NSAVEXREGPAIRS 8 |
184 | stp x29, x30, [sp,#-16*NSAVEXREGPAIRS]! | |
554066b8 | 185 | cfi_adjust_cfa_offset (16*NSAVEXREGPAIRS) |
659ca267 SN |
186 | cfi_rel_offset (x29, 0) |
187 | cfi_rel_offset (x30, 8) | |
188 | mov x29, sp | |
189 | stp x5, x6, [sp, #16*1] | |
190 | stp x7, x8, [sp, #16*2] | |
191 | stp x9, x10, [sp, #16*3] | |
192 | stp x11, x12, [sp, #16*4] | |
193 | stp x13, x14, [sp, #16*5] | |
194 | stp x15, x16, [sp, #16*6] | |
195 | stp x17, x18, [sp, #16*7] | |
196 | cfi_rel_offset (x5, 16*1) | |
197 | cfi_rel_offset (x6, 16*1+8) | |
198 | cfi_rel_offset (x7, 16*2) | |
199 | cfi_rel_offset (x8, 16*2+8) | |
200 | cfi_rel_offset (x9, 16*3) | |
201 | cfi_rel_offset (x10, 16*3+8) | |
202 | cfi_rel_offset (x11, 16*4) | |
203 | cfi_rel_offset (x12, 16*4+8) | |
204 | cfi_rel_offset (x13, 16*5) | |
205 | cfi_rel_offset (x14, 16*5+8) | |
206 | cfi_rel_offset (x15, 16*6) | |
207 | cfi_rel_offset (x16, 16*6+8) | |
208 | cfi_rel_offset (x17, 16*7) | |
209 | cfi_rel_offset (x18, 16*7+8) | |
554066b8 MS |
210 | |
211 | SAVE_Q_REGISTERS | |
212 | ||
213 | mov x0, x1 | |
214 | bl __tls_get_addr | |
215 | ||
216 | mrs x1, tpidr_el0 | |
389d1f1b | 217 | sub PTR_REG (0), PTR_REG (0), PTR_REG (1) |
554066b8 MS |
218 | |
219 | RESTORE_Q_REGISTERS | |
220 | ||
659ca267 SN |
221 | ldp x5, x6, [sp, #16*1] |
222 | ldp x7, x8, [sp, #16*2] | |
223 | ldp x9, x10, [sp, #16*3] | |
224 | ldp x11, x12, [sp, #16*4] | |
225 | ldp x13, x14, [sp, #16*5] | |
226 | ldp x15, x16, [sp, #16*6] | |
227 | ldp x17, x18, [sp, #16*7] | |
228 | ||
229 | ldp x29, x30, [sp], #16*NSAVEXREGPAIRS | |
554066b8 | 230 | cfi_adjust_cfa_offset (-16*NSAVEXREGPAIRS) |
659ca267 SN |
231 | cfi_restore (x29) |
232 | cfi_restore (x30) | |
554066b8 MS |
233 | b 1b |
234 | cfi_endproc | |
235 | .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic | |
236 | # undef NSAVEXREGPAIRS | |
237 | #endif |