1 | /* Copyright (C) 2005-2022 Free Software Foundation, Inc. |
2 | |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public License as |
7 | published by the Free Software Foundation; either version 2.1 of the |
8 | License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library. If not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <sysdep.h> |
20 | #include <libc-symbols.h> |
21 | |
22 | #include "dl-link.h" |
23 | |
24 | #define ip0 x16 |
25 | #define ip0l PTR_REG (16) |
26 | #define ip1 x17 |
27 | #define lr x30 |
28 | |
29 | /* RELA relocatons are 3 pointers */ |
30 | #define RELA_SIZE (PTR_SIZE * 3) |
31 | |
32 | .text |
33 | .globl _dl_runtime_resolve |
34 | .type _dl_runtime_resolve, #function |
35 | cfi_startproc |
36 | .align 2 |
37 | _dl_runtime_resolve: |
38 | BTI_C |
39 | /* AArch64 we get called with: |
40 | ip0 &PLTGOT[2] |
41 | ip1 temp(dl resolver entry point) |
42 | [sp, #8] lr |
43 | [sp, #0] &PLTGOT[n] |
44 | */ |
45 | |
46 | cfi_rel_offset (lr, 8) |
47 | |
48 | /* Note: Saving x9 is not required by the ABI but the assembler requires |
49 | the immediate values of operand 3 to be a multiple of 16 */ |
50 | stp x8, x9, [sp, #-(80+8*16)]! |
51 | cfi_adjust_cfa_offset (80+8*16) |
52 | cfi_rel_offset (x8, 0) |
53 | cfi_rel_offset (x9, 8) |
54 | |
55 | stp x6, x7, [sp, #16] |
56 | cfi_rel_offset (x6, 16) |
57 | cfi_rel_offset (x7, 24) |
58 | |
59 | stp x4, x5, [sp, #32] |
60 | cfi_rel_offset (x4, 32) |
61 | cfi_rel_offset (x5, 40) |
62 | |
63 | stp x2, x3, [sp, #48] |
64 | cfi_rel_offset (x2, 48) |
65 | cfi_rel_offset (x3, 56) |
66 | |
67 | stp x0, x1, [sp, #64] |
68 | cfi_rel_offset (x0, 64) |
69 | cfi_rel_offset (x1, 72) |
70 | |
71 | stp q0, q1, [sp, #(80+0*16)] |
72 | cfi_rel_offset (q0, 80+0*16) |
73 | cfi_rel_offset (q1, 80+1*16) |
74 | |
75 | stp q2, q3, [sp, #(80+2*16)] |
76 | cfi_rel_offset (q0, 80+2*16) |
77 | cfi_rel_offset (q1, 80+3*16) |
78 | |
79 | stp q4, q5, [sp, #(80+4*16)] |
80 | cfi_rel_offset (q0, 80+4*16) |
81 | cfi_rel_offset (q1, 80+5*16) |
82 | |
83 | stp q6, q7, [sp, #(80+6*16)] |
84 | cfi_rel_offset (q0, 80+6*16) |
85 | cfi_rel_offset (q1, 80+7*16) |
86 | |
87 | /* Get pointer to linker struct. */ |
88 | ldr PTR_REG (0), [ip0, #-PTR_SIZE] |
89 | |
90 | /* Prepare to call _dl_fixup(). */ |
91 | ldr x1, [sp, 80+8*16] /* Recover &PLTGOT[n] */ |
92 | |
93 | sub x1, x1, ip0 |
94 | add x1, x1, x1, lsl #1 |
95 | lsl x1, x1, #3 |
96 | sub x1, x1, #(RELA_SIZE<<3) |
97 | lsr x1, x1, #3 |
98 | |
99 | /* Call fixup routine. */ |
100 | bl _dl_fixup |
101 | |
102 | /* Save the return. */ |
103 | mov ip0, x0 |
104 | |
105 | /* Get arguments and return address back. */ |
106 | ldp q0, q1, [sp, #(80+0*16)] |
107 | ldp q2, q3, [sp, #(80+2*16)] |
108 | ldp q4, q5, [sp, #(80+4*16)] |
109 | ldp q6, q7, [sp, #(80+6*16)] |
110 | ldp x0, x1, [sp, #64] |
111 | ldp x2, x3, [sp, #48] |
112 | ldp x4, x5, [sp, #32] |
113 | ldp x6, x7, [sp, #16] |
114 | ldp x8, x9, [sp], #(80+8*16) |
115 | cfi_adjust_cfa_offset (-(80+8*16)) |
116 | |
117 | ldp ip1, lr, [sp], #16 |
118 | cfi_adjust_cfa_offset (-16) |
119 | |
120 | /* Jump to the newly found address. */ |
121 | br ip0 |
122 | |
123 | cfi_endproc |
124 | .size _dl_runtime_resolve, .-_dl_runtime_resolve |
125 | #ifndef PROF |
126 | .globl _dl_runtime_profile |
127 | .type _dl_runtime_profile, #function |
128 | cfi_startproc |
129 | .align 2 |
130 | _dl_runtime_profile: |
131 | # if HAVE_AARCH64_PAC_RET |
132 | PACIASP |
133 | cfi_window_save |
134 | # else |
135 | BTI_C |
136 | # endif |
137 | /* AArch64 we get called with: |
138 | ip0 &PLTGOT[2] |
139 | ip1 temp(dl resolver entry point) |
140 | [sp, #8] lr |
141 | [sp, #0] &PLTGOT[n] |
142 | |
143 | Stack frame layout: |
144 | [sp, #...] lr |
145 | [sp, #...] &PLTGOT[n] |
146 | [sp, #256] La_aarch64_regs |
147 | [sp, #48] La_aarch64_retval |
148 | [sp, #40] frame size return from pltenter |
149 | [sp, #32] dl_profile_call saved x1 |
150 | [sp, #24] dl_profile_call saved x0 |
151 | [sp, #16] t1 |
152 | [sp, #0] x29, lr <- x29 |
153 | */ |
154 | |
155 | # define OFFSET_T1 16 |
156 | # define OFFSET_SAVED_CALL_X0 OFFSET_T1 + 8 |
157 | # define OFFSET_FS OFFSET_SAVED_CALL_X0 + 16 |
158 | # define OFFSET_RV OFFSET_FS + 8 |
159 | # define OFFSET_RG OFFSET_RV + DL_SIZEOF_RV |
160 | |
161 | # define SF_SIZE OFFSET_RG + DL_SIZEOF_RG |
162 | |
163 | # define OFFSET_PLTGOTN SF_SIZE |
164 | # define OFFSET_LR OFFSET_PLTGOTN + 8 |
165 | |
166 | /* Save arguments. */ |
167 | sub sp, sp, #SF_SIZE |
168 | cfi_adjust_cfa_offset (SF_SIZE) |
169 | stp x29, x30, [SP, #0] |
170 | mov x29, sp |
171 | cfi_def_cfa_register (x29) |
172 | cfi_rel_offset (x29, 0) |
173 | cfi_rel_offset (lr, 8) |
174 | |
175 | stp x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*0] |
176 | cfi_rel_offset (x0, OFFSET_RG + DL_OFFSET_RG_X0 + 16*0 + 0) |
177 | cfi_rel_offset (x1, OFFSET_RG + DL_OFFSET_RG_X0 + 16*0 + 8) |
178 | stp x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1] |
179 | cfi_rel_offset (x2, OFFSET_RG + DL_OFFSET_RG_X0 + 16*1 + 0) |
180 | cfi_rel_offset (x3, OFFSET_RG + DL_OFFSET_RG_X0 + 16*1 + 8) |
181 | stp x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2] |
182 | cfi_rel_offset (x4, OFFSET_RG + DL_OFFSET_RG_X0 + 16*2 + 0) |
183 | cfi_rel_offset (x5, OFFSET_RG + DL_OFFSET_RG_X0 + 16*2 + 8) |
184 | stp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] |
185 | cfi_rel_offset (x6, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 0) |
186 | cfi_rel_offset (x7, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 8) |
187 | str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4 + 0] |
188 | cfi_rel_offset (x8, OFFSET_RG + DL_OFFSET_RG_X0 + 16*4 + 0) |
189 | /* Note 8 bytes of padding is in the stack frame for alignment */ |
190 | |
191 | stp q0, q1, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0] |
192 | cfi_rel_offset (q0, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0) |
193 | cfi_rel_offset (q1, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0 + 16) |
194 | stp q2, q3, [X29, #OFFSET_RG+ DL_OFFSET_RG_V0 + 32*1] |
195 | cfi_rel_offset (q2, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 0) |
196 | cfi_rel_offset (q3, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 16) |
197 | stp q4, q5, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2] |
198 | cfi_rel_offset (q4, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 0) |
199 | cfi_rel_offset (q5, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 16) |
200 | stp q6, q7, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3] |
201 | cfi_rel_offset (q6, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 0) |
202 | cfi_rel_offset (q7, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 16) |
203 | |
204 | /* No APCS extension supported. */ |
205 | str xzr, [X29, #OFFSET_RG + DL_OFFSET_RG_VPCS] |
206 | |
207 | add x0, x29, #SF_SIZE + 16 |
208 | ldr x1, [x29, #OFFSET_LR] |
209 | stp x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_SP] |
210 | |
211 | /* Get pointer to linker struct. */ |
212 | ldr PTR_REG (0), [ip0, #-PTR_SIZE] |
213 | |
214 | /* Prepare to call _dl_profile_fixup(). */ |
215 | ldr x1, [x29, OFFSET_PLTGOTN] /* Recover &PLTGOT[n] */ |
216 | |
217 | sub x1, x1, ip0 |
218 | add x1, x1, x1, lsl #1 |
219 | lsl x1, x1, #3 |
220 | sub x1, x1, #(RELA_SIZE<<3) |
221 | lsr x1, x1, #3 |
222 | |
223 | stp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] |
224 | |
225 | /* Set up extra args for _dl_profile_fixup */ |
226 | ldr x2, [x29, #OFFSET_LR] /* load saved LR */ |
227 | add x3, x29, #OFFSET_RG /* address of La_aarch64_reg */ |
228 | add x4, x29, #OFFSET_FS /* address of framesize */ |
229 | bl _dl_profile_fixup |
230 | |
231 | ldr ip0l, [x29, #OFFSET_FS] /* framesize == 0 */ |
232 | cmp ip0l, #0 |
233 | bge 1f |
234 | cfi_remember_state |
235 | |
236 | /* Save the return. */ |
237 | mov ip0, x0 |
238 | |
239 | /* Get arguments and return address back. */ |
240 | ldp x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*0] |
241 | ldp x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1] |
242 | ldp x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2] |
243 | ldp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] |
244 | ldr x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] |
245 | ldp q0, q1, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0] |
246 | ldp q2, q3, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1] |
247 | ldp q4, q5, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2] |
248 | ldp q6, q7, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3] |
249 | |
250 | cfi_def_cfa_register (sp) |
251 | ldp x29, x30, [x29, #0] |
252 | cfi_restore(x29) |
253 | cfi_restore(x30) |
254 | |
255 | # if HAVE_AARCH64_PAC_RET |
256 | add sp, sp, SF_SIZE |
257 | cfi_adjust_cfa_offset (-SF_SIZE) |
258 | AUTIASP |
259 | cfi_window_save |
260 | add sp, sp, 16 |
261 | cfi_adjust_cfa_offset (-16) |
262 | # else |
263 | add sp, sp, SF_SIZE + 16 |
264 | cfi_adjust_cfa_offset (- SF_SIZE - 16) |
265 | # endif |
266 | |
267 | /* Jump to the newly found address. */ |
268 | br ip0 |
269 | |
270 | cfi_restore_state |
271 | 1: |
272 | /* The new frame size is in ip0. */ |
273 | |
274 | sub PTR_REG (1), PTR_REG (29), ip0l |
275 | and sp, x1, #0xfffffffffffffff0 |
276 | |
277 | str x0, [x29, #OFFSET_T1] |
278 | |
279 | mov x0, sp |
280 | add x1, x29, #SF_SIZE + 16 |
281 | mov x2, ip0 |
282 | bl memcpy |
283 | |
284 | ldr ip0, [x29, #OFFSET_T1] |
285 | |
286 | /* Call the function. */ |
287 | ldp x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*0] |
288 | ldp x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1] |
289 | ldp x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2] |
290 | ldp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] |
291 | ldr x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] |
292 | ldp q0, q1, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0] |
293 | ldp q2, q3, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1] |
294 | ldp q4, q5, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2] |
295 | ldp q6, q7, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3] |
296 | blr ip0 |
297 | stp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*0] |
298 | stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] |
299 | stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] |
300 | stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] |
301 | stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] |
302 | stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] |
303 | stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] |
304 | stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] |
305 | str xzr, [X29, #OFFSET_RV + DL_OFFSET_RV_VPCS] |
306 | |
307 | /* Setup call to pltexit */ |
308 | ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] |
309 | add x2, x29, #OFFSET_RG |
310 | add x3, x29, #OFFSET_RV |
311 | bl _dl_audit_pltexit |
312 | |
313 | ldp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*0] |
314 | ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] |
315 | ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] |
316 | ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] |
317 | ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] |
318 | ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] |
319 | ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] |
320 | ldp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] |
321 | |
322 | /* LR from within La_aarch64_reg */ |
323 | ldr lr, [x29, #OFFSET_RG + DL_OFFSET_RG_LR] |
324 | cfi_restore(lr) |
325 | # if HAVE_AARCH64_PAC_RET |
326 | /* Note: LR restored from La_aarch64_reg has no PAC. */ |
327 | cfi_window_save |
328 | # endif |
329 | mov sp, x29 |
330 | cfi_def_cfa_register (sp) |
331 | ldr x29, [x29, #0] |
332 | cfi_restore(x29) |
333 | add sp, sp, SF_SIZE + 16 |
334 | cfi_adjust_cfa_offset (- SF_SIZE - 16) |
335 | |
336 | br lr |
337 | |
338 | cfi_endproc |
339 | .size _dl_runtime_profile, .-_dl_runtime_profile |
340 | #endif |
341 | .previous |
342 | |