1 /* -----------------------------------------------------------------------
2 sysv.S - Copyright (c) 1998, 2008 Red Hat, Inc.
4 ARM Foreign Function Interface
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 ``Software''), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 DEALINGS IN THE SOFTWARE.
25 ----------------------------------------------------------------------- */
28 #include <fficonfig.h>
30 #ifdef HAVE_MACHINE_ASM_H
31 #include <machine/asm.h>
33 #ifdef __USER_LABEL_PREFIX__
34 #define CONCAT1(a, b) CONCAT2(a, b)
35 #define CONCAT2(a, b) a ## b
37 /* Use the right prefix for global labels. */
38 #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
42 #define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
51 /* We need a better way of testing for this, but for now, this is all
53 @ This selects the minimum architecture level required.
54 #define __ARM_ARCH__ 3
56 #if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
58 # define __ARM_ARCH__ 4
61 #if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
62 || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
63 || defined(__ARM_ARCH_5TEJ__)
65 # define __ARM_ARCH__ 5
68 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
69 || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
70 || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
71 || defined(__ARM_ARCH_6M__)
73 # define __ARM_ARCH__ 6
76 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
77 || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
78 || defined(__ARM_ARCH_7EM__)
80 # define __ARM_ARCH__ 7
84 # define call_reg(x) blx x
85 #elif defined (__ARM_ARCH_4T__)
86 # define call_reg(x) mov lr, pc ; bx x
87 # if defined(__thumb__) || defined(__THUMB_INTERWORK__)
88 # define __INTERWORKING__
91 # define call_reg(x) mov lr, pc ; mov pc, x
94 /* Conditionally compile unwinder directives. */
102 #if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
103 .macro ARM_FUNC_START name
113 /* A hook to tell gdb that we've switched to ARM mode. Also used to call
114 directly from other local arm routines. */
118 .macro ARM_FUNC_START name
127 .macro RETLDM regs=, cond=, dirn=ia
128 #if defined (__INTERWORKING__)
130 ldr\cond lr, [sp], #4
132 ldm\cond\dirn sp!, {\regs, lr}
137 ldr\cond pc, [sp], #4
139 ldm\cond\dirn sp!, {\regs, pc}
152 @ This assumes we are using gas.
153 ARM_FUNC_START ffi_call_SYSV
155 stmfd sp!, {r0-r3, fp, lr}
156 UNWIND .save {r0-r3, fp, lr}
161 @ Make room for all of the new args.
164 @ Place all of the ffi_prep_args in position
169 @ Call ffi_prep_args(stack, &ecif)
172 @ move first 4 parameters in registers
185 @ Remove the space we pushed for the args
188 @ Load r2 with the pointer to storage for the return value
191 @ Load r3 with the return type code
194 @ If the return value pointer is NULL, assume no return value.
199 cmp r3, #FFI_TYPE_INT
200 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
201 cmpne r3, #FFI_TYPE_FLOAT
207 cmp r3, #FFI_TYPE_SINT64
208 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
209 cmpne r3, #FFI_TYPE_DOUBLE
213 #if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
217 cmp r3, #FFI_TYPE_FLOAT
221 @ return DOUBLE or LONGDOUBLE
222 cmp r3, #FFI_TYPE_DOUBLE
231 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
234 unsigned int FFI_HIDDEN
235 ffi_closure_SYSV_inner (closure, respp, args)
236 ffi_closure *closure;
241 ARM_FUNC_START ffi_closure_SYSV
245 UNWIND .save {r0, lr}
251 bl ffi_closure_SYSV_inner
252 cmp r0, #FFI_TYPE_INT
255 cmp r0, #FFI_TYPE_FLOAT
256 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
262 cmp r0, #FFI_TYPE_DOUBLE
263 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
269 cmp r0, #FFI_TYPE_LONGDOUBLE
270 #if defined(__SOFTFP__) || defined(__ARM_EABI__)
276 cmp r0, #FFI_TYPE_SINT64
289 #if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
301 .ffi_closure_SYSV_end:
303 .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
305 #if defined __ELF__ && defined __linux__
306 .section .note.GNU-stack,"",%progbits