1 /* -----------------------------------------------------------------------
2 sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
3 Copyright (c) 2011 Plausible Labs Cooperative, Inc.
5 ARM Foreign Function Interface
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 ``Software''), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 ----------------------------------------------------------------------- */
29 #include <fficonfig.h>
31 #ifdef HAVE_MACHINE_ASM_H
32 #include <machine/asm.h>
34 #ifdef __USER_LABEL_PREFIX__
35 #define CONCAT1(a, b) CONCAT2(a, b)
36 #define CONCAT2(a, b) a ## b
38 /* Use the right prefix for global labels. */
39 #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
44 #define ENTRY(x) .globl _##x; _##x:
46 #define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
47 #endif /* __APPLE__ */
56 /* Use the SOFTFP return value ABI on Mac OS X, as per the iOS ABI
57 Function Call Guide */
62 /* We need a better way of testing for this, but for now, this is all
64 @ This selects the minimum architecture level required.
65 #define __ARM_ARCH__ 3
67 #if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
69 # define __ARM_ARCH__ 4
72 #if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
73 || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
74 || defined(__ARM_ARCH_5TEJ__)
76 # define __ARM_ARCH__ 5
79 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
80 || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
81 || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
82 || defined(__ARM_ARCH_6M__)
84 # define __ARM_ARCH__ 6
87 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
88 || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
89 || defined(__ARM_ARCH_7EM__)
91 # define __ARM_ARCH__ 7
95 # define call_reg(x) blx x
96 #elif defined (__ARM_ARCH_4T__)
97 # define call_reg(x) mov lr, pc ; bx x
98 # if defined(__thumb__) || defined(__THUMB_INTERWORK__)
99 # define __INTERWORKING__
102 # define call_reg(x) mov lr, pc ; mov pc, x
105 /* Conditionally compile unwinder directives. */
113 #if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
114 .macro ARM_FUNC_START name
128 /* A hook to tell gdb that we've switched to ARM mode. Also used to call
129 directly from other local arm routines. */
137 .macro ARM_FUNC_START name
150 .macro RETLDM regs=, cond=, dirn=ia
151 #if defined (__INTERWORKING__)
153 ldr\cond lr, [sp], #4
155 ldm\cond\dirn sp!, {\regs, lr}
160 ldr\cond pc, [sp], #4
162 ldm\cond\dirn sp!, {\regs, pc}
173 @ This assumes we are using gas.
174 ARM_FUNC_START ffi_call_SYSV
176 stmfd sp!, {r0-r3, fp, lr}
177 UNWIND .save {r0-r3, fp, lr}
182 @ Make room for all of the new args.
185 @ Place all of the ffi_prep_args in position
189 @ Call ffi_prep_args(stack, &ecif)
190 bl CNAME(ffi_prep_args)
192 @ move first 4 parameters in registers
196 sub lr, fp, sp @ cif->bytes == fp - sp
197 ldr ip, [fp] @ load fn() in advance
205 @ Remove the space we pushed for the args
208 @ Load r2 with the pointer to storage for the return value
211 @ Load r3 with the return type code
214 @ If the return value pointer is NULL, assume no return value.
219 cmp r3, #FFI_TYPE_INT
220 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
221 cmpne r3, #FFI_TYPE_FLOAT
227 cmp r3, #FFI_TYPE_SINT64
228 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
229 cmpne r3, #FFI_TYPE_DOUBLE
233 #if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
237 cmp r3, #FFI_TYPE_FLOAT
241 @ return DOUBLE or LONGDOUBLE
242 cmp r3, #FFI_TYPE_DOUBLE
247 #if defined (__INTERWORKING__)
248 ldmia sp!, {r0-r3,fp, lr}
251 ldmia sp!, {r0-r3,fp, pc}
257 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
262 unsigned int FFI_HIDDEN
263 ffi_closure_SYSV_inner (closure, respp, args)
264 ffi_closure *closure;
269 ARM_FUNC_START ffi_closure_SYSV
273 UNWIND .save {r0, lr}
279 bl CNAME(ffi_closure_SYSV_inner)
280 cmp r0, #FFI_TYPE_INT
283 cmp r0, #FFI_TYPE_FLOAT
284 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
290 cmp r0, #FFI_TYPE_DOUBLE
291 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
297 cmp r0, #FFI_TYPE_LONGDOUBLE
298 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
304 cmp r0, #FFI_TYPE_SINT64
317 #if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
329 .ffi_closure_SYSV_end:
332 .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
336 /* Below are VFP hard-float ABI call and closure implementations.
337 Add VFP FPU directive here. This is only compiled into the library
348 ARM_FUNC_START ffi_call_VFP
350 stmfd sp!, {r0-r3, fp, lr}
351 UNWIND .save {r0-r3, fp, lr}
355 @ Make room for all of the new args.
358 @ Make room for loading VFP args
361 @ Place all of the ffi_prep_args in position
364 sub r2, fp, #64 @ VFP scratch space
366 @ Call ffi_prep_args(stack, &ecif, vfp_space)
367 bl CNAME(ffi_prep_args)
369 @ Load VFP register args if needed
373 @ Load only d0 if possible
377 fldmiadgt ip, {d0-d7}
380 @ move first 4 parameters in registers
384 sub lr, ip, sp @ cif->bytes == (fp - 64) - sp
385 ldr ip, [fp] @ load fn() in advance
393 @ Remove the space we pushed for the args
396 @ Load r2 with the pointer to storage for
400 @ Load r3 with the return type code
403 @ If the return value pointer is NULL,
404 @ assume no return value.
406 beq LSYM(Lepilogue_vfp)
408 cmp r3, #FFI_TYPE_INT
410 beq LSYM(Lepilogue_vfp)
412 cmp r3, #FFI_TYPE_SINT64
414 beq LSYM(Lepilogue_vfp)
416 cmp r3, #FFI_TYPE_FLOAT
418 beq LSYM(Lepilogue_vfp)
420 cmp r3, #FFI_TYPE_DOUBLE
422 beq LSYM(Lepilogue_vfp)
424 cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT
425 cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE
426 fstmiadeq r2, {d0-d3}
433 .size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP)
436 ARM_FUNC_START ffi_closure_VFP
442 UNWIND .save {r0, lr}
449 bl CNAME(ffi_closure_SYSV_inner)
451 cmp r0, #FFI_TYPE_INT
454 cmp r0, #FFI_TYPE_FLOAT
457 cmp r0, #FFI_TYPE_DOUBLE
458 cmpne r0, #FFI_TYPE_LONGDOUBLE
461 cmp r0, #FFI_TYPE_SINT64
462 beq .Lretlonglong_vfp
464 cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT
465 beq .Lretfloat_struct_vfp
467 cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE
468 beq .Lretdouble_struct_vfp
470 .Lclosure_epilogue_vfp:
476 b .Lclosure_epilogue_vfp
479 b .Lclosure_epilogue_vfp
482 b .Lclosure_epilogue_vfp
485 b .Lclosure_epilogue_vfp
486 .Lretfloat_struct_vfp:
488 b .Lclosure_epilogue_vfp
489 .Lretdouble_struct_vfp:
491 b .Lclosure_epilogue_vfp
493 .ffi_closure_VFP_end:
495 .size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP)
498 ENTRY(ffi_arm_trampoline)
503 #if defined __ELF__ && defined __linux__
504 .section .note.GNU-stack,"",%progbits