stdlib: Implement introsort for qsort (BZ 19305)
[glibc.git] / sysdeps / aarch64 / dl-trampoline.S
bloba3474ba741a8d2c5679e4e86ff81a4c62a448e38
1 /* Copyright (C) 2005-2023 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
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.
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.
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/>.  */
19 #include <sysdep.h>
20 #include <libc-symbols.h>
22 #include "dl-link.h"
24 #define ip0 x16
25 #define ip0l PTR_REG (16)
26 #define ip1 x17
27 #define lr  x30
29 /* RELA relocatons are 3 pointers */
30 #define RELA_SIZE (PTR_SIZE * 3)
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          */
46         cfi_rel_offset (lr, 8)
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)
55         stp     x6, x7, [sp,  #16]
56         cfi_rel_offset (x6, 16)
57         cfi_rel_offset (x7, 24)
59         stp     x4, x5, [sp,  #32]
60         cfi_rel_offset (x4, 32)
61         cfi_rel_offset (x5, 40)
63         stp     x2, x3, [sp,  #48]
64         cfi_rel_offset (x2, 48)
65         cfi_rel_offset (x3, 56)
67         stp     x0, x1, [sp,  #64]
68         cfi_rel_offset (x0, 64)
69         cfi_rel_offset (x1, 72)
71         stp     q0, q1, [sp, #(80+0*16)]
72         cfi_rel_offset (q0, 80+0*16)
73         cfi_rel_offset (q1, 80+1*16)
75         stp     q2, q3, [sp, #(80+2*16)]
76         cfi_rel_offset (q0, 80+2*16)
77         cfi_rel_offset (q1, 80+3*16)
79         stp     q4, q5, [sp, #(80+4*16)]
80         cfi_rel_offset (q0, 80+4*16)
81         cfi_rel_offset (q1, 80+5*16)
83         stp     q6, q7, [sp, #(80+6*16)]
84         cfi_rel_offset (q0, 80+6*16)
85         cfi_rel_offset (q1, 80+7*16)
87         /* Get pointer to linker struct.  */
88         ldr     PTR_REG (0), [ip0, #-PTR_SIZE]
90         /* Prepare to call _dl_fixup().  */
91         ldr     x1, [sp, 80+8*16]       /* Recover &PLTGOT[n] */
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
99         /* Call fixup routine.  */
100         bl      _dl_fixup
102         /* Save the return.  */
103         mov     ip0, x0
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))
117         ldp     ip1, lr, [sp], #16
118         cfi_adjust_cfa_offset (-16)
120         /* Jump to the newly found address.  */
121         br      ip0
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]
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          */
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
161 # define SF_SIZE                OFFSET_RG + DL_SIZEOF_RG
163 # define OFFSET_PLTGOTN         SF_SIZE
164 # define OFFSET_LR              OFFSET_PLTGOTN + 8
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)
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 */
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)
204         /* No APCS extension supported.  */
205         str     xzr,    [X29, #OFFSET_RG + DL_OFFSET_RG_VPCS]
207         add     x0, x29, #SF_SIZE + 16
208         ldr     x1, [x29, #OFFSET_LR]
209         stp     x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_SP]
211         /* Get pointer to linker struct.  */
212         ldr     PTR_REG (0), [ip0, #-PTR_SIZE]
214         /* Prepare to call _dl_profile_fixup().  */
215         ldr     x1, [x29, OFFSET_PLTGOTN]       /* Recover &PLTGOT[n] */
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
223         stp     x0, x1, [x29, #OFFSET_SAVED_CALL_X0]
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
231         ldr     ip0l, [x29, #OFFSET_FS]         /* framesize == 0 */
232         cmp     ip0l, #0
233         bge     1f
234         cfi_remember_state
236         /* Save the return.  */
237         mov     ip0, x0
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]
250         cfi_def_cfa_register (sp)
251         ldp     x29, x30, [x29, #0]
252         cfi_restore(x29)
253         cfi_restore(x30)
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
267         /* Jump to the newly found address.  */
268         br      ip0
270         cfi_restore_state
272         /* The new frame size is in ip0.  */
274         sub     PTR_REG (1), PTR_REG (29), ip0l
275         and     sp, x1, #0xfffffffffffffff0
277         str     x0, [x29, #OFFSET_T1]
279         mov     x0, sp
280         add     x1, x29, #SF_SIZE + 16
281         mov     x2, ip0
282         bl      memcpy
284         ldr     ip0, [x29, #OFFSET_T1]
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]
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
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]
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)
336         br      lr
338         cfi_endproc
339         .size _dl_runtime_profile, .-_dl_runtime_profile
340 #endif
341         .previous