diff --git a/SOURCES/ffi-multilib.h b/SOURCES/ffi-multilib.h new file mode 100644 index 00000000..50a6226d --- /dev/null +++ b/SOURCES/ffi-multilib.h @@ -0,0 +1,23 @@ +/* This file is here to prevent a file conflict on multiarch systems. */ +#ifdef ffi_wrapper_h +#error "Do not define ffi_wrapper_h!" +#endif +#define ffi_wrapper_h + +#if defined(__i386__) +#include "ffi-i386.h" +#elif defined(__powerpc64__) +#include "ffi-ppc64.h" +#elif defined(__powerpc__) +#include "ffi-ppc.h" +#elif defined(__s390x__) +#include "ffi-s390x.h" +#elif defined(__s390__) +#include "ffi-s390.h" +#elif defined(__x86_64__) +#include "ffi-x86_64.h" +#else +#error "The libffi-devel package is not usable with the architecture." +#endif + +#undef ffi_wrapper_h diff --git a/SOURCES/ffitarget-multilib.h b/SOURCES/ffitarget-multilib.h new file mode 100644 index 00000000..b2ed5459 --- /dev/null +++ b/SOURCES/ffitarget-multilib.h @@ -0,0 +1,23 @@ +/* This file is here to prevent a file conflict on multiarch systems. */ +#ifdef ffitarget_wrapper_h +#error "Do not define ffitarget_wrapper_h!" +#endif +#define ffitarget_wrapper_h + +#if defined(__i386__) +#include "ffitarget-i386.h" +#elif defined(__powerpc64__) +#include "ffitarget-ppc64.h" +#elif defined(__powerpc__) +#include "ffitarget-ppc.h" +#elif defined(__s390x__) +#include "ffitarget-s390x.h" +#elif defined(__s390__) +#include "ffitarget-s390.h" +#elif defined(__x86_64__) +#include "ffitarget-x86_64.h" +#else +#error "The libffi-devel package is not usable with the architecture." +#endif + +#undef ffitarget_wrapper_h diff --git a/SOURCES/libffi-3.0.13-closures-Create-temporary-file-with-O_TMPFILE-and-O_.patch b/SOURCES/libffi-3.0.13-closures-Create-temporary-file-with-O_TMPFILE-and-O_.patch new file mode 100644 index 00000000..d5bb938f --- /dev/null +++ b/SOURCES/libffi-3.0.13-closures-Create-temporary-file-with-O_TMPFILE-and-O_.patch @@ -0,0 +1,82 @@ +From 8daeed9570af72eb135c8ded460d2888f05b2e68 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= +Date: Sun, 11 May 2014 22:54:58 +0200 +Subject: [PATCH 626/627] closures: Create temporary file with O_TMPFILE and + O_CLOEXEC when available + +The open_temp_exec_file_dir function can create a temporary file without +file system accessible link. If the O_TMPFILE flag is not defined (old +Linux kernel or libc) the behavior is unchanged. + +The open_temp_exec_file_name function now need a new argument "flags" +(like O_CLOEXEC) used for temporary file creation. + +The O_TMPFILE flag allow temporary file creation without race condition. +This feature/fix prevent another process to access the (future) +executable file from the file system. + +The O_CLOEXEC flag automatically close the temporary file for any +execve. This avoid transmitting (executable) file descriptor to a child +process. +--- + src/closures.c | 29 ++++++++++++++++++++++++----- + 1 file changed, 24 insertions(+), 5 deletions(-) + +diff --git a/src/closures.c b/src/closures.c +index c7863f3..9799ce6 100644 +--- a/src/closures.c ++++ b/src/closures.c +@@ -265,9 +265,9 @@ static size_t execsize = 0; + + /* Open a temporary file name, and immediately unlink it. */ + static int +-open_temp_exec_file_name (char *name) ++open_temp_exec_file_name (char *name, int flags) + { +- int fd = mkstemp (name); ++ int fd = mkostemp (name, flags); + + if (fd != -1) + unlink (name); +@@ -280,8 +280,27 @@ static int + open_temp_exec_file_dir (const char *dir) + { + static const char suffix[] = "/ffiXXXXXX"; +- int lendir = strlen (dir); +- char *tempname = __builtin_alloca (lendir + sizeof (suffix)); ++ int lendir, flags, fd; ++ char *tempname; ++ ++#ifdef O_CLOEXEC ++ flags = O_CLOEXEC; ++#else ++ flags = 0; ++#endif ++ ++#ifdef O_TMPFILE ++ fd = open (dir, flags | O_RDWR | O_EXCL | O_TMPFILE, 0700); ++ /* If the running system does not support the O_TMPFILE flag then retry without it. */ ++ if (fd != -1 || (errno != EINVAL && errno != EISDIR && errno != EOPNOTSUPP)) { ++ return fd; ++ } else { ++ errno = 0; ++ } ++#endif ++ ++ lendir = strlen (dir); ++ tempname = __builtin_alloca (lendir + sizeof (suffix)); + + if (!tempname) + return -1; +@@ -289,7 +308,7 @@ open_temp_exec_file_dir (const char *dir) + memcpy (tempname, dir, lendir); + memcpy (tempname + lendir, suffix, sizeof (suffix)); + +- return open_temp_exec_file_name (tempname); ++ return open_temp_exec_file_name (tempname, flags); + } + + /* Open a temporary file in the directory in the named environment +-- +1.7.12.1 + diff --git a/SOURCES/libffi-3.0.13-fix-include-path.patch b/SOURCES/libffi-3.0.13-fix-include-path.patch new file mode 100644 index 00000000..4502333a --- /dev/null +++ b/SOURCES/libffi-3.0.13-fix-include-path.patch @@ -0,0 +1,34 @@ +diff -up libffi-3.0.13/include/Makefile.am.fixpath libffi-3.0.13/include/Makefile.am +--- libffi-3.0.13/include/Makefile.am.fixpath 2013-05-25 22:11:25.983889342 -0400 ++++ libffi-3.0.13/include/Makefile.am 2013-05-25 22:12:12.337890037 -0400 +@@ -5,5 +5,5 @@ AUTOMAKE_OPTIONS=foreign + DISTCLEANFILES=ffitarget.h + EXTRA_DIST=ffi.h.in ffi_common.h + +-includesdir = $(libdir)/@PACKAGE_NAME@-@PACKAGE_VERSION@/include ++includesdir = $(includedir)/ + nodist_includes_HEADERS = ffi.h ffitarget.h +diff -up libffi-3.0.13/include/Makefile.in.fixpath libffi-3.0.13/include/Makefile.in +--- libffi-3.0.13/include/Makefile.in.fixpath 2013-05-25 22:12:56.259890696 -0400 ++++ libffi-3.0.13/include/Makefile.in 2013-05-25 22:13:12.101890934 -0400 +@@ -250,7 +250,7 @@ top_srcdir = @top_srcdir@ + AUTOMAKE_OPTIONS = foreign + DISTCLEANFILES = ffitarget.h + EXTRA_DIST = ffi.h.in ffi_common.h +-includesdir = $(libdir)/@PACKAGE_NAME@-@PACKAGE_VERSION@/include ++includesdir = $(includedir)/ + nodist_includes_HEADERS = ffi.h ffitarget.h + all: all-am + +diff -up libffi-3.0.13/libffi.pc.in.fixpath libffi-3.0.13/libffi.pc.in +--- libffi-3.0.13/libffi.pc.in.fixpath 2013-05-25 22:14:21.037891968 -0400 ++++ libffi-3.0.13/libffi.pc.in 2013-05-25 22:14:31.652892128 -0400 +@@ -1,7 +1,7 @@ + prefix=@prefix@ + exec_prefix=@exec_prefix@ + libdir=@libdir@ +-includedir=${libdir}/@PACKAGE_NAME@-@PACKAGE_VERSION@/include ++includedir=@includedir@ + + Name: @PACKAGE_NAME@ + Description: Library supporting Foreign Function Interfaces diff --git a/SOURCES/libffi-3.0.13-ppc64le-0.patch b/SOURCES/libffi-3.0.13-ppc64le-0.patch new file mode 100644 index 00000000..17925703 --- /dev/null +++ b/SOURCES/libffi-3.0.13-ppc64le-0.patch @@ -0,0 +1,1832 @@ +diff -urp libffi-3.0.13/src/powerpc/ffi.c libffi-current/src/powerpc/ffi.c +--- libffi-3.0.13/src/powerpc/ffi.c 2013-03-16 22:46:20.000000000 +1030 ++++ libffi-current/src/powerpc/ffi.c 2013-11-18 00:48:55.218044221 +1030 +@@ -48,12 +48,8 @@ enum { + + FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */ + +- FLAG_SYSV_SMST_R4 = 1 << (31-26), /* use r4 for FFI_SYSV 8 byte +- structs. */ +- FLAG_SYSV_SMST_R3 = 1 << (31-25), /* use r3 for FFI_SYSV 4 byte +- structs. */ +- + FLAG_ARG_NEEDS_COPY = 1 << (31- 7), ++ FLAG_ARG_NEEDS_PSAVE = FLAG_ARG_NEEDS_COPY, /* Used by ELFv2 */ + #ifndef __NO_FPRS__ + FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ + #endif +@@ -132,6 +128,9 @@ ffi_prep_args_SYSV (extended_cif *ecif, + + int i; + ffi_type **ptr; ++#ifndef __NO_FPRS__ ++ double double_tmp; ++#endif + union { + void **v; + char **c; +@@ -151,7 +150,6 @@ ffi_prep_args_SYSV (extended_cif *ecif, + gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS; + intarg_count = 0; + #ifndef __NO_FPRS__ +- double double_tmp; + fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS; + fparg_count = 0; + copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c); +@@ -374,7 +372,7 @@ ffi_prep_args_SYSV (extended_cif *ecif, + FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS); + /* The assert below is testing that the number of integer arguments agrees + with the number found in ffi_prep_cif_machdep(). However, intarg_count +- is incremeneted whenever we place an FP arg on the stack, so account for ++ is incremented whenever we place an FP arg on the stack, so account for + that before our assert test. */ + #ifndef __NO_FPRS__ + if (fparg_count > NUM_FPR_ARG_REGISTERS) +@@ -392,6 +390,45 @@ enum { + }; + enum { ASM_NEEDS_REGISTERS64 = 4 }; + ++#if _CALL_ELF == 2 ++static unsigned int ++discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum) ++{ ++ switch (t->type) ++ { ++ case FFI_TYPE_FLOAT: ++ case FFI_TYPE_DOUBLE: ++ *elnum = 1; ++ return (int) t->type; ++ ++ case FFI_TYPE_STRUCT:; ++ { ++ unsigned int base_elt = 0, total_elnum = 0; ++ ffi_type **el = t->elements; ++ while (*el) ++ { ++ unsigned int el_elt, el_elnum = 0; ++ el_elt = discover_homogeneous_aggregate (*el, &el_elnum); ++ if (el_elt == 0 ++ || (base_elt && base_elt != el_elt)) ++ return 0; ++ base_elt = el_elt; ++ total_elnum += el_elnum; ++ if (total_elnum > 8) ++ return 0; ++ el++; ++ } ++ *elnum = total_elnum; ++ return base_elt; ++ } ++ ++ default: ++ return 0; ++ } ++} ++#endif ++ ++ + /* ffi_prep_args64 is called by the assembly routine once stack space + has been allocated for the function's arguments. + +@@ -437,6 +474,7 @@ ffi_prep_args64 (extended_cif *ecif, uns + unsigned long *ul; + float *f; + double *d; ++ size_t p; + } valp; + + /* 'stacktop' points at the previous backchain pointer. */ +@@ -452,9 +490,9 @@ ffi_prep_args64 (extended_cif *ecif, uns + /* 'fpr_base' points at the space for fpr3, and grows upwards as + we use FPR registers. */ + valp fpr_base; +- int fparg_count; ++ unsigned int fparg_count; + +- int i, words; ++ unsigned int i, words, nargs, nfixedargs; + ffi_type **ptr; + double double_tmp; + union { +@@ -471,11 +509,18 @@ ffi_prep_args64 (extended_cif *ecif, uns + double **d; + } p_argv; + unsigned long gprvalue; ++#ifdef __STRUCT_PARM_ALIGN__ ++ unsigned long align; ++#endif + + stacktop.c = (char *) stack + bytes; + gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64; + gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64; ++#if _CALL_ELF == 2 ++ rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64; ++#else + rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64; ++#endif + fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64; + fparg_count = 0; + next_arg.ul = gpr_base.ul; +@@ -491,30 +536,36 @@ ffi_prep_args64 (extended_cif *ecif, uns + + /* Now for the arguments. */ + p_argv.v = ecif->avalue; +- for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; +- i > 0; +- i--, ptr++, p_argv.v++) ++ nargs = ecif->cif->nargs; ++ nfixedargs = ecif->cif->nfixedargs; ++ for (ptr = ecif->cif->arg_types, i = 0; ++ i < nargs; ++ i++, ptr++, p_argv.v++) + { ++ unsigned int elt, elnum; ++ + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + double_tmp = **p_argv.f; +- *next_arg.f = (float) double_tmp; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ *fpr_base.d++ = double_tmp; ++ else ++ *next_arg.f = (float) double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64) +- *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_DOUBLE: + double_tmp = **p_argv.d; +- *next_arg.d = double_tmp; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ *fpr_base.d++ = double_tmp; ++ else ++ *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64) +- *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; +@@ -522,18 +573,20 @@ ffi_prep_args64 (extended_cif *ecif, uns + #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + double_tmp = (*p_argv.d)[0]; +- *next_arg.d = double_tmp; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ *fpr_base.d++ = double_tmp; ++ else ++ *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64) +- *fpr_base.d++ = double_tmp; + fparg_count++; + double_tmp = (*p_argv.d)[1]; +- *next_arg.d = double_tmp; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ *fpr_base.d++ = double_tmp; ++ else ++ *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64) +- *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (__LDBL_MANT_DIG__ == 106); + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); +@@ -541,27 +594,86 @@ ffi_prep_args64 (extended_cif *ecif, uns + #endif + + case FFI_TYPE_STRUCT: +- words = ((*ptr)->size + 7) / 8; +- if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul) +- { +- size_t first = gpr_end.c - next_arg.c; +- memcpy (next_arg.c, *p_argv.c, first); +- memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first); +- next_arg.c = rest.c + words * 8 - first; ++#ifdef __STRUCT_PARM_ALIGN__ ++ align = (*ptr)->alignment; ++ if (align > __STRUCT_PARM_ALIGN__) ++ align = __STRUCT_PARM_ALIGN__; ++ if (align > 1) ++ next_arg.p = ALIGN (next_arg.p, align); ++#endif ++ elt = 0; ++#if _CALL_ELF == 2 ++ elt = discover_homogeneous_aggregate (*ptr, &elnum); ++#endif ++ if (elt) ++ { ++ union { ++ void *v; ++ float *f; ++ double *d; ++ } arg; ++ ++ arg.v = *p_argv.v; ++ if (elt == FFI_TYPE_FLOAT) ++ { ++ do ++ { ++ double_tmp = *arg.f++; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 ++ && i < nfixedargs) ++ *fpr_base.d++ = double_tmp; ++ else ++ *next_arg.f = (float) double_tmp; ++ if (++next_arg.f == gpr_end.f) ++ next_arg.f = rest.f; ++ fparg_count++; ++ } ++ while (--elnum != 0); ++ if ((next_arg.p & 3) != 0) ++ { ++ if (++next_arg.f == gpr_end.f) ++ next_arg.f = rest.f; ++ } ++ } ++ else ++ do ++ { ++ double_tmp = *arg.d++; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ *fpr_base.d++ = double_tmp; ++ else ++ *next_arg.d = double_tmp; ++ if (++next_arg.d == gpr_end.d) ++ next_arg.d = rest.d; ++ fparg_count++; ++ } ++ while (--elnum != 0); + } + else + { +- char *where = next_arg.c; +- +- /* Structures with size less than eight bytes are passed +- left-padded. */ +- if ((*ptr)->size < 8) +- where += 8 - (*ptr)->size; ++ words = ((*ptr)->size + 7) / 8; ++ if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul) ++ { ++ size_t first = gpr_end.c - next_arg.c; ++ memcpy (next_arg.c, *p_argv.c, first); ++ memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first); ++ next_arg.c = rest.c + words * 8 - first; ++ } ++ else ++ { ++ char *where = next_arg.c; + +- memcpy (where, *p_argv.c, (*ptr)->size); +- next_arg.ul += words; +- if (next_arg.ul == gpr_end.ul) +- next_arg.ul = rest.ul; ++#ifndef __LITTLE_ENDIAN__ ++ /* Structures with size less than eight bytes are passed ++ left-padded. */ ++ if ((*ptr)->size < 8) ++ where += 8 - (*ptr)->size; ++#endif ++ memcpy (where, *p_argv.c, (*ptr)->size); ++ next_arg.ul += words; ++ if (next_arg.ul == gpr_end.ul) ++ next_arg.ul = rest.ul; ++ } + } + break; + +@@ -605,24 +717,22 @@ ffi_prep_args64 (extended_cif *ecif, uns + + + /* Perform machine dependent cif processing */ +-ffi_status +-ffi_prep_cif_machdep (ffi_cif *cif) ++static ffi_status ++ffi_prep_cif_machdep_core (ffi_cif *cif) + { + /* All this is for the SYSV and LINUX64 ABI. */ +- int i; + ffi_type **ptr; + unsigned bytes; +- int fparg_count = 0, intarg_count = 0; +- unsigned flags = 0; ++ unsigned i, fparg_count = 0, intarg_count = 0; ++ unsigned flags = cif->flags; + unsigned struct_copy_size = 0; + unsigned type = cif->rtype->type; + unsigned size = cif->rtype->size; + ++ /* The machine-independent calculation of cif->bytes doesn't work ++ for us. Redo the calculation. */ + if (cif->abi != FFI_LINUX64) + { +- /* All the machine-independent calculation of cif->bytes will be wrong. +- Redo the calculation for SYSV. */ +- + /* Space for the frame pointer, callee's LR, and the asm's temp regs. */ + bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int); + +@@ -632,13 +742,20 @@ ffi_prep_cif_machdep (ffi_cif *cif) + else + { + /* 64-bit ABI. */ ++#if _CALL_ELF == 2 ++ /* Space for backchain, CR, LR, TOC and the asm's temp regs. */ ++ bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long); + ++ /* Space for the general registers. */ ++ bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long); ++#else + /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp + regs. */ + bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long); + + /* Space for the mandatory parm save area and general registers. */ + bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long); ++#endif + } + + /* Return value handling. The rules for SYSV are as follows: +@@ -658,19 +775,23 @@ ffi_prep_cif_machdep (ffi_cif *cif) + - soft-float float/doubles are treated as UINT32/UINT64 respectivley. + - soft-float long doubles are returned in gpr3-gpr6. */ + /* First translate for softfloat/nonlinux */ +- if (cif->abi == FFI_LINUX_SOFT_FLOAT) { +- if (type == FFI_TYPE_FLOAT) +- type = FFI_TYPE_UINT32; +- if (type == FFI_TYPE_DOUBLE) +- type = FFI_TYPE_UINT64; +- if (type == FFI_TYPE_LONGDOUBLE) +- type = FFI_TYPE_UINT128; +- } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) { ++ if (cif->abi == FFI_LINUX_SOFT_FLOAT) ++ { ++ if (type == FFI_TYPE_FLOAT) ++ type = FFI_TYPE_UINT32; ++ if (type == FFI_TYPE_DOUBLE) ++ type = FFI_TYPE_UINT64; ++ if (type == FFI_TYPE_LONGDOUBLE) ++ type = FFI_TYPE_UINT128; ++ } ++ else if (cif->abi != FFI_LINUX ++ && cif->abi != FFI_LINUX64) ++ { + #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- if (type == FFI_TYPE_LONGDOUBLE) +- type = FFI_TYPE_STRUCT; ++ if (type == FFI_TYPE_LONGDOUBLE) ++ type = FFI_TYPE_STRUCT; + #endif +- } ++ } + + switch (type) + { +@@ -697,35 +818,40 @@ ffi_prep_cif_machdep (ffi_cif *cif) + break; + + case FFI_TYPE_STRUCT: +- if (cif->abi == FFI_SYSV) ++ /* ++ * The final SYSV ABI says that structures smaller or equal 8 bytes ++ * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them ++ * in memory. ++ * ++ * NOTE: The assembly code can safely assume that it just needs to ++ * store both r3 and r4 into a 8-byte word-aligned buffer, as ++ * we allocate a temporary buffer in ffi_call() if this flag is ++ * set. ++ */ ++ if (cif->abi == FFI_SYSV && size <= 8) + { +- /* The final SYSV ABI says that structures smaller or equal 8 bytes +- are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them +- in memory. */ +- +- /* Treat structs with size <= 8 bytes. */ +- if (size <= 8) ++ flags |= FLAG_RETURNS_SMST; ++ break; ++ } ++#if _CALL_ELF == 2 ++ if (cif->abi == FFI_LINUX64) ++ { ++ unsigned int elt, elnum; ++ elt = discover_homogeneous_aggregate (cif->rtype, &elnum); ++ if (elt) ++ { ++ if (elt == FFI_TYPE_DOUBLE) ++ flags |= FLAG_RETURNS_64BITS; ++ flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST; ++ break; ++ } ++ if (size <= 16) + { + flags |= FLAG_RETURNS_SMST; +- /* These structs are returned in r3. We pack the type and the +- precalculated shift value (needed in the sysv.S) into flags. +- The same applies for the structs returned in r3/r4. */ +- if (size <= 4) +- { +- flags |= FLAG_SYSV_SMST_R3; +- flags |= 8 * (4 - size) << 8; +- break; +- } +- /* These structs are returned in r3 and r4. See above. */ +- if (size <= 8) +- { +- flags |= FLAG_SYSV_SMST_R3 | FLAG_SYSV_SMST_R4; +- flags |= 8 * (8 - size) << 8; +- break; +- } ++ break; + } + } +- ++#endif + intarg_count++; + flags |= FLAG_RETVAL_REFERENCE; + /* Fall through. */ +@@ -841,27 +967,54 @@ ffi_prep_cif_machdep (ffi_cif *cif) + else + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { ++ unsigned int elt, elnum; ++#ifdef __STRUCT_PARM_ALIGN__ ++ unsigned int align; ++#endif ++ + switch ((*ptr)->type) + { + #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +- if (cif->abi == FFI_LINUX_SOFT_FLOAT) +- intarg_count += 4; +- else +- { +- fparg_count += 2; +- intarg_count += 2; +- } ++ fparg_count += 2; ++ intarg_count += 2; ++ if (fparg_count > NUM_FPR_ARG_REGISTERS) ++ flags |= FLAG_ARG_NEEDS_PSAVE; + break; + #endif + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + fparg_count++; + intarg_count++; ++ if (fparg_count > NUM_FPR_ARG_REGISTERS) ++ flags |= FLAG_ARG_NEEDS_PSAVE; + break; + + case FFI_TYPE_STRUCT: ++#ifdef __STRUCT_PARM_ALIGN__ ++ align = (*ptr)->alignment; ++ if (align > __STRUCT_PARM_ALIGN__) ++ align = __STRUCT_PARM_ALIGN__; ++ align = align / 8; ++ if (align > 1) ++ intarg_count = ALIGN (intarg_count, align); ++#endif + intarg_count += ((*ptr)->size + 7) / 8; ++ elt = 0; ++#if _CALL_ELF == 2 ++ elt = discover_homogeneous_aggregate (*ptr, &elnum); ++#endif ++ if (elt) ++ { ++ fparg_count += elnum; ++ if (fparg_count > NUM_FPR_ARG_REGISTERS) ++ flags |= FLAG_ARG_NEEDS_PSAVE; ++ } ++ else ++ { ++ if (intarg_count > NUM_GPR_ARG_REGISTERS) ++ flags |= FLAG_ARG_NEEDS_PSAVE; ++ } + break; + + case FFI_TYPE_POINTER: +@@ -877,9 +1030,11 @@ ffi_prep_cif_machdep (ffi_cif *cif) + /* Everything else is passed as a 8-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; ++ if (intarg_count > NUM_GPR_ARG_REGISTERS) ++ flags |= FLAG_ARG_NEEDS_PSAVE; + break; + default: +- FFI_ASSERT (0); ++ FFI_ASSERT (0); + } + } + +@@ -917,8 +1072,13 @@ ffi_prep_cif_machdep (ffi_cif *cif) + #endif + + /* Stack space. */ ++#if _CALL_ELF == 2 ++ if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0) ++ bytes += intarg_count * sizeof (long); ++#else + if (intarg_count > NUM_GPR_ARG_REGISTERS64) + bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long); ++#endif + } + + /* The stack space allocated needs to be a multiple of 16 bytes. */ +@@ -933,6 +1093,26 @@ ffi_prep_cif_machdep (ffi_cif *cif) + return FFI_OK; + } + ++ffi_status ++ffi_prep_cif_machdep (ffi_cif *cif) ++{ ++ cif->nfixedargs = cif->nargs; ++ return ffi_prep_cif_machdep_core (cif); ++} ++ ++ffi_status ++ffi_prep_cif_machdep_var (ffi_cif *cif, ++ unsigned int nfixedargs, ++ unsigned int ntotalargs MAYBE_UNUSED) ++{ ++ cif->nfixedargs = nfixedargs; ++#if _CALL_ELF == 2 ++ if (cif->abi == FFI_LINUX64) ++ cif->flags |= FLAG_ARG_NEEDS_PSAVE; ++#endif ++ return ffi_prep_cif_machdep_core (cif); ++} ++ + extern void ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *, + void (*fn)(void)); + extern void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long, +@@ -944,30 +1124,28 @@ ffi_call(ffi_cif *cif, void (*fn)(void), + { + /* + * The final SYSV ABI says that structures smaller or equal 8 bytes +- * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them ++ * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them + * in memory. + * +- * Just to keep things simple for the assembly code, we will always +- * bounce-buffer struct return values less than or equal to 8 bytes. +- * This allows the ASM to handle SYSV small structures by directly +- * writing r3 and r4 to memory without worrying about struct size. ++ * We bounce-buffer SYSV small struct return values so that sysv.S ++ * can write r3 and r4 to memory without worrying about struct size. ++ * ++ * For ELFv2 ABI, use a bounce buffer for homogeneous structs too, ++ * for similar reasons. + */ +- unsigned int smst_buffer[2]; ++ unsigned long smst_buffer[8]; + extended_cif ecif; +- unsigned int rsize = 0; + + ecif.cif = cif; + ecif.avalue = avalue; + +- /* Ensure that we have a valid struct return value */ + ecif.rvalue = rvalue; +- if (cif->rtype->type == FFI_TYPE_STRUCT) { +- rsize = cif->rtype->size; +- if (rsize <= 8) +- ecif.rvalue = smst_buffer; +- else if (!rvalue) +- ecif.rvalue = alloca(rsize); +- } ++ if ((cif->flags & FLAG_RETURNS_SMST) != 0) ++ ecif.rvalue = smst_buffer; ++ /* Ensure that we have a valid struct return value. ++ FIXME: Isn't this just papering over a user problem? */ ++ else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT) ++ ecif.rvalue = alloca (cif->rtype->size); + + switch (cif->abi) + { +@@ -992,11 +1170,26 @@ ffi_call(ffi_cif *cif, void (*fn)(void), + + /* Check for a bounce-buffered return value */ + if (rvalue && ecif.rvalue == smst_buffer) +- memcpy(rvalue, smst_buffer, rsize); ++ { ++ unsigned int rsize = cif->rtype->size; ++#ifndef __LITTLE_ENDIAN__ ++ /* The SYSV ABI returns a structure of up to 4 bytes in size ++ left-padded in r3. */ ++ if (cif->abi == FFI_SYSV && rsize <= 4) ++ memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize); ++ /* The SYSV ABI returns a structure of up to 8 bytes in size ++ left-padded in r3/r4, and the ELFv2 ABI similarly returns a ++ structure of up to 8 bytes in size left-padded in r3. */ ++ else if (rsize <= 8) ++ memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize); ++ else ++#endif ++ memcpy (rvalue, smst_buffer, rsize); ++ } + } + + +-#ifndef POWERPC64 ++#if !defined POWERPC64 || _CALL_ELF == 2 + #define MIN_CACHE_LINE_SIZE 8 + + static void +@@ -1020,6 +1213,22 @@ ffi_prep_closure_loc (ffi_closure *closu + void *codeloc) + { + #ifdef POWERPC64 ++# if _CALL_ELF == 2 ++ unsigned int *tramp = (unsigned int *) &closure->tramp[0]; ++ ++ if (cif->abi != FFI_LINUX64) ++ return FFI_BAD_ABI; ++ ++ tramp[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */ ++ tramp[1] = 0xe98c0010; /* ld 12,1f-0b(12) */ ++ tramp[2] = 0x7d8903a6; /* mtctr 12 */ ++ tramp[3] = 0x4e800420; /* bctr */ ++ /* 1: .quad function_addr */ ++ /* 2: .quad context */ ++ *(void **) &tramp[4] = (void *) ffi_closure_LINUX64; ++ *(void **) &tramp[6] = codeloc; ++ flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE); ++# else + void **tramp = (void **) &closure->tramp[0]; + + if (cif->abi != FFI_LINUX64) +@@ -1027,6 +1236,7 @@ ffi_prep_closure_loc (ffi_closure *closu + /* Copy function address and TOC from ffi_closure_LINUX64. */ + memcpy (tramp, (char *) ffi_closure_LINUX64, 16); + tramp[2] = codeloc; ++# endif + #else + unsigned int *tramp; + +@@ -1236,6 +1446,7 @@ ffi_closure_helper_SYSV (ffi_closure *cl + + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: ++#ifndef __LITTLE_ENDIAN__ + /* there are 8 gpr registers used to pass values */ + if (ng < 8) + { +@@ -1249,9 +1460,11 @@ ffi_closure_helper_SYSV (ffi_closure *cl + pst++; + } + break; ++#endif + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: ++#ifndef __LITTLE_ENDIAN__ + /* there are 8 gpr registers used to pass values */ + if (ng < 8) + { +@@ -1265,6 +1478,7 @@ ffi_closure_helper_SYSV (ffi_closure *cl + pst++; + } + break; ++#endif + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: +@@ -1369,16 +1583,20 @@ ffi_closure_helper_LINUX64 (ffi_closure + + void **avalue; + ffi_type **arg_types; +- long i, avn; ++ unsigned long i, avn, nfixedargs; + ffi_cif *cif; + ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; ++#ifdef __STRUCT_PARM_ALIGN__ ++ unsigned long align; ++#endif + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (void *)); + +- /* Copy the caller's structure return value address so that the closure +- returns the data directly to the caller. */ +- if (cif->rtype->type == FFI_TYPE_STRUCT) ++ /* Copy the caller's structure return value address so that the ++ closure returns the data directly to the caller. */ ++ if (cif->rtype->type == FFI_TYPE_STRUCT ++ && (cif->flags & FLAG_RETURNS_SMST) == 0) + { + rvalue = (void *) *pst; + pst++; +@@ -1386,30 +1604,39 @@ ffi_closure_helper_LINUX64 (ffi_closure + + i = 0; + avn = cif->nargs; ++ nfixedargs = cif->nfixedargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { ++ unsigned int elt, elnum; ++ + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: ++#ifndef __LITTLE_ENDIAN__ + avalue[i] = (char *) pst + 7; + pst++; + break; ++#endif + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: ++#ifndef __LITTLE_ENDIAN__ + avalue[i] = (char *) pst + 6; + pst++; + break; ++#endif + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: ++#ifndef __LITTLE_ENDIAN__ + avalue[i] = (char *) pst + 4; + pst++; + break; ++#endif + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: +@@ -1419,12 +1646,82 @@ ffi_closure_helper_LINUX64 (ffi_closure + break; + + case FFI_TYPE_STRUCT: +- /* Structures with size less than eight bytes are passed +- left-padded. */ +- if (arg_types[i]->size < 8) +- avalue[i] = (char *) pst + 8 - arg_types[i]->size; ++#ifdef __STRUCT_PARM_ALIGN__ ++ align = arg_types[i]->alignment; ++ if (align > __STRUCT_PARM_ALIGN__) ++ align = __STRUCT_PARM_ALIGN__; ++ if (align > 1) ++ pst = (unsigned long *) ALIGN ((size_t) pst, align); ++#endif ++ elt = 0; ++#if _CALL_ELF == 2 ++ elt = discover_homogeneous_aggregate (arg_types[i], &elnum); ++#endif ++ if (elt) ++ { ++ union { ++ void *v; ++ unsigned long *ul; ++ float *f; ++ double *d; ++ size_t p; ++ } to, from; ++ ++ /* Repackage the aggregate from its parts. The ++ aggregate size is not greater than the space taken by ++ the registers so store back to the register/parameter ++ save arrays. */ ++ if (pfr + elnum <= end_pfr) ++ to.v = pfr; ++ else ++ to.v = pst; ++ ++ avalue[i] = to.v; ++ from.ul = pst; ++ if (elt == FFI_TYPE_FLOAT) ++ { ++ do ++ { ++ if (pfr < end_pfr && i < nfixedargs) ++ { ++ *to.f = (float) pfr->d; ++ pfr++; ++ } ++ else ++ *to.f = *from.f; ++ to.f++; ++ from.f++; ++ } ++ while (--elnum != 0); ++ } ++ else ++ { ++ do ++ { ++ if (pfr < end_pfr && i < nfixedargs) ++ { ++ *to.d = pfr->d; ++ pfr++; ++ } ++ else ++ *to.d = *from.d; ++ to.d++; ++ from.d++; ++ } ++ while (--elnum != 0); ++ } ++ } + else +- avalue[i] = pst; ++ { ++#ifndef __LITTLE_ENDIAN__ ++ /* Structures with size less than eight bytes are passed ++ left-padded. */ ++ if (arg_types[i]->size < 8) ++ avalue[i] = (char *) pst + 8 - arg_types[i]->size; ++ else ++#endif ++ avalue[i] = pst; ++ } + pst += (arg_types[i]->size + 7) / 8; + break; + +@@ -1436,7 +1733,7 @@ ffi_closure_helper_LINUX64 (ffi_closure + + /* there are 13 64bit floating point registers */ + +- if (pfr < end_pfr) ++ if (pfr < end_pfr && i < nfixedargs) + { + double temp = pfr->d; + pfr->f = (float) temp; +@@ -1452,7 +1749,7 @@ ffi_closure_helper_LINUX64 (ffi_closure + /* On the outgoing stack all values are aligned to 8 */ + /* there are 13 64bit floating point registers */ + +- if (pfr < end_pfr) ++ if (pfr < end_pfr && i < nfixedargs) + { + avalue[i] = pfr; + pfr++; +@@ -1464,14 +1761,14 @@ ffi_closure_helper_LINUX64 (ffi_closure + + #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +- if (pfr + 1 < end_pfr) ++ if (pfr + 1 < end_pfr && i + 1 < nfixedargs) + { + avalue[i] = pfr; + pfr += 2; + } + else + { +- if (pfr < end_pfr) ++ if (pfr < end_pfr && i < nfixedargs) + { + /* Passed partly in f13 and partly on the stack. + Move it all to the stack. */ +@@ -1495,5 +1792,14 @@ ffi_closure_helper_LINUX64 (ffi_closure + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ ++ if ((cif->flags & FLAG_RETURNS_SMST) != 0) ++ { ++ if ((cif->flags & FLAG_RETURNS_FP) == 0) ++ return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1; ++ else if ((cif->flags & FLAG_RETURNS_64BITS) != 0) ++ return FFI_V2_TYPE_DOUBLE_HOMOG; ++ else ++ return FFI_V2_TYPE_FLOAT_HOMOG; ++ } + return cif->rtype->type; + } +diff -urp libffi-3.0.13/src/powerpc/ffitarget.h libffi-current/src/powerpc/ffitarget.h +--- libffi-3.0.13/src/powerpc/ffitarget.h 2013-03-16 21:49:39.000000000 +1030 ++++ libffi-current/src/powerpc/ffitarget.h 2013-11-17 09:07:45.433681274 +1030 +@@ -106,6 +106,10 @@ typedef enum ffi_abi { + + #define FFI_CLOSURES 1 + #define FFI_NATIVE_RAW_API 0 ++#if defined (POWERPC) || defined (POWERPC_FREEBSD) ++# define FFI_TARGET_SPECIFIC_VARIADIC 1 ++# define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs ++#endif + + /* For additional types like the below, take care about the order in + ppc_closures.S. They must follow after the FFI_TYPE_LAST. */ +@@ -118,14 +122,23 @@ typedef enum ffi_abi { + defined in ffi.c, to determine the exact return type and its size. */ + #define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2) + +-#if defined(POWERPC64) || defined(POWERPC_AIX) ++/* Used by ELFv2 for homogenous structure returns. */ ++#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_TYPE_LAST + 1) ++#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_TYPE_LAST + 2) ++#define FFI_V2_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 3) ++ ++#if _CALL_ELF == 2 ++# define FFI_TRAMPOLINE_SIZE 32 ++#else ++# if defined(POWERPC64) || defined(POWERPC_AIX) + # if defined(POWERPC_DARWIN64) + # define FFI_TRAMPOLINE_SIZE 48 + # else + # define FFI_TRAMPOLINE_SIZE 24 + # endif +-#else /* POWERPC || POWERPC_AIX */ ++# else /* POWERPC || POWERPC_AIX */ + # define FFI_TRAMPOLINE_SIZE 40 ++# endif + #endif + + #ifndef LIBFFI_ASM +diff -urp libffi-3.0.13/src/powerpc/linux64_closure.S libffi-current/src/powerpc/linux64_closure.S +--- libffi-3.0.13/src/powerpc/linux64_closure.S 2013-03-16 21:49:39.000000000 +1030 ++++ libffi-current/src/powerpc/linux64_closure.S 2013-11-17 09:11:54.267742403 +1030 +@@ -33,15 +33,22 @@ + #ifdef __powerpc64__ + FFI_HIDDEN (ffi_closure_LINUX64) + .globl ffi_closure_LINUX64 ++# if _CALL_ELF == 2 ++ .text ++ffi_closure_LINUX64: ++ addis %r2, %r12, .TOC.-ffi_closure_LINUX64@ha ++ addi %r2, %r2, .TOC.-ffi_closure_LINUX64@l ++ .localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64 ++# else + .section ".opd","aw" + .align 3 + ffi_closure_LINUX64: +-#ifdef _CALL_LINUX ++# ifdef _CALL_LINUX + .quad .L.ffi_closure_LINUX64,.TOC.@tocbase,0 + .type ffi_closure_LINUX64,@function + .text + .L.ffi_closure_LINUX64: +-#else ++# else + FFI_HIDDEN (.ffi_closure_LINUX64) + .globl .ffi_closure_LINUX64 + .quad .ffi_closure_LINUX64,.TOC.@tocbase,0 +@@ -49,61 +56,103 @@ ffi_closure_LINUX64: + .type .ffi_closure_LINUX64,@function + .text + .ffi_closure_LINUX64: +-#endif ++# endif ++# endif ++ ++# if _CALL_ELF == 2 ++# 32 byte special reg save area + 64 byte parm save area and retval ++# + 13*8 fpr save area + round to 16 ++# define STACKFRAME 208 ++# define PARMSAVE 32 ++# No parameter save area is needed for the call to ffi_closure_helper_LINUX64, ++# so return value can start there. ++# define RETVAL PARMSAVE ++# else ++# 48 bytes special reg save area + 64 bytes parm save area ++# + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 ++# define STACKFRAME 240 ++# define PARMSAVE 48 ++# define RETVAL PARMSAVE+64 ++# endif ++ + .LFB1: +- # save general regs into parm save area +- std %r3, 48(%r1) +- std %r4, 56(%r1) +- std %r5, 64(%r1) +- std %r6, 72(%r1) ++# if _CALL_ELF == 2 ++ ld %r12, FFI_TRAMPOLINE_SIZE(%r11) # closure->cif ++ mflr %r0 ++ lwz %r12, 28(%r12) # cif->flags ++ mtcrf 0x40, %r12 ++ addi %r12, %r1, PARMSAVE ++ bt 7, .Lparmsave ++ # Our caller has not allocated a parameter save area. ++ # We need to allocate one here and use it to pass gprs to ++ # ffi_closure_helper_LINUX64. The return value area will do. ++ addi %r12, %r1, -STACKFRAME+RETVAL ++.Lparmsave: ++ std %r0, 16(%r1) ++ # Save general regs into parm save area ++ std %r3, 0(%r12) ++ std %r4, 8(%r12) ++ std %r5, 16(%r12) ++ std %r6, 24(%r12) ++ std %r7, 32(%r12) ++ std %r8, 40(%r12) ++ std %r9, 48(%r12) ++ std %r10, 56(%r12) ++ ++ # load up the pointer to the parm save area ++ mr %r5, %r12 ++# else + mflr %r0 ++ # Save general regs into parm save area ++ # This is the parameter save area set up by our caller. ++ std %r3, PARMSAVE+0(%r1) ++ std %r4, PARMSAVE+8(%r1) ++ std %r5, PARMSAVE+16(%r1) ++ std %r6, PARMSAVE+24(%r1) ++ std %r7, PARMSAVE+32(%r1) ++ std %r8, PARMSAVE+40(%r1) ++ std %r9, PARMSAVE+48(%r1) ++ std %r10, PARMSAVE+56(%r1) + +- std %r7, 80(%r1) +- std %r8, 88(%r1) +- std %r9, 96(%r1) +- std %r10, 104(%r1) + std %r0, 16(%r1) + +- # mandatory 48 bytes special reg save area + 64 bytes parm save area +- # + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 +- stdu %r1, -240(%r1) +-.LCFI0: ++ # load up the pointer to the parm save area ++ addi %r5, %r1, PARMSAVE ++# endif + + # next save fpr 1 to fpr 13 +- stfd %f1, 128+(0*8)(%r1) +- stfd %f2, 128+(1*8)(%r1) +- stfd %f3, 128+(2*8)(%r1) +- stfd %f4, 128+(3*8)(%r1) +- stfd %f5, 128+(4*8)(%r1) +- stfd %f6, 128+(5*8)(%r1) +- stfd %f7, 128+(6*8)(%r1) +- stfd %f8, 128+(7*8)(%r1) +- stfd %f9, 128+(8*8)(%r1) +- stfd %f10, 128+(9*8)(%r1) +- stfd %f11, 128+(10*8)(%r1) +- stfd %f12, 128+(11*8)(%r1) +- stfd %f13, 128+(12*8)(%r1) ++ stfd %f1, -104+(0*8)(%r1) ++ stfd %f2, -104+(1*8)(%r1) ++ stfd %f3, -104+(2*8)(%r1) ++ stfd %f4, -104+(3*8)(%r1) ++ stfd %f5, -104+(4*8)(%r1) ++ stfd %f6, -104+(5*8)(%r1) ++ stfd %f7, -104+(6*8)(%r1) ++ stfd %f8, -104+(7*8)(%r1) ++ stfd %f9, -104+(8*8)(%r1) ++ stfd %f10, -104+(9*8)(%r1) ++ stfd %f11, -104+(10*8)(%r1) ++ stfd %f12, -104+(11*8)(%r1) ++ stfd %f13, -104+(12*8)(%r1) + +- # set up registers for the routine that actually does the work +- # get the context pointer from the trampoline +- mr %r3, %r11 ++ # load up the pointer to the saved fpr registers */ ++ addi %r6, %r1, -104 + +- # now load up the pointer to the result storage +- addi %r4, %r1, 112 ++ # load up the pointer to the result storage ++ addi %r4, %r1, -STACKFRAME+RETVAL + +- # now load up the pointer to the parameter save area +- # in the previous frame +- addi %r5, %r1, 240 + 48 ++ stdu %r1, -STACKFRAME(%r1) ++.LCFI0: + +- # now load up the pointer to the saved fpr registers */ +- addi %r6, %r1, 128 ++ # get the context pointer from the trampoline ++ mr %r3, %r11 + + # make the call +-#ifdef _CALL_LINUX ++# if defined _CALL_LINUX || _CALL_ELF == 2 + bl ffi_closure_helper_LINUX64 +-#else ++# else + bl .ffi_closure_helper_LINUX64 +-#endif ++# endif + .Lret: + + # now r3 contains the return type +@@ -112,10 +161,12 @@ ffi_closure_LINUX64: + + # look up the proper starting point in table + # by using return type as offset ++ ld %r0, STACKFRAME+16(%r1) ++ cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT ++ bge .Lsmall + mflr %r4 # move address of .Lret to r4 + sldi %r3, %r3, 4 # now multiply return type by 16 + addi %r4, %r4, .Lret_type0 - .Lret +- ld %r0, 240+16(%r1) + add %r3, %r3, %r4 # add contents of table to table address + mtctr %r3 + bctr # jump to it +@@ -128,89 +179,175 @@ ffi_closure_LINUX64: + .Lret_type0: + # case FFI_TYPE_VOID + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + nop + # case FFI_TYPE_INT +- lwa %r3, 112+4(%r1) ++# ifdef __LITTLE_ENDIAN__ ++ lwa %r3, RETVAL+0(%r1) ++# else ++ lwa %r3, RETVAL+4(%r1) ++# endif + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_FLOAT +- lfs %f1, 112+0(%r1) ++ lfs %f1, RETVAL+0(%r1) + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_DOUBLE +- lfd %f1, 112+0(%r1) ++ lfd %f1, RETVAL+0(%r1) + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_LONGDOUBLE +- lfd %f1, 112+0(%r1) ++ lfd %f1, RETVAL+0(%r1) + mtlr %r0 +- lfd %f2, 112+8(%r1) ++ lfd %f2, RETVAL+8(%r1) + b .Lfinish + # case FFI_TYPE_UINT8 +- lbz %r3, 112+7(%r1) ++# ifdef __LITTLE_ENDIAN__ ++ lbz %r3, RETVAL+0(%r1) ++# else ++ lbz %r3, RETVAL+7(%r1) ++# endif + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_SINT8 +- lbz %r3, 112+7(%r1) ++# ifdef __LITTLE_ENDIAN__ ++ lbz %r3, RETVAL+0(%r1) ++# else ++ lbz %r3, RETVAL+7(%r1) ++# endif + extsb %r3,%r3 + mtlr %r0 + b .Lfinish + # case FFI_TYPE_UINT16 +- lhz %r3, 112+6(%r1) ++# ifdef __LITTLE_ENDIAN__ ++ lhz %r3, RETVAL+0(%r1) ++# else ++ lhz %r3, RETVAL+6(%r1) ++# endif + mtlr %r0 + .Lfinish: +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_SINT16 +- lha %r3, 112+6(%r1) ++# ifdef __LITTLE_ENDIAN__ ++ lha %r3, RETVAL+0(%r1) ++# else ++ lha %r3, RETVAL+6(%r1) ++# endif + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_UINT32 +- lwz %r3, 112+4(%r1) ++# ifdef __LITTLE_ENDIAN__ ++ lwz %r3, RETVAL+0(%r1) ++# else ++ lwz %r3, RETVAL+4(%r1) ++# endif + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_SINT32 +- lwa %r3, 112+4(%r1) ++# ifdef __LITTLE_ENDIAN__ ++ lwa %r3, RETVAL+0(%r1) ++# else ++ lwa %r3, RETVAL+4(%r1) ++# endif + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_UINT64 +- ld %r3, 112+0(%r1) ++ ld %r3, RETVAL+0(%r1) + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_SINT64 +- ld %r3, 112+0(%r1) ++ ld %r3, RETVAL+0(%r1) + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + # case FFI_TYPE_STRUCT + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr + nop + # case FFI_TYPE_POINTER +- ld %r3, 112+0(%r1) ++ ld %r3, RETVAL+0(%r1) + mtlr %r0 +- addi %r1, %r1, 240 ++ addi %r1, %r1, STACKFRAME + blr +-# esac ++# case FFI_V2_TYPE_FLOAT_HOMOG ++ lfs %f1, RETVAL+0(%r1) ++ lfs %f2, RETVAL+4(%r1) ++ lfs %f3, RETVAL+8(%r1) ++ b .Lmorefloat ++# case FFI_V2_TYPE_DOUBLE_HOMOG ++ lfd %f1, RETVAL+0(%r1) ++ lfd %f2, RETVAL+8(%r1) ++ lfd %f3, RETVAL+16(%r1) ++ lfd %f4, RETVAL+24(%r1) ++ mtlr %r0 ++ lfd %f5, RETVAL+32(%r1) ++ lfd %f6, RETVAL+40(%r1) ++ lfd %f7, RETVAL+48(%r1) ++ lfd %f8, RETVAL+56(%r1) ++ addi %r1, %r1, STACKFRAME ++ blr ++.Lmorefloat: ++ lfs %f4, RETVAL+12(%r1) ++ mtlr %r0 ++ lfs %f5, RETVAL+16(%r1) ++ lfs %f6, RETVAL+20(%r1) ++ lfs %f7, RETVAL+24(%r1) ++ lfs %f8, RETVAL+28(%r1) ++ addi %r1, %r1, STACKFRAME ++ blr ++.Lsmall: ++# ifdef __LITTLE_ENDIAN__ ++ ld %r3,RETVAL+0(%r1) ++ mtlr %r0 ++ ld %r4,RETVAL+8(%r1) ++ addi %r1, %r1, STACKFRAME ++ blr ++# else ++ # A struct smaller than a dword is returned in the low bits of r3 ++ # ie. right justified. Larger structs are passed left justified ++ # in r3 and r4. The return value area on the stack will have ++ # the structs as they are usually stored in memory. ++ cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes? ++ neg %r5, %r3 ++ ld %r3,RETVAL+0(%r1) ++ blt .Lsmalldown ++ mtlr %r0 ++ ld %r4,RETVAL+8(%r1) ++ addi %r1, %r1, STACKFRAME ++ blr ++.Lsmalldown: ++ addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7 ++ mtlr %r0 ++ sldi %r5, %r5, 3 ++ addi %r1, %r1, STACKFRAME ++ srd %r3, %r3, %r5 ++ blr ++# endif ++ + .LFE1: + .long 0 + .byte 0,12,0,1,128,0,0,0 +-#ifdef _CALL_LINUX ++# if _CALL_ELF == 2 ++ .size ffi_closure_LINUX64,.-ffi_closure_LINUX64 ++# else ++# ifdef _CALL_LINUX + .size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64 +-#else ++# else + .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 +-#endif ++# endif ++# endif + + .section .eh_frame,EH_FRAME_FLAGS,@progbits + .Lframe1: +@@ -239,14 +376,14 @@ ffi_closure_LINUX64: + .byte 0x2 # DW_CFA_advance_loc1 + .byte .LCFI0-.LFB1 + .byte 0xe # DW_CFA_def_cfa_offset +- .uleb128 240 ++ .uleb128 STACKFRAME + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x41 + .sleb128 -2 + .align 3 + .LEFDE1: +-#endif + +-#if defined __ELF__ && defined __linux__ ++# if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits ++# endif + #endif +diff -urp libffi-3.0.13/src/powerpc/linux64.S libffi-current/src/powerpc/linux64.S +--- libffi-3.0.13/src/powerpc/linux64.S 2013-03-16 21:49:39.000000000 +1030 ++++ libffi-current/src/powerpc/linux64.S 2013-11-17 09:09:09.742314090 +1030 +@@ -32,15 +32,22 @@ + #ifdef __powerpc64__ + .hidden ffi_call_LINUX64 + .globl ffi_call_LINUX64 ++# if _CALL_ELF == 2 ++ .text ++ffi_call_LINUX64: ++ addis %r2, %r12, .TOC.-ffi_call_LINUX64@ha ++ addi %r2, %r2, .TOC.-ffi_call_LINUX64@l ++ .localentry ffi_call_LINUX64, . - ffi_call_LINUX64 ++# else + .section ".opd","aw" + .align 3 + ffi_call_LINUX64: +-#ifdef _CALL_LINUX ++# ifdef _CALL_LINUX + .quad .L.ffi_call_LINUX64,.TOC.@tocbase,0 + .type ffi_call_LINUX64,@function + .text + .L.ffi_call_LINUX64: +-#else ++# else + .hidden .ffi_call_LINUX64 + .globl .ffi_call_LINUX64 + .quad .ffi_call_LINUX64,.TOC.@tocbase,0 +@@ -48,7 +55,8 @@ ffi_call_LINUX64: + .type .ffi_call_LINUX64,@function + .text + .ffi_call_LINUX64: +-#endif ++# endif ++# endif + .LFB1: + mflr %r0 + std %r28, -32(%r1) +@@ -63,26 +71,35 @@ ffi_call_LINUX64: + mr %r31, %r5 /* flags, */ + mr %r30, %r6 /* rvalue, */ + mr %r29, %r7 /* function address. */ ++/* Save toc pointer, not for the ffi_prep_args64 call, but for the later ++ bctrl function call. */ ++# if _CALL_ELF == 2 ++ std %r2, 24(%r1) ++# else + std %r2, 40(%r1) ++# endif + + /* Call ffi_prep_args64. */ + mr %r4, %r1 +-#ifdef _CALL_LINUX ++# if defined _CALL_LINUX || _CALL_ELF == 2 + bl ffi_prep_args64 +-#else ++# else + bl .ffi_prep_args64 +-#endif ++# endif + +- ld %r0, 0(%r29) ++# if _CALL_ELF == 2 ++ mr %r12, %r29 ++# else ++ ld %r12, 0(%r29) + ld %r2, 8(%r29) + ld %r11, 16(%r29) +- ++# endif + /* Now do the call. */ + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40, %r31 + + /* Get the address to call into CTR. */ +- mtctr %r0 ++ mtctr %r12 + /* Load all those argument registers. */ + ld %r3, -32-(8*8)(%r28) + ld %r4, -32-(7*8)(%r28) +@@ -117,12 +134,17 @@ ffi_call_LINUX64: + + /* This must follow the call immediately, the unwinder + uses this to find out if r2 has been saved or not. */ ++# if _CALL_ELF == 2 ++ ld %r2, 24(%r1) ++# else + ld %r2, 40(%r1) ++# endif + + /* Now, deal with the return value. */ + mtcrf 0x01, %r31 +- bt- 30, .Ldone_return_value +- bt- 29, .Lfp_return_value ++ bt 31, .Lstruct_return_value ++ bt 30, .Ldone_return_value ++ bt 29, .Lfp_return_value + std %r3, 0(%r30) + /* Fall through... */ + +@@ -130,7 +152,7 @@ ffi_call_LINUX64: + /* Restore the registers we used and return. */ + mr %r1, %r28 + ld %r0, 16(%r28) +- ld %r28, -32(%r1) ++ ld %r28, -32(%r28) + mtlr %r0 + ld %r29, -24(%r1) + ld %r30, -16(%r1) +@@ -147,14 +169,48 @@ ffi_call_LINUX64: + .Lfloat_return_value: + stfs %f1, 0(%r30) + b .Ldone_return_value ++ ++.Lstruct_return_value: ++ bf 29, .Lsmall_struct ++ bf 28, .Lfloat_homog_return_value ++ stfd %f1, 0(%r30) ++ stfd %f2, 8(%r30) ++ stfd %f3, 16(%r30) ++ stfd %f4, 24(%r30) ++ stfd %f5, 32(%r30) ++ stfd %f6, 40(%r30) ++ stfd %f7, 48(%r30) ++ stfd %f8, 56(%r30) ++ b .Ldone_return_value ++ ++.Lfloat_homog_return_value: ++ stfs %f1, 0(%r30) ++ stfs %f2, 4(%r30) ++ stfs %f3, 8(%r30) ++ stfs %f4, 12(%r30) ++ stfs %f5, 16(%r30) ++ stfs %f6, 20(%r30) ++ stfs %f7, 24(%r30) ++ stfs %f8, 28(%r30) ++ b .Ldone_return_value ++ ++.Lsmall_struct: ++ std %r3, 0(%r30) ++ std %r4, 8(%r30) ++ b .Ldone_return_value ++ + .LFE1: + .long 0 + .byte 0,12,0,1,128,4,0,0 +-#ifdef _CALL_LINUX ++# if _CALL_ELF == 2 ++ .size ffi_call_LINUX64,.-ffi_call_LINUX64 ++# else ++# ifdef _CALL_LINUX + .size ffi_call_LINUX64,.-.L.ffi_call_LINUX64 +-#else ++# else + .size .ffi_call_LINUX64,.-.ffi_call_LINUX64 +-#endif ++# endif ++# endif + + .section .eh_frame,EH_FRAME_FLAGS,@progbits + .Lframe1: +@@ -197,8 +253,8 @@ ffi_call_LINUX64: + .uleb128 0x4 + .align 3 + .LEFDE1: +-#endif + +-#if defined __ELF__ && defined __linux__ ++# if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 + .section .note.GNU-stack,"",@progbits ++# endif + #endif +diff -urp libffi-3.0.13/src/powerpc/ppc_closure.S libffi-current/src/powerpc/ppc_closure.S +--- libffi-3.0.13/src/powerpc/ppc_closure.S 2013-03-16 21:49:39.000000000 +1030 ++++ libffi-current/src/powerpc/ppc_closure.S 2013-11-17 13:06:22.569393369 +1030 +@@ -159,25 +159,41 @@ ENTRY(ffi_closure_SYSV) + #endif + + # case FFI_TYPE_UINT8 ++#ifdef __LITTLE_ENDIAN__ ++ lbz %r3,112+0(%r1) ++#else + lbz %r3,112+3(%r1) ++#endif + mtlr %r0 + addi %r1,%r1,144 + blr + + # case FFI_TYPE_SINT8 ++#ifdef __LITTLE_ENDIAN__ ++ lbz %r3,112+0(%r1) ++#else + lbz %r3,112+3(%r1) ++#endif + extsb %r3,%r3 + mtlr %r0 + b .Lfinish + + # case FFI_TYPE_UINT16 ++#ifdef __LITTLE_ENDIAN__ ++ lhz %r3,112+0(%r1) ++#else + lhz %r3,112+2(%r1) ++#endif + mtlr %r0 + addi %r1,%r1,144 + blr + + # case FFI_TYPE_SINT16 ++#ifdef __LITTLE_ENDIAN__ ++ lha %r3,112+0(%r1) ++#else + lha %r3,112+2(%r1) ++#endif + mtlr %r0 + addi %r1,%r1,144 + blr +@@ -222,7 +238,7 @@ ENTRY(ffi_closure_SYSV) + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + lwz %r5,112+8(%r1) +- bl .Luint128 ++ b .Luint128 + + # The return types below are only used when the ABI type is FFI_SYSV. + # case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct. +@@ -239,9 +255,15 @@ ENTRY(ffi_closure_SYSV) + + # case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct. + lwz %r3,112+0(%r1) ++#ifdef __LITTLE_ENDIAN__ ++ mtlr %r0 ++ addi %r1,%r1,144 ++ blr ++#else + srwi %r3,%r3,8 + mtlr %r0 + b .Lfinish ++#endif + + # case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct. + lwz %r3,112+0(%r1) +@@ -252,20 +274,35 @@ ENTRY(ffi_closure_SYSV) + # case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) ++#ifdef __LITTLE_ENDIAN__ ++ mtlr %r0 ++ b .Lfinish ++#else + li %r5,24 + b .Lstruct567 ++#endif + + # case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) ++#ifdef __LITTLE_ENDIAN__ ++ mtlr %r0 ++ b .Lfinish ++#else + li %r5,16 + b .Lstruct567 ++#endif + + # case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) ++#ifdef __LITTLE_ENDIAN__ ++ mtlr %r0 ++ b .Lfinish ++#else + li %r5,8 + b .Lstruct567 ++#endif + + # case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct. + lwz %r3,112+0(%r1) +@@ -273,6 +310,7 @@ ENTRY(ffi_closure_SYSV) + mtlr %r0 + b .Lfinish + ++#ifndef __LITTLE_ENDIAN__ + .Lstruct567: + subfic %r6,%r5,32 + srw %r4,%r4,%r5 +@@ -282,6 +320,7 @@ ENTRY(ffi_closure_SYSV) + mtlr %r0 + addi %r1,%r1,144 + blr ++#endif + + .Luint128: + lwz %r6,112+12(%r1) +diff -urp libffi-3.0.13/src/powerpc/sysv.S libffi-current/src/powerpc/sysv.S +--- libffi-3.0.13/src/powerpc/sysv.S 2013-03-16 21:49:39.000000000 +1030 ++++ libffi-current/src/powerpc/sysv.S 2013-11-13 22:36:35.222994628 +1030 +@@ -142,19 +142,14 @@ L(float_return_value): + #endif + + L(small_struct_return_value): +- extrwi %r6,%r31,2,19 /* number of bytes padding = shift/8 */ +- mtcrf 0x02,%r31 /* copy flags to cr[24:27] (cr6) */ +- extrwi %r5,%r31,5,19 /* r5 <- number of bits of padding */ +- subfic %r6,%r6,4 /* r6 <- number of useful bytes in r3 */ +- bf- 25,L(done_return_value) /* struct in r3 ? if not, done. */ +-/* smst_one_register: */ +- slw %r3,%r3,%r5 /* Left-justify value in r3 */ +- mtxer %r6 /* move byte count to XER ... */ +- stswx %r3,0,%r30 /* ... and store that many bytes */ +- bf+ 26,L(done_return_value) /* struct in r3:r4 ? */ +- add %r6,%r6,%r30 /* adjust pointer */ +- stswi %r4,%r6,4 /* store last four bytes */ +- b L(done_return_value) ++ /* ++ * The C code always allocates a properly-aligned 8-byte bounce ++ * buffer to make this assembly code very simple. Just write out ++ * r3 and r4 to the buffer to allow the C code to handle the rest. ++ */ ++ stw %r3, 0(%r30) ++ stw %r4, 4(%r30) ++ b L(done_return_value) + + .LFE1: + END(ffi_call_SYSV) +diff -urp libffi-3.0.13/testsuite/libffi.call/cls_double_va.c libffi-current/testsuite/libffi.call/cls_double_va.c +--- libffi-3.0.13/testsuite/libffi.call/cls_double_va.c 2013-03-16 21:49:39.000000000 +1030 ++++ libffi-current/testsuite/libffi.call/cls_double_va.c 2013-11-13 22:37:13.437459229 +1030 +@@ -38,7 +38,7 @@ int main (void) + + /* This printf call is variadic */ + CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint, +- arg_types) == FFI_OK); ++ arg_types) == FFI_OK); + + args[0] = &format; + args[1] = &doubleArg; +@@ -49,12 +49,10 @@ int main (void) + printf("res: %d\n", (int) res); + /* { dg-output "\nres: 4" } */ + +- /* The call to cls_double_va_fn is static, so have to use a normal prep_cif */ +- CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, arg_types) == FFI_OK); ++ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL, ++ code) == FFI_OK); + +- CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL, code) == FFI_OK); +- +- res = ((int(*)(char*, double))(code))(format, doubleArg); ++ res = ((int(*)(char*, ...))(code))(format, doubleArg); + /* { dg-output "\n7.0" } */ + printf("res: %d\n", (int) res); + /* { dg-output "\nres: 4" } */ +diff -urp libffi-3.0.13/testsuite/libffi.call/cls_longdouble_va.c libffi-current/testsuite/libffi.call/cls_longdouble_va.c +--- libffi-3.0.13/testsuite/libffi.call/cls_longdouble_va.c 2013-03-16 21:49:39.000000000 +1030 ++++ libffi-current/testsuite/libffi.call/cls_longdouble_va.c 2013-11-13 22:37:13.437459229 +1030 +@@ -38,7 +38,7 @@ int main (void) + + /* This printf call is variadic */ + CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint, +- arg_types) == FFI_OK); ++ arg_types) == FFI_OK); + + args[0] = &format; + args[1] = &ldArg; +@@ -49,13 +49,10 @@ int main (void) + printf("res: %d\n", (int) res); + /* { dg-output "\nres: 4" } */ + +- /* The call to cls_longdouble_va_fn is static, so have to use a normal prep_cif */ +- CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, +- arg_types) == FFI_OK); ++ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, ++ code) == FFI_OK); + +- CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK); +- +- res = ((int(*)(char*, long double))(code))(format, ldArg); ++ res = ((int(*)(char*, ...))(code))(format, ldArg); + /* { dg-output "\n7.0" } */ + printf("res: %d\n", (int) res); + /* { dg-output "\nres: 4" } */ +diff -urp libffi-3.0.13/doc/libffi.texi libffi-current/doc/libffi.texi +--- libffi-3.0.13/doc/libffi.texi 2013-03-16 22:41:19.000000000 +1030 ++++ libffi-current/doc/libffi.texi 2013-11-17 09:06:03.209763612 +1030 +@@ -184,11 +184,11 @@ This calls the function @var{fn} accordi + + @var{rvalue} is a pointer to a chunk of memory that will hold the + result of the function call. This must be large enough to hold the +-result and must be suitably aligned; it is the caller's responsibility ++result, no smaller than the system register size (generally 32 or 64 ++bits), and must be suitably aligned; it is the caller's responsibility + to ensure this. If @var{cif} declares that the function returns + @code{void} (using @code{ffi_type_void}), then @var{rvalue} is +-ignored. If @var{rvalue} is @samp{NULL}, then the return value is +-discarded. ++ignored. + + @var{avalues} is a vector of @code{void *} pointers that point to the + memory locations holding the argument values for a call. If @var{cif} +@@ -214,7 +214,7 @@ int main() + ffi_type *args[1]; + void *values[1]; + char *s; +- int rc; ++ ffi_arg rc; + + /* Initialize the argument info vectors */ + args[0] = &ffi_type_pointer; +@@ -222,7 +222,7 @@ int main() + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, +- &ffi_type_uint, args) == FFI_OK) ++ &ffi_type_sint, args) == FFI_OK) + @{ + s = "Hello World!"; + ffi_call(&cif, puts, &rc, values); +@@ -414,6 +414,7 @@ Here is the corresponding code to descri + int i; + + tm_type.size = tm_type.alignment = 0; ++ tm_type.type = FFI_TYPE_STRUCT; + tm_type.elements = &tm_type_elements; + + for (i = 0; i < 9; i++) +@@ -540,21 +541,23 @@ A trivial example that creates a new @co + #include + + /* Acts like puts with the file given at time of enclosure. */ +-void puts_binding(ffi_cif *cif, unsigned int *ret, void* args[], +- FILE *stream) ++void puts_binding(ffi_cif *cif, void *ret, void* args[], ++ void *stream) + @{ +- *ret = fputs(*(char **)args[0], stream); ++ *(ffi_arg *)ret = fputs(*(char **)args[0], (FILE *)stream); + @} + ++typedef int (*puts_t)(char *); ++ + int main() + @{ + ffi_cif cif; + ffi_type *args[1]; + ffi_closure *closure; + +- int (*bound_puts)(char *); ++ void *bound_puts; + int rc; +- ++ + /* Allocate closure and bound_puts */ + closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts); + +@@ -565,13 +568,13 @@ int main() + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, +- &ffi_type_uint, args) == FFI_OK) ++ &ffi_type_sint, args) == FFI_OK) + @{ + /* Initialize the closure, setting stream to stdout */ +- if (ffi_prep_closure_loc(closure, &cif, puts_binding, ++ if (ffi_prep_closure_loc(closure, &cif, puts_binding, + stdout, bound_puts) == FFI_OK) + @{ +- rc = bound_puts("Hello World!"); ++ rc = ((puts_t)bound_puts)("Hello World!"); + /* rc now holds the result of the call to fputs */ + @} + @} diff --git a/SOURCES/libffi-3.0.13-ppc64le-1.patch b/SOURCES/libffi-3.0.13-ppc64le-1.patch new file mode 100644 index 00000000..d227b146 --- /dev/null +++ b/SOURCES/libffi-3.0.13-ppc64le-1.patch @@ -0,0 +1,56 @@ +Date: Wed, 20 Nov 2013 18:03:32 +1030 +From: Alan Modra +To: libffi-discuss at sourceware dot org +Subject: PowerPC64 ELFv2 fix 1 of 2 +Message-ID: <20131120073332.GF22514@bubble.grove.modra.org> +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline +User-Agent: Mutt/1.5.21 (2010-09-15) + +Using the return value area as a place to pass parameters wasn't such +a good idea, causing a failure of cls_ulonglong.c. I didn't see this +when running the mainline gcc libffi testsuite because that version of +the test is inferior to the upstreamm libffi test. + + * src/powerpc/linux64_closure.S: Don't use the return value area + as a parameter save area on ELFv2. + +diff --git a/src/powerpc/linux64_closure.S b/src/powerpc/linux64_closure.S +index 9b6b5f3..4d012cc 100644 +--- a/src/powerpc/linux64_closure.S ++++ b/src/powerpc/linux64_closure.S +@@ -60,13 +60,11 @@ ffi_closure_LINUX64: + # endif + + # if _CALL_ELF == 2 +-# 32 byte special reg save area + 64 byte parm save area and retval +-# + 13*8 fpr save area + round to 16 +-# define STACKFRAME 208 ++# 32 byte special reg save area + 64 byte parm save area ++# + 64 byte retval area + 13*8 fpr save area + round to 16 ++# define STACKFRAME 272 + # define PARMSAVE 32 +-# No parameter save area is needed for the call to ffi_closure_helper_LINUX64, +-# so return value can start there. +-# define RETVAL PARMSAVE ++# define RETVAL PARMSAVE+64 + # else + # 48 bytes special reg save area + 64 bytes parm save area + # + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 +@@ -85,8 +83,8 @@ ffi_closure_LINUX64: + bt 7, .Lparmsave + # Our caller has not allocated a parameter save area. + # We need to allocate one here and use it to pass gprs to +- # ffi_closure_helper_LINUX64. The return value area will do. +- addi %r12, %r1, -STACKFRAME+RETVAL ++ # ffi_closure_helper_LINUX64. ++ addi %r12, %r1, -STACKFRAME+PARMSAVE + .Lparmsave: + std %r0, 16(%r1) + # Save general regs into parm save area + +-- +Alan Modra +Australia Development Lab, IBM + diff --git a/SOURCES/libffi-3.0.13-ppc64le-2.patch b/SOURCES/libffi-3.0.13-ppc64le-2.patch new file mode 100644 index 00000000..d0b79216 --- /dev/null +++ b/SOURCES/libffi-3.0.13-ppc64le-2.patch @@ -0,0 +1,72 @@ +Date: Wed, 20 Nov 2013 18:05:21 +1030 +From: Alan Modra +To: libffi-discuss at sourceware dot org +Subject: PowerPC64 ELFv2 fix 2 of 2 +Message-ID: <20131120073521.GG22514@bubble.grove.modra.org> +References: <20131117031650.GR22514@bubble.grove.modra.org> <87eh6e2b4o.fsf@redhat.com> <20131119001430.GX22514@bubble.grove.modra.org> +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline +In-Reply-To: <20131119001430 dot GX22514 at bubble dot grove dot modra dot org> +User-Agent: Mutt/1.5.21 (2010-09-15) + +Using NUM_FPR_ARG_REGISTERS rather than NUM_FPR_ARG_REGISTERS64 meant +that a parameter save area could be allocated before it was strictly +necessary. Wrong but harmless. Found when splitting apart ffi.c +into 32-bit and 64-bit support. + + * src/powerpc/ffi.c (ffi_prep_cif_machdep_core): Use + NUM_FPR_ARG_REGISTERS64 and NUM_GPR_ARG_REGISTERS64 not their + 32-bit versions for 64-bit code. + +diff --git a/src/powerpc/ffi.c b/src/powerpc/ffi.c +index feb2144..6896065 100644 +--- a/src/powerpc/ffi.c ++++ b/src/powerpc/ffi.c +@@ -978,7 +978,7 @@ ffi_prep_cif_machdep_core (ffi_cif *cif) + case FFI_TYPE_LONGDOUBLE: + fparg_count += 2; + intarg_count += 2; +- if (fparg_count > NUM_FPR_ARG_REGISTERS) ++ if (fparg_count > NUM_FPR_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + break; + #endif +@@ -986,7 +986,7 @@ ffi_prep_cif_machdep_core (ffi_cif *cif) + case FFI_TYPE_DOUBLE: + fparg_count++; + intarg_count++; +- if (fparg_count > NUM_FPR_ARG_REGISTERS) ++ if (fparg_count > NUM_FPR_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + break; + +@@ -1007,12 +1007,12 @@ ffi_prep_cif_machdep_core (ffi_cif *cif) + if (elt) + { + fparg_count += elnum; +- if (fparg_count > NUM_FPR_ARG_REGISTERS) ++ if (fparg_count > NUM_FPR_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + } + else + { +- if (intarg_count > NUM_GPR_ARG_REGISTERS) ++ if (intarg_count > NUM_GPR_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + } + break; +@@ -1030,7 +1030,7 @@ ffi_prep_cif_machdep_core (ffi_cif *cif) + /* Everything else is passed as a 8-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; +- if (intarg_count > NUM_GPR_ARG_REGISTERS) ++ if (intarg_count > NUM_GPR_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + break; + default: + +-- +Alan Modra +Australia Development Lab, IBM + diff --git a/SOURCES/libffi-3.0.13-ppc64le-3.patch b/SOURCES/libffi-3.0.13-ppc64le-3.patch new file mode 100644 index 00000000..fb1e66d1 --- /dev/null +++ b/SOURCES/libffi-3.0.13-ppc64le-3.patch @@ -0,0 +1,4184 @@ +From 97705d3071654cebd6c4f0492432372b8840977b Mon Sep 17 00:00:00 2001 +From: Alan Modra +Date: Wed, 20 Nov 2013 14:18:33 +1030 +Subject: [PATCH 3/3] Tidy powerpc*-linux support + +This separates the 32-bit sysv/linux/bsd code from the 64-bit linux +code, and makes it possible to link code compiled with different +options to those used to compile libffi. For example, a +-mlong-double-128 libffi can be used with -mlong-double-64 code. + +Tested powerpc-linux, powerpc64-linux, powerpc64le-linux, and the +hacky powerpc-freebsd simulated setup I used earlier. I've tried a +few combinations of ABI variations; -mlong-double-64/-mlong-double-128 +and -msvr4-struct-return/-maix-struct-return pass the testuite with +flying colours. Testing -msoft-float ran into lack of soft-float +multilibs on my system, but I looked at some testcases under gdb and +they seemed to do the right thing. + +I also tested backward compatibility on powerpc-linux and powerpc64-linux +by building libfff-3.0.13, then running the testsuite so that tests +were built linked against the 3.0.13 libffi.so but ran with the new +libffi. + + * Makefile.am (EXTRA_DIST): Add new src/powerpc files. + (nodist_libffi_la_SOURCES ): Likewise. + * configure.ac (HAVE_LONG_DOUBLE_VARIANT): Define for powerpc. + * include/ffi.h.in (ffi_prep_types): Declare. + * src/prep_cif.c (ffi_prep_cif_core): Call ffi_prep_types. + * src/types.c (FFI_NONCONST_TYPEDEF): Define and use for + HAVE_LONG_DOUBLE_VARIANT. + * src/powerpc/ffi_powerpc.h: New file. + * src/powerpc/ffi.c: Split into.. + * src/powerpc/ffi_sysv.c: ..new file, and.. + * src/powerpc/ffi_linux64.c: ..new file, rewriting parts. + * src/powerpc/ffitarget.h (enum ffi_abi): Rewrite powerpc ABI + selection as bits controlling features. + * src/powerpc/linux64.S: For consistency, use POWERPC64 rather + than __powerpc64__. + * src/powerpc/linux64_closure.S: Likewise. + * src/powerpc/ppc_closure.S: Likewise. Move .note.FNU-stack + inside guard. + * src/powerpc/sysv.S: Likewise. + * configure: Regenerate. + * fficonfig.h.in: Regenerate. + * Makefile.in: Regenerate. + +Index: libffi-3.0.13/Makefile.am +=================================================================== +--- libffi-3.0.13.orig/Makefile.am ++++ libffi-3.0.13/Makefile.am +@@ -20,7 +20,9 @@ EXTRA_DIST = LICENSE ChangeLog.v1 Change + src/m32r/ffi.c src/m32r/sysv.S src/m32r/ffitarget.h \ + src/m68k/ffi.c src/m68k/sysv.S src/m68k/ffitarget.h \ + src/microblaze/ffi.c src/microblaze/sysv.S \ +- src/microblaze/ffitarget.h src/powerpc/ffi.c \ ++ src/microblaze/ffitarget.h \ ++ src/powerpc/ffi.c src/powerpc/ffi_powerpc.h \ ++ src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c \ + src/powerpc/sysv.S src/powerpc/linux64.S \ + src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S \ + src/powerpc/asm.h src/powerpc/aix.S src/powerpc/darwin.S \ +@@ -156,7 +158,7 @@ if MICROBLAZE + nodist_libffi_la_SOURCES += src/microblaze/ffi.c src/microblaze/sysv.S + endif + if POWERPC +-nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S ++nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S + endif + if POWERPC_AIX + nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S +@@ -165,7 +167,7 @@ if POWERPC_DARWIN + nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S + endif + if POWERPC_FREEBSD +-nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S ++nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/sysv.S src/powerpc/ppc_closure.S + endif + if AARCH64 + nodist_libffi_la_SOURCES += src/aarch64/sysv.S src/aarch64/ffi.c +Index: libffi-3.0.13/configure.ac +=================================================================== +--- libffi-3.0.13.orig/configure.ac ++++ libffi-3.0.13/configure.ac +@@ -66,6 +66,7 @@ dnl The -no-testsuite modules omit the t + AM_CONDITIONAL(TESTSUBDIR, test -d $srcdir/testsuite) + + TARGETDIR="unknown" ++HAVE_LONG_DOUBLE_VARIANT=0 + case "$host" in + aarch64*-*-*) + TARGET=AARCH64; TARGETDIR=aarch64 +@@ -214,6 +215,7 @@ case "$host" in + + powerpc*-*-linux* | powerpc-*-sysv*) + TARGET=POWERPC; TARGETDIR=powerpc ++ HAVE_LONG_DOUBLE_VARIANT=1 + ;; + powerpc-*-amigaos*) + TARGET=POWERPC; TARGETDIR=powerpc +@@ -229,6 +231,7 @@ case "$host" in + ;; + powerpc-*-freebsd* | powerpc-*-openbsd*) + TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc ++ HAVE_LONG_DOUBLE_VARIANT=1 + ;; + powerpc64-*-freebsd*) + TARGET=POWERPC; TARGETDIR=powerpc +@@ -313,14 +316,20 @@ AC_CHECK_SIZEOF(long double) + # Also AC_SUBST this variable for ffi.h. + if test -z "$HAVE_LONG_DOUBLE"; then + HAVE_LONG_DOUBLE=0 +- if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then +- if test $ac_cv_sizeof_long_double != 0; then ++ if test $ac_cv_sizeof_long_double != 0; then ++ if test $HAVE_LONG_DOUBLE_VARIANT != 0; then ++ AC_DEFINE(HAVE_LONG_DOUBLE_VARIANT, 1, [Define if you support more than one size of the long double type]) + HAVE_LONG_DOUBLE=1 +- AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type and it is bigger than a double]) ++ else ++ if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then ++ HAVE_LONG_DOUBLE=1 ++ AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type and it is bigger than a double]) ++ fi + fi + fi + fi + AC_SUBST(HAVE_LONG_DOUBLE) ++AC_SUBST(HAVE_LONG_DOUBLE_VARIANT) + + AC_C_BIGENDIAN + +Index: libffi-3.0.13/include/ffi.h.in +=================================================================== +--- libffi-3.0.13.orig/include/ffi.h.in ++++ libffi-3.0.13/include/ffi.h.in +@@ -221,6 +221,11 @@ typedef struct { + #endif + } ffi_cif; + ++#if HAVE_LONG_DOUBLE_VARIANT ++/* Used to adjust size/alignment of ffi types. */ ++void ffi_prep_types (ffi_abi abi); ++# endif ++ + /* Used internally, but overridden by some architectures */ + ffi_status ffi_prep_cif_core(ffi_cif *cif, + ffi_abi abi, +Index: libffi-3.0.13/src/powerpc/ffi.c +=================================================================== +--- libffi-3.0.13.orig/src/powerpc/ffi.c ++++ libffi-3.0.13/src/powerpc/ffi.c +@@ -1,5 +1,6 @@ + /* ----------------------------------------------------------------------- +- ffi.c - Copyright (C) 2011 Anthony Green ++ ffi.c - Copyright (C) 2013 IBM ++ Copyright (C) 2011 Anthony Green + Copyright (C) 2011 Kyle Moffett + Copyright (C) 2008 Red Hat, Inc + Copyright (C) 2007, 2008 Free Software Foundation, Inc +@@ -27,1112 +28,60 @@ + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +-#include +-#include +- +-#include +-#include +- +- +-extern void ffi_closure_SYSV (void); +-extern void FFI_HIDDEN ffi_closure_LINUX64 (void); +- +-enum { +- /* The assembly depends on these exact flags. */ +- FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */ +- FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */ +-#ifndef __NO_FPRS__ +- FLAG_RETURNS_FP = 1 << (31-29), +-#endif +- FLAG_RETURNS_64BITS = 1 << (31-28), +- +- FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */ +- +- FLAG_ARG_NEEDS_COPY = 1 << (31- 7), +- FLAG_ARG_NEEDS_PSAVE = FLAG_ARG_NEEDS_COPY, /* Used by ELFv2 */ +-#ifndef __NO_FPRS__ +- FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ +-#endif +- FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), +- FLAG_RETVAL_REFERENCE = 1 << (31- 4) +-}; +- +-/* About the SYSV ABI. */ +-#define ASM_NEEDS_REGISTERS 4 +-#define NUM_GPR_ARG_REGISTERS 8 +-#ifndef __NO_FPRS__ +-# define NUM_FPR_ARG_REGISTERS 8 +-#endif +- +-/* ffi_prep_args_SYSV is called by the assembly routine once stack space +- has been allocated for the function's arguments. +- +- The stack layout we want looks like this: +- +- | Return address from ffi_call_SYSV 4bytes | higher addresses +- |--------------------------------------------| +- | Previous backchain pointer 4 | stack pointer here +- |--------------------------------------------|<+ <<< on entry to +- | Saved r28-r31 4*4 | | ffi_call_SYSV +- |--------------------------------------------| | +- | GPR registers r3-r10 8*4 | | ffi_call_SYSV +- |--------------------------------------------| | +- | FPR registers f1-f8 (optional) 8*8 | | +- |--------------------------------------------| | stack | +- | Space for copied structures | | grows | +- |--------------------------------------------| | down V +- | Parameters that didn't fit in registers | | +- |--------------------------------------------| | lower addresses +- | Space for callee's LR 4 | | +- |--------------------------------------------| | stack pointer here +- | Current backchain pointer 4 |-/ during +- |--------------------------------------------| <<< ffi_call_SYSV +- +-*/ +- +-void +-ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack) +-{ +- const unsigned bytes = ecif->cif->bytes; +- const unsigned flags = ecif->cif->flags; +- +- typedef union { +- char *c; +- unsigned *u; +- long long *ll; +- float *f; +- double *d; +- } valp; +- +- /* 'stacktop' points at the previous backchain pointer. */ +- valp stacktop; +- +- /* 'gpr_base' points at the space for gpr3, and grows upwards as +- we use GPR registers. */ +- valp gpr_base; +- int intarg_count; +- +-#ifndef __NO_FPRS__ +- /* 'fpr_base' points at the space for fpr1, and grows upwards as +- we use FPR registers. */ +- valp fpr_base; +- int fparg_count; +-#endif +- +- /* 'copy_space' grows down as we put structures in it. It should +- stay 16-byte aligned. */ +- valp copy_space; +- +- /* 'next_arg' grows up as we put parameters in it. */ +- valp next_arg; +- +- int i; +- ffi_type **ptr; +-#ifndef __NO_FPRS__ +- double double_tmp; +-#endif +- union { +- void **v; +- char **c; +- signed char **sc; +- unsigned char **uc; +- signed short **ss; +- unsigned short **us; +- unsigned int **ui; +- long long **ll; +- float **f; +- double **d; +- } p_argv; +- size_t struct_copy_size; +- unsigned gprvalue; +- +- stacktop.c = (char *) stack + bytes; +- gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS; +- intarg_count = 0; +-#ifndef __NO_FPRS__ +- fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS; +- fparg_count = 0; +- copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c); +-#else +- copy_space.c = gpr_base.c; +-#endif +- next_arg.u = stack + 2; +- +- /* Check that everything starts aligned properly. */ +- FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); +- FFI_ASSERT (((unsigned long) copy_space.c & 0xF) == 0); +- FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0); +- FFI_ASSERT ((bytes & 0xF) == 0); +- FFI_ASSERT (copy_space.c >= next_arg.c); +- +- /* Deal with return values that are actually pass-by-reference. */ +- if (flags & FLAG_RETVAL_REFERENCE) +- { +- *gpr_base.u++ = (unsigned long) (char *) ecif->rvalue; +- intarg_count++; +- } +- +- /* Now for the arguments. */ +- p_argv.v = ecif->avalue; +- for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; +- i > 0; +- i--, ptr++, p_argv.v++) +- { +- unsigned short typenum = (*ptr)->type; +- +- /* We may need to handle some values depending on ABI */ +- if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) { +- if (typenum == FFI_TYPE_FLOAT) +- typenum = FFI_TYPE_UINT32; +- if (typenum == FFI_TYPE_DOUBLE) +- typenum = FFI_TYPE_UINT64; +- if (typenum == FFI_TYPE_LONGDOUBLE) +- typenum = FFI_TYPE_UINT128; +- } else if (ecif->cif->abi != FFI_LINUX) { +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- if (typenum == FFI_TYPE_LONGDOUBLE) +- typenum = FFI_TYPE_STRUCT; +-#endif +- } +- +- /* Now test the translated value */ +- switch (typenum) { +-#ifndef __NO_FPRS__ +- case FFI_TYPE_FLOAT: +- /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */ +- double_tmp = **p_argv.f; +- if (fparg_count >= NUM_FPR_ARG_REGISTERS) +- { +- *next_arg.f = (float) double_tmp; +- next_arg.u += 1; +- intarg_count++; +- } +- else +- *fpr_base.d++ = double_tmp; +- fparg_count++; +- FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); +- break; +- +- case FFI_TYPE_DOUBLE: +- /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */ +- double_tmp = **p_argv.d; +- +- if (fparg_count >= NUM_FPR_ARG_REGISTERS) +- { +- if (intarg_count >= NUM_GPR_ARG_REGISTERS +- && intarg_count % 2 != 0) +- { +- intarg_count++; +- next_arg.u++; +- } +- *next_arg.d = double_tmp; +- next_arg.u += 2; +- } +- else +- *fpr_base.d++ = double_tmp; +- fparg_count++; +- FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); +- break; +- +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- case FFI_TYPE_LONGDOUBLE: +- double_tmp = (*p_argv.d)[0]; +- +- if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1) +- { +- if (intarg_count >= NUM_GPR_ARG_REGISTERS +- && intarg_count % 2 != 0) +- { +- intarg_count++; +- next_arg.u++; +- } +- *next_arg.d = double_tmp; +- next_arg.u += 2; +- double_tmp = (*p_argv.d)[1]; +- *next_arg.d = double_tmp; +- next_arg.u += 2; +- } +- else +- { +- *fpr_base.d++ = double_tmp; +- double_tmp = (*p_argv.d)[1]; +- *fpr_base.d++ = double_tmp; +- } +- +- fparg_count += 2; +- FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); +- break; +-#endif +-#endif /* have FPRs */ +- +- /* +- * The soft float ABI for long doubles works like this, a long double +- * is passed in four consecutive GPRs if available. A maximum of 2 +- * long doubles can be passed in gprs. If we do not have 4 GPRs +- * left, the long double is passed on the stack, 4-byte aligned. +- */ +- case FFI_TYPE_UINT128: { +- unsigned int int_tmp = (*p_argv.ui)[0]; +- unsigned int ii; +- if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3) { +- if (intarg_count < NUM_GPR_ARG_REGISTERS) +- intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count; +- *(next_arg.u++) = int_tmp; +- for (ii = 1; ii < 4; ii++) { +- int_tmp = (*p_argv.ui)[ii]; +- *(next_arg.u++) = int_tmp; +- } +- } else { +- *(gpr_base.u++) = int_tmp; +- for (ii = 1; ii < 4; ii++) { +- int_tmp = (*p_argv.ui)[ii]; +- *(gpr_base.u++) = int_tmp; +- } +- } +- intarg_count += 4; +- break; +- } +- +- case FFI_TYPE_UINT64: +- case FFI_TYPE_SINT64: +- if (intarg_count == NUM_GPR_ARG_REGISTERS-1) +- intarg_count++; +- if (intarg_count >= NUM_GPR_ARG_REGISTERS) +- { +- if (intarg_count % 2 != 0) +- { +- intarg_count++; +- next_arg.u++; +- } +- *next_arg.ll = **p_argv.ll; +- next_arg.u += 2; +- } +- else +- { +- /* whoops: abi states only certain register pairs +- * can be used for passing long long int +- * specifically (r3,r4), (r5,r6), (r7,r8), +- * (r9,r10) and if next arg is long long but +- * not correct starting register of pair then skip +- * until the proper starting register +- */ +- if (intarg_count % 2 != 0) +- { +- intarg_count ++; +- gpr_base.u++; +- } +- *gpr_base.ll++ = **p_argv.ll; +- } +- intarg_count += 2; +- break; +- +- case FFI_TYPE_STRUCT: +- struct_copy_size = ((*ptr)->size + 15) & ~0xF; +- copy_space.c -= struct_copy_size; +- memcpy (copy_space.c, *p_argv.c, (*ptr)->size); +- +- gprvalue = (unsigned long) copy_space.c; +- +- FFI_ASSERT (copy_space.c > next_arg.c); +- FFI_ASSERT (flags & FLAG_ARG_NEEDS_COPY); +- goto putgpr; +- +- case FFI_TYPE_UINT8: +- gprvalue = **p_argv.uc; +- goto putgpr; +- case FFI_TYPE_SINT8: +- gprvalue = **p_argv.sc; +- goto putgpr; +- case FFI_TYPE_UINT16: +- gprvalue = **p_argv.us; +- goto putgpr; +- case FFI_TYPE_SINT16: +- gprvalue = **p_argv.ss; +- goto putgpr; +- +- case FFI_TYPE_INT: +- case FFI_TYPE_UINT32: +- case FFI_TYPE_SINT32: +- case FFI_TYPE_POINTER: +- +- gprvalue = **p_argv.ui; +- +- putgpr: +- if (intarg_count >= NUM_GPR_ARG_REGISTERS) +- *next_arg.u++ = gprvalue; +- else +- *gpr_base.u++ = gprvalue; +- intarg_count++; +- break; +- } +- } +- +- /* Check that we didn't overrun the stack... */ +- FFI_ASSERT (copy_space.c >= next_arg.c); +- FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS); +- /* The assert below is testing that the number of integer arguments agrees +- with the number found in ffi_prep_cif_machdep(). However, intarg_count +- is incremented whenever we place an FP arg on the stack, so account for +- that before our assert test. */ +-#ifndef __NO_FPRS__ +- if (fparg_count > NUM_FPR_ARG_REGISTERS) +- intarg_count -= fparg_count - NUM_FPR_ARG_REGISTERS; +- FFI_ASSERT (fpr_base.u +- <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); +-#endif +- FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); +-} +- +-/* About the LINUX64 ABI. */ +-enum { +- NUM_GPR_ARG_REGISTERS64 = 8, +- NUM_FPR_ARG_REGISTERS64 = 13 +-}; +-enum { ASM_NEEDS_REGISTERS64 = 4 }; +- +-#if _CALL_ELF == 2 +-static unsigned int +-discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum) +-{ +- switch (t->type) +- { +- case FFI_TYPE_FLOAT: +- case FFI_TYPE_DOUBLE: +- *elnum = 1; +- return (int) t->type; +- +- case FFI_TYPE_STRUCT:; +- { +- unsigned int base_elt = 0, total_elnum = 0; +- ffi_type **el = t->elements; +- while (*el) +- { +- unsigned int el_elt, el_elnum = 0; +- el_elt = discover_homogeneous_aggregate (*el, &el_elnum); +- if (el_elt == 0 +- || (base_elt && base_elt != el_elt)) +- return 0; +- base_elt = el_elt; +- total_elnum += el_elnum; +- if (total_elnum > 8) +- return 0; +- el++; +- } +- *elnum = total_elnum; +- return base_elt; +- } +- +- default: +- return 0; +- } +-} +-#endif +- +- +-/* ffi_prep_args64 is called by the assembly routine once stack space +- has been allocated for the function's arguments. +- +- The stack layout we want looks like this: +- +- | Ret addr from ffi_call_LINUX64 8bytes | higher addresses +- |--------------------------------------------| +- | CR save area 8bytes | +- |--------------------------------------------| +- | Previous backchain pointer 8 | stack pointer here +- |--------------------------------------------|<+ <<< on entry to +- | Saved r28-r31 4*8 | | ffi_call_LINUX64 +- |--------------------------------------------| | +- | GPR registers r3-r10 8*8 | | +- |--------------------------------------------| | +- | FPR registers f1-f13 (optional) 13*8 | | +- |--------------------------------------------| | +- | Parameter save area | | +- |--------------------------------------------| | +- | TOC save area 8 | | +- |--------------------------------------------| | stack | +- | Linker doubleword 8 | | grows | +- |--------------------------------------------| | down V +- | Compiler doubleword 8 | | +- |--------------------------------------------| | lower addresses +- | Space for callee's LR 8 | | +- |--------------------------------------------| | +- | CR save area 8 | | +- |--------------------------------------------| | stack pointer here +- | Current backchain pointer 8 |-/ during +- |--------------------------------------------| <<< ffi_call_LINUX64 +- +-*/ ++#include "ffi.h" ++#include "ffi_common.h" ++#include "ffi_powerpc.h" + ++#if HAVE_LONG_DOUBLE_VARIANT ++/* Adjust ffi_type_longdouble. */ + void FFI_HIDDEN +-ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack) ++ffi_prep_types (ffi_abi abi) + { +- const unsigned long bytes = ecif->cif->bytes; +- const unsigned long flags = ecif->cif->flags; +- +- typedef union { +- char *c; +- unsigned long *ul; +- float *f; +- double *d; +- size_t p; +- } valp; +- +- /* 'stacktop' points at the previous backchain pointer. */ +- valp stacktop; +- +- /* 'next_arg' points at the space for gpr3, and grows upwards as +- we use GPR registers, then continues at rest. */ +- valp gpr_base; +- valp gpr_end; +- valp rest; +- valp next_arg; +- +- /* 'fpr_base' points at the space for fpr3, and grows upwards as +- we use FPR registers. */ +- valp fpr_base; +- unsigned int fparg_count; +- +- unsigned int i, words, nargs, nfixedargs; +- ffi_type **ptr; +- double double_tmp; +- union { +- void **v; +- char **c; +- signed char **sc; +- unsigned char **uc; +- signed short **ss; +- unsigned short **us; +- signed int **si; +- unsigned int **ui; +- unsigned long **ul; +- float **f; +- double **d; +- } p_argv; +- unsigned long gprvalue; +-#ifdef __STRUCT_PARM_ALIGN__ +- unsigned long align; +-#endif +- +- stacktop.c = (char *) stack + bytes; +- gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64; +- gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64; +-#if _CALL_ELF == 2 +- rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64; +-#else +- rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64; +-#endif +- fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64; +- fparg_count = 0; +- next_arg.ul = gpr_base.ul; +- +- /* Check that everything starts aligned properly. */ +- FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); +- FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0); +- FFI_ASSERT ((bytes & 0xF) == 0); +- +- /* Deal with return values that are actually pass-by-reference. */ +- if (flags & FLAG_RETVAL_REFERENCE) +- *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue; +- +- /* Now for the arguments. */ +- p_argv.v = ecif->avalue; +- nargs = ecif->cif->nargs; +- nfixedargs = ecif->cif->nfixedargs; +- for (ptr = ecif->cif->arg_types, i = 0; +- i < nargs; +- i++, ptr++, p_argv.v++) +- { +- unsigned int elt, elnum; +- +- switch ((*ptr)->type) +- { +- case FFI_TYPE_FLOAT: +- double_tmp = **p_argv.f; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) +- *fpr_base.d++ = double_tmp; +- else +- *next_arg.f = (float) double_tmp; +- if (++next_arg.ul == gpr_end.ul) +- next_arg.ul = rest.ul; +- fparg_count++; +- FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); +- break; +- +- case FFI_TYPE_DOUBLE: +- double_tmp = **p_argv.d; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) +- *fpr_base.d++ = double_tmp; +- else +- *next_arg.d = double_tmp; +- if (++next_arg.ul == gpr_end.ul) +- next_arg.ul = rest.ul; +- fparg_count++; +- FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); +- break; +- +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- case FFI_TYPE_LONGDOUBLE: +- double_tmp = (*p_argv.d)[0]; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) +- *fpr_base.d++ = double_tmp; +- else +- *next_arg.d = double_tmp; +- if (++next_arg.ul == gpr_end.ul) +- next_arg.ul = rest.ul; +- fparg_count++; +- double_tmp = (*p_argv.d)[1]; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) +- *fpr_base.d++ = double_tmp; +- else +- *next_arg.d = double_tmp; +- if (++next_arg.ul == gpr_end.ul) +- next_arg.ul = rest.ul; +- fparg_count++; +- FFI_ASSERT (__LDBL_MANT_DIG__ == 106); +- FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); +- break; +-#endif +- +- case FFI_TYPE_STRUCT: +-#ifdef __STRUCT_PARM_ALIGN__ +- align = (*ptr)->alignment; +- if (align > __STRUCT_PARM_ALIGN__) +- align = __STRUCT_PARM_ALIGN__; +- if (align > 1) +- next_arg.p = ALIGN (next_arg.p, align); +-#endif +- elt = 0; +-#if _CALL_ELF == 2 +- elt = discover_homogeneous_aggregate (*ptr, &elnum); +-#endif +- if (elt) +- { +- union { +- void *v; +- float *f; +- double *d; +- } arg; +- +- arg.v = *p_argv.v; +- if (elt == FFI_TYPE_FLOAT) +- { +- do +- { +- double_tmp = *arg.f++; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64 +- && i < nfixedargs) +- *fpr_base.d++ = double_tmp; +- else +- *next_arg.f = (float) double_tmp; +- if (++next_arg.f == gpr_end.f) +- next_arg.f = rest.f; +- fparg_count++; +- } +- while (--elnum != 0); +- if ((next_arg.p & 3) != 0) +- { +- if (++next_arg.f == gpr_end.f) +- next_arg.f = rest.f; +- } +- } +- else +- do +- { +- double_tmp = *arg.d++; +- if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) +- *fpr_base.d++ = double_tmp; +- else +- *next_arg.d = double_tmp; +- if (++next_arg.d == gpr_end.d) +- next_arg.d = rest.d; +- fparg_count++; +- } +- while (--elnum != 0); +- } +- else +- { +- words = ((*ptr)->size + 7) / 8; +- if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul) +- { +- size_t first = gpr_end.c - next_arg.c; +- memcpy (next_arg.c, *p_argv.c, first); +- memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first); +- next_arg.c = rest.c + words * 8 - first; +- } +- else +- { +- char *where = next_arg.c; +- +-#ifndef __LITTLE_ENDIAN__ +- /* Structures with size less than eight bytes are passed +- left-padded. */ +- if ((*ptr)->size < 8) +- where += 8 - (*ptr)->size; +-#endif +- memcpy (where, *p_argv.c, (*ptr)->size); +- next_arg.ul += words; +- if (next_arg.ul == gpr_end.ul) +- next_arg.ul = rest.ul; +- } +- } +- break; +- +- case FFI_TYPE_UINT8: +- gprvalue = **p_argv.uc; +- goto putgpr; +- case FFI_TYPE_SINT8: +- gprvalue = **p_argv.sc; +- goto putgpr; +- case FFI_TYPE_UINT16: +- gprvalue = **p_argv.us; +- goto putgpr; +- case FFI_TYPE_SINT16: +- gprvalue = **p_argv.ss; +- goto putgpr; +- case FFI_TYPE_UINT32: +- gprvalue = **p_argv.ui; +- goto putgpr; +- case FFI_TYPE_INT: +- case FFI_TYPE_SINT32: +- gprvalue = **p_argv.si; +- goto putgpr; +- +- case FFI_TYPE_UINT64: +- case FFI_TYPE_SINT64: +- case FFI_TYPE_POINTER: +- gprvalue = **p_argv.ul; +- putgpr: +- *next_arg.ul++ = gprvalue; +- if (next_arg.ul == gpr_end.ul) +- next_arg.ul = rest.ul; +- break; +- } +- } +- +- FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS +- || (next_arg.ul >= gpr_base.ul +- && next_arg.ul <= gpr_base.ul + 4)); ++# if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++# ifdef POWERPC64 ++ ffi_prep_types_linux64 (abi); ++# else ++ ffi_prep_types_sysv (abi); ++# endif ++# endif + } +- +- ++#endif + + /* Perform machine dependent cif processing */ +-static ffi_status +-ffi_prep_cif_machdep_core (ffi_cif *cif) ++ffi_status FFI_HIDDEN ++ffi_prep_cif_machdep (ffi_cif *cif) + { +- /* All this is for the SYSV and LINUX64 ABI. */ +- ffi_type **ptr; +- unsigned bytes; +- unsigned i, fparg_count = 0, intarg_count = 0; +- unsigned flags = cif->flags; +- unsigned struct_copy_size = 0; +- unsigned type = cif->rtype->type; +- unsigned size = cif->rtype->size; +- +- /* The machine-independent calculation of cif->bytes doesn't work +- for us. Redo the calculation. */ +- if (cif->abi != FFI_LINUX64) +- { +- /* Space for the frame pointer, callee's LR, and the asm's temp regs. */ +- bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int); +- +- /* Space for the GPR registers. */ +- bytes += NUM_GPR_ARG_REGISTERS * sizeof (int); +- } +- else +- { +- /* 64-bit ABI. */ +-#if _CALL_ELF == 2 +- /* Space for backchain, CR, LR, TOC and the asm's temp regs. */ +- bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long); +- +- /* Space for the general registers. */ +- bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long); +-#else +- /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp +- regs. */ +- bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long); +- +- /* Space for the mandatory parm save area and general registers. */ +- bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long); +-#endif +- } +- +- /* Return value handling. The rules for SYSV are as follows: +- - 32-bit (or less) integer values are returned in gpr3; +- - Structures of size <= 4 bytes also returned in gpr3; +- - 64-bit integer values and structures between 5 and 8 bytes are returned +- in gpr3 and gpr4; +- - Single/double FP values are returned in fpr1; +- - Larger structures are allocated space and a pointer is passed as +- the first argument. +- - long doubles (if not equivalent to double) are returned in +- fpr1,fpr2 for Linux and as for large structs for SysV. +- For LINUX64: +- - integer values in gpr3; +- - Structures/Unions by reference; +- - Single/double FP values in fpr1, long double in fpr1,fpr2. +- - soft-float float/doubles are treated as UINT32/UINT64 respectivley. +- - soft-float long doubles are returned in gpr3-gpr6. */ +- /* First translate for softfloat/nonlinux */ +- if (cif->abi == FFI_LINUX_SOFT_FLOAT) +- { +- if (type == FFI_TYPE_FLOAT) +- type = FFI_TYPE_UINT32; +- if (type == FFI_TYPE_DOUBLE) +- type = FFI_TYPE_UINT64; +- if (type == FFI_TYPE_LONGDOUBLE) +- type = FFI_TYPE_UINT128; +- } +- else if (cif->abi != FFI_LINUX +- && cif->abi != FFI_LINUX64) +- { +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- if (type == FFI_TYPE_LONGDOUBLE) +- type = FFI_TYPE_STRUCT; +-#endif +- } +- +- switch (type) +- { +-#ifndef __NO_FPRS__ +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- case FFI_TYPE_LONGDOUBLE: +- flags |= FLAG_RETURNS_128BITS; +- /* Fall through. */ +-#endif +- case FFI_TYPE_DOUBLE: +- flags |= FLAG_RETURNS_64BITS; +- /* Fall through. */ +- case FFI_TYPE_FLOAT: +- flags |= FLAG_RETURNS_FP; +- break; +-#endif +- +- case FFI_TYPE_UINT128: +- flags |= FLAG_RETURNS_128BITS; +- /* Fall through. */ +- case FFI_TYPE_UINT64: +- case FFI_TYPE_SINT64: +- flags |= FLAG_RETURNS_64BITS; +- break; +- +- case FFI_TYPE_STRUCT: +- /* +- * The final SYSV ABI says that structures smaller or equal 8 bytes +- * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them +- * in memory. +- * +- * NOTE: The assembly code can safely assume that it just needs to +- * store both r3 and r4 into a 8-byte word-aligned buffer, as +- * we allocate a temporary buffer in ffi_call() if this flag is +- * set. +- */ +- if (cif->abi == FFI_SYSV && size <= 8) +- { +- flags |= FLAG_RETURNS_SMST; +- break; +- } +-#if _CALL_ELF == 2 +- if (cif->abi == FFI_LINUX64) +- { +- unsigned int elt, elnum; +- elt = discover_homogeneous_aggregate (cif->rtype, &elnum); +- if (elt) +- { +- if (elt == FFI_TYPE_DOUBLE) +- flags |= FLAG_RETURNS_64BITS; +- flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST; +- break; +- } +- if (size <= 16) +- { +- flags |= FLAG_RETURNS_SMST; +- break; +- } +- } +-#endif +- intarg_count++; +- flags |= FLAG_RETVAL_REFERENCE; +- /* Fall through. */ +- case FFI_TYPE_VOID: +- flags |= FLAG_RETURNS_NOTHING; +- break; +- +- default: +- /* Returns 32-bit integer, or similar. Nothing to do here. */ +- break; +- } +- +- if (cif->abi != FFI_LINUX64) +- /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the +- first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest +- goes on the stack. Structures and long doubles (if not equivalent +- to double) are passed as a pointer to a copy of the structure. +- Stuff on the stack needs to keep proper alignment. */ +- for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) +- { +- unsigned short typenum = (*ptr)->type; +- +- /* We may need to handle some values depending on ABI */ +- if (cif->abi == FFI_LINUX_SOFT_FLOAT) { +- if (typenum == FFI_TYPE_FLOAT) +- typenum = FFI_TYPE_UINT32; +- if (typenum == FFI_TYPE_DOUBLE) +- typenum = FFI_TYPE_UINT64; +- if (typenum == FFI_TYPE_LONGDOUBLE) +- typenum = FFI_TYPE_UINT128; +- } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) { +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- if (typenum == FFI_TYPE_LONGDOUBLE) +- typenum = FFI_TYPE_STRUCT; +-#endif +- } +- +- switch (typenum) { +-#ifndef __NO_FPRS__ +- case FFI_TYPE_FLOAT: +- fparg_count++; +- /* floating singles are not 8-aligned on stack */ +- break; +- +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- case FFI_TYPE_LONGDOUBLE: +- fparg_count++; +- /* Fall thru */ +-#endif +- case FFI_TYPE_DOUBLE: +- fparg_count++; +- /* If this FP arg is going on the stack, it must be +- 8-byte-aligned. */ +- if (fparg_count > NUM_FPR_ARG_REGISTERS +- && intarg_count >= NUM_GPR_ARG_REGISTERS +- && intarg_count % 2 != 0) +- intarg_count++; +- break; +-#endif +- case FFI_TYPE_UINT128: +- /* +- * A long double in FFI_LINUX_SOFT_FLOAT can use only a set +- * of four consecutive gprs. If we do not have enough, we +- * have to adjust the intarg_count value. +- */ +- if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3 +- && intarg_count < NUM_GPR_ARG_REGISTERS) +- intarg_count = NUM_GPR_ARG_REGISTERS; +- intarg_count += 4; +- break; +- +- case FFI_TYPE_UINT64: +- case FFI_TYPE_SINT64: +- /* 'long long' arguments are passed as two words, but +- either both words must fit in registers or both go +- on the stack. If they go on the stack, they must +- be 8-byte-aligned. +- +- Also, only certain register pairs can be used for +- passing long long int -- specifically (r3,r4), (r5,r6), +- (r7,r8), (r9,r10). +- */ +- if (intarg_count == NUM_GPR_ARG_REGISTERS-1 +- || intarg_count % 2 != 0) +- intarg_count++; +- intarg_count += 2; +- break; +- +- case FFI_TYPE_STRUCT: +- /* We must allocate space for a copy of these to enforce +- pass-by-value. Pad the space up to a multiple of 16 +- bytes (the maximum alignment required for anything under +- the SYSV ABI). */ +- struct_copy_size += ((*ptr)->size + 15) & ~0xF; +- /* Fall through (allocate space for the pointer). */ +- +- case FFI_TYPE_POINTER: +- case FFI_TYPE_INT: +- case FFI_TYPE_UINT32: +- case FFI_TYPE_SINT32: +- case FFI_TYPE_UINT16: +- case FFI_TYPE_SINT16: +- case FFI_TYPE_UINT8: +- case FFI_TYPE_SINT8: +- /* Everything else is passed as a 4-byte word in a GPR, either +- the object itself or a pointer to it. */ +- intarg_count++; +- break; +- default: +- FFI_ASSERT (0); +- } +- } +- else +- for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) +- { +- unsigned int elt, elnum; +-#ifdef __STRUCT_PARM_ALIGN__ +- unsigned int align; +-#endif +- +- switch ((*ptr)->type) +- { +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- case FFI_TYPE_LONGDOUBLE: +- fparg_count += 2; +- intarg_count += 2; +- if (fparg_count > NUM_FPR_ARG_REGISTERS64) +- flags |= FLAG_ARG_NEEDS_PSAVE; +- break; +-#endif +- case FFI_TYPE_FLOAT: +- case FFI_TYPE_DOUBLE: +- fparg_count++; +- intarg_count++; +- if (fparg_count > NUM_FPR_ARG_REGISTERS64) +- flags |= FLAG_ARG_NEEDS_PSAVE; +- break; +- +- case FFI_TYPE_STRUCT: +-#ifdef __STRUCT_PARM_ALIGN__ +- align = (*ptr)->alignment; +- if (align > __STRUCT_PARM_ALIGN__) +- align = __STRUCT_PARM_ALIGN__; +- align = align / 8; +- if (align > 1) +- intarg_count = ALIGN (intarg_count, align); +-#endif +- intarg_count += ((*ptr)->size + 7) / 8; +- elt = 0; +-#if _CALL_ELF == 2 +- elt = discover_homogeneous_aggregate (*ptr, &elnum); +-#endif +- if (elt) +- { +- fparg_count += elnum; +- if (fparg_count > NUM_FPR_ARG_REGISTERS64) +- flags |= FLAG_ARG_NEEDS_PSAVE; +- } +- else +- { +- if (intarg_count > NUM_GPR_ARG_REGISTERS64) +- flags |= FLAG_ARG_NEEDS_PSAVE; +- } +- break; +- +- case FFI_TYPE_POINTER: +- case FFI_TYPE_UINT64: +- case FFI_TYPE_SINT64: +- case FFI_TYPE_INT: +- case FFI_TYPE_UINT32: +- case FFI_TYPE_SINT32: +- case FFI_TYPE_UINT16: +- case FFI_TYPE_SINT16: +- case FFI_TYPE_UINT8: +- case FFI_TYPE_SINT8: +- /* Everything else is passed as a 8-byte word in a GPR, either +- the object itself or a pointer to it. */ +- intarg_count++; +- if (intarg_count > NUM_GPR_ARG_REGISTERS64) +- flags |= FLAG_ARG_NEEDS_PSAVE; +- break; +- default: +- FFI_ASSERT (0); +- } +- } +- +-#ifndef __NO_FPRS__ +- if (fparg_count != 0) +- flags |= FLAG_FP_ARGUMENTS; +-#endif +- if (intarg_count > 4) +- flags |= FLAG_4_GPR_ARGUMENTS; +- if (struct_copy_size != 0) +- flags |= FLAG_ARG_NEEDS_COPY; +- +- if (cif->abi != FFI_LINUX64) +- { +-#ifndef __NO_FPRS__ +- /* Space for the FPR registers, if needed. */ +- if (fparg_count != 0) +- bytes += NUM_FPR_ARG_REGISTERS * sizeof (double); +-#endif +- +- /* Stack space. */ +- if (intarg_count > NUM_GPR_ARG_REGISTERS) +- bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int); +-#ifndef __NO_FPRS__ +- if (fparg_count > NUM_FPR_ARG_REGISTERS) +- bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double); +-#endif +- } +- else +- { +-#ifndef __NO_FPRS__ +- /* Space for the FPR registers, if needed. */ +- if (fparg_count != 0) +- bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double); +-#endif +- +- /* Stack space. */ +-#if _CALL_ELF == 2 +- if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0) +- bytes += intarg_count * sizeof (long); ++#ifdef POWERPC64 ++ return ffi_prep_cif_linux64 (cif); + #else +- if (intarg_count > NUM_GPR_ARG_REGISTERS64) +- bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long); ++ return ffi_prep_cif_sysv (cif); + #endif +- } +- +- /* The stack space allocated needs to be a multiple of 16 bytes. */ +- bytes = (bytes + 15) & ~0xF; +- +- /* Add in the space for the copied structures. */ +- bytes += struct_copy_size; +- +- cif->flags = flags; +- cif->bytes = bytes; +- +- return FFI_OK; +-} +- +-ffi_status +-ffi_prep_cif_machdep (ffi_cif *cif) +-{ +- cif->nfixedargs = cif->nargs; +- return ffi_prep_cif_machdep_core (cif); + } + +-ffi_status ++ffi_status FFI_HIDDEN + ffi_prep_cif_machdep_var (ffi_cif *cif, +- unsigned int nfixedargs, ++ unsigned int nfixedargs MAYBE_UNUSED, + unsigned int ntotalargs MAYBE_UNUSED) + { +- cif->nfixedargs = nfixedargs; +-#if _CALL_ELF == 2 +- if (cif->abi == FFI_LINUX64) +- cif->flags |= FLAG_ARG_NEEDS_PSAVE; ++#ifdef POWERPC64 ++ return ffi_prep_cif_linux64_var (cif, nfixedargs, ntotalargs); ++#else ++ return ffi_prep_cif_sysv (cif); + #endif +- return ffi_prep_cif_machdep_core (cif); + } + +-extern void ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *, +- void (*fn)(void)); +-extern void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long, +- unsigned long, unsigned long *, +- void (*fn)(void)); +- + void + ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) + { +- /* +- * The final SYSV ABI says that structures smaller or equal 8 bytes +- * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them +- * in memory. +- * +- * We bounce-buffer SYSV small struct return values so that sysv.S +- * can write r3 and r4 to memory without worrying about struct size. +- * +- * For ELFv2 ABI, use a bounce buffer for homogeneous structs too, +- * for similar reasons. +- */ ++ /* The final SYSV ABI says that structures smaller or equal 8 bytes ++ are returned in r3/r4. A draft ABI used by linux instead returns ++ them in memory. ++ ++ We bounce-buffer SYSV small struct return values so that sysv.S ++ can write r3 and r4 to memory without worrying about struct size. ++ ++ For ELFv2 ABI, use a bounce buffer for homogeneous structs too, ++ for similar reasons. */ + unsigned long smst_buffer[8]; + extended_cif ecif; + +@@ -1147,26 +96,11 @@ ffi_call(ffi_cif *cif, void (*fn)(void), + else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT) + ecif.rvalue = alloca (cif->rtype->size); + +- switch (cif->abi) +- { +-#ifndef POWERPC64 +-# ifndef __NO_FPRS__ +- case FFI_SYSV: +- case FFI_GCC_SYSV: +- case FFI_LINUX: +-# endif +- case FFI_LINUX_SOFT_FLOAT: +- ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); +- break; ++#ifdef POWERPC64 ++ ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn); + #else +- case FFI_LINUX64: +- ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn); +- break; ++ ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); + #endif +- default: +- FFI_ASSERT (0); +- break; +- } + + /* Check for a bounce-buffered return value */ + if (rvalue && ecif.rvalue == smst_buffer) +@@ -1175,36 +109,23 @@ ffi_call(ffi_cif *cif, void (*fn)(void), + #ifndef __LITTLE_ENDIAN__ + /* The SYSV ABI returns a structure of up to 4 bytes in size + left-padded in r3. */ +- if (cif->abi == FFI_SYSV && rsize <= 4) ++# ifndef POWERPC64 ++ if (rsize <= 4) + memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize); +- /* The SYSV ABI returns a structure of up to 8 bytes in size +- left-padded in r3/r4, and the ELFv2 ABI similarly returns a +- structure of up to 8 bytes in size left-padded in r3. */ +- else if (rsize <= 8) +- memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize); + else ++# endif ++ /* The SYSV ABI returns a structure of up to 8 bytes in size ++ left-padded in r3/r4, and the ELFv2 ABI similarly returns a ++ structure of up to 8 bytes in size left-padded in r3. */ ++ if (rsize <= 8) ++ memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize); ++ else + #endif +- memcpy (rvalue, smst_buffer, rsize); ++ memcpy (rvalue, smst_buffer, rsize); + } + } + + +-#if !defined POWERPC64 || _CALL_ELF == 2 +-#define MIN_CACHE_LINE_SIZE 8 +- +-static void +-flush_icache (char *wraddr, char *xaddr, int size) +-{ +- int i; +- for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) +- __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" +- : : "r" (xaddr + i), "r" (wraddr + i) : "memory"); +- __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;" +- : : "r"(xaddr + size - 1), "r"(wraddr + size - 1) +- : "memory"); +-} +-#endif +- + ffi_status + ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif *cif, +@@ -1213,593 +134,8 @@ ffi_prep_closure_loc (ffi_closure *closu + void *codeloc) + { + #ifdef POWERPC64 +-# if _CALL_ELF == 2 +- unsigned int *tramp = (unsigned int *) &closure->tramp[0]; +- +- if (cif->abi != FFI_LINUX64) +- return FFI_BAD_ABI; +- +- tramp[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */ +- tramp[1] = 0xe98c0010; /* ld 12,1f-0b(12) */ +- tramp[2] = 0x7d8903a6; /* mtctr 12 */ +- tramp[3] = 0x4e800420; /* bctr */ +- /* 1: .quad function_addr */ +- /* 2: .quad context */ +- *(void **) &tramp[4] = (void *) ffi_closure_LINUX64; +- *(void **) &tramp[6] = codeloc; +- flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE); +-# else +- void **tramp = (void **) &closure->tramp[0]; +- +- if (cif->abi != FFI_LINUX64) +- return FFI_BAD_ABI; +- /* Copy function address and TOC from ffi_closure_LINUX64. */ +- memcpy (tramp, (char *) ffi_closure_LINUX64, 16); +- tramp[2] = codeloc; +-# endif ++ return ffi_prep_closure_loc_linux64 (closure, cif, fun, user_data, codeloc); + #else +- unsigned int *tramp; +- +- if (! (cif->abi == FFI_GCC_SYSV +- || cif->abi == FFI_SYSV +- || cif->abi == FFI_LINUX +- || cif->abi == FFI_LINUX_SOFT_FLOAT)) +- return FFI_BAD_ABI; +- +- tramp = (unsigned int *) &closure->tramp[0]; +- tramp[0] = 0x7c0802a6; /* mflr r0 */ +- tramp[1] = 0x4800000d; /* bl 10 */ +- tramp[4] = 0x7d6802a6; /* mflr r11 */ +- tramp[5] = 0x7c0803a6; /* mtlr r0 */ +- tramp[6] = 0x800b0000; /* lwz r0,0(r11) */ +- tramp[7] = 0x816b0004; /* lwz r11,4(r11) */ +- tramp[8] = 0x7c0903a6; /* mtctr r0 */ +- tramp[9] = 0x4e800420; /* bctr */ +- *(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */ +- *(void **) &tramp[3] = codeloc; /* context */ +- +- /* Flush the icache. */ +- flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE); +-#endif +- +- closure->cif = cif; +- closure->fun = fun; +- closure->user_data = user_data; +- +- return FFI_OK; +-} +- +-typedef union +-{ +- float f; +- double d; +-} ffi_dblfl; +- +-int ffi_closure_helper_SYSV (ffi_closure *, void *, unsigned long *, +- ffi_dblfl *, unsigned long *); +- +-/* Basically the trampoline invokes ffi_closure_SYSV, and on +- * entry, r11 holds the address of the closure. +- * After storing the registers that could possibly contain +- * parameters to be passed into the stack frame and setting +- * up space for a return value, ffi_closure_SYSV invokes the +- * following helper function to do most of the work +- */ +- +-int +-ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, +- unsigned long *pgr, ffi_dblfl *pfr, +- unsigned long *pst) +-{ +- /* rvalue is the pointer to space for return value in closure assembly */ +- /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */ +- /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */ +- /* pst is the pointer to outgoing parameter stack in original caller */ +- +- void ** avalue; +- ffi_type ** arg_types; +- long i, avn; +-#ifndef __NO_FPRS__ +- long nf = 0; /* number of floating registers already used */ +-#endif +- long ng = 0; /* number of general registers already used */ +- +- ffi_cif *cif = closure->cif; +- unsigned size = cif->rtype->size; +- unsigned short rtypenum = cif->rtype->type; +- +- avalue = alloca (cif->nargs * sizeof (void *)); +- +- /* First translate for softfloat/nonlinux */ +- if (cif->abi == FFI_LINUX_SOFT_FLOAT) { +- if (rtypenum == FFI_TYPE_FLOAT) +- rtypenum = FFI_TYPE_UINT32; +- if (rtypenum == FFI_TYPE_DOUBLE) +- rtypenum = FFI_TYPE_UINT64; +- if (rtypenum == FFI_TYPE_LONGDOUBLE) +- rtypenum = FFI_TYPE_UINT128; +- } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) { +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- if (rtypenum == FFI_TYPE_LONGDOUBLE) +- rtypenum = FFI_TYPE_STRUCT; +-#endif +- } +- +- +- /* Copy the caller's structure return value address so that the closure +- returns the data directly to the caller. +- For FFI_SYSV the result is passed in r3/r4 if the struct size is less +- or equal 8 bytes. */ +- if (rtypenum == FFI_TYPE_STRUCT && ((cif->abi != FFI_SYSV) || (size > 8))) { +- rvalue = (void *) *pgr; +- ng++; +- pgr++; +- } +- +- i = 0; +- avn = cif->nargs; +- arg_types = cif->arg_types; +- +- /* Grab the addresses of the arguments from the stack frame. */ +- while (i < avn) { +- unsigned short typenum = arg_types[i]->type; +- +- /* We may need to handle some values depending on ABI */ +- if (cif->abi == FFI_LINUX_SOFT_FLOAT) { +- if (typenum == FFI_TYPE_FLOAT) +- typenum = FFI_TYPE_UINT32; +- if (typenum == FFI_TYPE_DOUBLE) +- typenum = FFI_TYPE_UINT64; +- if (typenum == FFI_TYPE_LONGDOUBLE) +- typenum = FFI_TYPE_UINT128; +- } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) { +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- if (typenum == FFI_TYPE_LONGDOUBLE) +- typenum = FFI_TYPE_STRUCT; ++ return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc); + #endif +- } +- +- switch (typenum) { +-#ifndef __NO_FPRS__ +- case FFI_TYPE_FLOAT: +- /* unfortunately float values are stored as doubles +- * in the ffi_closure_SYSV code (since we don't check +- * the type in that routine). +- */ +- +- /* there are 8 64bit floating point registers */ +- +- if (nf < 8) +- { +- double temp = pfr->d; +- pfr->f = (float) temp; +- avalue[i] = pfr; +- nf++; +- pfr++; +- } +- else +- { +- /* FIXME? here we are really changing the values +- * stored in the original calling routines outgoing +- * parameter stack. This is probably a really +- * naughty thing to do but... +- */ +- avalue[i] = pst; +- pst += 1; +- } +- break; +- +- case FFI_TYPE_DOUBLE: +- /* On the outgoing stack all values are aligned to 8 */ +- /* there are 8 64bit floating point registers */ +- +- if (nf < 8) +- { +- avalue[i] = pfr; +- nf++; +- pfr++; +- } +- else +- { +- if (((long) pst) & 4) +- pst++; +- avalue[i] = pst; +- pst += 2; +- } +- break; +- +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- case FFI_TYPE_LONGDOUBLE: +- if (nf < 7) +- { +- avalue[i] = pfr; +- pfr += 2; +- nf += 2; +- } +- else +- { +- if (((long) pst) & 4) +- pst++; +- avalue[i] = pst; +- pst += 4; +- nf = 8; +- } +- break; +-#endif +-#endif /* have FPRS */ +- +- case FFI_TYPE_UINT128: +- /* +- * Test if for the whole long double, 4 gprs are available. +- * otherwise the stuff ends up on the stack. +- */ +- if (ng < 5) { +- avalue[i] = pgr; +- pgr += 4; +- ng += 4; +- } else { +- avalue[i] = pst; +- pst += 4; +- ng = 8+4; +- } +- break; +- +- case FFI_TYPE_SINT8: +- case FFI_TYPE_UINT8: +-#ifndef __LITTLE_ENDIAN__ +- /* there are 8 gpr registers used to pass values */ +- if (ng < 8) +- { +- avalue[i] = (char *) pgr + 3; +- ng++; +- pgr++; +- } +- else +- { +- avalue[i] = (char *) pst + 3; +- pst++; +- } +- break; +-#endif +- +- case FFI_TYPE_SINT16: +- case FFI_TYPE_UINT16: +-#ifndef __LITTLE_ENDIAN__ +- /* there are 8 gpr registers used to pass values */ +- if (ng < 8) +- { +- avalue[i] = (char *) pgr + 2; +- ng++; +- pgr++; +- } +- else +- { +- avalue[i] = (char *) pst + 2; +- pst++; +- } +- break; +-#endif +- +- case FFI_TYPE_SINT32: +- case FFI_TYPE_UINT32: +- case FFI_TYPE_POINTER: +- /* there are 8 gpr registers used to pass values */ +- if (ng < 8) +- { +- avalue[i] = pgr; +- ng++; +- pgr++; +- } +- else +- { +- avalue[i] = pst; +- pst++; +- } +- break; +- +- case FFI_TYPE_STRUCT: +- /* Structs are passed by reference. The address will appear in a +- gpr if it is one of the first 8 arguments. */ +- if (ng < 8) +- { +- avalue[i] = (void *) *pgr; +- ng++; +- pgr++; +- } +- else +- { +- avalue[i] = (void *) *pst; +- pst++; +- } +- break; +- +- case FFI_TYPE_SINT64: +- case FFI_TYPE_UINT64: +- /* passing long long ints are complex, they must +- * be passed in suitable register pairs such as +- * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) +- * and if the entire pair aren't available then the outgoing +- * parameter stack is used for both but an alignment of 8 +- * must will be kept. So we must either look in pgr +- * or pst to find the correct address for this type +- * of parameter. +- */ +- if (ng < 7) +- { +- if (ng & 0x01) +- { +- /* skip r4, r6, r8 as starting points */ +- ng++; +- pgr++; +- } +- avalue[i] = pgr; +- ng += 2; +- pgr += 2; +- } +- else +- { +- if (((long) pst) & 4) +- pst++; +- avalue[i] = pst; +- pst += 2; +- ng = 8; +- } +- break; +- +- default: +- FFI_ASSERT (0); +- } +- +- i++; +- } +- +- +- (closure->fun) (cif, rvalue, avalue, closure->user_data); +- +- /* Tell ffi_closure_SYSV how to perform return type promotions. +- Because the FFI_SYSV ABI returns the structures <= 8 bytes in r3/r4 +- we have to tell ffi_closure_SYSV how to treat them. We combine the base +- type FFI_SYSV_TYPE_SMALL_STRUCT - 1 with the size of the struct. +- So a one byte struct gets the return type 16. Return type 1 to 15 are +- already used and we never have a struct with size zero. That is the reason +- for the subtraction of 1. See the comment in ffitarget.h about ordering. +- */ +- if (cif->abi == FFI_SYSV && rtypenum == FFI_TYPE_STRUCT && size <= 8) +- return (FFI_SYSV_TYPE_SMALL_STRUCT - 1) + size; +- return rtypenum; +-} +- +-int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *, +- unsigned long *, ffi_dblfl *); +- +-int FFI_HIDDEN +-ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, +- unsigned long *pst, ffi_dblfl *pfr) +-{ +- /* rvalue is the pointer to space for return value in closure assembly */ +- /* pst is the pointer to parameter save area +- (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */ +- /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */ +- +- void **avalue; +- ffi_type **arg_types; +- unsigned long i, avn, nfixedargs; +- ffi_cif *cif; +- ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; +-#ifdef __STRUCT_PARM_ALIGN__ +- unsigned long align; +-#endif +- +- cif = closure->cif; +- avalue = alloca (cif->nargs * sizeof (void *)); +- +- /* Copy the caller's structure return value address so that the +- closure returns the data directly to the caller. */ +- if (cif->rtype->type == FFI_TYPE_STRUCT +- && (cif->flags & FLAG_RETURNS_SMST) == 0) +- { +- rvalue = (void *) *pst; +- pst++; +- } +- +- i = 0; +- avn = cif->nargs; +- nfixedargs = cif->nfixedargs; +- arg_types = cif->arg_types; +- +- /* Grab the addresses of the arguments from the stack frame. */ +- while (i < avn) +- { +- unsigned int elt, elnum; +- +- switch (arg_types[i]->type) +- { +- case FFI_TYPE_SINT8: +- case FFI_TYPE_UINT8: +-#ifndef __LITTLE_ENDIAN__ +- avalue[i] = (char *) pst + 7; +- pst++; +- break; +-#endif +- +- case FFI_TYPE_SINT16: +- case FFI_TYPE_UINT16: +-#ifndef __LITTLE_ENDIAN__ +- avalue[i] = (char *) pst + 6; +- pst++; +- break; +-#endif +- +- case FFI_TYPE_SINT32: +- case FFI_TYPE_UINT32: +-#ifndef __LITTLE_ENDIAN__ +- avalue[i] = (char *) pst + 4; +- pst++; +- break; +-#endif +- +- case FFI_TYPE_SINT64: +- case FFI_TYPE_UINT64: +- case FFI_TYPE_POINTER: +- avalue[i] = pst; +- pst++; +- break; +- +- case FFI_TYPE_STRUCT: +-#ifdef __STRUCT_PARM_ALIGN__ +- align = arg_types[i]->alignment; +- if (align > __STRUCT_PARM_ALIGN__) +- align = __STRUCT_PARM_ALIGN__; +- if (align > 1) +- pst = (unsigned long *) ALIGN ((size_t) pst, align); +-#endif +- elt = 0; +-#if _CALL_ELF == 2 +- elt = discover_homogeneous_aggregate (arg_types[i], &elnum); +-#endif +- if (elt) +- { +- union { +- void *v; +- unsigned long *ul; +- float *f; +- double *d; +- size_t p; +- } to, from; +- +- /* Repackage the aggregate from its parts. The +- aggregate size is not greater than the space taken by +- the registers so store back to the register/parameter +- save arrays. */ +- if (pfr + elnum <= end_pfr) +- to.v = pfr; +- else +- to.v = pst; +- +- avalue[i] = to.v; +- from.ul = pst; +- if (elt == FFI_TYPE_FLOAT) +- { +- do +- { +- if (pfr < end_pfr && i < nfixedargs) +- { +- *to.f = (float) pfr->d; +- pfr++; +- } +- else +- *to.f = *from.f; +- to.f++; +- from.f++; +- } +- while (--elnum != 0); +- } +- else +- { +- do +- { +- if (pfr < end_pfr && i < nfixedargs) +- { +- *to.d = pfr->d; +- pfr++; +- } +- else +- *to.d = *from.d; +- to.d++; +- from.d++; +- } +- while (--elnum != 0); +- } +- } +- else +- { +-#ifndef __LITTLE_ENDIAN__ +- /* Structures with size less than eight bytes are passed +- left-padded. */ +- if (arg_types[i]->size < 8) +- avalue[i] = (char *) pst + 8 - arg_types[i]->size; +- else +-#endif +- avalue[i] = pst; +- } +- pst += (arg_types[i]->size + 7) / 8; +- break; +- +- case FFI_TYPE_FLOAT: +- /* unfortunately float values are stored as doubles +- * in the ffi_closure_LINUX64 code (since we don't check +- * the type in that routine). +- */ +- +- /* there are 13 64bit floating point registers */ +- +- if (pfr < end_pfr && i < nfixedargs) +- { +- double temp = pfr->d; +- pfr->f = (float) temp; +- avalue[i] = pfr; +- pfr++; +- } +- else +- avalue[i] = pst; +- pst++; +- break; +- +- case FFI_TYPE_DOUBLE: +- /* On the outgoing stack all values are aligned to 8 */ +- /* there are 13 64bit floating point registers */ +- +- if (pfr < end_pfr && i < nfixedargs) +- { +- avalue[i] = pfr; +- pfr++; +- } +- else +- avalue[i] = pst; +- pst++; +- break; +- +-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +- case FFI_TYPE_LONGDOUBLE: +- if (pfr + 1 < end_pfr && i + 1 < nfixedargs) +- { +- avalue[i] = pfr; +- pfr += 2; +- } +- else +- { +- if (pfr < end_pfr && i < nfixedargs) +- { +- /* Passed partly in f13 and partly on the stack. +- Move it all to the stack. */ +- *pst = *(unsigned long *) pfr; +- pfr++; +- } +- avalue[i] = pst; +- } +- pst += 2; +- break; +-#endif +- +- default: +- FFI_ASSERT (0); +- } +- +- i++; +- } +- +- +- (closure->fun) (cif, rvalue, avalue, closure->user_data); +- +- /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ +- if ((cif->flags & FLAG_RETURNS_SMST) != 0) +- { +- if ((cif->flags & FLAG_RETURNS_FP) == 0) +- return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1; +- else if ((cif->flags & FLAG_RETURNS_64BITS) != 0) +- return FFI_V2_TYPE_DOUBLE_HOMOG; +- else +- return FFI_V2_TYPE_FLOAT_HOMOG; +- } +- return cif->rtype->type; + } +Index: libffi-3.0.13/src/powerpc/ffi_linux64.c +=================================================================== +--- /dev/null ++++ libffi-3.0.13/src/powerpc/ffi_linux64.c +@@ -0,0 +1,942 @@ ++/* ----------------------------------------------------------------------- ++ ffi_linux64.c - Copyright (C) 2013 IBM ++ Copyright (C) 2011 Anthony Green ++ Copyright (C) 2011 Kyle Moffett ++ Copyright (C) 2008 Red Hat, Inc ++ Copyright (C) 2007, 2008 Free Software Foundation, Inc ++ Copyright (c) 1998 Geoffrey Keating ++ ++ PowerPC Foreign Function Interface ++ ++ Permission is hereby granted, free of charge, to any person obtaining ++ a copy of this software and associated documentation files (the ++ ``Software''), to deal in the Software without restriction, including ++ without limitation the rights to use, copy, modify, merge, publish, ++ distribute, sublicense, and/or sell copies of the Software, and to ++ permit persons to whom the Software is furnished to do so, subject to ++ the following conditions: ++ ++ The above copyright notice and this permission notice shall be included ++ in all copies or substantial portions of the Software. ++ ++ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ OTHER DEALINGS IN THE SOFTWARE. ++ ----------------------------------------------------------------------- */ ++ ++#include "ffi.h" ++ ++#ifdef POWERPC64 ++#include "ffi_common.h" ++#include "ffi_powerpc.h" ++ ++ ++/* About the LINUX64 ABI. */ ++enum { ++ NUM_GPR_ARG_REGISTERS64 = 8, ++ NUM_FPR_ARG_REGISTERS64 = 13 ++}; ++enum { ASM_NEEDS_REGISTERS64 = 4 }; ++ ++ ++#if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++/* Adjust size of ffi_type_longdouble. */ ++void FFI_HIDDEN ++ffi_prep_types_linux64 (ffi_abi abi) ++{ ++ if ((abi & (FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128)) == FFI_LINUX) ++ { ++ ffi_type_longdouble.size = 8; ++ ffi_type_longdouble.alignment = 8; ++ } ++ else ++ { ++ ffi_type_longdouble.size = 16; ++ ffi_type_longdouble.alignment = 16; ++ } ++} ++#endif ++ ++ ++#if _CALL_ELF == 2 ++static unsigned int ++discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum) ++{ ++ switch (t->type) ++ { ++ case FFI_TYPE_FLOAT: ++ case FFI_TYPE_DOUBLE: ++ *elnum = 1; ++ return (int) t->type; ++ ++ case FFI_TYPE_STRUCT:; ++ { ++ unsigned int base_elt = 0, total_elnum = 0; ++ ffi_type **el = t->elements; ++ while (*el) ++ { ++ unsigned int el_elt, el_elnum = 0; ++ el_elt = discover_homogeneous_aggregate (*el, &el_elnum); ++ if (el_elt == 0 ++ || (base_elt && base_elt != el_elt)) ++ return 0; ++ base_elt = el_elt; ++ total_elnum += el_elnum; ++ if (total_elnum > 8) ++ return 0; ++ el++; ++ } ++ *elnum = total_elnum; ++ return base_elt; ++ } ++ ++ default: ++ return 0; ++ } ++} ++#endif ++ ++ ++/* Perform machine dependent cif processing */ ++static ffi_status ++ffi_prep_cif_linux64_core (ffi_cif *cif) ++{ ++ ffi_type **ptr; ++ unsigned bytes; ++ unsigned i, fparg_count = 0, intarg_count = 0; ++ unsigned flags = cif->flags; ++#if _CALL_ELF == 2 ++ unsigned int elt, elnum; ++#endif ++ ++#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE ++ /* If compiled without long double support.. */ ++ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) ++ return FFI_BAD_ABI; ++#endif ++ ++ /* The machine-independent calculation of cif->bytes doesn't work ++ for us. Redo the calculation. */ ++#if _CALL_ELF == 2 ++ /* Space for backchain, CR, LR, TOC and the asm's temp regs. */ ++ bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long); ++ ++ /* Space for the general registers. */ ++ bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long); ++#else ++ /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp ++ regs. */ ++ bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long); ++ ++ /* Space for the mandatory parm save area and general registers. */ ++ bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long); ++#endif ++ ++ /* Return value handling. */ ++ switch (cif->rtype->type) ++ { ++#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ case FFI_TYPE_LONGDOUBLE: ++ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) ++ flags |= FLAG_RETURNS_128BITS; ++ /* Fall through. */ ++#endif ++ case FFI_TYPE_DOUBLE: ++ flags |= FLAG_RETURNS_64BITS; ++ /* Fall through. */ ++ case FFI_TYPE_FLOAT: ++ flags |= FLAG_RETURNS_FP; ++ break; ++ ++ case FFI_TYPE_UINT128: ++ flags |= FLAG_RETURNS_128BITS; ++ /* Fall through. */ ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ flags |= FLAG_RETURNS_64BITS; ++ break; ++ ++ case FFI_TYPE_STRUCT: ++#if _CALL_ELF == 2 ++ elt = discover_homogeneous_aggregate (cif->rtype, &elnum); ++ if (elt) ++ { ++ if (elt == FFI_TYPE_DOUBLE) ++ flags |= FLAG_RETURNS_64BITS; ++ flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST; ++ break; ++ } ++ if (cif->rtype->size <= 16) ++ { ++ flags |= FLAG_RETURNS_SMST; ++ break; ++ } ++#endif ++ intarg_count++; ++ flags |= FLAG_RETVAL_REFERENCE; ++ /* Fall through. */ ++ case FFI_TYPE_VOID: ++ flags |= FLAG_RETURNS_NOTHING; ++ break; ++ ++ default: ++ /* Returns 32-bit integer, or similar. Nothing to do here. */ ++ break; ++ } ++ ++ for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) ++ { ++ unsigned int align; ++ ++ switch ((*ptr)->type) ++ { ++#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ case FFI_TYPE_LONGDOUBLE: ++ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) ++ { ++ fparg_count++; ++ intarg_count++; ++ } ++ /* Fall through. */ ++#endif ++ case FFI_TYPE_DOUBLE: ++ case FFI_TYPE_FLOAT: ++ fparg_count++; ++ intarg_count++; ++ if (fparg_count > NUM_FPR_ARG_REGISTERS64) ++ flags |= FLAG_ARG_NEEDS_PSAVE; ++ break; ++ ++ case FFI_TYPE_STRUCT: ++ if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0) ++ { ++ align = (*ptr)->alignment; ++ if (align > 16) ++ align = 16; ++ align = align / 8; ++ if (align > 1) ++ intarg_count = ALIGN (intarg_count, align); ++ } ++ intarg_count += ((*ptr)->size + 7) / 8; ++#if _CALL_ELF == 2 ++ elt = discover_homogeneous_aggregate (*ptr, &elnum); ++ if (elt) ++ { ++ fparg_count += elnum; ++ if (fparg_count > NUM_FPR_ARG_REGISTERS64) ++ flags |= FLAG_ARG_NEEDS_PSAVE; ++ } ++ else ++#endif ++ { ++ if (intarg_count > NUM_GPR_ARG_REGISTERS64) ++ flags |= FLAG_ARG_NEEDS_PSAVE; ++ } ++ break; ++ ++ case FFI_TYPE_POINTER: ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ case FFI_TYPE_INT: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_UINT16: ++ case FFI_TYPE_SINT16: ++ case FFI_TYPE_UINT8: ++ case FFI_TYPE_SINT8: ++ /* Everything else is passed as a 8-byte word in a GPR, either ++ the object itself or a pointer to it. */ ++ intarg_count++; ++ if (intarg_count > NUM_GPR_ARG_REGISTERS64) ++ flags |= FLAG_ARG_NEEDS_PSAVE; ++ break; ++ default: ++ FFI_ASSERT (0); ++ } ++ } ++ ++ if (fparg_count != 0) ++ flags |= FLAG_FP_ARGUMENTS; ++ if (intarg_count > 4) ++ flags |= FLAG_4_GPR_ARGUMENTS; ++ ++ /* Space for the FPR registers, if needed. */ ++ if (fparg_count != 0) ++ bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double); ++ ++ /* Stack space. */ ++#if _CALL_ELF == 2 ++ if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0) ++ bytes += intarg_count * sizeof (long); ++#else ++ if (intarg_count > NUM_GPR_ARG_REGISTERS64) ++ bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long); ++#endif ++ ++ /* The stack space allocated needs to be a multiple of 16 bytes. */ ++ bytes = (bytes + 15) & ~0xF; ++ ++ cif->flags = flags; ++ cif->bytes = bytes; ++ ++ return FFI_OK; ++} ++ ++ffi_status FFI_HIDDEN ++ffi_prep_cif_linux64 (ffi_cif *cif) ++{ ++ if ((cif->abi & FFI_LINUX) != 0) ++ cif->nfixedargs = cif->nargs; ++#if _CALL_ELF != 2 ++ else if (cif->abi == FFI_COMPAT_LINUX64) ++ { ++ /* This call is from old code. Don't touch cif->nfixedargs ++ since old code will be using a smaller cif. */ ++ cif->flags |= FLAG_COMPAT; ++ /* Translate to new abi value. */ ++ cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128; ++ } ++#endif ++ else ++ return FFI_BAD_ABI; ++ return ffi_prep_cif_linux64_core (cif); ++} ++ ++ffi_status FFI_HIDDEN ++ffi_prep_cif_linux64_var (ffi_cif *cif, ++ unsigned int nfixedargs, ++ unsigned int ntotalargs MAYBE_UNUSED) ++{ ++ if ((cif->abi & FFI_LINUX) != 0) ++ cif->nfixedargs = nfixedargs; ++#if _CALL_ELF != 2 ++ else if (cif->abi == FFI_COMPAT_LINUX64) ++ { ++ /* This call is from old code. Don't touch cif->nfixedargs ++ since old code will be using a smaller cif. */ ++ cif->flags |= FLAG_COMPAT; ++ /* Translate to new abi value. */ ++ cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128; ++ } ++#endif ++ else ++ return FFI_BAD_ABI; ++#if _CALL_ELF == 2 ++ cif->flags |= FLAG_ARG_NEEDS_PSAVE; ++#endif ++ return ffi_prep_cif_linux64_core (cif); ++} ++ ++ ++/* ffi_prep_args64 is called by the assembly routine once stack space ++ has been allocated for the function's arguments. ++ ++ The stack layout we want looks like this: ++ ++ | Ret addr from ffi_call_LINUX64 8bytes | higher addresses ++ |--------------------------------------------| ++ | CR save area 8bytes | ++ |--------------------------------------------| ++ | Previous backchain pointer 8 | stack pointer here ++ |--------------------------------------------|<+ <<< on entry to ++ | Saved r28-r31 4*8 | | ffi_call_LINUX64 ++ |--------------------------------------------| | ++ | GPR registers r3-r10 8*8 | | ++ |--------------------------------------------| | ++ | FPR registers f1-f13 (optional) 13*8 | | ++ |--------------------------------------------| | ++ | Parameter save area | | ++ |--------------------------------------------| | ++ | TOC save area 8 | | ++ |--------------------------------------------| | stack | ++ | Linker doubleword 8 | | grows | ++ |--------------------------------------------| | down V ++ | Compiler doubleword 8 | | ++ |--------------------------------------------| | lower addresses ++ | Space for callee's LR 8 | | ++ |--------------------------------------------| | ++ | CR save area 8 | | ++ |--------------------------------------------| | stack pointer here ++ | Current backchain pointer 8 |-/ during ++ |--------------------------------------------| <<< ffi_call_LINUX64 ++ ++*/ ++ ++void FFI_HIDDEN ++ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack) ++{ ++ const unsigned long bytes = ecif->cif->bytes; ++ const unsigned long flags = ecif->cif->flags; ++ ++ typedef union ++ { ++ char *c; ++ unsigned long *ul; ++ float *f; ++ double *d; ++ size_t p; ++ } valp; ++ ++ /* 'stacktop' points at the previous backchain pointer. */ ++ valp stacktop; ++ ++ /* 'next_arg' points at the space for gpr3, and grows upwards as ++ we use GPR registers, then continues at rest. */ ++ valp gpr_base; ++ valp gpr_end; ++ valp rest; ++ valp next_arg; ++ ++ /* 'fpr_base' points at the space for fpr3, and grows upwards as ++ we use FPR registers. */ ++ valp fpr_base; ++ unsigned int fparg_count; ++ ++ unsigned int i, words, nargs, nfixedargs; ++ ffi_type **ptr; ++ double double_tmp; ++ union ++ { ++ void **v; ++ char **c; ++ signed char **sc; ++ unsigned char **uc; ++ signed short **ss; ++ unsigned short **us; ++ signed int **si; ++ unsigned int **ui; ++ unsigned long **ul; ++ float **f; ++ double **d; ++ } p_argv; ++ unsigned long gprvalue; ++ unsigned long align; ++ ++ stacktop.c = (char *) stack + bytes; ++ gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64; ++ gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64; ++#if _CALL_ELF == 2 ++ rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64; ++#else ++ rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64; ++#endif ++ fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64; ++ fparg_count = 0; ++ next_arg.ul = gpr_base.ul; ++ ++ /* Check that everything starts aligned properly. */ ++ FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); ++ FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0); ++ FFI_ASSERT ((bytes & 0xF) == 0); ++ ++ /* Deal with return values that are actually pass-by-reference. */ ++ if (flags & FLAG_RETVAL_REFERENCE) ++ *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue; ++ ++ /* Now for the arguments. */ ++ p_argv.v = ecif->avalue; ++ nargs = ecif->cif->nargs; ++#if _CALL_ELF != 2 ++ nfixedargs = (unsigned) -1; ++ if ((flags & FLAG_COMPAT) == 0) ++#endif ++ nfixedargs = ecif->cif->nfixedargs; ++ for (ptr = ecif->cif->arg_types, i = 0; ++ i < nargs; ++ i++, ptr++, p_argv.v++) ++ { ++#if _CALL_ELF == 2 ++ unsigned int elt, elnum; ++#endif ++ ++ switch ((*ptr)->type) ++ { ++#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ case FFI_TYPE_LONGDOUBLE: ++ if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) ++ { ++ double_tmp = (*p_argv.d)[0]; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ { ++ *fpr_base.d++ = double_tmp; ++# if _CALL_ELF != 2 ++ if ((flags & FLAG_COMPAT) != 0) ++ *next_arg.d = double_tmp; ++# endif ++ } ++ else ++ *next_arg.d = double_tmp; ++ if (++next_arg.ul == gpr_end.ul) ++ next_arg.ul = rest.ul; ++ fparg_count++; ++ double_tmp = (*p_argv.d)[1]; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ { ++ *fpr_base.d++ = double_tmp; ++# if _CALL_ELF != 2 ++ if ((flags & FLAG_COMPAT) != 0) ++ *next_arg.d = double_tmp; ++# endif ++ } ++ else ++ *next_arg.d = double_tmp; ++ if (++next_arg.ul == gpr_end.ul) ++ next_arg.ul = rest.ul; ++ fparg_count++; ++ FFI_ASSERT (__LDBL_MANT_DIG__ == 106); ++ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); ++ break; ++ } ++ /* Fall through. */ ++#endif ++ case FFI_TYPE_DOUBLE: ++ double_tmp = **p_argv.d; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ { ++ *fpr_base.d++ = double_tmp; ++#if _CALL_ELF != 2 ++ if ((flags & FLAG_COMPAT) != 0) ++ *next_arg.d = double_tmp; ++#endif ++ } ++ else ++ *next_arg.d = double_tmp; ++ if (++next_arg.ul == gpr_end.ul) ++ next_arg.ul = rest.ul; ++ fparg_count++; ++ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); ++ break; ++ ++ case FFI_TYPE_FLOAT: ++ double_tmp = **p_argv.f; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ { ++ *fpr_base.d++ = double_tmp; ++#if _CALL_ELF != 2 ++ if ((flags & FLAG_COMPAT) != 0) ++ *next_arg.f = (float) double_tmp; ++#endif ++ } ++ else ++ *next_arg.f = (float) double_tmp; ++ if (++next_arg.ul == gpr_end.ul) ++ next_arg.ul = rest.ul; ++ fparg_count++; ++ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); ++ break; ++ ++ case FFI_TYPE_STRUCT: ++ if ((ecif->cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0) ++ { ++ align = (*ptr)->alignment; ++ if (align > 16) ++ align = 16; ++ if (align > 1) ++ next_arg.p = ALIGN (next_arg.p, align); ++ } ++#if _CALL_ELF == 2 ++ elt = discover_homogeneous_aggregate (*ptr, &elnum); ++ if (elt) ++ { ++ union { ++ void *v; ++ float *f; ++ double *d; ++ } arg; ++ ++ arg.v = *p_argv.v; ++ if (elt == FFI_TYPE_FLOAT) ++ { ++ do ++ { ++ double_tmp = *arg.f++; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 ++ && i < nfixedargs) ++ *fpr_base.d++ = double_tmp; ++ else ++ *next_arg.f = (float) double_tmp; ++ if (++next_arg.f == gpr_end.f) ++ next_arg.f = rest.f; ++ fparg_count++; ++ } ++ while (--elnum != 0); ++ if ((next_arg.p & 3) != 0) ++ { ++ if (++next_arg.f == gpr_end.f) ++ next_arg.f = rest.f; ++ } ++ } ++ else ++ do ++ { ++ double_tmp = *arg.d++; ++ if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) ++ *fpr_base.d++ = double_tmp; ++ else ++ *next_arg.d = double_tmp; ++ if (++next_arg.d == gpr_end.d) ++ next_arg.d = rest.d; ++ fparg_count++; ++ } ++ while (--elnum != 0); ++ } ++ else ++#endif ++ { ++ words = ((*ptr)->size + 7) / 8; ++ if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul) ++ { ++ size_t first = gpr_end.c - next_arg.c; ++ memcpy (next_arg.c, *p_argv.c, first); ++ memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first); ++ next_arg.c = rest.c + words * 8 - first; ++ } ++ else ++ { ++ char *where = next_arg.c; ++ ++#ifndef __LITTLE_ENDIAN__ ++ /* Structures with size less than eight bytes are passed ++ left-padded. */ ++ if ((*ptr)->size < 8) ++ where += 8 - (*ptr)->size; ++#endif ++ memcpy (where, *p_argv.c, (*ptr)->size); ++ next_arg.ul += words; ++ if (next_arg.ul == gpr_end.ul) ++ next_arg.ul = rest.ul; ++ } ++ } ++ break; ++ ++ case FFI_TYPE_UINT8: ++ gprvalue = **p_argv.uc; ++ goto putgpr; ++ case FFI_TYPE_SINT8: ++ gprvalue = **p_argv.sc; ++ goto putgpr; ++ case FFI_TYPE_UINT16: ++ gprvalue = **p_argv.us; ++ goto putgpr; ++ case FFI_TYPE_SINT16: ++ gprvalue = **p_argv.ss; ++ goto putgpr; ++ case FFI_TYPE_UINT32: ++ gprvalue = **p_argv.ui; ++ goto putgpr; ++ case FFI_TYPE_INT: ++ case FFI_TYPE_SINT32: ++ gprvalue = **p_argv.si; ++ goto putgpr; ++ ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ case FFI_TYPE_POINTER: ++ gprvalue = **p_argv.ul; ++ putgpr: ++ *next_arg.ul++ = gprvalue; ++ if (next_arg.ul == gpr_end.ul) ++ next_arg.ul = rest.ul; ++ break; ++ } ++ } ++ ++ FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS ++ || (next_arg.ul >= gpr_base.ul ++ && next_arg.ul <= gpr_base.ul + 4)); ++} ++ ++ ++#if _CALL_ELF == 2 ++#define MIN_CACHE_LINE_SIZE 8 ++ ++static void ++flush_icache (char *wraddr, char *xaddr, int size) ++{ ++ int i; ++ for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) ++ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" ++ : : "r" (xaddr + i), "r" (wraddr + i) : "memory"); ++ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;" ++ : : "r"(xaddr + size - 1), "r"(wraddr + size - 1) ++ : "memory"); ++} ++#endif ++ ++ffi_status ++ffi_prep_closure_loc_linux64 (ffi_closure *closure, ++ ffi_cif *cif, ++ void (*fun) (ffi_cif *, void *, void **, void *), ++ void *user_data, ++ void *codeloc) ++{ ++#if _CALL_ELF == 2 ++ unsigned int *tramp = (unsigned int *) &closure->tramp[0]; ++ ++ if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI) ++ return FFI_BAD_ABI; ++ ++ tramp[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */ ++ tramp[1] = 0xe98c0010; /* ld 12,1f-0b(12) */ ++ tramp[2] = 0x7d8903a6; /* mtctr 12 */ ++ tramp[3] = 0x4e800420; /* bctr */ ++ /* 1: .quad function_addr */ ++ /* 2: .quad context */ ++ *(void **) &tramp[4] = (void *) ffi_closure_LINUX64; ++ *(void **) &tramp[6] = codeloc; ++ flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE); ++#else ++ void **tramp = (void **) &closure->tramp[0]; ++ ++ if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI) ++ return FFI_BAD_ABI; ++ ++ /* Copy function address and TOC from ffi_closure_LINUX64. */ ++ memcpy (tramp, (char *) ffi_closure_LINUX64, 16); ++ tramp[2] = codeloc; ++#endif ++ ++ closure->cif = cif; ++ closure->fun = fun; ++ closure->user_data = user_data; ++ ++ return FFI_OK; ++} ++ ++ ++int FFI_HIDDEN ++ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, ++ unsigned long *pst, ffi_dblfl *pfr) ++{ ++ /* rvalue is the pointer to space for return value in closure assembly */ ++ /* pst is the pointer to parameter save area ++ (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */ ++ /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */ ++ ++ void **avalue; ++ ffi_type **arg_types; ++ unsigned long i, avn, nfixedargs; ++ ffi_cif *cif; ++ ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; ++ unsigned long align; ++ ++ cif = closure->cif; ++ avalue = alloca (cif->nargs * sizeof (void *)); ++ ++ /* Copy the caller's structure return value address so that the ++ closure returns the data directly to the caller. */ ++ if (cif->rtype->type == FFI_TYPE_STRUCT ++ && (cif->flags & FLAG_RETURNS_SMST) == 0) ++ { ++ rvalue = (void *) *pst; ++ pst++; ++ } ++ ++ i = 0; ++ avn = cif->nargs; ++#if _CALL_ELF != 2 ++ nfixedargs = (unsigned) -1; ++ if ((cif->flags & FLAG_COMPAT) == 0) ++#endif ++ nfixedargs = cif->nfixedargs; ++ arg_types = cif->arg_types; ++ ++ /* Grab the addresses of the arguments from the stack frame. */ ++ while (i < avn) ++ { ++ unsigned int elt, elnum; ++ ++ switch (arg_types[i]->type) ++ { ++ case FFI_TYPE_SINT8: ++ case FFI_TYPE_UINT8: ++#ifndef __LITTLE_ENDIAN__ ++ avalue[i] = (char *) pst + 7; ++ pst++; ++ break; ++#endif ++ ++ case FFI_TYPE_SINT16: ++ case FFI_TYPE_UINT16: ++#ifndef __LITTLE_ENDIAN__ ++ avalue[i] = (char *) pst + 6; ++ pst++; ++ break; ++#endif ++ ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_UINT32: ++#ifndef __LITTLE_ENDIAN__ ++ avalue[i] = (char *) pst + 4; ++ pst++; ++ break; ++#endif ++ ++ case FFI_TYPE_SINT64: ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_POINTER: ++ avalue[i] = pst; ++ pst++; ++ break; ++ ++ case FFI_TYPE_STRUCT: ++ if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0) ++ { ++ align = arg_types[i]->alignment; ++ if (align > 16) ++ align = 16; ++ if (align > 1) ++ pst = (unsigned long *) ALIGN ((size_t) pst, align); ++ } ++ elt = 0; ++#if _CALL_ELF == 2 ++ elt = discover_homogeneous_aggregate (arg_types[i], &elnum); ++#endif ++ if (elt) ++ { ++ union { ++ void *v; ++ unsigned long *ul; ++ float *f; ++ double *d; ++ size_t p; ++ } to, from; ++ ++ /* Repackage the aggregate from its parts. The ++ aggregate size is not greater than the space taken by ++ the registers so store back to the register/parameter ++ save arrays. */ ++ if (pfr + elnum <= end_pfr) ++ to.v = pfr; ++ else ++ to.v = pst; ++ ++ avalue[i] = to.v; ++ from.ul = pst; ++ if (elt == FFI_TYPE_FLOAT) ++ { ++ do ++ { ++ if (pfr < end_pfr && i < nfixedargs) ++ { ++ *to.f = (float) pfr->d; ++ pfr++; ++ } ++ else ++ *to.f = *from.f; ++ to.f++; ++ from.f++; ++ } ++ while (--elnum != 0); ++ } ++ else ++ { ++ do ++ { ++ if (pfr < end_pfr && i < nfixedargs) ++ { ++ *to.d = pfr->d; ++ pfr++; ++ } ++ else ++ *to.d = *from.d; ++ to.d++; ++ from.d++; ++ } ++ while (--elnum != 0); ++ } ++ } ++ else ++ { ++#ifndef __LITTLE_ENDIAN__ ++ /* Structures with size less than eight bytes are passed ++ left-padded. */ ++ if (arg_types[i]->size < 8) ++ avalue[i] = (char *) pst + 8 - arg_types[i]->size; ++ else ++#endif ++ avalue[i] = pst; ++ } ++ pst += (arg_types[i]->size + 7) / 8; ++ break; ++ ++#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ case FFI_TYPE_LONGDOUBLE: ++ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) ++ { ++ if (pfr + 1 < end_pfr && i + 1 < nfixedargs) ++ { ++ avalue[i] = pfr; ++ pfr += 2; ++ } ++ else ++ { ++ if (pfr < end_pfr && i < nfixedargs) ++ { ++ /* Passed partly in f13 and partly on the stack. ++ Move it all to the stack. */ ++ *pst = *(unsigned long *) pfr; ++ pfr++; ++ } ++ avalue[i] = pst; ++ } ++ pst += 2; ++ break; ++ } ++ /* Fall through. */ ++#endif ++ case FFI_TYPE_DOUBLE: ++ /* On the outgoing stack all values are aligned to 8 */ ++ /* there are 13 64bit floating point registers */ ++ ++ if (pfr < end_pfr && i < nfixedargs) ++ { ++ avalue[i] = pfr; ++ pfr++; ++ } ++ else ++ avalue[i] = pst; ++ pst++; ++ break; ++ ++ case FFI_TYPE_FLOAT: ++ if (pfr < end_pfr && i < nfixedargs) ++ { ++ /* Float values are stored as doubles in the ++ ffi_closure_LINUX64 code. Fix them here. */ ++ pfr->f = (float) pfr->d; ++ avalue[i] = pfr; ++ pfr++; ++ } ++ else ++ avalue[i] = pst; ++ pst++; ++ break; ++ ++ default: ++ FFI_ASSERT (0); ++ } ++ ++ i++; ++ } ++ ++ ++ (closure->fun) (cif, rvalue, avalue, closure->user_data); ++ ++ /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ ++ if ((cif->flags & FLAG_RETURNS_SMST) != 0) ++ { ++ if ((cif->flags & FLAG_RETURNS_FP) == 0) ++ return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1; ++ else if ((cif->flags & FLAG_RETURNS_64BITS) != 0) ++ return FFI_V2_TYPE_DOUBLE_HOMOG; ++ else ++ return FFI_V2_TYPE_FLOAT_HOMOG; ++ } ++ return cif->rtype->type; ++} ++#endif +Index: libffi-3.0.13/src/powerpc/ffi_powerpc.h +=================================================================== +--- /dev/null ++++ libffi-3.0.13/src/powerpc/ffi_powerpc.h +@@ -0,0 +1,77 @@ ++/* ----------------------------------------------------------------------- ++ ffi_powerpc.h - Copyright (C) 2013 IBM ++ Copyright (C) 2011 Anthony Green ++ Copyright (C) 2011 Kyle Moffett ++ Copyright (C) 2008 Red Hat, Inc ++ Copyright (C) 2007, 2008 Free Software Foundation, Inc ++ Copyright (c) 1998 Geoffrey Keating ++ ++ PowerPC Foreign Function Interface ++ ++ Permission is hereby granted, free of charge, to any person obtaining ++ a copy of this software and associated documentation files (the ++ ``Software''), to deal in the Software without restriction, including ++ without limitation the rights to use, copy, modify, merge, publish, ++ distribute, sublicense, and/or sell copies of the Software, and to ++ permit persons to whom the Software is furnished to do so, subject to ++ the following conditions: ++ ++ The above copyright notice and this permission notice shall be included ++ in all copies or substantial portions of the Software. ++ ++ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ OTHER DEALINGS IN THE SOFTWARE. ++ ----------------------------------------------------------------------- */ ++ ++enum { ++ /* The assembly depends on these exact flags. */ ++ /* These go in cr7 */ ++ FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */ ++ FLAG_RETURNS_NOTHING = 1 << (31-30), ++ FLAG_RETURNS_FP = 1 << (31-29), ++ FLAG_RETURNS_64BITS = 1 << (31-28), ++ ++ /* This goes in cr6 */ ++ FLAG_RETURNS_128BITS = 1 << (31-27), ++ ++ FLAG_COMPAT = 1 << (31- 8), /* Not used by assembly */ ++ ++ /* These go in cr1 */ ++ FLAG_ARG_NEEDS_COPY = 1 << (31- 7), /* Used by sysv code */ ++ FLAG_ARG_NEEDS_PSAVE = FLAG_ARG_NEEDS_COPY, /* Used by linux64 code */ ++ FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ ++ FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), ++ FLAG_RETVAL_REFERENCE = 1 << (31- 4) ++}; ++ ++typedef union ++{ ++ float f; ++ double d; ++} ffi_dblfl; ++ ++void FFI_HIDDEN ffi_closure_SYSV (void); ++void FFI_HIDDEN ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *, ++ void (*)(void)); ++ ++void FFI_HIDDEN ffi_prep_types_sysv (ffi_abi); ++ffi_status FFI_HIDDEN ffi_prep_cif_sysv (ffi_cif *); ++int FFI_HIDDEN ffi_closure_helper_SYSV (ffi_closure *, void *, unsigned long *, ++ ffi_dblfl *, unsigned long *); ++ ++void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long, unsigned long, ++ unsigned long *, void (*)(void)); ++void FFI_HIDDEN ffi_closure_LINUX64 (void); ++ ++void FFI_HIDDEN ffi_prep_types_linux64 (ffi_abi); ++ffi_status FFI_HIDDEN ffi_prep_cif_linux64 (ffi_cif *); ++ffi_status FFI_HIDDEN ffi_prep_cif_linux64_var (ffi_cif *, unsigned int, ++ unsigned int); ++void FFI_HIDDEN ffi_prep_args64 (extended_cif *, unsigned long *const); ++int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *, ++ unsigned long *, ffi_dblfl *); +Index: libffi-3.0.13/src/powerpc/ffi_sysv.c +=================================================================== +--- /dev/null ++++ libffi-3.0.13/src/powerpc/ffi_sysv.c +@@ -0,0 +1,931 @@ ++/* ----------------------------------------------------------------------- ++ ffi_sysv.c - Copyright (C) 2013 IBM ++ Copyright (C) 2011 Anthony Green ++ Copyright (C) 2011 Kyle Moffett ++ Copyright (C) 2008 Red Hat, Inc ++ Copyright (C) 2007, 2008 Free Software Foundation, Inc ++ Copyright (c) 1998 Geoffrey Keating ++ ++ PowerPC Foreign Function Interface ++ ++ Permission is hereby granted, free of charge, to any person obtaining ++ a copy of this software and associated documentation files (the ++ ``Software''), to deal in the Software without restriction, including ++ without limitation the rights to use, copy, modify, merge, publish, ++ distribute, sublicense, and/or sell copies of the Software, and to ++ permit persons to whom the Software is furnished to do so, subject to ++ the following conditions: ++ ++ The above copyright notice and this permission notice shall be included ++ in all copies or substantial portions of the Software. ++ ++ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ OTHER DEALINGS IN THE SOFTWARE. ++ ----------------------------------------------------------------------- */ ++ ++#include "ffi.h" ++ ++#ifndef POWERPC64 ++#include "ffi_common.h" ++#include "ffi_powerpc.h" ++ ++ ++/* About the SYSV ABI. */ ++#define ASM_NEEDS_REGISTERS 4 ++#define NUM_GPR_ARG_REGISTERS 8 ++#define NUM_FPR_ARG_REGISTERS 8 ++ ++ ++#if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++/* Adjust size of ffi_type_longdouble. */ ++void FFI_HIDDEN ++ffi_prep_types_sysv (ffi_abi abi) ++{ ++ if ((abi & (FFI_SYSV | FFI_SYSV_LONG_DOUBLE_128)) == FFI_SYSV) ++ { ++ ffi_type_longdouble.size = 8; ++ ffi_type_longdouble.alignment = 8; ++ } ++ else ++ { ++ ffi_type_longdouble.size = 16; ++ ffi_type_longdouble.alignment = 16; ++ } ++} ++#endif ++ ++/* Transform long double, double and float to other types as per abi. */ ++static int ++translate_float (int abi, int type) ++{ ++#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ if (type == FFI_TYPE_LONGDOUBLE ++ && (abi & FFI_SYSV_LONG_DOUBLE_128) == 0) ++ type = FFI_TYPE_DOUBLE; ++#endif ++ if ((abi & FFI_SYSV_SOFT_FLOAT) != 0) ++ { ++ if (type == FFI_TYPE_FLOAT) ++ type = FFI_TYPE_UINT32; ++ else if (type == FFI_TYPE_DOUBLE) ++ type = FFI_TYPE_UINT64; ++#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ else if (type == FFI_TYPE_LONGDOUBLE) ++ type = FFI_TYPE_UINT128; ++ } ++ else if ((abi & FFI_SYSV_IBM_LONG_DOUBLE) == 0) ++ { ++ if (type == FFI_TYPE_LONGDOUBLE) ++ type = FFI_TYPE_STRUCT; ++#endif ++ } ++ return type; ++} ++ ++/* Perform machine dependent cif processing */ ++static ffi_status ++ffi_prep_cif_sysv_core (ffi_cif *cif) ++{ ++ ffi_type **ptr; ++ unsigned bytes; ++ unsigned i, fparg_count = 0, intarg_count = 0; ++ unsigned flags = cif->flags; ++ unsigned struct_copy_size = 0; ++ unsigned type = cif->rtype->type; ++ unsigned size = cif->rtype->size; ++ ++ /* The machine-independent calculation of cif->bytes doesn't work ++ for us. Redo the calculation. */ ++ ++ /* Space for the frame pointer, callee's LR, and the asm's temp regs. */ ++ bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int); ++ ++ /* Space for the GPR registers. */ ++ bytes += NUM_GPR_ARG_REGISTERS * sizeof (int); ++ ++ /* Return value handling. The rules for SYSV are as follows: ++ - 32-bit (or less) integer values are returned in gpr3; ++ - Structures of size <= 4 bytes also returned in gpr3; ++ - 64-bit integer values and structures between 5 and 8 bytes are returned ++ in gpr3 and gpr4; ++ - Larger structures are allocated space and a pointer is passed as ++ the first argument. ++ - Single/double FP values are returned in fpr1; ++ - long doubles (if not equivalent to double) are returned in ++ fpr1,fpr2 for Linux and as for large structs for SysV. */ ++ ++ type = translate_float (cif->abi, type); ++ ++ switch (type) ++ { ++#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ case FFI_TYPE_LONGDOUBLE: ++ flags |= FLAG_RETURNS_128BITS; ++ /* Fall through. */ ++#endif ++ case FFI_TYPE_DOUBLE: ++ flags |= FLAG_RETURNS_64BITS; ++ /* Fall through. */ ++ case FFI_TYPE_FLOAT: ++ flags |= FLAG_RETURNS_FP; ++#ifdef __NO_FPRS__ ++ return FFI_BAD_ABI; ++#endif ++ break; ++ ++ case FFI_TYPE_UINT128: ++ flags |= FLAG_RETURNS_128BITS; ++ /* Fall through. */ ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ flags |= FLAG_RETURNS_64BITS; ++ break; ++ ++ case FFI_TYPE_STRUCT: ++ /* The final SYSV ABI says that structures smaller or equal 8 bytes ++ are returned in r3/r4. A draft ABI used by linux instead ++ returns them in memory. */ ++ if ((cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8) ++ { ++ flags |= FLAG_RETURNS_SMST; ++ break; ++ } ++ intarg_count++; ++ flags |= FLAG_RETVAL_REFERENCE; ++ /* Fall through. */ ++ case FFI_TYPE_VOID: ++ flags |= FLAG_RETURNS_NOTHING; ++ break; ++ ++ default: ++ /* Returns 32-bit integer, or similar. Nothing to do here. */ ++ break; ++ } ++ ++ /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the ++ first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest ++ goes on the stack. Structures and long doubles (if not equivalent ++ to double) are passed as a pointer to a copy of the structure. ++ Stuff on the stack needs to keep proper alignment. */ ++ for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) ++ { ++ unsigned short typenum = (*ptr)->type; ++ ++ typenum = translate_float (cif->abi, typenum); ++ ++ switch (typenum) ++ { ++#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ case FFI_TYPE_LONGDOUBLE: ++ fparg_count++; ++ /* Fall thru */ ++#endif ++ case FFI_TYPE_DOUBLE: ++ fparg_count++; ++ /* If this FP arg is going on the stack, it must be ++ 8-byte-aligned. */ ++ if (fparg_count > NUM_FPR_ARG_REGISTERS ++ && intarg_count >= NUM_GPR_ARG_REGISTERS ++ && intarg_count % 2 != 0) ++ intarg_count++; ++#ifdef __NO_FPRS__ ++ return FFI_BAD_ABI; ++#endif ++ break; ++ ++ case FFI_TYPE_FLOAT: ++ fparg_count++; ++#ifdef __NO_FPRS__ ++ return FFI_BAD_ABI; ++#endif ++ break; ++ ++ case FFI_TYPE_UINT128: ++ /* A long double in FFI_LINUX_SOFT_FLOAT can use only a set ++ of four consecutive gprs. If we do not have enough, we ++ have to adjust the intarg_count value. */ ++ if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3 ++ && intarg_count < NUM_GPR_ARG_REGISTERS) ++ intarg_count = NUM_GPR_ARG_REGISTERS; ++ intarg_count += 4; ++ break; ++ ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ /* 'long long' arguments are passed as two words, but ++ either both words must fit in registers or both go ++ on the stack. If they go on the stack, they must ++ be 8-byte-aligned. ++ ++ Also, only certain register pairs can be used for ++ passing long long int -- specifically (r3,r4), (r5,r6), ++ (r7,r8), (r9,r10). */ ++ if (intarg_count == NUM_GPR_ARG_REGISTERS-1 ++ || intarg_count % 2 != 0) ++ intarg_count++; ++ intarg_count += 2; ++ break; ++ ++ case FFI_TYPE_STRUCT: ++ /* We must allocate space for a copy of these to enforce ++ pass-by-value. Pad the space up to a multiple of 16 ++ bytes (the maximum alignment required for anything under ++ the SYSV ABI). */ ++ struct_copy_size += ((*ptr)->size + 15) & ~0xF; ++ /* Fall through (allocate space for the pointer). */ ++ ++ case FFI_TYPE_POINTER: ++ case FFI_TYPE_INT: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_UINT16: ++ case FFI_TYPE_SINT16: ++ case FFI_TYPE_UINT8: ++ case FFI_TYPE_SINT8: ++ /* Everything else is passed as a 4-byte word in a GPR, either ++ the object itself or a pointer to it. */ ++ intarg_count++; ++ break; ++ ++ default: ++ FFI_ASSERT (0); ++ } ++ } ++ ++ if (fparg_count != 0) ++ flags |= FLAG_FP_ARGUMENTS; ++ if (intarg_count > 4) ++ flags |= FLAG_4_GPR_ARGUMENTS; ++ if (struct_copy_size != 0) ++ flags |= FLAG_ARG_NEEDS_COPY; ++ ++ /* Space for the FPR registers, if needed. */ ++ if (fparg_count != 0) ++ bytes += NUM_FPR_ARG_REGISTERS * sizeof (double); ++ ++ /* Stack space. */ ++ if (intarg_count > NUM_GPR_ARG_REGISTERS) ++ bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int); ++ if (fparg_count > NUM_FPR_ARG_REGISTERS) ++ bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double); ++ ++ /* The stack space allocated needs to be a multiple of 16 bytes. */ ++ bytes = (bytes + 15) & ~0xF; ++ ++ /* Add in the space for the copied structures. */ ++ bytes += struct_copy_size; ++ ++ cif->flags = flags; ++ cif->bytes = bytes; ++ ++ return FFI_OK; ++} ++ ++ffi_status FFI_HIDDEN ++ffi_prep_cif_sysv (ffi_cif *cif) ++{ ++ if ((cif->abi & FFI_SYSV) == 0) ++ { ++ /* This call is from old code. Translate to new ABI values. */ ++ cif->flags |= FLAG_COMPAT; ++ switch (cif->abi) ++ { ++ default: ++ return FFI_BAD_ABI; ++ ++ case FFI_COMPAT_SYSV: ++ cif->abi = FFI_SYSV | FFI_SYSV_STRUCT_RET | FFI_SYSV_LONG_DOUBLE_128; ++ break; ++ ++ case FFI_COMPAT_GCC_SYSV: ++ cif->abi = FFI_SYSV | FFI_SYSV_LONG_DOUBLE_128; ++ break; ++ ++ case FFI_COMPAT_LINUX: ++ cif->abi = (FFI_SYSV | FFI_SYSV_IBM_LONG_DOUBLE ++ | FFI_SYSV_LONG_DOUBLE_128); ++ break; ++ ++ case FFI_COMPAT_LINUX_SOFT_FLOAT: ++ cif->abi = (FFI_SYSV | FFI_SYSV_SOFT_FLOAT | FFI_SYSV_IBM_LONG_DOUBLE ++ | FFI_SYSV_LONG_DOUBLE_128); ++ break; ++ } ++ } ++ return ffi_prep_cif_sysv_core (cif); ++} ++ ++/* ffi_prep_args_SYSV is called by the assembly routine once stack space ++ has been allocated for the function's arguments. ++ ++ The stack layout we want looks like this: ++ ++ | Return address from ffi_call_SYSV 4bytes | higher addresses ++ |--------------------------------------------| ++ | Previous backchain pointer 4 | stack pointer here ++ |--------------------------------------------|<+ <<< on entry to ++ | Saved r28-r31 4*4 | | ffi_call_SYSV ++ |--------------------------------------------| | ++ | GPR registers r3-r10 8*4 | | ffi_call_SYSV ++ |--------------------------------------------| | ++ | FPR registers f1-f8 (optional) 8*8 | | ++ |--------------------------------------------| | stack | ++ | Space for copied structures | | grows | ++ |--------------------------------------------| | down V ++ | Parameters that didn't fit in registers | | ++ |--------------------------------------------| | lower addresses ++ | Space for callee's LR 4 | | ++ |--------------------------------------------| | stack pointer here ++ | Current backchain pointer 4 |-/ during ++ |--------------------------------------------| <<< ffi_call_SYSV ++ ++*/ ++ ++void FFI_HIDDEN ++ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack) ++{ ++ const unsigned bytes = ecif->cif->bytes; ++ const unsigned flags = ecif->cif->flags; ++ ++ typedef union ++ { ++ char *c; ++ unsigned *u; ++ long long *ll; ++ float *f; ++ double *d; ++ } valp; ++ ++ /* 'stacktop' points at the previous backchain pointer. */ ++ valp stacktop; ++ ++ /* 'gpr_base' points at the space for gpr3, and grows upwards as ++ we use GPR registers. */ ++ valp gpr_base; ++ int intarg_count; ++ ++#ifndef __NO_FPRS__ ++ /* 'fpr_base' points at the space for fpr1, and grows upwards as ++ we use FPR registers. */ ++ valp fpr_base; ++ int fparg_count; ++#endif ++ ++ /* 'copy_space' grows down as we put structures in it. It should ++ stay 16-byte aligned. */ ++ valp copy_space; ++ ++ /* 'next_arg' grows up as we put parameters in it. */ ++ valp next_arg; ++ ++ int i; ++ ffi_type **ptr; ++#ifndef __NO_FPRS__ ++ double double_tmp; ++#endif ++ union ++ { ++ void **v; ++ char **c; ++ signed char **sc; ++ unsigned char **uc; ++ signed short **ss; ++ unsigned short **us; ++ unsigned int **ui; ++ long long **ll; ++ float **f; ++ double **d; ++ } p_argv; ++ size_t struct_copy_size; ++ unsigned gprvalue; ++ ++ stacktop.c = (char *) stack + bytes; ++ gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS; ++ intarg_count = 0; ++#ifndef __NO_FPRS__ ++ fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS; ++ fparg_count = 0; ++ copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c); ++#else ++ copy_space.c = gpr_base.c; ++#endif ++ next_arg.u = stack + 2; ++ ++ /* Check that everything starts aligned properly. */ ++ FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); ++ FFI_ASSERT (((unsigned long) copy_space.c & 0xF) == 0); ++ FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0); ++ FFI_ASSERT ((bytes & 0xF) == 0); ++ FFI_ASSERT (copy_space.c >= next_arg.c); ++ ++ /* Deal with return values that are actually pass-by-reference. */ ++ if (flags & FLAG_RETVAL_REFERENCE) ++ { ++ *gpr_base.u++ = (unsigned long) (char *) ecif->rvalue; ++ intarg_count++; ++ } ++ ++ /* Now for the arguments. */ ++ p_argv.v = ecif->avalue; ++ for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; ++ i > 0; ++ i--, ptr++, p_argv.v++) ++ { ++ unsigned int typenum = (*ptr)->type; ++ ++ typenum = translate_float (ecif->cif->abi, typenum); ++ ++ /* Now test the translated value */ ++ switch (typenum) ++ { ++#ifndef __NO_FPRS__ ++# if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ case FFI_TYPE_LONGDOUBLE: ++ double_tmp = (*p_argv.d)[0]; ++ ++ if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1) ++ { ++ if (intarg_count >= NUM_GPR_ARG_REGISTERS ++ && intarg_count % 2 != 0) ++ { ++ intarg_count++; ++ next_arg.u++; ++ } ++ *next_arg.d = double_tmp; ++ next_arg.u += 2; ++ double_tmp = (*p_argv.d)[1]; ++ *next_arg.d = double_tmp; ++ next_arg.u += 2; ++ } ++ else ++ { ++ *fpr_base.d++ = double_tmp; ++ double_tmp = (*p_argv.d)[1]; ++ *fpr_base.d++ = double_tmp; ++ } ++ ++ fparg_count += 2; ++ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); ++ break; ++# endif ++ case FFI_TYPE_DOUBLE: ++ double_tmp = **p_argv.d; ++ ++ if (fparg_count >= NUM_FPR_ARG_REGISTERS) ++ { ++ if (intarg_count >= NUM_GPR_ARG_REGISTERS ++ && intarg_count % 2 != 0) ++ { ++ intarg_count++; ++ next_arg.u++; ++ } ++ *next_arg.d = double_tmp; ++ next_arg.u += 2; ++ } ++ else ++ *fpr_base.d++ = double_tmp; ++ fparg_count++; ++ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); ++ break; ++ ++ case FFI_TYPE_FLOAT: ++ double_tmp = **p_argv.f; ++ if (fparg_count >= NUM_FPR_ARG_REGISTERS) ++ { ++ *next_arg.f = (float) double_tmp; ++ next_arg.u += 1; ++ intarg_count++; ++ } ++ else ++ *fpr_base.d++ = double_tmp; ++ fparg_count++; ++ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); ++ break; ++#endif /* have FPRs */ ++ ++ case FFI_TYPE_UINT128: ++ /* The soft float ABI for long doubles works like this, a long double ++ is passed in four consecutive GPRs if available. A maximum of 2 ++ long doubles can be passed in gprs. If we do not have 4 GPRs ++ left, the long double is passed on the stack, 4-byte aligned. */ ++ { ++ unsigned int int_tmp; ++ unsigned int ii; ++ if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3) ++ { ++ if (intarg_count < NUM_GPR_ARG_REGISTERS) ++ intarg_count = NUM_GPR_ARG_REGISTERS; ++ for (ii = 0; ii < 4; ii++) ++ { ++ int_tmp = (*p_argv.ui)[ii]; ++ *next_arg.u++ = int_tmp; ++ } ++ } ++ else ++ { ++ for (ii = 0; ii < 4; ii++) ++ { ++ int_tmp = (*p_argv.ui)[ii]; ++ *gpr_base.u++ = int_tmp; ++ } ++ } ++ intarg_count += 4; ++ break; ++ } ++ ++ case FFI_TYPE_UINT64: ++ case FFI_TYPE_SINT64: ++ if (intarg_count == NUM_GPR_ARG_REGISTERS-1) ++ intarg_count++; ++ if (intarg_count >= NUM_GPR_ARG_REGISTERS) ++ { ++ if (intarg_count % 2 != 0) ++ { ++ intarg_count++; ++ next_arg.u++; ++ } ++ *next_arg.ll = **p_argv.ll; ++ next_arg.u += 2; ++ } ++ else ++ { ++ /* The abi states only certain register pairs can be ++ used for passing long long int specifically (r3,r4), ++ (r5,r6), (r7,r8), (r9,r10). If next arg is long long ++ but not correct starting register of pair then skip ++ until the proper starting register. */ ++ if (intarg_count % 2 != 0) ++ { ++ intarg_count ++; ++ gpr_base.u++; ++ } ++ *gpr_base.ll++ = **p_argv.ll; ++ } ++ intarg_count += 2; ++ break; ++ ++ case FFI_TYPE_STRUCT: ++ struct_copy_size = ((*ptr)->size + 15) & ~0xF; ++ copy_space.c -= struct_copy_size; ++ memcpy (copy_space.c, *p_argv.c, (*ptr)->size); ++ ++ gprvalue = (unsigned long) copy_space.c; ++ ++ FFI_ASSERT (copy_space.c > next_arg.c); ++ FFI_ASSERT (flags & FLAG_ARG_NEEDS_COPY); ++ goto putgpr; ++ ++ case FFI_TYPE_UINT8: ++ gprvalue = **p_argv.uc; ++ goto putgpr; ++ case FFI_TYPE_SINT8: ++ gprvalue = **p_argv.sc; ++ goto putgpr; ++ case FFI_TYPE_UINT16: ++ gprvalue = **p_argv.us; ++ goto putgpr; ++ case FFI_TYPE_SINT16: ++ gprvalue = **p_argv.ss; ++ goto putgpr; ++ ++ case FFI_TYPE_INT: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_POINTER: ++ ++ gprvalue = **p_argv.ui; ++ ++ putgpr: ++ if (intarg_count >= NUM_GPR_ARG_REGISTERS) ++ *next_arg.u++ = gprvalue; ++ else ++ *gpr_base.u++ = gprvalue; ++ intarg_count++; ++ break; ++ } ++ } ++ ++ /* Check that we didn't overrun the stack... */ ++ FFI_ASSERT (copy_space.c >= next_arg.c); ++ FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS); ++ /* The assert below is testing that the number of integer arguments agrees ++ with the number found in ffi_prep_cif_machdep(). However, intarg_count ++ is incremented whenever we place an FP arg on the stack, so account for ++ that before our assert test. */ ++#ifndef __NO_FPRS__ ++ if (fparg_count > NUM_FPR_ARG_REGISTERS) ++ intarg_count -= fparg_count - NUM_FPR_ARG_REGISTERS; ++ FFI_ASSERT (fpr_base.u ++ <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); ++#endif ++ FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); ++} ++ ++#define MIN_CACHE_LINE_SIZE 8 ++ ++static void ++flush_icache (char *wraddr, char *xaddr, int size) ++{ ++ int i; ++ for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) ++ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" ++ : : "r" (xaddr + i), "r" (wraddr + i) : "memory"); ++ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;" ++ : : "r"(xaddr + size - 1), "r"(wraddr + size - 1) ++ : "memory"); ++} ++ ++ffi_status FFI_HIDDEN ++ffi_prep_closure_loc_sysv (ffi_closure *closure, ++ ffi_cif *cif, ++ void (*fun) (ffi_cif *, void *, void **, void *), ++ void *user_data, ++ void *codeloc) ++{ ++ unsigned int *tramp; ++ ++ if (cif->abi < FFI_SYSV || cif->abi >= FFI_LAST_ABI) ++ return FFI_BAD_ABI; ++ ++ tramp = (unsigned int *) &closure->tramp[0]; ++ tramp[0] = 0x7c0802a6; /* mflr r0 */ ++ tramp[1] = 0x4800000d; /* bl 10 */ ++ tramp[4] = 0x7d6802a6; /* mflr r11 */ ++ tramp[5] = 0x7c0803a6; /* mtlr r0 */ ++ tramp[6] = 0x800b0000; /* lwz r0,0(r11) */ ++ tramp[7] = 0x816b0004; /* lwz r11,4(r11) */ ++ tramp[8] = 0x7c0903a6; /* mtctr r0 */ ++ tramp[9] = 0x4e800420; /* bctr */ ++ *(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */ ++ *(void **) &tramp[3] = codeloc; /* context */ ++ ++ /* Flush the icache. */ ++ flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE); ++ ++ closure->cif = cif; ++ closure->fun = fun; ++ closure->user_data = user_data; ++ ++ return FFI_OK; ++} ++ ++/* Basically the trampoline invokes ffi_closure_SYSV, and on ++ entry, r11 holds the address of the closure. ++ After storing the registers that could possibly contain ++ parameters to be passed into the stack frame and setting ++ up space for a return value, ffi_closure_SYSV invokes the ++ following helper function to do most of the work. */ ++ ++int ++ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, ++ unsigned long *pgr, ffi_dblfl *pfr, ++ unsigned long *pst) ++{ ++ /* rvalue is the pointer to space for return value in closure assembly */ ++ /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */ ++ /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */ ++ /* pst is the pointer to outgoing parameter stack in original caller */ ++ ++ void ** avalue; ++ ffi_type ** arg_types; ++ long i, avn; ++#ifndef __NO_FPRS__ ++ long nf = 0; /* number of floating registers already used */ ++#endif ++ long ng = 0; /* number of general registers already used */ ++ ++ ffi_cif *cif = closure->cif; ++ unsigned size = cif->rtype->size; ++ unsigned short rtypenum = cif->rtype->type; ++ ++ avalue = alloca (cif->nargs * sizeof (void *)); ++ ++ /* First translate for softfloat/nonlinux */ ++ rtypenum = translate_float (cif->abi, rtypenum); ++ ++ /* Copy the caller's structure return value address so that the closure ++ returns the data directly to the caller. ++ For FFI_SYSV the result is passed in r3/r4 if the struct size is less ++ or equal 8 bytes. */ ++ if (rtypenum == FFI_TYPE_STRUCT ++ && !((cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8)) ++ { ++ rvalue = (void *) *pgr; ++ ng++; ++ pgr++; ++ } ++ ++ i = 0; ++ avn = cif->nargs; ++ arg_types = cif->arg_types; ++ ++ /* Grab the addresses of the arguments from the stack frame. */ ++ while (i < avn) { ++ unsigned short typenum = arg_types[i]->type; ++ ++ /* We may need to handle some values depending on ABI. */ ++ typenum = translate_float (cif->abi, typenum); ++ ++ switch (typenum) ++ { ++#ifndef __NO_FPRS__ ++ case FFI_TYPE_FLOAT: ++ /* Unfortunately float values are stored as doubles ++ in the ffi_closure_SYSV code (since we don't check ++ the type in that routine). */ ++ if (nf < NUM_FPR_ARG_REGISTERS) ++ { ++ /* FIXME? here we are really changing the values ++ stored in the original calling routines outgoing ++ parameter stack. This is probably a really ++ naughty thing to do but... */ ++ double temp = pfr->d; ++ pfr->f = (float) temp; ++ avalue[i] = pfr; ++ nf++; ++ pfr++; ++ } ++ else ++ { ++ avalue[i] = pst; ++ pst += 1; ++ } ++ break; ++ ++ case FFI_TYPE_DOUBLE: ++ if (nf < NUM_FPR_ARG_REGISTERS) ++ { ++ avalue[i] = pfr; ++ nf++; ++ pfr++; ++ } ++ else ++ { ++ if (((long) pst) & 4) ++ pst++; ++ avalue[i] = pst; ++ pst += 2; ++ } ++ break; ++ ++# if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++ case FFI_TYPE_LONGDOUBLE: ++ if (nf < NUM_FPR_ARG_REGISTERS - 1) ++ { ++ avalue[i] = pfr; ++ pfr += 2; ++ nf += 2; ++ } ++ else ++ { ++ if (((long) pst) & 4) ++ pst++; ++ avalue[i] = pst; ++ pst += 4; ++ nf = 8; ++ } ++ break; ++# endif ++#endif ++ ++ case FFI_TYPE_UINT128: ++ /* Test if for the whole long double, 4 gprs are available. ++ otherwise the stuff ends up on the stack. */ ++ if (ng < NUM_GPR_ARG_REGISTERS - 3) ++ { ++ avalue[i] = pgr; ++ pgr += 4; ++ ng += 4; ++ } ++ else ++ { ++ avalue[i] = pst; ++ pst += 4; ++ ng = 8+4; ++ } ++ break; ++ ++ case FFI_TYPE_SINT8: ++ case FFI_TYPE_UINT8: ++#ifndef __LITTLE_ENDIAN__ ++ if (ng < NUM_GPR_ARG_REGISTERS) ++ { ++ avalue[i] = (char *) pgr + 3; ++ ng++; ++ pgr++; ++ } ++ else ++ { ++ avalue[i] = (char *) pst + 3; ++ pst++; ++ } ++ break; ++#endif ++ ++ case FFI_TYPE_SINT16: ++ case FFI_TYPE_UINT16: ++#ifndef __LITTLE_ENDIAN__ ++ if (ng < NUM_GPR_ARG_REGISTERS) ++ { ++ avalue[i] = (char *) pgr + 2; ++ ng++; ++ pgr++; ++ } ++ else ++ { ++ avalue[i] = (char *) pst + 2; ++ pst++; ++ } ++ break; ++#endif ++ ++ case FFI_TYPE_SINT32: ++ case FFI_TYPE_UINT32: ++ case FFI_TYPE_POINTER: ++ if (ng < NUM_GPR_ARG_REGISTERS) ++ { ++ avalue[i] = pgr; ++ ng++; ++ pgr++; ++ } ++ else ++ { ++ avalue[i] = pst; ++ pst++; ++ } ++ break; ++ ++ case FFI_TYPE_STRUCT: ++ /* Structs are passed by reference. The address will appear in a ++ gpr if it is one of the first 8 arguments. */ ++ if (ng < NUM_GPR_ARG_REGISTERS) ++ { ++ avalue[i] = (void *) *pgr; ++ ng++; ++ pgr++; ++ } ++ else ++ { ++ avalue[i] = (void *) *pst; ++ pst++; ++ } ++ break; ++ ++ case FFI_TYPE_SINT64: ++ case FFI_TYPE_UINT64: ++ /* Passing long long ints are complex, they must ++ be passed in suitable register pairs such as ++ (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) ++ and if the entire pair aren't available then the outgoing ++ parameter stack is used for both but an alignment of 8 ++ must will be kept. So we must either look in pgr ++ or pst to find the correct address for this type ++ of parameter. */ ++ if (ng < NUM_GPR_ARG_REGISTERS - 1) ++ { ++ if (ng & 1) ++ { ++ /* skip r4, r6, r8 as starting points */ ++ ng++; ++ pgr++; ++ } ++ avalue[i] = pgr; ++ ng += 2; ++ pgr += 2; ++ } ++ else ++ { ++ if (((long) pst) & 4) ++ pst++; ++ avalue[i] = pst; ++ pst += 2; ++ ng = NUM_GPR_ARG_REGISTERS; ++ } ++ break; ++ ++ default: ++ FFI_ASSERT (0); ++ } ++ ++ i++; ++ } ++ ++ (closure->fun) (cif, rvalue, avalue, closure->user_data); ++ ++ /* Tell ffi_closure_SYSV how to perform return type promotions. ++ Because the FFI_SYSV ABI returns the structures <= 8 bytes in ++ r3/r4 we have to tell ffi_closure_SYSV how to treat them. We ++ combine the base type FFI_SYSV_TYPE_SMALL_STRUCT with the size of ++ the struct less one. We never have a struct with size zero. ++ See the comment in ffitarget.h about ordering. */ ++ if (rtypenum == FFI_TYPE_STRUCT ++ && (cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8) ++ return FFI_SYSV_TYPE_SMALL_STRUCT - 1 + size; ++ return rtypenum; ++} ++#endif +Index: libffi-3.0.13/src/powerpc/ffitarget.h +=================================================================== +--- libffi-3.0.13.orig/src/powerpc/ffitarget.h ++++ libffi-3.0.13/src/powerpc/ffitarget.h +@@ -60,45 +60,76 @@ typedef signed long ffi_sarg; + typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + +-#ifdef POWERPC +- FFI_SYSV, +- FFI_GCC_SYSV, +- FFI_LINUX64, +- FFI_LINUX, +- FFI_LINUX_SOFT_FLOAT, +-# if defined(POWERPC64) +- FFI_DEFAULT_ABI = FFI_LINUX64, +-# elif defined(__NO_FPRS__) +- FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT, +-# elif (__LDBL_MANT_DIG__ == 106) +- FFI_DEFAULT_ABI = FFI_LINUX, +-# else +- FFI_DEFAULT_ABI = FFI_GCC_SYSV, +-# endif +-#endif +- +-#ifdef POWERPC_AIX ++#if defined (POWERPC_AIX) + FFI_AIX, + FFI_DARWIN, + FFI_DEFAULT_ABI = FFI_AIX, +-#endif ++ FFI_LAST_ABI + +-#ifdef POWERPC_DARWIN ++#elif defined (POWERPC_DARWIN) + FFI_AIX, + FFI_DARWIN, + FFI_DEFAULT_ABI = FFI_DARWIN, +-#endif ++ FFI_LAST_ABI ++ ++#else ++ /* The FFI_COMPAT values are used by old code. Since libffi may be ++ a shared library we have to support old values for backwards ++ compatibility. */ ++ FFI_COMPAT_SYSV, ++ FFI_COMPAT_GCC_SYSV, ++ FFI_COMPAT_LINUX64, ++ FFI_COMPAT_LINUX, ++ FFI_COMPAT_LINUX_SOFT_FLOAT, ++ ++# if defined (POWERPC64) ++ /* This bit, always set in new code, must not be set in any of the ++ old FFI_COMPAT values that might be used for 64-bit linux. We ++ only need worry about FFI_COMPAT_LINUX64, but to be safe avoid ++ all old values. */ ++ FFI_LINUX = 8, ++ /* This and following bits can reuse FFI_COMPAT values. */ ++ FFI_LINUX_STRUCT_ALIGN = 1, ++ FFI_LINUX_LONG_DOUBLE_128 = 2, ++ FFI_DEFAULT_ABI = (FFI_LINUX ++# ifdef __STRUCT_PARM_ALIGN__ ++ | FFI_LINUX_STRUCT_ALIGN ++# endif ++# ifdef __LONG_DOUBLE_128__ ++ | FFI_LINUX_LONG_DOUBLE_128 ++# endif ++ ), ++ FFI_LAST_ABI = 12 + +-#ifdef POWERPC_FREEBSD +- FFI_SYSV, +- FFI_GCC_SYSV, +- FFI_LINUX64, +- FFI_LINUX, +- FFI_LINUX_SOFT_FLOAT, +- FFI_DEFAULT_ABI = FFI_SYSV, ++# else ++ /* This bit, always set in new code, must not be set in any of the ++ old FFI_COMPAT values that might be used for 32-bit linux/sysv/bsd. */ ++ FFI_SYSV = 8, ++ /* This and following bits can reuse FFI_COMPAT values. */ ++ FFI_SYSV_SOFT_FLOAT = 1, ++ FFI_SYSV_STRUCT_RET = 2, ++ FFI_SYSV_IBM_LONG_DOUBLE = 4, ++ FFI_SYSV_LONG_DOUBLE_128 = 16, ++ ++ FFI_DEFAULT_ABI = (FFI_SYSV ++# ifdef __NO_FPRS__ ++ | FFI_SYSV_SOFT_FLOAT ++# endif ++# if (defined (__SVR4_STRUCT_RETURN) \ ++ || defined (POWERPC_FREEBSD) && !defined (__AIX_STRUCT_RETURN)) ++ | FFI_SYSV_STRUCT_RET ++# endif ++# if __LDBL_MANT_DIG__ == 106 ++ | FFI_SYSV_IBM_LONG_DOUBLE ++# endif ++# ifdef __LONG_DOUBLE_128__ ++ | FFI_SYSV_LONG_DOUBLE_128 ++# endif ++ ), ++ FFI_LAST_ABI = 32 ++# endif + #endif + +- FFI_LAST_ABI + } ffi_abi; + #endif + +@@ -117,9 +148,7 @@ typedef enum ffi_abi { + /* Needed for soft-float long-double-128 support. */ + #define FFI_TYPE_UINT128 (FFI_TYPE_LAST + 1) + +-/* Needed for FFI_SYSV small structure returns. +- We use two flag bits, (FLAG_SYSV_SMST_R3, FLAG_SYSV_SMST_R4) which are +- defined in ffi.c, to determine the exact return type and its size. */ ++/* Needed for FFI_SYSV small structure returns. */ + #define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2) + + /* Used by ELFv2 for homogenous structure returns. */ +Index: libffi-3.0.13/src/powerpc/linux64.S +=================================================================== +--- libffi-3.0.13.orig/src/powerpc/linux64.S ++++ libffi-3.0.13/src/powerpc/linux64.S +@@ -29,7 +29,7 @@ + #include + #include + +-#ifdef __powerpc64__ ++#ifdef POWERPC64 + .hidden ffi_call_LINUX64 + .globl ffi_call_LINUX64 + # if _CALL_ELF == 2 +Index: libffi-3.0.13/src/powerpc/linux64_closure.S +=================================================================== +--- libffi-3.0.13.orig/src/powerpc/linux64_closure.S ++++ libffi-3.0.13/src/powerpc/linux64_closure.S +@@ -30,7 +30,7 @@ + + .file "linux64_closure.S" + +-#ifdef __powerpc64__ ++#ifdef POWERPC64 + FFI_HIDDEN (ffi_closure_LINUX64) + .globl ffi_closure_LINUX64 + # if _CALL_ELF == 2 +Index: libffi-3.0.13/src/powerpc/ppc_closure.S +=================================================================== +--- libffi-3.0.13.orig/src/powerpc/ppc_closure.S ++++ libffi-3.0.13/src/powerpc/ppc_closure.S +@@ -31,7 +31,7 @@ + + .file "ppc_closure.S" + +-#ifndef __powerpc64__ ++#ifndef POWERPC64 + + ENTRY(ffi_closure_SYSV) + .LFB1: +@@ -378,8 +378,7 @@ END(ffi_closure_SYSV) + .align 2 + .LEFDE1: + +-#endif +- + #if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits + #endif ++#endif +Index: libffi-3.0.13/src/powerpc/sysv.S +=================================================================== +--- libffi-3.0.13.orig/src/powerpc/sysv.S ++++ libffi-3.0.13/src/powerpc/sysv.S +@@ -30,7 +30,7 @@ + #include + #include + +-#ifndef __powerpc64__ ++#ifndef POWERPC64 + .globl ffi_prep_args_SYSV + ENTRY(ffi_call_SYSV) + .LFB1: +@@ -213,8 +213,8 @@ END(ffi_call_SYSV) + .uleb128 0x1c + .align 2 + .LEFDE1: +-#endif + + #if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits + #endif ++#endif +Index: libffi-3.0.13/src/prep_cif.c +=================================================================== +--- libffi-3.0.13.orig/src/prep_cif.c ++++ libffi-3.0.13/src/prep_cif.c +@@ -126,6 +126,10 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core( + + cif->flags = 0; + ++#if HAVE_LONG_DOUBLE_VARIANT ++ ffi_prep_types (abi); ++#endif ++ + /* Initialize the return type if necessary */ + if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) + return FFI_BAD_TYPEDEF; +Index: libffi-3.0.13/src/types.c +=================================================================== +--- libffi-3.0.13.orig/src/types.c ++++ libffi-3.0.13/src/types.c +@@ -44,6 +44,17 @@ const ffi_type ffi_type_##name = { \ + id, NULL \ + } + ++#define FFI_NONCONST_TYPEDEF(name, type, id) \ ++struct struct_align_##name { \ ++ char c; \ ++ type x; \ ++}; \ ++ffi_type ffi_type_##name = { \ ++ sizeof(type), \ ++ offsetof(struct struct_align_##name, x), \ ++ id, NULL \ ++} ++ + /* Size and alignment are fake here. They must not be 0. */ + const ffi_type ffi_type_void = { + 1, 1, FFI_TYPE_VOID, NULL +@@ -73,5 +84,9 @@ FFI_TYPEDEF(double, double, FFI_TYPE_DOU + # endif + const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL }; + #elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE ++# if HAVE_LONG_DOUBLE_VARIANT ++FFI_NONCONST_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE); ++# else + FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE); ++# endif + #endif diff --git a/SOURCES/libffi-aarch64-rhbz1174037.patch b/SOURCES/libffi-aarch64-rhbz1174037.patch new file mode 100644 index 00000000..dbf63080 --- /dev/null +++ b/SOURCES/libffi-aarch64-rhbz1174037.patch @@ -0,0 +1,11 @@ +--- libffi-3.1/src/aarch64/ffi.c.orig 2014-04-25 18:45:13.000000000 +0100 ++++ libffi-3.1/src/aarch64/ffi.c 2015-01-15 02:36:56.314906455 +0000 +@@ -728,7 +728,7 @@ + state.ngrn = N_X_ARG_REG; + + memcpy (allocate_to_stack (&state, stack, ty->alignment, +- ty->size), ecif->avalue + i, ty->size); ++ ty->size), ecif->avalue[i], ty->size); + } + break; + diff --git a/SOURCES/libffi-fix-ppc-tests.patch b/SOURCES/libffi-fix-ppc-tests.patch new file mode 100644 index 00000000..5c05c6f2 --- /dev/null +++ b/SOURCES/libffi-fix-ppc-tests.patch @@ -0,0 +1,60 @@ +diff --git a/testsuite/libffi.call/cls_struct_va1.c b/testsuite/libffi.call/cls_struct_va1.c +index 175ed96..6d1fdae 100644 +--- a/testsuite/libffi.call/cls_struct_va1.c ++++ b/testsuite/libffi.call/cls_struct_va1.c +@@ -35,7 +35,7 @@ test_fn (ffi_cif* cif __UNUSED__, void* resp, + printf ("%d %d %d %d %d %d %d %d %d %d\n", n, s1.a, s1.b, + l1.a, l1.b, l1.c, l1.d, l1.e, + s2.a, s2.b); +- * (int*) resp = 42; ++ * (ffi_arg*) resp = 42; + } + + int +diff --git a/testsuite/libffi.call/cls_uint_va.c b/testsuite/libffi.call/cls_uint_va.c +index 150fddd..548d8c6 100644 +--- a/testsuite/libffi.call/cls_uint_va.c ++++ b/testsuite/libffi.call/cls_uint_va.c +@@ -10,12 +10,13 @@ + + typedef unsigned int T; + +-static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, ++static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void *resp, void** args, + void* userdata __UNUSED__) + { +- *(T *)resp = *(T *)args[0]; ++ *(ffi_arg*)resp = *(T *)args[0]; + +- printf("%d: %d %d\n", *(T *)resp, *(T *)args[0], *(T *)args[1]); ++ ++ printf("%d: %d %d\n", (int)*(ffi_arg *)resp, *(T *)args[0], *(T *)args[1]); + } + + typedef T (*cls_ret_T)(T, ...); +diff --git a/testsuite/libffi.call/va_1.c b/testsuite/libffi.call/va_1.c +index cf4dd85..7f96809 100644 +--- a/testsuite/libffi.call/va_1.c ++++ b/testsuite/libffi.call/va_1.c +@@ -94,7 +94,7 @@ main (void) + struct large_tag l1; + + int n; +- int res; ++ ffi_arg res; + + unsigned char uc; + signed char sc; +diff --git a/testsuite/libffi.call/va_struct1.c b/testsuite/libffi.call/va_struct1.c +index 11d1f10..e645206 100644 +--- a/testsuite/libffi.call/va_struct1.c ++++ b/testsuite/libffi.call/va_struct1.c +@@ -61,7 +61,7 @@ main (void) + struct large_tag l1; + + int n; +- int res; ++ ffi_arg res; + + s_type.size = 0; + s_type.alignment = 0; diff --git a/SPECS/libffi.spec b/SPECS/libffi.spec new file mode 100644 index 00000000..7f2919bf --- /dev/null +++ b/SPECS/libffi.spec @@ -0,0 +1,278 @@ +%global multilib_arches %{ix86} ppc ppc64 s390 s390x x86_64 + +Name: libffi +Version: 3.0.13 +Release: 18%{?dist} +Summary: A portable foreign function interface library + +Group: System Environment/Libraries +License: MIT and Public Domain +URL: http://sourceware.org/libffi +Source0: ftp://sourceware.org/pub/libffi/libffi-%{version}.tar.gz +# part of upstream commit 5feacad4 +Source1: ffi-multilib.h +Source2: ffitarget-multilib.h +Patch0: libffi-3.0.13-fix-include-path.patch +Patch1: libffi-fix-ppc-tests.patch +# part of upstream commit 5feacad4 +Patch10: libffi-3.0.13-ppc64le-0.patch +Patch11: libffi-3.0.13-ppc64le-1.patch +Patch12: libffi-3.0.13-ppc64le-2.patch +Patch13: libffi-3.0.13-ppc64le-3.patch +# rhbz 1287815: +Patch20: libffi-aarch64-rhbz1174037.patch + +Patch21: libffi-3.0.13-closures-Create-temporary-file-with-O_TMPFILE-and-O_.patch +%ifarch ppc64le +BuildRequires: autoconf automake libtool texinfo +%endif +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +%description +Compilers for high level languages generate code that follow certain +conventions. These conventions are necessary, in part, for separate +compilation to work. One such convention is the "calling convention". +The calling convention is a set of assumptions made by the compiler +about where function arguments will be found on entry to a function. A +calling convention also specifies where the return value for a function +is found. + +Some programs may not know at the time of compilation what arguments +are to be passed to a function. For instance, an interpreter may be +told at run-time about the number and types of arguments used to call a +given function. `Libffi' can be used in such programs to provide a +bridge from the interpreter program to compiled code. + +The `libffi' library provides a portable, high level programming +interface to various calling conventions. This allows a programmer to +call any function specified by a call interface description at run time. + +FFI stands for Foreign Function Interface. A foreign function +interface is the popular name for the interface that allows code +written in one language to call code written in another language. The +`libffi' library really only provides the lowest, machine dependent +layer of a fully featured foreign function interface. A layer must +exist above `libffi' that handles type conversions for values passed +between the two languages. + + +%package devel +Summary: Development files for %{name} +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Requires: pkgconfig +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + + +%prep +%setup -q +%patch0 -p1 -b .fixpath +%patch1 -p1 -b .fixpath +%ifarch ppc64le +%patch10 -p1 -b .ppc64le-0 +%patch11 -p1 -b .ppc64le-1 +%patch12 -p1 -b .ppc64le-2 +%patch13 -p1 -b .ppc64le-3 + +autoreconf -vif +%endif + +%patch20 -p1 -b .aarch64 +%patch21 -p1 -b .tmpfile +%build +CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" %configure --disable-static +make %{?_smp_mflags} + + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT +find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' +rm -f $RPM_BUILD_ROOT%{_infodir}/dir + +# Determine generic arch target name for multilib wrapper +basearch=%{_arch} +%ifarch %{ix86} +basearch=i386 +%endif + +%ifarch %{multilib_arches} +# Do header file switcheroo to avoid file conflicts on systems where you +# can have both a 32- and 64-bit version of the library, and they each need +# their own correct-but-different versions of the headers to be usable. +for i in ffi ffitarget; do + mv $RPM_BUILD_ROOT%{_includedir}/$i.h $RPM_BUILD_ROOT%{_includedir}/$i-${basearch}.h +done +install -m644 %{SOURCE1} $RPM_BUILD_ROOT%{_includedir}/ffi.h +install -m644 %{SOURCE2} $RPM_BUILD_ROOT%{_includedir}/ffitarget.h +%endif + + +%clean +rm -rf $RPM_BUILD_ROOT + + +%post -p /sbin/ldconfig + +%post devel +/sbin/install-info --info-dir=%{_infodir} %{_infodir}/libffi.info.gz + +%preun devel +if [ $1 = 0 ] ;then + /sbin/install-info --delete --info-dir=%{_infodir} %{_infodir}/libffi.info.gz +fi + +%postun -p /sbin/ldconfig + + +%files +%defattr(-,root,root,-) +%doc LICENSE README +%{_libdir}/*.so.* + +%files devel +%defattr(-,root,root,-) +%{_libdir}/pkgconfig/*.pc +%{_includedir}/ffi*.h +%{_libdir}/*.so +%{_mandir}/man3/*.gz +%{_infodir}/libffi.info.gz + +%changelog +* Tue Apr 5 2016 Andrew Haley - 3.0.13-18 +- closures: Create temporary file with O_TMPFILE and O_CLOEXEC +- Resolves: RHBZ1151568 + +* Tue Apr 5 2016 Andrew Haley - 3.0.13-17 +- libffi needs fix for structures not passed in registers +- Resolves: RHBZ1287815 + +* Tue Sep 02 2014 Dan Horák - 3.0.13-16 +- Drop ppc64le from the multilib list +- Use additional BR: only in ppc64le build +- Resolves: RHBZ1116945 + +* Tue Aug 26 2014 Andrew Haley - 3.0.13-15 +- Add requires for libtool and texinfo +- Resolves: RHBZ1116945 + +* Tue Aug 26 2014 Andrew Haley - 3.0.13-14 +- Add requires for automake +- Resolves: RHBZ1116945 + +* Tue Aug 26 2014 Andrew Haley - 3.0.13-13 +- Add requires for autoconf +- Resolves: RHBZ1116945 + +* Tue Aug 26 2014 Andrew Haley - 3.0.13-12 +- Merge from private-rhel-7.0-ppc64le branch +- Resolves: RHBZ1116945 + +* Fri Jan 24 2014 Daniel Mach - 3.0.13-11 +- Mass rebuild 2014-01-24 + +* Fri Dec 27 2013 Daniel Mach - 3.0.13-10 +- Mass rebuild 2013-12-27 + +* Wed Dec 18 2013 Deepak Bhole - 3.0.13-9 +- Added -fno-strict-aliasing (pointed out by rpmdiff) +- Fixes RHBZ 1006261 + +* Fri Nov 15 2013 Jon VanAlten - 3.0.13-8 +- Patch test suite to fix errors on ppc64 +- Fixes RHBZ 1006261 + +* Thu Aug 22 2013 Deepak Bhole - 3.0.13-7 +- Removed temporarily introduced compat package for OpenJDk6 bootstrap + +* Wed Aug 21 2013 Deepak Bhole - 3.0.13-6 +- Temporarily build with a .so.5 compat package to allow OpenJDK6 bootstrap + +* Mon Jul 15 2013 Jon VanAlten - 3.0.13-5 +- Correct spec license + +* Tue May 28 2013 Tom Callaway - 3.0.13-4 +- fix typos in wrapper headers + +* Mon May 27 2013 Tom Callaway - 3.0.13-3 +- make header files multilib safe + +* Sat May 25 2013 Tom Callaway - 3.0.13-2 +- fix incorrect header pathing (and .pc file) + +* Wed Mar 20 2013 Anthony Green - 3.0.13-1 +- update to 3.0.13 + +* Thu Feb 14 2013 Fedora Release Engineering - 3.0.11-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Mon Jan 14 2013 Dennis Gilmore - 3.0.11-1 +- update to 3.0.11 + +* Fri Nov 02 2012 Deepak Bhole - 3.0.10-4 +- Fixed source location + +* Fri Aug 10 2012 Dennis Gilmore - 3.0.10-3 +- drop back to 3.0.10, 3.0.11 was never pushed anywhere as the soname bump broke buildroots +- as 3.0.11 never went out no epoch needed. + +* Thu Jul 19 2012 Fedora Release Engineering - 3.0.11-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Fri Apr 13 2012 Anthony Green - 3.0.11-1 +- Upgrade to 3.0.11. + +* Fri Jan 13 2012 Fedora Release Engineering - 3.0.10-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Aug 23 2011 Anthony Green - 3.0.10-1 +- Upgrade to 3.0.10. + +* Fri Mar 18 2011 Dan Horák - 3.0.9-3 +- added patch for being careful when defining relatively generic symbols + +* Mon Feb 07 2011 Fedora Release Engineering - 3.0.9-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Dec 29 2009 Anthony Green - 3.0.9-1 +- Upgrade + +* Fri Jul 24 2009 Fedora Release Engineering - 3.0.5-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Wed Feb 25 2009 Fedora Release Engineering - 3.0.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Tue Jul 08 2008 Anthony Green 3.0.5-1 +- Upgrade to 3.0.5 + +* Fri Feb 15 2008 Anthony Green 3.0.1-1 +- Upgrade to 3.0.1 + +* Fri Feb 15 2008 Anthony Green 2.99.9-1 +- Upgrade to 2.99.9 +- Require pkgconfig for the devel package. +- Update summary. + +* Fri Feb 15 2008 Anthony Green 2.99.8-1 +- Upgrade to 2.99.8 + +* Thu Feb 14 2008 Anthony Green 2.99.7-1 +- Upgrade to 2.99.7 + +* Thu Feb 14 2008 Anthony Green 2.99.6-1 +- Upgrade to 2.99.6 + +* Thu Feb 14 2008 Anthony Green 2.99.4-1 +- Upgrade to 2.99.4 + +* Thu Feb 14 2008 Anthony Green 2.99.3-1 +- Upgrade to 2.99.3 + +* Thu Feb 14 2008 Anthony Green 2.99.2-1 +- Created.