• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.syntax unified
113
114#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
115#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:
126#else
127#define ARM_FUNC_START(name) \
128	.text; \
129	.align 2; \
130	.arm; \
131	ENTRY(name); \
132	UNWIND .fnstart
133#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
152	@ r0:   ffi_prep_args
153	@ r1:   &ecif
154	@ r2:   cif->bytes
155	@ r3:   fig->flags
156	@ sp+0: ecif.rvalue
157
158	@ This assumes we are using gas.
159ARM_FUNC_START(ffi_call_SYSV)
160	@ Save registers
161        stmfd	sp!, {r0-r3, fp, lr}
162	UNWIND .save	{r0-r3, fp, lr}
163	mov	fp, sp
164
165	UNWIND .setfp	fp, sp
166
167	@ Make room for all of the new args.
168	sub	sp, fp, r2
169
170	@ Place all of the ffi_prep_args in position
171	mov	r0, sp
172	@     r1 already set
173
174	@ Call ffi_prep_args(stack, &ecif)
175	bl	CNAME(ffi_prep_args_SYSV)
176
177	@ move first 4 parameters in registers
178	ldmia	sp, {r0-r3}
179
180	@ and adjust stack
181	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
186
187	@ call (fn) (...)
188	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
205#if defined(__SOFTFP__) || defined(__ARM_EABI__)
206	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
213#if defined(__SOFTFP__) || defined(__ARM_EABI__)
214	cmpne	r3, #FFI_TYPE_DOUBLE
215#endif
216	stmiaeq	r2, {r0, r1}
217
218#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
219	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):
232#if defined (__INTERWORKING__)
233	ldmia   sp!, {r0-r3,fp, lr}
234	bx	lr
235#else
236	ldmia   sp!, {r0-r3,fp, pc}
237#endif
238
239.ffi_call_SYSV_end:
240	UNWIND .fnend
241#ifdef __ELF__
242        .size    CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
243#endif
244
245
246/*
247	unsigned int FFI_HIDDEN
248	ffi_closure_inner (closure, respp, args)
249	     ffi_closure *closure;
250	     void **respp;
251  	     void *args;
252*/
253
254ARM_FUNC_START(ffi_closure_SYSV)
255	UNWIND .pad #16
256	add	ip, sp, #16
257	stmfd	sp!, {ip, lr}
258	UNWIND .save	{r0, lr}
259	add	r2, sp, #8
260	UNWIND .pad #16
261	sub	sp, sp, #16
262	str	sp, [sp, #8]
263	add	r1, sp, #8
264	bl	CNAME(ffi_closure_inner)
265	cmp	r0, #FFI_TYPE_INT
266	beq	.Lretint
267
268	cmp	r0, #FFI_TYPE_FLOAT
269#if defined(__SOFTFP__) || defined(__ARM_EABI__)
270	beq	.Lretint
271#else
272	beq	.Lretfloat
273#endif
274
275	cmp	r0, #FFI_TYPE_DOUBLE
276#if defined(__SOFTFP__) || defined(__ARM_EABI__)
277	beq	.Lretlonglong
278#else
279	beq	.Lretdouble
280#endif
281
282	cmp	r0, #FFI_TYPE_LONGDOUBLE
283#if defined(__SOFTFP__) || defined(__ARM_EABI__)
284	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
302#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
303.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
316#ifdef __ELF__
317        .size    CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
318#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
333ARM_FUNC_START(ffi_call_VFP)
334	@ 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)
352	bl	CNAME(ffi_prep_args_VFP)
353
354	@ Load VFP register args if needed
355	cmp	r0, #0
356	mov	ip, fp
357	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	vldmiagt	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	stmiaeq	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	vstmiaeq	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
422ARM_FUNC_START(ffi_closure_VFP)
423	vpush	{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
435	bl	CNAME(ffi_closure_inner)
436
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	vldmia	sp, {d0-d1}
474	b	.Lclosure_epilogue_vfp
475.Lretdouble_struct_vfp:
476	vldmia	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]
488
489#if defined __ELF__ && defined __linux__
490	.section	.note.GNU-stack,"",%progbits
491#endif
492