sysv.S revision 46ce27ab1e22ca98957e0900c6a2415b86578b2e
1/* -----------------------------------------------------------------------
2   sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
3	    Copyright (c) 2011 Plausible Labs Cooperative, Inc.
4
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
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   ----------------------------------------------------------------------- */
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
43#ifdef __APPLE__
44#define ENTRY(x) .globl _##x; _##x:
45#else
46#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
47#endif /* __APPLE__ */
48#endif
49
50#ifdef __ELF__
51#define LSYM(x) .x
52#else
53#define LSYM(x) x
54#endif
55
56/* 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
62/* 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__) \
81        || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
82	|| defined(__ARM_ARCH_6M__)
83# undef __ARM_ARCH__
84# define __ARM_ARCH__ 6
85#endif
86
87#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
94#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
105/* Conditionally compile unwinder directives.  */
106#ifdef __ARM_EABI__
107#define UNWIND
108#else
109#define UNWIND @
110#endif
111
112
113#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
114.macro	ARM_FUNC_START name
115	.text
116	.align 0
117	.thumb
118	.thumb_func
119#ifdef __APPLE__
120	ENTRY($0)
121#else
122	ENTRY(\name)
123#endif
124	bx	pc
125	nop
126	.arm
127	UNWIND .fnstart
128/* A hook to tell gdb that we've switched to ARM mode.  Also used to call
129   directly from other local arm routines.  */
130#ifdef __APPLE__
131_L__$0:
132#else
133_L__\name:
134#endif
135.endm
136#else
137.macro	ARM_FUNC_START name
138	.text
139	.align 0
140	.arm
141#ifdef __APPLE__
142	ENTRY($0)
143#else
144	ENTRY(\name)
145#endif
146	UNWIND .fnstart
147.endm
148#endif
149
150.macro	RETLDM	regs=, cond=, dirn=ia
151#if defined (__INTERWORKING__)
152	.ifc "\regs",""
153	ldr\cond	lr, [sp], #4
154	.else
155	ldm\cond\dirn	sp!, {\regs, lr}
156	.endif
157	bx\cond	lr
158#else
159	.ifc "\regs",""
160	ldr\cond	pc, [sp], #4
161	.else
162	ldm\cond\dirn	sp!, {\regs, pc}
163	.endif
164#endif
165.endm
166
167	@ r0:   ffi_prep_args
168	@ r1:   &ecif
169	@ r2:   cif->bytes
170	@ r3:   fig->flags
171	@ sp+0: ecif.rvalue
172
173	@ This assumes we are using gas.
174ARM_FUNC_START ffi_call_SYSV
175	@ Save registers
176        stmfd	sp!, {r0-r3, fp, lr}
177	UNWIND .save	{r0-r3, fp, lr}
178	mov	fp, sp
179
180	UNWIND .setfp	fp, sp
181
182	@ Make room for all of the new args.
183	sub	sp, fp, r2
184
185	@ Place all of the ffi_prep_args in position
186	mov	r0, sp
187	@     r1 already set
188
189	@ Call ffi_prep_args(stack, &ecif)
190	bl	CNAME(ffi_prep_args)
191
192	@ move first 4 parameters in registers
193	ldmia	sp, {r0-r3}
194
195	@ and adjust stack
196	sub	lr, fp, sp	@ cif->bytes == fp - sp
197	ldr	ip, [fp]	@ load fn() in advance
198	cmp	lr, #16
199	movhs	lr, #16
200	add	sp, sp, lr
201
202	@ call (fn) (...)
203	call_reg(ip)
204
205	@ Remove the space we pushed for the args
206	mov	sp, fp
207
208	@ Load r2 with the pointer to storage for the return value
209	ldr	r2, [sp, #24]
210
211	@ Load r3 with the return type code
212	ldr	r3, [sp, #12]
213
214	@ If the return value pointer is NULL, assume no return value.
215	cmp	r2, #0
216	beq	LSYM(Lepilogue)
217
218@ return INT
219	cmp	r3, #FFI_TYPE_INT
220#if defined(__SOFTFP__) || defined(__ARM_EABI__)
221	cmpne	r3, #FFI_TYPE_FLOAT
222#endif
223	streq	r0, [r2]
224	beq	LSYM(Lepilogue)
225
226	@ return INT64
227	cmp	r3, #FFI_TYPE_SINT64
228#if defined(__SOFTFP__) || defined(__ARM_EABI__)
229	cmpne	r3, #FFI_TYPE_DOUBLE
230#endif
231	stmeqia	r2, {r0, r1}
232
233#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
234	beq	LSYM(Lepilogue)
235
236@ return FLOAT
237	cmp	r3, #FFI_TYPE_FLOAT
238	stfeqs	f0, [r2]
239	beq	LSYM(Lepilogue)
240
241@ return DOUBLE or LONGDOUBLE
242	cmp	r3, #FFI_TYPE_DOUBLE
243	stfeqd	f0, [r2]
244#endif
245
246LSYM(Lepilogue):
247#if defined (__INTERWORKING__)
248	ldmia   sp!, {r0-r3,fp, lr}
249	bx	lr
250#else
251	ldmia   sp!, {r0-r3,fp, pc}
252#endif
253
254.ffi_call_SYSV_end:
255	UNWIND .fnend
256#ifdef __ELF__
257        .size    CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
258#endif
259
260
261/*
262	unsigned int FFI_HIDDEN
263	ffi_closure_SYSV_inner (closure, respp, args)
264	     ffi_closure *closure;
265	     void **respp;
266  	     void *args;
267*/
268
269ARM_FUNC_START ffi_closure_SYSV
270	UNWIND .pad #16
271	add	ip, sp, #16
272	stmfd	sp!, {ip, lr}
273	UNWIND .save	{r0, lr}
274	add	r2, sp, #8
275	UNWIND .pad #16
276	sub	sp, sp, #16
277	str	sp, [sp, #8]
278	add	r1, sp, #8
279	bl	CNAME(ffi_closure_SYSV_inner)
280	cmp	r0, #FFI_TYPE_INT
281	beq	.Lretint
282
283	cmp	r0, #FFI_TYPE_FLOAT
284#if defined(__SOFTFP__) || defined(__ARM_EABI__)
285	beq	.Lretint
286#else
287	beq	.Lretfloat
288#endif
289
290	cmp	r0, #FFI_TYPE_DOUBLE
291#if defined(__SOFTFP__) || defined(__ARM_EABI__)
292	beq	.Lretlonglong
293#else
294	beq	.Lretdouble
295#endif
296
297	cmp	r0, #FFI_TYPE_LONGDOUBLE
298#if defined(__SOFTFP__) || defined(__ARM_EABI__)
299	beq	.Lretlonglong
300#else
301	beq	.Lretlongdouble
302#endif
303
304	cmp	r0, #FFI_TYPE_SINT64
305	beq	.Lretlonglong
306.Lclosure_epilogue:
307	add	sp, sp, #16
308	ldmfd	sp, {sp, pc}
309.Lretint:
310	ldr	r0, [sp]
311	b	.Lclosure_epilogue
312.Lretlonglong:
313	ldr	r0, [sp]
314	ldr	r1, [sp, #4]
315	b	.Lclosure_epilogue
316
317#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
318.Lretfloat:
319	ldfs	f0, [sp]
320	b	.Lclosure_epilogue
321.Lretdouble:
322	ldfd	f0, [sp]
323	b	.Lclosure_epilogue
324.Lretlongdouble:
325	ldfd	f0, [sp]
326	b	.Lclosure_epilogue
327#endif
328
329.ffi_closure_SYSV_end:
330	UNWIND .fnend
331#ifdef __ELF__
332        .size    CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
333#endif
334
335
336/* Below are VFP hard-float ABI call and closure implementations.
337   Add VFP FPU directive here. This is only compiled into the library
338   under EABI.  */
339#ifdef __ARM_EABI__
340	.fpu	vfp
341
342	@ r0:   fn
343	@ r1:   &ecif
344	@ r2:   cif->bytes
345	@ r3:   fig->flags
346	@ sp+0: ecif.rvalue
347
348ARM_FUNC_START ffi_call_VFP
349	@ Save registers
350        stmfd	sp!, {r0-r3, fp, lr}
351	UNWIND .save	{r0-r3, fp, lr}
352	mov	fp, sp
353	UNWIND .setfp	fp, sp
354
355	@ Make room for all of the new args.
356	sub	sp, sp, r2
357
358	@ Make room for loading VFP args
359	sub	sp, sp, #64
360
361	@ Place all of the ffi_prep_args in position
362	mov	r0, sp
363	@     r1 already set
364	sub	r2, fp, #64   @ VFP scratch space
365
366	@ Call ffi_prep_args(stack, &ecif, vfp_space)
367	bl	CNAME(ffi_prep_args)
368
369	@ Load VFP register args if needed
370	cmp	r0, #0
371	beq	LSYM(Lbase_args)
372
373	@ Load only d0 if possible
374	cmp	r0, #3
375	sub	ip, fp, #64
376	flddle	d0, [ip]
377	fldmiadgt	ip, {d0-d7}
378
379LSYM(Lbase_args):
380	@ move first 4 parameters in registers
381	ldmia	sp, {r0-r3}
382
383	@ and adjust stack
384	sub	lr, ip, sp	@ cif->bytes == (fp - 64) - sp
385	ldr	ip, [fp]	@ load fn() in advance
386        cmp	lr, #16
387	movhs	lr, #16
388        add	sp, sp, lr
389
390	@ call (fn) (...)
391	call_reg(ip)
392
393	@ Remove the space we pushed for the args
394	mov	sp, fp
395
396	@ Load r2 with the pointer to storage for
397	@ the return value
398	ldr	r2, [sp, #24]
399
400	@ Load r3 with the return type code
401	ldr	r3, [sp, #12]
402
403	@ If the return value pointer is NULL,
404	@ assume no return value.
405	cmp	r2, #0
406	beq	LSYM(Lepilogue_vfp)
407
408	cmp	r3, #FFI_TYPE_INT
409	streq	r0, [r2]
410	beq	LSYM(Lepilogue_vfp)
411
412	cmp	r3, #FFI_TYPE_SINT64
413	stmeqia	r2, {r0, r1}
414	beq	LSYM(Lepilogue_vfp)
415
416	cmp	r3, #FFI_TYPE_FLOAT
417	fstseq	s0, [r2]
418	beq	LSYM(Lepilogue_vfp)
419
420	cmp	r3, #FFI_TYPE_DOUBLE
421	fstdeq	d0, [r2]
422	beq	LSYM(Lepilogue_vfp)
423
424	cmp	r3, #FFI_TYPE_STRUCT_VFP_FLOAT
425	cmpne	r3, #FFI_TYPE_STRUCT_VFP_DOUBLE
426	fstmiadeq	r2, {d0-d3}
427
428LSYM(Lepilogue_vfp):
429	RETLDM	"r0-r3,fp"
430
431.ffi_call_VFP_end:
432	UNWIND .fnend
433        .size    CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP)
434
435
436ARM_FUNC_START ffi_closure_VFP
437	fstmfdd	sp!, {d0-d7}
438	@ r0-r3, then d0-d7
439	UNWIND .pad #80
440	add	ip, sp, #80
441	stmfd	sp!, {ip, lr}
442	UNWIND .save	{r0, lr}
443	add	r2, sp, #72
444	add	r3, sp, #8
445	UNWIND .pad #72
446	sub	sp, sp, #72
447	str	sp, [sp, #64]
448	add	r1, sp, #64
449	bl	CNAME(ffi_closure_SYSV_inner)
450
451	cmp	r0, #FFI_TYPE_INT
452	beq	.Lretint_vfp
453
454	cmp	r0, #FFI_TYPE_FLOAT
455	beq	.Lretfloat_vfp
456
457	cmp	r0, #FFI_TYPE_DOUBLE
458	cmpne	r0, #FFI_TYPE_LONGDOUBLE
459	beq	.Lretdouble_vfp
460
461	cmp	r0, #FFI_TYPE_SINT64
462	beq	.Lretlonglong_vfp
463
464	cmp	r0, #FFI_TYPE_STRUCT_VFP_FLOAT
465	beq	.Lretfloat_struct_vfp
466
467	cmp	r0, #FFI_TYPE_STRUCT_VFP_DOUBLE
468	beq	.Lretdouble_struct_vfp
469
470.Lclosure_epilogue_vfp:
471	add	sp, sp, #72
472	ldmfd	sp, {sp, pc}
473
474.Lretfloat_vfp:
475	flds	s0, [sp]
476	b	.Lclosure_epilogue_vfp
477.Lretdouble_vfp:
478	fldd	d0, [sp]
479	b	.Lclosure_epilogue_vfp
480.Lretint_vfp:
481	ldr	r0, [sp]
482	b	.Lclosure_epilogue_vfp
483.Lretlonglong_vfp:
484	ldmia	sp, {r0, r1}
485	b	.Lclosure_epilogue_vfp
486.Lretfloat_struct_vfp:
487	fldmiad	sp, {d0-d1}
488	b	.Lclosure_epilogue_vfp
489.Lretdouble_struct_vfp:
490	fldmiad	sp, {d0-d3}
491	b	.Lclosure_epilogue_vfp
492
493.ffi_closure_VFP_end:
494	UNWIND .fnend
495        .size    CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP)
496#endif
497
498ENTRY(ffi_arm_trampoline)
499	stmfd sp!, {r0-r3}
500	ldr r0, [pc]
501	ldr pc, [pc]
502
503#if defined __ELF__ && defined __linux__
504	.section	.note.GNU-stack,"",%progbits
505#endif
506