blob: 541bbe92300219fe3cbecc1e52c8e788449aaeaa [file] [log] [blame]
Thomas Hellerd4c93202006-03-08 19:35:11 +00001/* -----------------------------------------------------------------------
doko@ubuntu.com2a918762012-06-26 17:56:44 +02002 sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
3 Copyright (c) 2011 Plausible Labs Cooperative, Inc.
Thomas Hellerd4c93202006-03-08 19:35:11 +00004
5 ARM Foreign Function Interface
6
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:
14
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
17
Christian Heimes78644762008-03-04 23:39:23 +000018 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.
Thomas Hellerd4c93202006-03-08 19:35:11 +000026 ----------------------------------------------------------------------- */
27
28#define LIBFFI_ASM
29#include <fficonfig.h>
30#include <ffi.h>
31#ifdef HAVE_MACHINE_ASM_H
32#include <machine/asm.h>
33#else
34#ifdef __USER_LABEL_PREFIX__
35#define CONCAT1(a, b) CONCAT2(a, b)
36#define CONCAT2(a, b) a ## b
37
38/* Use the right prefix for global labels. */
39#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
40#else
41#define CNAME(x) x
42#endif
doko@ubuntu.com2a918762012-06-26 17:56:44 +020043#ifdef __APPLE__
44#define ENTRY(x) .globl _##x; _##x:
45#else
Thomas Hellerd4c93202006-03-08 19:35:11 +000046#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
doko@ubuntu.com2a918762012-06-26 17:56:44 +020047#endif /* __APPLE__ */
Thomas Hellerd4c93202006-03-08 19:35:11 +000048#endif
49
50#ifdef __ELF__
51#define LSYM(x) .x
52#else
53#define LSYM(x) x
54#endif
55
doko@ubuntu.com2a918762012-06-26 17:56:44 +020056/* Use the SOFTFP return value ABI on Mac OS X, as per the iOS ABI
57 Function Call Guide */
58#ifdef __APPLE__
59#define __SOFTFP__
60#endif
61
Thomas Hellerd4c93202006-03-08 19:35:11 +000062/* We need a better way of testing for this, but for now, this is all
63 we can do. */
64@ This selects the minimum architecture level required.
65#define __ARM_ARCH__ 3
66
67#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
68# undef __ARM_ARCH__
69# define __ARM_ARCH__ 4
70#endif
71
72#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
73 || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
74 || defined(__ARM_ARCH_5TEJ__)
75# undef __ARM_ARCH__
76# define __ARM_ARCH__ 5
77#endif
78
79#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
80 || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
Matthias Klosea8349752010-03-15 13:25:28 +000081 || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
82 || defined(__ARM_ARCH_6M__)
Thomas Hellerd4c93202006-03-08 19:35:11 +000083# undef __ARM_ARCH__
84# define __ARM_ARCH__ 6
85#endif
86
Matthias Klosea8349752010-03-15 13:25:28 +000087#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
88 || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
89 || defined(__ARM_ARCH_7EM__)
90# undef __ARM_ARCH__
91# define __ARM_ARCH__ 7
92#endif
93
Thomas Hellerd4c93202006-03-08 19:35:11 +000094#if __ARM_ARCH__ >= 5
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__
100# endif
101#else
102# define call_reg(x) mov lr, pc ; mov pc, x
103#endif
104
Christian Heimes78644762008-03-04 23:39:23 +0000105/* Conditionally compile unwinder directives. */
106#ifdef __ARM_EABI__
107#define UNWIND
108#else
109#define UNWIND @
110#endif
111
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200112.syntax unified
113
Thomas Hellerd4c93202006-03-08 19:35:11 +0000114#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200115#define ARM_FUNC_START(name) \
116 .text; \
117 .align 2; \
118 .thumb; \
119 .thumb_func; \
120 ENTRY(name); \
121 bx pc; \
122 nop; \
123 .arm; \
124 UNWIND .fnstart; \
125_L__##name:
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200126#else
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200127#define ARM_FUNC_START(name) \
128 .text; \
129 .align 2; \
130 .arm; \
131 ENTRY(name); \
Christian Heimes78644762008-03-04 23:39:23 +0000132 UNWIND .fnstart
Thomas Hellerd4c93202006-03-08 19:35:11 +0000133#endif
134
135.macro RETLDM regs=, cond=, dirn=ia
136#if defined (__INTERWORKING__)
137 .ifc "\regs",""
138 ldr\cond lr, [sp], #4
139 .else
140 ldm\cond\dirn sp!, {\regs, lr}
141 .endif
142 bx\cond lr
143#else
144 .ifc "\regs",""
145 ldr\cond pc, [sp], #4
146 .else
147 ldm\cond\dirn sp!, {\regs, pc}
148 .endif
149#endif
150.endm
151
Thomas Hellerd4c93202006-03-08 19:35:11 +0000152 @ r0: ffi_prep_args
153 @ r1: &ecif
154 @ r2: cif->bytes
155 @ r3: fig->flags
156 @ sp+0: ecif.rvalue
Thomas Hellerd4c93202006-03-08 19:35:11 +0000157
158 @ This assumes we are using gas.
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200159ARM_FUNC_START(ffi_call_SYSV)
Thomas Hellerd4c93202006-03-08 19:35:11 +0000160 @ Save registers
161 stmfd sp!, {r0-r3, fp, lr}
Christian Heimes78644762008-03-04 23:39:23 +0000162 UNWIND .save {r0-r3, fp, lr}
Thomas Hellerd4c93202006-03-08 19:35:11 +0000163 mov fp, sp
164
Christian Heimes78644762008-03-04 23:39:23 +0000165 UNWIND .setfp fp, sp
166
Thomas Hellerd4c93202006-03-08 19:35:11 +0000167 @ Make room for all of the new args.
168 sub sp, fp, r2
169
170 @ Place all of the ffi_prep_args in position
Thomas Hellerd4c93202006-03-08 19:35:11 +0000171 mov r0, sp
172 @ r1 already set
173
174 @ Call ffi_prep_args(stack, &ecif)
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200175 bl CNAME(ffi_prep_args_SYSV)
Thomas Hellerd4c93202006-03-08 19:35:11 +0000176
177 @ move first 4 parameters in registers
178 ldmia sp, {r0-r3}
179
180 @ and adjust stack
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200181 sub lr, fp, sp @ cif->bytes == fp - sp
182 ldr ip, [fp] @ load fn() in advance
183 cmp lr, #16
184 movhs lr, #16
185 add sp, sp, lr
Thomas Hellerd4c93202006-03-08 19:35:11 +0000186
187 @ call (fn) (...)
Thomas Hellerd4c93202006-03-08 19:35:11 +0000188 call_reg(ip)
189
190 @ Remove the space we pushed for the args
191 mov sp, fp
192
193 @ Load r2 with the pointer to storage for the return value
194 ldr r2, [sp, #24]
195
196 @ Load r3 with the return type code
197 ldr r3, [sp, #12]
198
199 @ If the return value pointer is NULL, assume no return value.
200 cmp r2, #0
201 beq LSYM(Lepilogue)
202
203@ return INT
204 cmp r3, #FFI_TYPE_INT
Matthias Klosea8349752010-03-15 13:25:28 +0000205#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Thomas Hellerd4c93202006-03-08 19:35:11 +0000206 cmpne r3, #FFI_TYPE_FLOAT
207#endif
208 streq r0, [r2]
209 beq LSYM(Lepilogue)
210
211 @ return INT64
212 cmp r3, #FFI_TYPE_SINT64
Matthias Klosea8349752010-03-15 13:25:28 +0000213#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Thomas Hellerd4c93202006-03-08 19:35:11 +0000214 cmpne r3, #FFI_TYPE_DOUBLE
215#endif
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200216 stmiaeq r2, {r0, r1}
Thomas Hellerd4c93202006-03-08 19:35:11 +0000217
Matthias Klosea8349752010-03-15 13:25:28 +0000218#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
Thomas Hellerd4c93202006-03-08 19:35:11 +0000219 beq LSYM(Lepilogue)
220
221@ return FLOAT
222 cmp r3, #FFI_TYPE_FLOAT
223 stfeqs f0, [r2]
224 beq LSYM(Lepilogue)
225
226@ return DOUBLE or LONGDOUBLE
227 cmp r3, #FFI_TYPE_DOUBLE
228 stfeqd f0, [r2]
229#endif
230
231LSYM(Lepilogue):
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200232#if defined (__INTERWORKING__)
233 ldmia sp!, {r0-r3,fp, lr}
234 bx lr
235#else
236 ldmia sp!, {r0-r3,fp, pc}
237#endif
Thomas Hellerd4c93202006-03-08 19:35:11 +0000238
239.ffi_call_SYSV_end:
Christian Heimes78644762008-03-04 23:39:23 +0000240 UNWIND .fnend
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200241#ifdef __ELF__
Thomas Hellerd4c93202006-03-08 19:35:11 +0000242 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200243#endif
244
Thomas Hellerd4c93202006-03-08 19:35:11 +0000245
Christian Heimes78644762008-03-04 23:39:23 +0000246/*
247 unsigned int FFI_HIDDEN
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200248 ffi_closure_inner (closure, respp, args)
Christian Heimes78644762008-03-04 23:39:23 +0000249 ffi_closure *closure;
250 void **respp;
251 void *args;
252*/
253
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200254ARM_FUNC_START(ffi_closure_SYSV)
Christian Heimes78644762008-03-04 23:39:23 +0000255 UNWIND .pad #16
256 add ip, sp, #16
257 stmfd sp!, {ip, lr}
258 UNWIND .save {r0, lr}
259 add r2, sp, #8
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200260 UNWIND .pad #16
Christian Heimes78644762008-03-04 23:39:23 +0000261 sub sp, sp, #16
262 str sp, [sp, #8]
263 add r1, sp, #8
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200264 bl CNAME(ffi_closure_inner)
Christian Heimes78644762008-03-04 23:39:23 +0000265 cmp r0, #FFI_TYPE_INT
266 beq .Lretint
267
268 cmp r0, #FFI_TYPE_FLOAT
Matthias Klosea8349752010-03-15 13:25:28 +0000269#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Christian Heimes78644762008-03-04 23:39:23 +0000270 beq .Lretint
271#else
272 beq .Lretfloat
273#endif
274
275 cmp r0, #FFI_TYPE_DOUBLE
Matthias Klosea8349752010-03-15 13:25:28 +0000276#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Christian Heimes78644762008-03-04 23:39:23 +0000277 beq .Lretlonglong
278#else
279 beq .Lretdouble
280#endif
281
282 cmp r0, #FFI_TYPE_LONGDOUBLE
Matthias Klosea8349752010-03-15 13:25:28 +0000283#if defined(__SOFTFP__) || defined(__ARM_EABI__)
Christian Heimes78644762008-03-04 23:39:23 +0000284 beq .Lretlonglong
285#else
286 beq .Lretlongdouble
287#endif
288
289 cmp r0, #FFI_TYPE_SINT64
290 beq .Lretlonglong
291.Lclosure_epilogue:
292 add sp, sp, #16
293 ldmfd sp, {sp, pc}
294.Lretint:
295 ldr r0, [sp]
296 b .Lclosure_epilogue
297.Lretlonglong:
298 ldr r0, [sp]
299 ldr r1, [sp, #4]
300 b .Lclosure_epilogue
301
Matthias Klosea8349752010-03-15 13:25:28 +0000302#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
Christian Heimes78644762008-03-04 23:39:23 +0000303.Lretfloat:
304 ldfs f0, [sp]
305 b .Lclosure_epilogue
306.Lretdouble:
307 ldfd f0, [sp]
308 b .Lclosure_epilogue
309.Lretlongdouble:
310 ldfd f0, [sp]
311 b .Lclosure_epilogue
312#endif
313
314.ffi_closure_SYSV_end:
315 UNWIND .fnend
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200316#ifdef __ELF__
Christian Heimes78644762008-03-04 23:39:23 +0000317 .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200318#endif
319
320
321/* Below are VFP hard-float ABI call and closure implementations.
322 Add VFP FPU directive here. This is only compiled into the library
323 under EABI. */
324#ifdef __ARM_EABI__
325 .fpu vfp
326
327 @ r0: fn
328 @ r1: &ecif
329 @ r2: cif->bytes
330 @ r3: fig->flags
331 @ sp+0: ecif.rvalue
332
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200333ARM_FUNC_START(ffi_call_VFP)
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200334 @ Save registers
335 stmfd sp!, {r0-r3, fp, lr}
336 UNWIND .save {r0-r3, fp, lr}
337 mov fp, sp
338 UNWIND .setfp fp, sp
339
340 @ Make room for all of the new args.
341 sub sp, sp, r2
342
343 @ Make room for loading VFP args
344 sub sp, sp, #64
345
346 @ Place all of the ffi_prep_args in position
347 mov r0, sp
348 @ r1 already set
349 sub r2, fp, #64 @ VFP scratch space
350
351 @ Call ffi_prep_args(stack, &ecif, vfp_space)
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200352 bl CNAME(ffi_prep_args_VFP)
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200353
354 @ Load VFP register args if needed
355 cmp r0, #0
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200356 mov ip, fp
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200357 beq LSYM(Lbase_args)
358
359 @ Load only d0 if possible
360 cmp r0, #3
361 sub ip, fp, #64
362 flddle d0, [ip]
363 fldmiadgt ip, {d0-d7}
364
365LSYM(Lbase_args):
366 @ move first 4 parameters in registers
367 ldmia sp, {r0-r3}
368
369 @ and adjust stack
370 sub lr, ip, sp @ cif->bytes == (fp - 64) - sp
371 ldr ip, [fp] @ load fn() in advance
372 cmp lr, #16
373 movhs lr, #16
374 add sp, sp, lr
375
376 @ call (fn) (...)
377 call_reg(ip)
378
379 @ Remove the space we pushed for the args
380 mov sp, fp
381
382 @ Load r2 with the pointer to storage for
383 @ the return value
384 ldr r2, [sp, #24]
385
386 @ Load r3 with the return type code
387 ldr r3, [sp, #12]
388
389 @ If the return value pointer is NULL,
390 @ assume no return value.
391 cmp r2, #0
392 beq LSYM(Lepilogue_vfp)
393
394 cmp r3, #FFI_TYPE_INT
395 streq r0, [r2]
396 beq LSYM(Lepilogue_vfp)
397
398 cmp r3, #FFI_TYPE_SINT64
399 stmeqia r2, {r0, r1}
400 beq LSYM(Lepilogue_vfp)
401
402 cmp r3, #FFI_TYPE_FLOAT
403 fstseq s0, [r2]
404 beq LSYM(Lepilogue_vfp)
405
406 cmp r3, #FFI_TYPE_DOUBLE
407 fstdeq d0, [r2]
408 beq LSYM(Lepilogue_vfp)
409
410 cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT
411 cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE
412 fstmiadeq r2, {d0-d3}
413
414LSYM(Lepilogue_vfp):
415 RETLDM "r0-r3,fp"
416
417.ffi_call_VFP_end:
418 UNWIND .fnend
419 .size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP)
420
421
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200422ARM_FUNC_START(ffi_closure_VFP)
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200423 fstmfdd sp!, {d0-d7}
424 @ r0-r3, then d0-d7
425 UNWIND .pad #80
426 add ip, sp, #80
427 stmfd sp!, {ip, lr}
428 UNWIND .save {r0, lr}
429 add r2, sp, #72
430 add r3, sp, #8
431 UNWIND .pad #72
432 sub sp, sp, #72
433 str sp, [sp, #64]
434 add r1, sp, #64
doko@ubuntu.com736a9132014-08-09 22:36:35 +0200435 bl CNAME(ffi_closure_inner)
doko@ubuntu.com2a918762012-06-26 17:56:44 +0200436
437 cmp r0, #FFI_TYPE_INT
438 beq .Lretint_vfp
439
440 cmp r0, #FFI_TYPE_FLOAT
441 beq .Lretfloat_vfp
442
443 cmp r0, #FFI_TYPE_DOUBLE
444 cmpne r0, #FFI_TYPE_LONGDOUBLE
445 beq .Lretdouble_vfp
446
447 cmp r0, #FFI_TYPE_SINT64
448 beq .Lretlonglong_vfp
449
450 cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT
451 beq .Lretfloat_struct_vfp
452
453 cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE
454 beq .Lretdouble_struct_vfp
455
456.Lclosure_epilogue_vfp:
457 add sp, sp, #72
458 ldmfd sp, {sp, pc}
459
460.Lretfloat_vfp:
461 flds s0, [sp]
462 b .Lclosure_epilogue_vfp
463.Lretdouble_vfp:
464 fldd d0, [sp]
465 b .Lclosure_epilogue_vfp
466.Lretint_vfp:
467 ldr r0, [sp]
468 b .Lclosure_epilogue_vfp
469.Lretlonglong_vfp:
470 ldmia sp, {r0, r1}
471 b .Lclosure_epilogue_vfp
472.Lretfloat_struct_vfp:
473 fldmiad sp, {d0-d1}
474 b .Lclosure_epilogue_vfp
475.Lretdouble_struct_vfp:
476 fldmiad sp, {d0-d3}
477 b .Lclosure_epilogue_vfp
478
479.ffi_closure_VFP_end:
480 UNWIND .fnend
481 .size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP)
482#endif
483
484ENTRY(ffi_arm_trampoline)
485 stmfd sp!, {r0-r3}
486 ldr r0, [pc]
487 ldr pc, [pc]
Christian Heimes78644762008-03-04 23:39:23 +0000488
489#if defined __ELF__ && defined __linux__
490 .section .note.GNU-stack,"",%progbits
491#endif