]> git.ipfire.org Git - thirdparty/gcc.git/blame - libffi/src/aarch64/sysv.S
Merge with upstream libffi db1b34b7e1f5e473d17557e454a29933dfecd1af
[thirdparty/gcc.git] / libffi / src / aarch64 / sysv.S
CommitLineData
b4b575ce
AG
1/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
2
3Permission is hereby granted, free of charge, to any person obtaining
4a copy of this software and associated documentation files (the
5``Software''), to deal in the Software without restriction, including
6without limitation the rights to use, copy, modify, merge, publish,
7distribute, sublicense, and/or sell copies of the Software, and to
8permit persons to whom the Software is furnished to do so, subject to
9the following conditions:
10
11The above copyright notice and this permission notice shall be
12included in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
15EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
21
22#define LIBFFI_ASM
23#include <fficonfig.h>
24#include <ffi.h>
b1760f7f
RH
25#include <ffi_cfi.h>
26#include "internal.h"
27
28#ifdef HAVE_MACHINE_ASM_H
29#include <machine/asm.h>
30#else
31#ifdef __USER_LABEL_PREFIX__
32#define CONCAT1(a, b) CONCAT2(a, b)
33#define CONCAT2(a, b) a ## b
34
35/* Use the right prefix for global labels. */
36#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
37#else
38#define CNAME(x) x
39#endif
40#endif
41
42#ifdef __AARCH64EB__
43# define BE(X) X
44#else
45# define BE(X) 0
46#endif
47
48 .text
49 .align 4
50
51/* ffi_call_SYSV
52 extern void ffi_call_SYSV (void *stack, void *frame,
53 void (*fn)(void), void *rvalue,
54 int flags, void *closure);
b4b575ce
AG
55
56 Therefore on entry we have:
57
b1760f7f
RH
58 x0 stack
59 x1 frame
60 x2 fn
61 x3 rvalue
62 x4 flags
63 x5 closure
64*/
65
66 cfi_startproc
67CNAME(ffi_call_SYSV):
68 /* Use a stack frame allocated by our caller. */
69 cfi_def_cfa(x1, 32);
70 stp x29, x30, [x1]
71 mov x29, x1
72 mov sp, x0
73 cfi_def_cfa_register(x29)
74 cfi_rel_offset (x29, 0)
75 cfi_rel_offset (x30, 8)
76
77 mov x9, x2 /* save fn */
78 mov x8, x3 /* install structure return */
79#ifdef FFI_GO_CLOSURES
80 mov x18, x5 /* install static chain */
81#endif
82 stp x3, x4, [x29, #16] /* save rvalue and flags */
83
84 /* Load the vector argument passing registers, if necessary. */
85 tbz w4, #AARCH64_FLAG_ARG_V_BIT, 1f
86 ldp q0, q1, [sp, #0]
87 ldp q2, q3, [sp, #32]
88 ldp q4, q5, [sp, #64]
89 ldp q6, q7, [sp, #96]
b4b575ce 901:
b1760f7f
RH
91 /* Load the core argument passing registers, including
92 the structure return pointer. */
93 ldp x0, x1, [sp, #16*N_V_ARG_REG + 0]
94 ldp x2, x3, [sp, #16*N_V_ARG_REG + 16]
95 ldp x4, x5, [sp, #16*N_V_ARG_REG + 32]
96 ldp x6, x7, [sp, #16*N_V_ARG_REG + 48]
b4b575ce 97
b1760f7f
RH
98 /* Deallocate the context, leaving the stacked arguments. */
99 add sp, sp, #CALL_CONTEXT_SIZE
b4b575ce 100
b1760f7f 101 blr x9 /* call fn */
b4b575ce 102
b1760f7f 103 ldp x3, x4, [x29, #16] /* reload rvalue and flags */
b4b575ce 104
b1760f7f
RH
105 /* Partially deconstruct the stack frame. */
106 mov sp, x29
107 cfi_def_cfa_register (sp)
108 ldp x29, x30, [x29]
109
110 /* Save the return value as directed. */
111 adr x5, 0f
112 and w4, w4, #AARCH64_RET_MASK
113 add x5, x5, x4, lsl #3
114 br x5
115
116 /* Note that each table entry is 2 insns, and thus 8 bytes.
117 For integer data, note that we're storing into ffi_arg
118 and therefore we want to extend to 64 bits; these types
119 have two consecutive entries allocated for them. */
120 .align 4
1210: ret /* VOID */
122 nop
1231: str x0, [x3] /* INT64 */
124 ret
1252: stp x0, x1, [x3] /* INT128 */
126 ret
1273: brk #1000 /* UNUSED */
128 ret
1294: brk #1000 /* UNUSED */
130 ret
1315: brk #1000 /* UNUSED */
132 ret
1336: brk #1000 /* UNUSED */
134 ret
1357: brk #1000 /* UNUSED */
136 ret
ed4bf691 1378: st4 { v0.s, v1.s, v2.s, v3.s }[0], [x3] /* S4 */
b1760f7f 138 ret
ed4bf691 1399: st3 { v0.s, v1.s, v2.s }[0], [x3] /* S3 */
b1760f7f
RH
140 ret
14110: stp s0, s1, [x3] /* S2 */
142 ret
14311: str s0, [x3] /* S1 */
144 ret
ed4bf691 14512: st4 { v0.d, v1.d, v2.d, v3.d }[0], [x3] /* D4 */
b1760f7f 146 ret
ed4bf691 14713: st3 { v0.d, v1.d, v2.d }[0], [x3] /* D3 */
b1760f7f
RH
148 ret
14914: stp d0, d1, [x3] /* D2 */
150 ret
15115: str d0, [x3] /* D1 */
152 ret
15316: str q3, [x3, #48] /* Q4 */
154 nop
15517: str q2, [x3, #32] /* Q3 */
156 nop
15718: stp q0, q1, [x3] /* Q2 */
158 ret
15919: str q0, [x3] /* Q1 */
160 ret
16120: uxtb w0, w0 /* UINT8 */
162 str x0, [x3]
16321: ret /* reserved */
164 nop
16522: uxth w0, w0 /* UINT16 */
166 str x0, [x3]
16723: ret /* reserved */
168 nop
16924: mov w0, w0 /* UINT32 */
170 str x0, [x3]
17125: ret /* reserved */
172 nop
17326: sxtb x0, w0 /* SINT8 */
174 str x0, [x3]
17527: ret /* reserved */
176 nop
17728: sxth x0, w0 /* SINT16 */
178 str x0, [x3]
17929: ret /* reserved */
180 nop
18130: sxtw x0, w0 /* SINT32 */
182 str x0, [x3]
18331: ret /* reserved */
184 nop
185
186 cfi_endproc
187
188 .globl CNAME(ffi_call_SYSV)
189#ifdef __ELF__
190 .type CNAME(ffi_call_SYSV), #function
191 .hidden CNAME(ffi_call_SYSV)
192 .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
193#endif
b4b575ce
AG
194
195/* ffi_closure_SYSV
196
197 Closure invocation glue. This is the low level code invoked directly by
198 the closure trampoline to setup and call a closure.
199
b1760f7f 200 On entry x17 points to a struct ffi_closure, x16 has been clobbered
b4b575ce
AG
201 all other registers are preserved.
202
203 We allocate a call context and save the argument passing registers,
204 then invoked the generic C ffi_closure_SYSV_inner() function to do all
205 the real work, on return we load the result passing registers back from
206 the call context.
b1760f7f
RH
207*/
208
209#define ffi_closure_SYSV_FS (8*2 + CALL_CONTEXT_SIZE + 64)
210
211 .align 4
212CNAME(ffi_closure_SYSV_V):
213 cfi_startproc
214 stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
215 cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
216 cfi_rel_offset (x29, 0)
217 cfi_rel_offset (x30, 8)
218
219 /* Save the argument passing vector registers. */
220 stp q0, q1, [sp, #16 + 0]
221 stp q2, q3, [sp, #16 + 32]
222 stp q4, q5, [sp, #16 + 64]
223 stp q6, q7, [sp, #16 + 96]
224 b 0f
225 cfi_endproc
226
227 .globl CNAME(ffi_closure_SYSV_V)
228#ifdef __ELF__
229 .type CNAME(ffi_closure_SYSV_V), #function
230 .hidden CNAME(ffi_closure_SYSV_V)
231 .size CNAME(ffi_closure_SYSV_V), . - CNAME(ffi_closure_SYSV_V)
232#endif
233
234 .align 4
235 cfi_startproc
236CNAME(ffi_closure_SYSV):
237 stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
238 cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
239 cfi_rel_offset (x29, 0)
240 cfi_rel_offset (x30, 8)
2410:
242 mov x29, sp
243
244 /* Save the argument passing core registers. */
245 stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
246 stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
247 stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
248 stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
249
250 /* Load ffi_closure_inner arguments. */
ed4bf691
RH
251 ldp x0, x1, [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET] /* load cif, fn */
252 ldr x2, [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET+16] /* load user_data */
b1760f7f
RH
253.Ldo_closure:
254 add x3, sp, #16 /* load context */
255 add x4, sp, #ffi_closure_SYSV_FS /* load stack */
256 add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */
257 mov x6, x8 /* load struct_rval */
258 bl CNAME(ffi_closure_SYSV_inner)
259
260 /* Load the return value as directed. */
261 adr x1, 0f
262 and w0, w0, #AARCH64_RET_MASK
263 add x1, x1, x0, lsl #3
264 add x3, sp, #16+CALL_CONTEXT_SIZE
265 br x1
266
267 /* Note that each table entry is 2 insns, and thus 8 bytes. */
268 .align 4
2690: b 99f /* VOID */
270 nop
2711: ldr x0, [x3] /* INT64 */
272 b 99f
2732: ldp x0, x1, [x3] /* INT128 */
274 b 99f
2753: brk #1000 /* UNUSED */
276 nop
2774: brk #1000 /* UNUSED */
278 nop
2795: brk #1000 /* UNUSED */
280 nop
2816: brk #1000 /* UNUSED */
282 nop
2837: brk #1000 /* UNUSED */
284 nop
2858: ldr s3, [x3, #12] /* S4 */
286 nop
2879: ldr s2, [x2, #8] /* S3 */
288 nop
28910: ldp s0, s1, [x3] /* S2 */
290 b 99f
29111: ldr s0, [x3] /* S1 */
292 b 99f
29312: ldr d3, [x3, #24] /* D4 */
294 nop
29513: ldr d2, [x3, #16] /* D3 */
296 nop
29714: ldp d0, d1, [x3] /* D2 */
298 b 99f
29915: ldr d0, [x3] /* D1 */
300 b 99f
30116: ldr q3, [x3, #48] /* Q4 */
302 nop
30317: ldr q2, [x3, #32] /* Q3 */
304 nop
30518: ldp q0, q1, [x3] /* Q2 */
306 b 99f
30719: ldr q0, [x3] /* Q1 */
308 b 99f
30920: ldrb w0, [x3, #BE(7)] /* UINT8 */
310 b 99f
31121: brk #1000 /* reserved */
312 nop
31322: ldrh w0, [x3, #BE(6)] /* UINT16 */
314 b 99f
31523: brk #1000 /* reserved */
316 nop
31724: ldr w0, [x3, #BE(4)] /* UINT32 */
318 b 99f
31925: brk #1000 /* reserved */
320 nop
32126: ldrsb x0, [x3, #BE(7)] /* SINT8 */
322 b 99f
32327: brk #1000 /* reserved */
324 nop
32528: ldrsh x0, [x3, #BE(6)] /* SINT16 */
326 b 99f
32729: brk #1000 /* reserved */
328 nop
32930: ldrsw x0, [x3, #BE(4)] /* SINT32 */
330 nop
33131: /* reserved */
33299: ldp x29, x30, [sp], #ffi_closure_SYSV_FS
333 cfi_adjust_cfa_offset (-ffi_closure_SYSV_FS)
334 cfi_restore (x29)
335 cfi_restore (x30)
336 ret
337 cfi_endproc
338
339 .globl CNAME(ffi_closure_SYSV)
340#ifdef __ELF__
341 .type CNAME(ffi_closure_SYSV), #function
342 .hidden CNAME(ffi_closure_SYSV)
343 .size CNAME(ffi_closure_SYSV), . - CNAME(ffi_closure_SYSV)
344#endif
345
ed4bf691
RH
346#if FFI_EXEC_TRAMPOLINE_TABLE
347 .align 12
348CNAME(ffi_closure_trampoline_table_page):
349 .rept 16384 / FFI_TRAMPOLINE_SIZE
350 adr x17, -16384
351 adr x16, -16380
352 ldr x16, [x16]
353 ldr x17, [x17]
354 br x16
355 .endr
356
357 .globl CNAME(ffi_closure_trampoline_table_page)
358 #ifdef __ELF__
359 .type CNAME(ffi_closure_trampoline_table_page), #function
360 .hidden CNAME(ffi_closure_trampoline_table_page)
361 .size CNAME(ffi_closure_trampoline_table_page), . - CNAME(ffi_closure_trampoline_table_page)
362 #endif
363#endif
364
b1760f7f
RH
365#ifdef FFI_GO_CLOSURES
366 .align 4
367CNAME(ffi_go_closure_SYSV_V):
368 cfi_startproc
369 stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
370 cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
371 cfi_rel_offset (x29, 0)
372 cfi_rel_offset (x30, 8)
373
374 /* Save the argument passing vector registers. */
375 stp q0, q1, [sp, #16 + 0]
376 stp q2, q3, [sp, #16 + 32]
377 stp q4, q5, [sp, #16 + 64]
378 stp q6, q7, [sp, #16 + 96]
379 b 0f
380 cfi_endproc
381
382 .globl CNAME(ffi_go_closure_SYSV_V)
383#ifdef __ELF__
384 .type CNAME(ffi_go_closure_SYSV_V), #function
385 .hidden CNAME(ffi_go_closure_SYSV_V)
386 .size CNAME(ffi_go_closure_SYSV_V), . - CNAME(ffi_go_closure_SYSV_V)
387#endif
388
389 .align 4
390 cfi_startproc
391CNAME(ffi_go_closure_SYSV):
392 stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
393 cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
394 cfi_rel_offset (x29, 0)
395 cfi_rel_offset (x30, 8)
3960:
397 mov x29, sp
398
399 /* Save the argument passing core registers. */
400 stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
401 stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
402 stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
403 stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
404
405 /* Load ffi_closure_inner arguments. */
406 ldp x0, x1, [x18, #8] /* load cif, fn */
407 mov x2, x18 /* load user_data */
408 b .Ldo_closure
409 cfi_endproc
410
411 .globl CNAME(ffi_go_closure_SYSV)
412#ifdef __ELF__
413 .type CNAME(ffi_go_closure_SYSV), #function
414 .hidden CNAME(ffi_go_closure_SYSV)
415 .size CNAME(ffi_go_closure_SYSV), . - CNAME(ffi_go_closure_SYSV)
416#endif
417#endif /* FFI_GO_CLOSURES */
418
419#if defined __ELF__ && defined __linux__
420 .section .note.GNU-stack,"",%progbits
421#endif
b4b575ce 422