1 /* -----------------------------------------------------------------------
2 ffi_linux64.c - Copyright (C) 2013 IBM
3 Copyright (C) 2011 Anthony Green
4 Copyright (C) 2011 Kyle Moffett
5 Copyright (C) 2008 Red Hat, Inc
6 Copyright (C) 2007, 2008 Free Software Foundation, Inc
7 Copyright (c) 1998 Geoffrey Keating
9 PowerPC Foreign Function Interface
11 Permission is hereby granted, free of charge, to any person obtaining
12 a copy of this software and associated documentation files (the
13 ``Software''), to deal in the Software without restriction, including
14 without limitation the rights to use, copy, modify, merge, publish,
15 distribute, sublicense, and/or sell copies of the Software, and to
16 permit persons to whom the Software is furnished to do so, subject to
17 the following conditions:
19 The above copyright notice and this permission notice shall be included
20 in all copies or substantial portions of the Software.
22 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
26 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 OTHER DEALINGS IN THE SOFTWARE.
29 ----------------------------------------------------------------------- */
34 #include "ffi_common.h"
35 #include "ffi_powerpc.h"
38 /* About the LINUX64 ABI. */
40 NUM_GPR_ARG_REGISTERS64
= 8,
41 NUM_FPR_ARG_REGISTERS64
= 13,
42 NUM_VEC_ARG_REGISTERS64
= 12,
44 enum { ASM_NEEDS_REGISTERS64
= 4 };
47 #if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
48 /* Adjust size of ffi_type_longdouble. */
50 ffi_prep_types_linux64 (ffi_abi abi
)
52 if ((abi
& (FFI_LINUX
| FFI_LINUX_LONG_DOUBLE_128
)) == FFI_LINUX
)
54 ffi_type_longdouble
.size
= 8;
55 ffi_type_longdouble
.alignment
= 8;
59 ffi_type_longdouble
.size
= 16;
60 ffi_type_longdouble
.alignment
= 16;
67 discover_homogeneous_aggregate (ffi_abi abi
,
73 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
74 case FFI_TYPE_LONGDOUBLE
:
75 /* 64-bit long doubles are equivalent to doubles. */
76 if ((abi
& FFI_LINUX_LONG_DOUBLE_128
) == 0)
79 return FFI_TYPE_DOUBLE
;
81 /* IBM extended precision values use unaligned pairs
82 of FPRs, but according to the ABI must be considered
83 distinct from doubles. They are also limited to a
84 maximum of four members in a homogeneous aggregate. */
85 else if ((abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) == 0)
88 return FFI_TYPE_LONGDOUBLE
;
97 case FFI_TYPE_STRUCT
:;
99 unsigned int base_elt
= 0, total_elnum
= 0;
100 ffi_type
**el
= t
->elements
;
103 unsigned int el_elt
, el_elnum
= 0;
104 el_elt
= discover_homogeneous_aggregate (abi
, *el
, &el_elnum
);
106 || (base_elt
&& base_elt
!= el_elt
))
109 total_elnum
+= el_elnum
;
119 *elnum
= total_elnum
;
129 /* Perform machine dependent cif processing */
131 ffi_prep_cif_linux64_core (ffi_cif
*cif
)
135 unsigned i
, fparg_count
= 0, intarg_count
= 0, vecarg_count
= 0;
136 unsigned flags
= cif
->flags
;
137 unsigned elt
, elnum
, rtype
;
139 #if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
140 /* If compiled without long double support... */
141 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0 ||
142 (cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
144 #elif !defined(__VEC__)
145 /* If compiled without vector register support (used by assembly)... */
146 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
149 /* If the IEEE128 flag is set, but long double is only 64 bits wide... */
150 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) == 0 &&
151 (cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
155 /* The machine-independent calculation of cif->bytes doesn't work
156 for us. Redo the calculation. */
158 /* Space for backchain, CR, LR, TOC and the asm's temp regs. */
159 bytes
= (4 + ASM_NEEDS_REGISTERS64
) * sizeof (long);
161 /* Space for the general registers. */
162 bytes
+= NUM_GPR_ARG_REGISTERS64
* sizeof (long);
164 /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
166 bytes
= (6 + ASM_NEEDS_REGISTERS64
) * sizeof (long);
168 /* Space for the mandatory parm save area and general registers. */
169 bytes
+= 2 * NUM_GPR_ARG_REGISTERS64
* sizeof (long);
172 /* Return value handling. */
173 rtype
= cif
->rtype
->type
;
179 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
180 case FFI_TYPE_LONGDOUBLE
:
181 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
183 flags
|= FLAG_RETURNS_VEC
;
186 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0)
187 flags
|= FLAG_RETURNS_128BITS
;
190 case FFI_TYPE_DOUBLE
:
191 flags
|= FLAG_RETURNS_64BITS
;
194 flags
|= FLAG_RETURNS_FP
;
197 case FFI_TYPE_UINT128
:
198 flags
|= FLAG_RETURNS_128BITS
;
200 case FFI_TYPE_UINT64
:
201 case FFI_TYPE_SINT64
:
202 case FFI_TYPE_POINTER
:
203 flags
|= FLAG_RETURNS_64BITS
;
206 case FFI_TYPE_STRUCT
:
208 elt
= discover_homogeneous_aggregate (cif
->abi
, cif
->rtype
, &elnum
);
211 flags
|= FLAG_RETURNS_SMST
;
215 if (cif
->rtype
->size
<= 16)
217 flags
|= FLAG_RETURNS_SMST
;
222 flags
|= FLAG_RETVAL_REFERENCE
;
225 flags
|= FLAG_RETURNS_NOTHING
;
229 /* Returns 32-bit integer, or similar. Nothing to do here. */
233 for (ptr
= cif
->arg_types
, i
= cif
->nargs
; i
> 0; i
--, ptr
++)
237 switch ((*ptr
)->type
)
239 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
240 case FFI_TYPE_LONGDOUBLE
:
241 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
244 /* Align to 16 bytes, plus the 16-byte argument. */
245 intarg_count
= (intarg_count
+ 3) & ~0x1;
246 if (vecarg_count
> NUM_VEC_ARG_REGISTERS64
)
247 flags
|= FLAG_ARG_NEEDS_PSAVE
;
250 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0)
257 case FFI_TYPE_DOUBLE
:
261 if (fparg_count
> NUM_FPR_ARG_REGISTERS64
)
262 flags
|= FLAG_ARG_NEEDS_PSAVE
;
265 case FFI_TYPE_STRUCT
:
266 if ((cif
->abi
& FFI_LINUX_STRUCT_ALIGN
) != 0)
268 align
= (*ptr
)->alignment
;
273 intarg_count
= FFI_ALIGN (intarg_count
, align
);
275 intarg_count
+= ((*ptr
)->size
+ 7) / 8;
276 elt
= discover_homogeneous_aggregate (cif
->abi
, *ptr
, &elnum
);
277 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
278 if (elt
== FFI_TYPE_LONGDOUBLE
&&
279 (cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
281 vecarg_count
+= elnum
;
282 if (vecarg_count
> NUM_VEC_ARG_REGISTERS64
)
283 flags
|= FLAG_ARG_NEEDS_PSAVE
;
290 fparg_count
+= elnum
;
291 if (fparg_count
> NUM_FPR_ARG_REGISTERS64
)
292 flags
|= FLAG_ARG_NEEDS_PSAVE
;
296 if (intarg_count
> NUM_GPR_ARG_REGISTERS64
)
297 flags
|= FLAG_ARG_NEEDS_PSAVE
;
301 case FFI_TYPE_POINTER
:
302 case FFI_TYPE_UINT64
:
303 case FFI_TYPE_SINT64
:
305 case FFI_TYPE_UINT32
:
306 case FFI_TYPE_SINT32
:
307 case FFI_TYPE_UINT16
:
308 case FFI_TYPE_SINT16
:
311 /* Everything else is passed as a 8-byte word in a GPR, either
312 the object itself or a pointer to it. */
314 if (intarg_count
> NUM_GPR_ARG_REGISTERS64
)
315 flags
|= FLAG_ARG_NEEDS_PSAVE
;
322 if (fparg_count
!= 0)
323 flags
|= FLAG_FP_ARGUMENTS
;
324 if (intarg_count
> 4)
325 flags
|= FLAG_4_GPR_ARGUMENTS
;
326 if (vecarg_count
!= 0)
327 flags
|= FLAG_VEC_ARGUMENTS
;
329 /* Space for the FPR registers, if needed. */
330 if (fparg_count
!= 0)
331 bytes
+= NUM_FPR_ARG_REGISTERS64
* sizeof (double);
332 /* Space for the vector registers, if needed, aligned to 16 bytes. */
333 if (vecarg_count
!= 0) {
334 bytes
= (bytes
+ 15) & ~0xF;
335 bytes
+= NUM_VEC_ARG_REGISTERS64
* sizeof (float128
);
340 if ((flags
& FLAG_ARG_NEEDS_PSAVE
) != 0)
341 bytes
+= intarg_count
* sizeof (long);
343 if (intarg_count
> NUM_GPR_ARG_REGISTERS64
)
344 bytes
+= (intarg_count
- NUM_GPR_ARG_REGISTERS64
) * sizeof (long);
347 /* The stack space allocated needs to be a multiple of 16 bytes. */
348 bytes
= (bytes
+ 15) & ~0xF;
356 ffi_status FFI_HIDDEN
357 ffi_prep_cif_linux64 (ffi_cif
*cif
)
359 if ((cif
->abi
& FFI_LINUX
) != 0)
360 cif
->nfixedargs
= cif
->nargs
;
362 else if (cif
->abi
== FFI_COMPAT_LINUX64
)
364 /* This call is from old code. Don't touch cif->nfixedargs
365 since old code will be using a smaller cif. */
366 cif
->flags
|= FLAG_COMPAT
;
367 /* Translate to new abi value. */
368 cif
->abi
= FFI_LINUX
| FFI_LINUX_LONG_DOUBLE_128
;
373 return ffi_prep_cif_linux64_core (cif
);
376 ffi_status FFI_HIDDEN
377 ffi_prep_cif_linux64_var (ffi_cif
*cif
,
378 unsigned int nfixedargs
,
379 unsigned int ntotalargs MAYBE_UNUSED
)
381 if ((cif
->abi
& FFI_LINUX
) != 0)
382 cif
->nfixedargs
= nfixedargs
;
384 else if (cif
->abi
== FFI_COMPAT_LINUX64
)
386 /* This call is from old code. Don't touch cif->nfixedargs
387 since old code will be using a smaller cif. */
388 cif
->flags
|= FLAG_COMPAT
;
389 /* Translate to new abi value. */
390 cif
->abi
= FFI_LINUX
| FFI_LINUX_LONG_DOUBLE_128
;
396 cif
->flags
|= FLAG_ARG_NEEDS_PSAVE
;
398 return ffi_prep_cif_linux64_core (cif
);
402 /* ffi_prep_args64 is called by the assembly routine once stack space
403 has been allocated for the function's arguments.
405 The stack layout we want looks like this:
407 | Ret addr from ffi_call_LINUX64 8bytes | higher addresses
408 |--------------------------------------------|
409 | CR save area 8bytes |
410 |--------------------------------------------|
411 | Previous backchain pointer 8 | stack pointer here
412 |--------------------------------------------|<+ <<< on entry to
413 | Saved r28-r31 4*8 | | ffi_call_LINUX64
414 |--------------------------------------------| |
415 | GPR registers r3-r10 8*8 | |
416 |--------------------------------------------| |
417 | FPR registers f1-f13 (optional) 13*8 | |
418 |--------------------------------------------| |
419 | VEC registers v2-v13 (optional) 12*16 | |
420 |--------------------------------------------| |
421 | Parameter save area | |
422 |--------------------------------------------| |
423 | TOC save area 8 | |
424 |--------------------------------------------| | stack |
425 | Linker doubleword 8 | | grows |
426 |--------------------------------------------| | down V
427 | Compiler doubleword 8 | |
428 |--------------------------------------------| | lower addresses
429 | Space for callee's LR 8 | |
430 |--------------------------------------------| |
432 |--------------------------------------------| | stack pointer here
433 | Current backchain pointer 8 |-/ during
434 |--------------------------------------------| <<< ffi_call_LINUX64
439 ffi_prep_args64 (extended_cif
*ecif
, unsigned long *const stack
)
441 const unsigned long bytes
= ecif
->cif
->bytes
;
442 const unsigned long flags
= ecif
->cif
->flags
;
454 /* 'stacktop' points at the previous backchain pointer. */
457 /* 'next_arg' points at the space for gpr3, and grows upwards as
458 we use GPR registers, then continues at rest. */
464 /* 'fpr_base' points at the space for f1, and grows upwards as
465 we use FPR registers. */
467 unsigned int fparg_count
;
469 /* 'vec_base' points at the space for v2, and grows upwards as
470 we use vector registers. */
472 unsigned int vecarg_count
;
474 unsigned int i
, words
, nargs
, nfixedargs
;
492 unsigned long gprvalue
;
495 stacktop
.c
= (char *) stack
+ bytes
;
496 gpr_base
.ul
= stacktop
.ul
- ASM_NEEDS_REGISTERS64
- NUM_GPR_ARG_REGISTERS64
;
497 gpr_end
.ul
= gpr_base
.ul
+ NUM_GPR_ARG_REGISTERS64
;
499 rest
.ul
= stack
+ 4 + NUM_GPR_ARG_REGISTERS64
;
501 rest
.ul
= stack
+ 6 + NUM_GPR_ARG_REGISTERS64
;
503 fpr_base
.d
= gpr_base
.d
- NUM_FPR_ARG_REGISTERS64
;
505 /* Place the vector args below the FPRs, if used, else the GPRs. */
506 if (ecif
->cif
->flags
& FLAG_FP_ARGUMENTS
)
507 vec_base
.p
= fpr_base
.p
& ~0xF;
509 vec_base
.p
= gpr_base
.p
;
510 vec_base
.f128
-= NUM_VEC_ARG_REGISTERS64
;
512 next_arg
.ul
= gpr_base
.ul
;
514 /* Check that everything starts aligned properly. */
515 FFI_ASSERT (((unsigned long) (char *) stack
& 0xF) == 0);
516 FFI_ASSERT (((unsigned long) stacktop
.c
& 0xF) == 0);
517 FFI_ASSERT (((unsigned long) gpr_base
.c
& 0xF) == 0);
518 FFI_ASSERT (((unsigned long) gpr_end
.c
& 0xF) == 0);
519 FFI_ASSERT (((unsigned long) vec_base
.c
& 0xF) == 0);
520 FFI_ASSERT ((bytes
& 0xF) == 0);
522 /* Deal with return values that are actually pass-by-reference. */
523 if (flags
& FLAG_RETVAL_REFERENCE
)
524 *next_arg
.ul
++ = (unsigned long) (char *) ecif
->rvalue
;
526 /* Now for the arguments. */
527 p_argv
.v
= ecif
->avalue
;
528 nargs
= ecif
->cif
->nargs
;
530 nfixedargs
= (unsigned) -1;
531 if ((flags
& FLAG_COMPAT
) == 0)
533 nfixedargs
= ecif
->cif
->nfixedargs
;
534 for (ptr
= ecif
->cif
->arg_types
, i
= 0;
536 i
++, ptr
++, p_argv
.v
++)
538 unsigned int elt
, elnum
;
540 switch ((*ptr
)->type
)
542 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
543 case FFI_TYPE_LONGDOUBLE
:
544 if ((ecif
->cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
546 next_arg
.p
= FFI_ALIGN (next_arg
.p
, 16);
547 if (next_arg
.ul
== gpr_end
.ul
)
548 next_arg
.ul
= rest
.ul
;
549 if (vecarg_count
< NUM_VEC_ARG_REGISTERS64
&& i
< nfixedargs
)
550 memcpy (vec_base
.f128
++, *p_argv
.f128
, sizeof (float128
));
552 memcpy (next_arg
.f128
, *p_argv
.f128
, sizeof (float128
));
553 if (++next_arg
.f128
== gpr_end
.f128
)
554 next_arg
.f128
= rest
.f128
;
556 FFI_ASSERT (__LDBL_MANT_DIG__
== 113);
557 FFI_ASSERT (flags
& FLAG_VEC_ARGUMENTS
);
560 if ((ecif
->cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0)
562 double_tmp
= (*p_argv
.d
)[0];
563 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
565 *fpr_base
.d
++ = double_tmp
;
567 if ((flags
& FLAG_COMPAT
) != 0)
568 *next_arg
.d
= double_tmp
;
572 *next_arg
.d
= double_tmp
;
573 if (++next_arg
.ul
== gpr_end
.ul
)
574 next_arg
.ul
= rest
.ul
;
576 double_tmp
= (*p_argv
.d
)[1];
577 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
579 *fpr_base
.d
++ = double_tmp
;
581 if ((flags
& FLAG_COMPAT
) != 0)
582 *next_arg
.d
= double_tmp
;
586 *next_arg
.d
= double_tmp
;
587 if (++next_arg
.ul
== gpr_end
.ul
)
588 next_arg
.ul
= rest
.ul
;
590 FFI_ASSERT (__LDBL_MANT_DIG__
== 106);
591 FFI_ASSERT (flags
& FLAG_FP_ARGUMENTS
);
596 case FFI_TYPE_DOUBLE
:
600 double_tmp
= **p_argv
.d
;
601 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
603 *fpr_base
.d
++ = double_tmp
;
605 if ((flags
& FLAG_COMPAT
) != 0)
606 *next_arg
.d
= double_tmp
;
610 *next_arg
.d
= double_tmp
;
611 if (++next_arg
.ul
== gpr_end
.ul
)
612 next_arg
.ul
= rest
.ul
;
614 FFI_ASSERT (flags
& FLAG_FP_ARGUMENTS
);
621 double_tmp
= **p_argv
.f
;
622 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
624 *fpr_base
.d
++ = double_tmp
;
626 if ((flags
& FLAG_COMPAT
) != 0)
628 # ifndef __LITTLE_ENDIAN__
629 next_arg
.f
[1] = (float) double_tmp
;
631 next_arg
.f
[0] = (float) double_tmp
;
638 # ifndef __LITTLE_ENDIAN__
639 next_arg
.f
[1] = (float) double_tmp
;
641 next_arg
.f
[0] = (float) double_tmp
;
644 if (++next_arg
.ul
== gpr_end
.ul
)
645 next_arg
.ul
= rest
.ul
;
647 FFI_ASSERT (flags
& FLAG_FP_ARGUMENTS
);
650 case FFI_TYPE_STRUCT
:
651 if ((ecif
->cif
->abi
& FFI_LINUX_STRUCT_ALIGN
) != 0)
653 align
= (*ptr
)->alignment
;
658 next_arg
.p
= FFI_ALIGN (next_arg
.p
, align
);
659 if (next_arg
.ul
== gpr_end
.ul
)
660 next_arg
.ul
= rest
.ul
;
663 elt
= discover_homogeneous_aggregate (ecif
->cif
->abi
, *ptr
, &elnum
);
675 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
676 if (elt
== FFI_TYPE_LONGDOUBLE
&&
677 (ecif
->cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
681 if (vecarg_count
< NUM_VEC_ARG_REGISTERS64
683 memcpy (vec_base
.f128
++, arg
.f128
++, sizeof (float128
));
685 memcpy (next_arg
.f128
, arg
.f128
++, sizeof (float128
));
686 if (++next_arg
.f128
== gpr_end
.f128
)
687 next_arg
.f128
= rest
.f128
;
690 while (--elnum
!= 0);
694 if (elt
== FFI_TYPE_FLOAT
)
698 double_tmp
= *arg
.f
++;
699 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
701 *fpr_base
.d
++ = double_tmp
;
703 *next_arg
.f
= (float) double_tmp
;
704 if (++next_arg
.f
== gpr_end
.f
)
708 while (--elnum
!= 0);
709 if ((next_arg
.p
& 7) != 0)
710 if (++next_arg
.f
== gpr_end
.f
)
716 double_tmp
= *arg
.d
++;
717 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
718 *fpr_base
.d
++ = double_tmp
;
720 *next_arg
.d
= double_tmp
;
721 if (++next_arg
.d
== gpr_end
.d
)
725 while (--elnum
!= 0);
727 if (elt
== FFI_TYPE_FLOAT
)
735 words
= ((*ptr
)->size
+ 7) / 8;
736 if (next_arg
.ul
>= gpr_base
.ul
&& next_arg
.ul
+ words
> gpr_end
.ul
)
738 size_t first
= gpr_end
.c
- next_arg
.c
;
739 memcpy (next_arg
.c
, *p_argv
.c
, first
);
740 memcpy (rest
.c
, *p_argv
.c
+ first
, (*ptr
)->size
- first
);
741 next_arg
.c
= rest
.c
+ words
* 8 - first
;
745 char *where
= next_arg
.c
;
747 #ifndef __LITTLE_ENDIAN__
748 /* Structures with size less than eight bytes are passed
750 if ((*ptr
)->size
< 8)
751 where
+= 8 - (*ptr
)->size
;
753 memcpy (where
, *p_argv
.c
, (*ptr
)->size
);
754 next_arg
.ul
+= words
;
755 if (next_arg
.ul
== gpr_end
.ul
)
756 next_arg
.ul
= rest
.ul
;
762 gprvalue
= **p_argv
.uc
;
765 gprvalue
= **p_argv
.sc
;
767 case FFI_TYPE_UINT16
:
768 gprvalue
= **p_argv
.us
;
770 case FFI_TYPE_SINT16
:
771 gprvalue
= **p_argv
.ss
;
773 case FFI_TYPE_UINT32
:
774 gprvalue
= **p_argv
.ui
;
777 case FFI_TYPE_SINT32
:
778 gprvalue
= **p_argv
.si
;
781 case FFI_TYPE_UINT64
:
782 case FFI_TYPE_SINT64
:
783 case FFI_TYPE_POINTER
:
784 gprvalue
= **p_argv
.ul
;
786 *next_arg
.ul
++ = gprvalue
;
787 if (next_arg
.ul
== gpr_end
.ul
)
788 next_arg
.ul
= rest
.ul
;
793 FFI_ASSERT (flags
& FLAG_4_GPR_ARGUMENTS
794 || (next_arg
.ul
>= gpr_base
.ul
795 && next_arg
.ul
<= gpr_base
.ul
+ 4));
800 #define MIN_CACHE_LINE_SIZE 8
803 flush_icache (char *wraddr
, char *xaddr
, int size
)
806 for (i
= 0; i
< size
; i
+= MIN_CACHE_LINE_SIZE
)
807 __asm__
volatile ("icbi 0,%0;" "dcbf 0,%1;"
808 : : "r" (xaddr
+ i
), "r" (wraddr
+ i
) : "memory");
809 __asm__
volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
810 : : "r"(xaddr
+ size
- 1), "r"(wraddr
+ size
- 1)
816 ffi_status FFI_HIDDEN
817 ffi_prep_closure_loc_linux64 (ffi_closure
*closure
,
819 void (*fun
) (ffi_cif
*, void *, void **, void *),
824 unsigned int *tramp
= (unsigned int *) &closure
->tramp
[0];
826 if (cif
->abi
< FFI_LINUX
|| cif
->abi
>= FFI_LAST_ABI
)
829 tramp
[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */
830 tramp
[1] = 0xe98c0010; /* ld 12,1f-0b(12) */
831 tramp
[2] = 0x7d8903a6; /* mtctr 12 */
832 tramp
[3] = 0x4e800420; /* bctr */
833 /* 1: .quad function_addr */
834 /* 2: .quad context */
835 *(void **) &tramp
[4] = (void *) ffi_closure_LINUX64
;
836 *(void **) &tramp
[6] = codeloc
;
837 flush_icache ((char *) tramp
, (char *) codeloc
, 4 * 4);
839 void **tramp
= (void **) &closure
->tramp
[0];
841 if (cif
->abi
< FFI_LINUX
|| cif
->abi
>= FFI_LAST_ABI
)
844 /* Copy function address and TOC from ffi_closure_LINUX64 OPD. */
845 memcpy (&tramp
[0], (void **) ffi_closure_LINUX64
, sizeof (void *));
847 memcpy (&tramp
[2], (void **) ffi_closure_LINUX64
+ 1, sizeof (void *));
852 closure
->user_data
= user_data
;
859 ffi_closure_helper_LINUX64 (ffi_cif
*cif
,
860 void (*fun
) (ffi_cif
*, void *, void **, void *),
867 /* rvalue is the pointer to space for return value in closure assembly */
868 /* pst is the pointer to parameter save area
869 (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
870 /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
871 /* pvec is the pointer to where v2-v13 are stored in ffi_closure_LINUX64 */
874 ffi_type
**arg_types
;
875 unsigned long i
, avn
, nfixedargs
;
876 ffi_dblfl
*end_pfr
= pfr
+ NUM_FPR_ARG_REGISTERS64
;
877 float128
*end_pvec
= pvec
+ NUM_VEC_ARG_REGISTERS64
;
880 avalue
= alloca (cif
->nargs
* sizeof (void *));
882 /* Copy the caller's structure return value address so that the
883 closure returns the data directly to the caller. */
884 if (cif
->rtype
->type
== FFI_TYPE_STRUCT
885 && (cif
->flags
& FLAG_RETURNS_SMST
) == 0)
887 rvalue
= (void *) *pst
;
894 nfixedargs
= (unsigned) -1;
895 if ((cif
->flags
& FLAG_COMPAT
) == 0)
897 nfixedargs
= cif
->nfixedargs
;
898 arg_types
= cif
->arg_types
;
900 /* Grab the addresses of the arguments from the stack frame. */
903 unsigned int elt
, elnum
;
905 switch (arg_types
[i
]->type
)
909 #ifndef __LITTLE_ENDIAN__
910 avalue
[i
] = (char *) pst
+ 7;
915 case FFI_TYPE_SINT16
:
916 case FFI_TYPE_UINT16
:
917 #ifndef __LITTLE_ENDIAN__
918 avalue
[i
] = (char *) pst
+ 6;
923 case FFI_TYPE_SINT32
:
924 case FFI_TYPE_UINT32
:
925 #ifndef __LITTLE_ENDIAN__
926 avalue
[i
] = (char *) pst
+ 4;
931 case FFI_TYPE_SINT64
:
932 case FFI_TYPE_UINT64
:
933 case FFI_TYPE_POINTER
:
938 case FFI_TYPE_STRUCT
:
939 if ((cif
->abi
& FFI_LINUX_STRUCT_ALIGN
) != 0)
941 align
= arg_types
[i
]->alignment
;
945 pst
= (unsigned long *) FFI_ALIGN ((size_t) pst
, align
);
947 elt
= discover_homogeneous_aggregate (cif
->abi
, arg_types
[i
], &elnum
);
960 /* Repackage the aggregate from its parts. The
961 aggregate size is not greater than the space taken by
962 the registers so store back to the register/parameter
964 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
965 if (elt
== FFI_TYPE_LONGDOUBLE
&&
966 (cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
968 if (pvec
+ elnum
<= end_pvec
)
975 if (pfr
+ elnum
<= end_pfr
)
982 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
983 if (elt
== FFI_TYPE_LONGDOUBLE
&&
984 (cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
988 if (pvec
< end_pvec
&& i
< nfixedargs
)
989 memcpy (to
.f128
, pvec
++, sizeof (float128
));
991 memcpy (to
.f128
, from
.f128
, sizeof (float128
));
995 while (--elnum
!= 0);
999 if (elt
== FFI_TYPE_FLOAT
)
1003 if (pfr
< end_pfr
&& i
< nfixedargs
)
1005 *to
.f
= (float) pfr
->d
;
1013 while (--elnum
!= 0);
1019 if (pfr
< end_pfr
&& i
< nfixedargs
)
1029 while (--elnum
!= 0);
1032 if (elt
== FFI_TYPE_FLOAT
)
1040 #ifndef __LITTLE_ENDIAN__
1041 /* Structures with size less than eight bytes are passed
1043 if (arg_types
[i
]->size
< 8)
1044 avalue
[i
] = (char *) pst
+ 8 - arg_types
[i
]->size
;
1049 pst
+= (arg_types
[i
]->size
+ 7) / 8;
1052 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
1053 case FFI_TYPE_LONGDOUBLE
:
1054 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_IEEE128
) != 0)
1056 if (((unsigned long) pst
& 0xF) != 0)
1058 if (pvec
< end_pvec
&& i
< nfixedargs
)
1065 else if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0)
1067 if (pfr
+ 1 < end_pfr
&& i
+ 1 < nfixedargs
)
1074 if (pfr
< end_pfr
&& i
< nfixedargs
)
1076 /* Passed partly in f13 and partly on the stack.
1077 Move it all to the stack. */
1078 *pst
= *(unsigned long *) pfr
;
1088 case FFI_TYPE_DOUBLE
:
1092 /* On the outgoing stack all values are aligned to 8 */
1093 /* there are 13 64bit floating point registers */
1095 if (pfr
< end_pfr
&& i
< nfixedargs
)
1105 case FFI_TYPE_FLOAT
:
1109 if (pfr
< end_pfr
&& i
< nfixedargs
)
1111 /* Float values are stored as doubles in the
1112 ffi_closure_LINUX64 code. Fix them here. */
1113 pfr
->f
= (float) pfr
->d
;
1119 #ifndef __LITTLE_ENDIAN__
1120 avalue
[i
] = (char *) pst
+ 4;
1135 (*fun
) (cif
, rvalue
, avalue
, user_data
);
1137 /* Tell ffi_closure_LINUX64 how to perform return type promotions. */
1138 if ((cif
->flags
& FLAG_RETURNS_SMST
) != 0)
1140 if ((cif
->flags
& (FLAG_RETURNS_FP
| FLAG_RETURNS_VEC
)) == 0)
1141 return FFI_V2_TYPE_SMALL_STRUCT
+ cif
->rtype
->size
- 1;
1142 else if ((cif
->flags
& FLAG_RETURNS_VEC
) != 0)
1143 return FFI_V2_TYPE_VECTOR_HOMOG
;
1144 else if ((cif
->flags
& FLAG_RETURNS_64BITS
) != 0)
1145 return FFI_V2_TYPE_DOUBLE_HOMOG
;
1147 return FFI_V2_TYPE_FLOAT_HOMOG
;
1149 if ((cif
->flags
& FLAG_RETURNS_VEC
) != 0)
1150 return FFI_V2_TYPE_VECTOR
;
1151 return cif
->rtype
->type
;