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>
34 /* GCC 4.8 provides __ARM_ARCH; construct it otherwise. */
36 # if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
37 || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
38 || defined(__ARM_ARCH_7EM__)
40 # elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
41 || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
42 || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
43 || defined(__ARM_ARCH_6M__)
45 # elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
46 || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
47 || defined(__ARM_ARCH_5TEJ__)
54 /* Conditionally compile unwinder directives. */
55 .macro UNWIND text:vararg
60 #if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__)
61 .cfi_sections .debug_frame
64 #define CONCAT(a, b) CONCAT2(a, b)
65 #define CONCAT2(a, b) a ## b
67 #ifdef __USER_LABEL_PREFIX__
68 # define CNAME(X) CONCAT (__USER_LABEL_PREFIX__, X)
73 # define SIZE(X) .size CNAME(X), . - CNAME(X)
74 # define TYPE(X, Y) .type CNAME(X), Y
80 #define ARM_FUNC_START(name, gl) \
82 .ifne gl; .globl CNAME(name); FFI_HIDDEN(CNAME(name)); .endif; \
83 TYPE(name, %function); \
86 #define ARM_FUNC_END(name) \
89 /* Aid in defining a jump table with 8 bytes between entries. */
92 .error "type table out of sync"
100 /* We require interworking on LDM, which implies ARMv5T,
101 which implies the existance of BLX. */
104 /* Note that we use STC and LDC to encode VFP instructions,
105 so that we do not need ".fpu vfp", nor get that added to
106 the object file attributes. These will not be executed
107 unless the FFI_VFP abi is used. */
114 ARM_FUNC_START(ffi_call_VFP, 1)
118 cmp r3, #3 @ load only d0 if possible
119 ldcle p11, cr0, [r0] @ vldrle d0, [sp]
120 ldcgt p11, cr0, [r0], {16} @ vldmgt sp, {d0-d7}
121 add r0, r0, #64 @ discard the vfp register args
123 ARM_FUNC_END(ffi_call_VFP)
125 ARM_FUNC_START(ffi_call_SYSV, 1)
129 @ This is a bit of a lie wrt the origin of the unwind info, but
130 @ now we've got the usual frame pointer and two saved registers.
134 cfi_rel_offset(fp, 0)
135 cfi_rel_offset(lr, 4)
137 mov sp, r0 @ install the stack pointer
138 mov lr, r2 @ move the fn pointer out of the way
139 ldr ip, [fp, #16] @ install the static chain
140 ldmia sp!, {r0-r3} @ move first 4 parameters in registers.
143 @ Load r2 with the pointer to storage for the return value
144 @ Load r3 with the return type code
148 @ Deallocate the stack with the arguments.
150 cfi_def_cfa_register(sp)
152 @ Store values stored in registers.
154 add pc, pc, r3, lsl #3
158 stc p10, cr0, [r2] @ vstr s0, [r2]
161 stc p11, cr0, [r2] @ vstr d0, [r2]
164 stc p11, cr0, [r2], {8} @ vstm r2, {d0-d3}
180 ARM_FUNC_END(ffi_call_SYSV)
184 int ffi_closure_inner_* (cif, fun, user_data, frame)
187 ARM_FUNC_START(ffi_go_closure_SYSV, 1)
189 stmdb sp!, {r0-r3} @ save argument regs
190 cfi_adjust_cfa_offset(16)
191 ldr r0, [ip, #4] @ load cif
192 ldr r1, [ip, #8] @ load fun
193 mov r2, ip @ load user_data
196 ARM_FUNC_END(ffi_go_closure_SYSV)
198 ARM_FUNC_START(ffi_closure_SYSV, 1)
201 stmdb sp!, {r0-r3} @ save argument regs
202 cfi_adjust_cfa_offset(16)
203 ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif
204 ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun
205 ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data
207 add ip, sp, #16 @ compute entry sp
208 sub sp, sp, #64+32 @ allocate frame
209 cfi_adjust_cfa_offset(64+32)
212 /* Remember that EABI unwind info only applies at call sites.
213 We need do nothing except note the save of the stack pointer
214 and the link registers. */
216 cfi_adjust_cfa_offset(8)
217 cfi_rel_offset(lr, 4)
219 add r3, sp, #8 @ load frame
220 bl CNAME(ffi_closure_inner_SYSV)
222 @ Load values returned in registers.
223 add r2, sp, #8+64 @ load result
224 adr r3, CNAME(ffi_closure_ret)
225 add pc, r3, r0, lsl #3
228 ARM_FUNC_END(ffi_closure_SYSV)
230 ARM_FUNC_START(ffi_go_closure_VFP, 1)
232 stmdb sp!, {r0-r3} @ save argument regs
233 cfi_adjust_cfa_offset(16)
234 ldr r0, [ip, #4] @ load cif
235 ldr r1, [ip, #8] @ load fun
236 mov r2, ip @ load user_data
239 ARM_FUNC_END(ffi_go_closure_VFP)
241 ARM_FUNC_START(ffi_closure_VFP, 1)
244 stmdb sp!, {r0-r3} @ save argument regs
245 cfi_adjust_cfa_offset(16)
246 ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif
247 ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun
248 ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data
251 sub sp, sp, #64+32 @ allocate frame
252 cfi_adjust_cfa_offset(64+32)
253 stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7}
258 cfi_adjust_cfa_offset(8)
259 cfi_rel_offset(lr, 4)
261 add r3, sp, #8 @ load frame
262 bl CNAME(ffi_closure_inner_VFP)
264 @ Load values returned in registers.
265 add r2, sp, #8+64 @ load result
266 adr r3, CNAME(ffi_closure_ret)
267 add pc, r3, r0, lsl #3
270 ARM_FUNC_END(ffi_closure_VFP)
272 /* Load values returned in registers for both closure entry points.
273 Note that we use LDM with SP in the register set. This is deprecated
274 by ARM, but not yet unpredictable. */
276 ARM_FUNC_START(ffi_closure_ret, 0)
278 cfi_rel_offset(sp, 0)
279 cfi_rel_offset(lr, 4)
282 ldc p10, cr0, [r2] @ vldr s0, [r2]
285 ldc p11, cr0, [r2] @ vldr d0, [r2]
288 ldc p11, cr0, [r2], {8} @ vldm r2, {d0-d3}
302 ARM_FUNC_END(ffi_closure_ret)
304 #if FFI_EXEC_TRAMPOLINE_TABLE
306 /* ??? The iOS support should be updated. The first insn used to
307 be STMFD, but that's been moved into ffi_closure_SYSV. If the
308 writable page is put after this one we can make use of the
309 pc+8 feature of the architecture. We can also reduce the size
310 of the thunk to 8 and pack more of these into the page.
312 In the meantime, simply replace the STMFD with a NOP so as to
313 keep all the magic numbers the same within ffi.c. */
316 ARM_FUNC_START(ffi_closure_trampoline_table_page)
325 ARM_FUNC_START(ffi_arm_trampoline, 1)
329 ARM_FUNC_END(ffi_arm_trampoline)
331 #endif /* FFI_EXEC_TRAMPOLINE_TABLE */
333 #if defined __ELF__ && defined __linux__
334 .section .note.GNU-stack,"",%progbits