aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rwxr-xr-xconfigure5
-rw-r--r--configure.in5
-rw-r--r--libffi/ChangeLog39
-rw-r--r--libffi/Makefile.am3
-rw-r--r--libffi/Makefile.in9
-rwxr-xr-xlibffi/configure2
-rw-r--r--libffi/configure.in2
-rw-r--r--libffi/include/ffi.h.in15
-rw-r--r--libffi/src/ffitest.c36
-rw-r--r--libffi/src/powerpc/ffi.c597
-rw-r--r--libffi/src/powerpc/linux64.S185
-rw-r--r--libffi/src/powerpc/linux64_closure.S210
-rw-r--r--libffi/src/powerpc/ppc_closure.S4
-rw-r--r--libffi/src/powerpc/sysv.S8
15 files changed, 997 insertions, 128 deletions
diff --git a/ChangeLog b/ChangeLog
index 4b26025899a..94dc6317f72 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2003-04-18 Jakub Jelinek <jakub@redhat.com>
+
+ * configure.in (powerpc64*-*-linux*): Remove.
+ * configure: Rebuilt.
+
2003-04-17 Phil Edwards <pme@gcc.gnu.org>
* Makefile.tpl (GCC_STRAP_TARGETS): New variable containing all the
diff --git a/configure b/configure
index 8b10e661505..045ad147f73 100755
--- a/configure
+++ b/configure
@@ -1267,11 +1267,6 @@ case "${target}" in
powerpc-*-eabi)
noconfigdirs="$noconfigdirs ${libgcj}"
;;
- powerpc64*-*-linux*)
- noconfigdirs="$noconfigdirs target-newlib target-libgloss"
- # not yet ported.
- noconfigdirs="$noconfigdirs target-libffi"
- ;;
rs6000-*-lynxos*)
noconfigdirs="$noconfigdirs target-newlib gprof ${libgcj}"
;;
diff --git a/configure.in b/configure.in
index b4e8099cbb0..f695982d796 100644
--- a/configure.in
+++ b/configure.in
@@ -607,11 +607,6 @@ case "${target}" in
powerpc-*-eabi)
noconfigdirs="$noconfigdirs ${libgcj}"
;;
- powerpc64*-*-linux*)
- noconfigdirs="$noconfigdirs target-newlib target-libgloss"
- # not yet ported.
- noconfigdirs="$noconfigdirs target-libffi"
- ;;
rs6000-*-lynxos*)
noconfigdirs="$noconfigdirs target-newlib gprof ${libgcj}"
;;
diff --git a/libffi/ChangeLog b/libffi/ChangeLog
index 93b171acbaf..e07b07fead6 100644
--- a/libffi/ChangeLog
+++ b/libffi/ChangeLog
@@ -1,3 +1,42 @@
+2003-04-18 Jakub Jelinek <jakub@redhat.com>
+
+ * include/ffi.h.in (POWERPC64): Define if 64-bit.
+ (enum ffi_abi): Add FFI_LINUX64 on POWERPC.
+ Make it the default on POWERPC64.
+ (FFI_TRAMPOLINE_SIZE): Define to 24 on POWERPC64.
+ * configure.in: Change powerpc-*-linux* into powerpc*-*-linux*.
+ * configure: Rebuilt.
+ * src/powerpc/ffi.c (hidden): Define.
+ (ffi_prep_args_SYSV): Renamed from
+ ffi_prep_args. Cast pointers to unsigned long to shut up warnings.
+ (NUM_GPR_ARG_REGISTERS64, NUM_FPR_ARG_REGISTERS64,
+ ASM_NEEDS_REGISTERS64): New.
+ (ffi_prep_args64): New function.
+ (ffi_prep_cif_machdep): Handle FFI_LINUX64 ABI.
+ (ffi_call): Likewise.
+ (ffi_prep_closure): Likewise.
+ (flush_icache): Surround by #ifndef POWERPC64.
+ (ffi_dblfl): New union type.
+ (ffi_closure_helper_SYSV): Use it to avoid aliasing problems.
+ (ffi_closure_helper_LINUX64): New function.
+ * src/powerpc/ppc_closure.S: Surround whole file by #ifndef
+ __powerpc64__.
+ * src/powerpc/sysv.S: Likewise.
+ (ffi_call_SYSV): Rename ffi_prep_args to ffi_prep_args_SYSV.
+ * src/powerpc/linux64.S: New file.
+ * src/powerpc/linux64_closure.S: New file.
+ * Makefile.am (EXTRA_DIST): Add src/powerpc/linux64.S and
+ src/powerpc/linux64_closure.S.
+ (TARGET_SRC_POWERPC): Likewise.
+
+ * src/ffitest.c (closure_test_fn, closure_test_fn1, closure_test_fn2,
+ closure_test_fn3): Fix result printing on big-endian 64-bit
+ machines.
+ (main): Print tst2_arg instead of uninitialized tst2_result.
+
+ * src/ffitest.c (main): Hide what closure pointer really points to
+ from the compiler.
+
2003-04-16 Richard Earnshaw <rearnsha@arm.com>
* configure.in (arm-*-netbsdelf*): Add configuration.
diff --git a/libffi/Makefile.am b/libffi/Makefile.am
index 33c365c2985..82381b8f242 100644
--- a/libffi/Makefile.am
+++ b/libffi/Makefile.am
@@ -12,6 +12,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
src/alpha/ffi.c src/alpha/osf.S \
src/m68k/ffi.c src/m68k/sysv.S \
src/powerpc/ffi.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/ffi_darwin.c \
src/powerpc/darwin.S src/powerpc/aix.S \
@@ -94,7 +95,7 @@ TARGET_SRC_SPARC = src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S
TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S
TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S
TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
-TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
+TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S
TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
TARGET_SRC_ARM = src/arm/sysv.S src/arm/ffi.c
diff --git a/libffi/Makefile.in b/libffi/Makefile.in
index 6f89e0a0bd5..08d8c73ada4 100644
--- a/libffi/Makefile.in
+++ b/libffi/Makefile.in
@@ -95,6 +95,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
src/alpha/ffi.c src/alpha/osf.S \
src/m68k/ffi.c src/m68k/sysv.S \
src/powerpc/ffi.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/ffi_darwin.c \
src/powerpc/darwin.S src/powerpc/aix.S \
@@ -173,7 +174,7 @@ TARGET_SRC_SPARC = src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S
TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S
TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S
TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
-TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
+TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S
TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
TARGET_SRC_ARM = src/arm/sysv.S src/arm/ffi.c
@@ -257,7 +258,8 @@ libffi_convenience_la_LIBADD =
@POWERPC_TRUE@libffi_convenience_la_OBJECTS = src/debug.lo \
@POWERPC_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \
@POWERPC_TRUE@src/java_raw_api.lo src/powerpc/ffi.lo \
-@POWERPC_TRUE@src/powerpc/sysv.lo src/powerpc/ppc_closure.lo
+@POWERPC_TRUE@src/powerpc/sysv.lo src/powerpc/ppc_closure.lo \
+@POWERPC_TRUE@src/powerpc/linux64.lo src/powerpc/linux64_closure.lo
@MIPS_LINUX_TRUE@libffi_convenience_la_OBJECTS = src/debug.lo \
@MIPS_LINUX_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \
@MIPS_LINUX_TRUE@src/java_raw_api.lo src/mips/ffi.lo src/mips/o32.lo
@@ -301,7 +303,8 @@ libffi_la_LIBADD =
@POWERPC_TRUE@libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo \
@POWERPC_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
@POWERPC_TRUE@src/powerpc/ffi.lo src/powerpc/sysv.lo \
-@POWERPC_TRUE@src/powerpc/ppc_closure.lo
+@POWERPC_TRUE@src/powerpc/ppc_closure.lo src/powerpc/linux64.lo \
+@POWERPC_TRUE@src/powerpc/linux64_closure.lo
@MIPS_LINUX_TRUE@libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo \
@MIPS_LINUX_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
@MIPS_LINUX_TRUE@src/mips/ffi.lo src/mips/o32.lo
diff --git a/libffi/configure b/libffi/configure
index 42ff71cffc4..6197a44a8cd 100755
--- a/libffi/configure
+++ b/libffi/configure
@@ -2469,7 +2469,7 @@ ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;;
m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;;
mips64*-*);;
mips*-*-linux*) TARGET=MIPS_LINUX; TARGETDIR=mips;;
-powerpc-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
+powerpc*-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;;
powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;;
powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
diff --git a/libffi/configure.in b/libffi/configure.in
index e6606f961a5..7bb01d68ca0 100644
--- a/libffi/configure.in
+++ b/libffi/configure.in
@@ -64,7 +64,7 @@ ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;;
m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;;
mips64*-*);;
mips*-*-linux*) TARGET=MIPS_LINUX; TARGETDIR=mips;;
-powerpc-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
+powerpc*-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;;
powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;;
powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in
index fe91ecd5e2e..c51a809ea3f 100644
--- a/libffi/include/ffi.h.in
+++ b/libffi/include/ffi.h.in
@@ -158,6 +158,12 @@ extern "C" {
#define SIZEOF_ARG SIZEOF_VOID_P
#endif
+#ifdef POWERPC
+#if defined (__powerpc64__)
+#define POWERPC64
+#endif
+#endif
+
#ifdef SPARC
#if defined(__arch64__) || defined(__sparcv9)
#define SPARC64
@@ -250,7 +256,12 @@ typedef enum ffi_abi {
#ifdef POWERPC
FFI_SYSV,
FFI_GCC_SYSV,
+ FFI_LINUX64,
+# ifdef POWERPC64
+ FFI_DEFAULT_ABI = FFI_LINUX64,
+# else
FFI_DEFAULT_ABI = FFI_GCC_SYSV,
+# endif
#endif
#ifdef POWERPC_AIX
@@ -435,7 +446,11 @@ struct ffi_ia64_trampoline_struct {
#elif defined(POWERPC)
#define FFI_CLOSURES 1
+#ifdef POWERPC64
+#define FFI_TRAMPOLINE_SIZE 24
+#else
#define FFI_TRAMPOLINE_SIZE 40
+#endif
#define FFI_NATIVE_RAW_API 0
#elif defined(POWERPC_DARWIN)
diff --git a/libffi/src/ffitest.c b/libffi/src/ffitest.c
index a05b746865d..223b49c6dd8 100644
--- a/libffi/src/ffitest.c
+++ b/libffi/src/ffitest.c
@@ -309,7 +309,7 @@ closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
(int)(*(int *)args[10]), (int)(*(float *)args[11]),
(int)*(int *)args[12], (int)(*(int *)args[13]),
(int)(*(int *)args[14]),*(int *)args[15],
- (int)(long)userdata, *(int*)resp);
+ (int)(long)userdata, (int)*(ffi_arg *)resp);
}
typedef int (*closure_test_type)(unsigned long long, int, unsigned long long,
@@ -339,7 +339,7 @@ static void closure_test_fn1(ffi_cif* cif,void* resp,void** args,
(int)(*(int *)args[10]), (int)(*(float *)args[11]),
(int)*(int *)args[12], (int)(*(int *)args[13]),
(int)(*(int *)args[14]), *(int *)args[15],
- (int)(long)userdata, *(int*)resp);
+ (int)(long)userdata, (int)*(ffi_arg *)resp);
}
typedef int (*closure_test_type1)(float, float, float, float, signed short,
@@ -368,7 +368,7 @@ static void closure_test_fn2(ffi_cif* cif,void* resp,void** args,
(int)(*(int *)args[10]), (int)(*(float *)args[11]),
(int)*(int *)args[12], (int)(*(float *)args[13]),
(int)(*(int *)args[14]), *(int *)args[15], (int)(long)userdata,
- *(int*)resp);
+ (int)*(ffi_arg *)resp);
}
typedef int (*closure_test_type2)(double, double, double, double, signed short,
@@ -397,7 +397,7 @@ static void closure_test_fn3(ffi_cif* cif,void* resp,void** args,
(int)(*(float *)args[10]), (int)(*(float *)args[11]),
(int)*(int *)args[12], (int)(*(float *)args[13]),
(int)(*(float *)args[14]), *(int *)args[15], (int)(long)userdata,
- *(int*)resp);
+ (int)*(ffi_arg *)resp);
}
typedef int (*closure_test_type3)(float, float, float, float, float, float,
@@ -430,6 +430,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
/* The closure must not be an automatic variable on
platforms (Solaris) that forbid stack execution by default. */
static ffi_closure cl;
+ ffi_closure *pcl = &cl;
#endif
ffi_type * cl_arg_types[17];
@@ -841,8 +842,8 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
ts2_arg.d1 = 5.55;
ts2_arg.d2 = 6.66;
- printf ("%g\n", ts2_result->d1);
- printf ("%g\n", ts2_result->d2);
+ printf ("%g\n", ts2_arg.d1);
+ printf ("%g\n", ts2_arg.d2);
ffi_call(&cif, FFI_FN(struct2), ts2_result, values);
@@ -1161,6 +1162,13 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
#endif /* X86_WIN32 */
# if FFI_CLOSURES
+# if __GNUC__ >= 2
+ /* Hide before the compiler that pcl is &cl, since on
+ some architectures it is not possible to call a data
+ object using direct function call. */
+ asm ("" : "=g" (pcl) : "0" (pcl));
+# endif
+
/* A simple closure test */
{
(void) puts("\nEnter FFI_CLOSURES\n");
@@ -1187,10 +1195,10 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
&ffi_type_sint, cl_arg_types) == FFI_OK);
- CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn,
+ CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn,
(void *) 3 /* userdata */) == FFI_OK);
- CHECK((*((closure_test_type)(&cl)))
+ CHECK((*((closure_test_type)pcl))
(1LL, 2, 3LL, 4, 127, 429LL, 7, 8, 9.5, 10, 11, 12, 13,
19, 21, 1) == 680);
}
@@ -1219,10 +1227,10 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
&ffi_type_sint, cl_arg_types) == FFI_OK);
- CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn1,
+ CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn1,
(void *) 3 /* userdata */) == FFI_OK);
- CHECK((*((closure_test_type1)(&cl)))
+ CHECK((*((closure_test_type1)pcl))
(1.1, 2.2, 3.3, 4.4, 127, 5.5, 6.6, 8, 9, 10, 11, 12.0, 13,
19, 21, 1) == 255);
}
@@ -1251,10 +1259,10 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
&ffi_type_sint, cl_arg_types) == FFI_OK);
- CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn2,
+ CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn2,
(void *) 3 /* userdata */) == FFI_OK);
- CHECK((*((closure_test_type2)(&cl)))
+ CHECK((*((closure_test_type2)pcl))
(1, 2, 3, 4, 127, 5, 6, 8, 9, 10, 11, 12.0, 13,
19.0, 21, 1) == 255);
@@ -1284,10 +1292,10 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
&ffi_type_sint, cl_arg_types) == FFI_OK);
- CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn3,
+ CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn3,
(void *) 3 /* userdata */) == FFI_OK);
- CHECK((*((closure_test_type3)(&cl)))
+ CHECK((*((closure_test_type3)pcl))
(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9, 10, 11.11, 12.0, 13,
19.19, 21.21, 1) == 135);
}
diff --git a/libffi/src/powerpc/ffi.c b/libffi/src/powerpc/ffi.c
index ea1a14e8f65..6f0e2a561af 100644
--- a/libffi/src/powerpc/ffi.c
+++ b/libffi/src/powerpc/ffi.c
@@ -31,7 +31,15 @@
#include <stdlib.h>
#include <stdio.h>
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 1)
+# define hidden __attribute__ ((visibility ("hidden")))
+#else
+# define hidden
+#endif
+
+
extern void ffi_closure_SYSV(void);
+extern void hidden ffi_closure_LINUX64(void);
enum {
/* The assembly depends on these exact flags. */
@@ -52,7 +60,7 @@ enum {
};
enum { ASM_NEEDS_REGISTERS = 4 };
-/* ffi_prep_args is called by the assembly routine once stack space
+/* 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:
@@ -79,7 +87,7 @@ enum { ASM_NEEDS_REGISTERS = 4 };
*/
/*@-exportheader@*/
-void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
+void ffi_prep_args_SYSV(extended_cif *ecif, unsigned *const stack)
/*@=exportheader@*/
{
const unsigned bytes = ecif->cif->bytes;
@@ -124,7 +132,7 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
/* Deal with return values that are actually pass-by-reference. */
if (flags & FLAG_RETVAL_REFERENCE)
{
- *gpr_base++ = (unsigned)(char *)ecif->rvalue;
+ *gpr_base++ = (unsigned long)(char *)ecif->rvalue;
intarg_count++;
}
@@ -210,7 +218,7 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
copy_space -= struct_copy_size;
memcpy(copy_space, (char *)*p_argv, (*ptr)->size);
- gprvalue = (unsigned)copy_space;
+ gprvalue = (unsigned long)copy_space;
FFI_ASSERT(copy_space > (char *)next_arg);
FFI_ASSERT(flags & FLAG_ARG_NEEDS_COPY);
@@ -252,34 +260,229 @@ void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
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 };
+
+/* 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 | | gorws |
+ |--------------------------------------------| | 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
+
+ */
+
+/*@-exportheader@*/
+void hidden ffi_prep_args64(extended_cif *ecif, unsigned long *const stack)
+/*@=exportheader@*/
+{
+ const unsigned long bytes = ecif->cif->bytes;
+ const unsigned long flags = ecif->cif->flags;
+
+ /* 'stacktop' points at the previous backchain pointer. */
+ unsigned long *const stacktop = stack + (bytes / sizeof(unsigned long));
+
+ /* 'next_arg' points at the space for gpr3, and grows upwards as
+ we use GPR registers, then continues at rest. */
+ unsigned long *const gpr_base = stacktop - ASM_NEEDS_REGISTERS64
+ - NUM_GPR_ARG_REGISTERS64;
+ unsigned long *const gpr_end = gpr_base + NUM_GPR_ARG_REGISTERS64;
+ unsigned long *const rest = stack + 6 + NUM_GPR_ARG_REGISTERS64;
+ unsigned long *next_arg = gpr_base;
+
+ /* 'fpr_base' points at the space for fpr3, and grows upwards as
+ we use FPR registers. */
+ double *fpr_base = (double *)gpr_base - NUM_FPR_ARG_REGISTERS64;
+ int fparg_count = 0;
+
+ int i, words;
+ ffi_type **ptr;
+ double double_tmp;
+ void **p_argv;
+ unsigned long gprvalue;
+
+ /* Check that everything starts aligned properly. */
+ FFI_ASSERT(((unsigned long)(char *)stack & 0xF) == 0);
+ FFI_ASSERT(((unsigned long)(char *)stacktop & 0xF) == 0);
+ FFI_ASSERT((bytes & 0xF) == 0);
+
+ /* Deal with return values that are actually pass-by-reference. */
+ if (flags & FLAG_RETVAL_REFERENCE)
+ *next_arg++ = (unsigned long)(char *)ecif->rvalue;
+
+ /* Now for the arguments. */
+ p_argv = ecif->avalue;
+ for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
+ i > 0;
+ i--, ptr++, p_argv++)
+ {
+ switch ((*ptr)->type)
+ {
+ case FFI_TYPE_FLOAT:
+ double_tmp = *(float *)*p_argv;
+ *(float *)next_arg = (float)double_tmp;
+ if (++next_arg == gpr_end)
+ next_arg = rest;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ double_tmp = *(double *)*p_argv;
+ *(double *)next_arg = double_tmp;
+ if (++next_arg == gpr_end)
+ next_arg = rest;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+
+ case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ words = ((*ptr)->size + 7) / 8;
+ if (next_arg >= gpr_base && next_arg + words > gpr_end)
+ {
+ unsigned int first = (char *) gpr_end - (char *) next_arg;
+ memcpy((char *) next_arg, (char *) *p_argv, first);
+ memcpy((char *) rest, (char *) *p_argv + first,
+ (*ptr)->size - first);
+ next_arg = rest + words * 8 - first;
+ }
+ else
+ {
+ /* Structures with 1, 2 and 4 byte sizes are passed left-padded
+ if they are in the first 8 arguments. */
+ if (next_arg >= gpr_base
+ && (*ptr)->size < 8
+ && ((*ptr)->size & ~((*ptr)->size - 1)) == (*ptr)->size)
+ memcpy((char *) next_arg + 8 - (*ptr)->size,
+ (char *) *p_argv, (*ptr)->size);
+ else
+ memcpy((char *) next_arg, (char *) *p_argv, (*ptr)->size);
+ next_arg += words;
+ if (next_arg == gpr_end)
+ next_arg = rest;
+ }
+ break;
+
+ case FFI_TYPE_UINT8:
+ gprvalue = *(unsigned char *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_SINT8:
+ gprvalue = *(signed char *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_UINT16:
+ gprvalue = *(unsigned short *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_SINT16:
+ gprvalue = *(signed short *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_UINT32:
+ gprvalue = *(unsigned int *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ gprvalue = *(signed int *)*p_argv;
+ goto putgpr;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_POINTER:
+ gprvalue = *(unsigned long *)*p_argv;
+ putgpr:
+ *next_arg++ = gprvalue;
+ if (next_arg == gpr_end)
+ next_arg = rest;
+ break;
+ }
+ }
+
+ FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS
+ || (next_arg >= gpr_base && next_arg <= gpr_base + 4));
+}
+
+
+
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
- /* All this is for the SYSV ABI. */
+ /* 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 struct_copy_size = 0;
-
- /* 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);
+ if (cif->abi != FFI_LINUX64)
+ {
+ /* All the machine-independent calculation of cif->bytes will be wrong.
+ Redo the calculation for SYSV. */
- /* Space for the GPR registers. */
- bytes += NUM_GPR_ARG_REGISTERS * sizeof(int);
+ /* Space for the frame pointer, callee's LR, and the asm's temp regs. */
+ bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof(int);
- /* Return value handling. The rules are as follows:
+ /* Space for the GPR registers. */
+ bytes += NUM_GPR_ARG_REGISTERS * sizeof(int);
+ }
+ else
+ {
+ /* 64-bit ABI. */
+
+ /* 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);
+ }
+
+ /* 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 and long double (if not equivalent to double) values
- are allocated space and a pointer is passed as the first argument. */
+ are allocated space and a pointer is passed as the first argument.
+ For LINUX64:
+ - integer values in gpr3;
+ - Structures/Unions and long double by reference;
+ - Single/double FP values in fpr1. */
switch (cif->rtype->type)
{
case FFI_TYPE_DOUBLE:
@@ -295,7 +498,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
break;
case FFI_TYPE_STRUCT:
- if (cif->abi != FFI_GCC_SYSV)
+ if (cif->abi != FFI_GCC_SYSV && cif->abi != FFI_LINUX64)
if (cif->rtype->size <= 4)
break;
else if (cif->rtype->size <= 8)
@@ -319,59 +522,86 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
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++)
- {
- switch ((*ptr)->type)
- {
- case FFI_TYPE_FLOAT:
- fparg_count++;
- /* floating singles are not 8-aligned on stack */
- 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++)
+ {
+ switch ((*ptr)->type)
+ {
+ case FFI_TYPE_FLOAT:
+ fparg_count++;
+ /* floating singles are not 8-aligned on stack */
+ break;
- 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%2 != 0)
- intarg_count++;
- break;
+ 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%2 != 0)
+ intarg_count++;
+ 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. */
- if (intarg_count == NUM_GPR_ARG_REGISTERS-1
- || intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0)
+ 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. */
+ if (intarg_count == NUM_GPR_ARG_REGISTERS-1
+ || (intarg_count >= NUM_GPR_ARG_REGISTERS
+ && intarg_count%2 != 0))
+ intarg_count++;
+ intarg_count += 2;
+ break;
+
+ case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ /* 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). */
+
+ default:
+ /* Everything else is passed as a 4-byte word in a GPR, either
+ the object itself or a pointer to it. */
intarg_count++;
- intarg_count += 2;
- break;
+ break;
+ }
+ }
+ else
+ for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+ {
+ switch ((*ptr)->type)
+ {
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ fparg_count++;
+ intarg_count++;
+ break;
- case FFI_TYPE_STRUCT:
+ case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
#endif
- /* 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). */
+ intarg_count += ((*ptr)->size + 7) & ~7;
+ break;
- default:
- /* 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:
+ /* Everything else is passed as a 8-byte word in a GPR, either
+ the object itself or a pointer to it. */
+ intarg_count++;
+ break;
+ }
+ }
if (fparg_count != 0)
flags |= FLAG_FP_ARGUMENTS;
@@ -379,16 +609,29 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
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);
+ if (cif->abi != FFI_LINUX64)
+ {
+ /* 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);
+ }
+ else
+ {
+ /* Space for the FPR registers, if needed. */
+ if (fparg_count != 0)
+ bytes += NUM_FPR_ARG_REGISTERS64 * sizeof(double);
+
+ /* Stack space. */
+ if (intarg_count > NUM_GPR_ARG_REGISTERS64)
+ bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof(long);
+ }
/* The stack space allocated needs to be a multiple of 16 bytes. */
bytes = (bytes + 15) & ~0xF;
@@ -408,6 +651,10 @@ extern void ffi_call_SYSV(/*@out@*/ extended_cif *,
unsigned, unsigned,
/*@out@*/ unsigned *,
void (*fn)());
+extern void hidden ffi_call_LINUX64(/*@out@*/ extended_cif *,
+ unsigned long, unsigned long,
+ /*@out@*/ unsigned long *,
+ void (*fn)());
/*@=declundef@*/
/*@=exportheader@*/
@@ -437,6 +684,7 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
switch (cif->abi)
{
+#ifndef POWERPC64
case FFI_SYSV:
case FFI_GCC_SYSV:
/*@-usedef@*/
@@ -444,6 +692,14 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
cif->flags, ecif.rvalue, fn);
/*@=usedef@*/
break;
+#else
+ case FFI_LINUX64:
+ /*@-usedef@*/
+ ffi_call_LINUX64(&ecif, -(long) cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#endif
default:
FFI_ASSERT(0);
break;
@@ -451,14 +707,38 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
}
+#ifndef POWERPC64
static void flush_icache(char *, int);
+#define MIN_CACHE_LINE_SIZE 8
+
+static void flush_icache(char * addr1, int size)
+{
+ int i;
+ char * addr;
+ for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) {
+ addr = addr1 + i;
+ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory");
+ }
+ addr = addr1 + size - 1;
+ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : "memory");
+}
+#endif
+
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
{
+#ifdef POWERPC64
+ void **tramp = (void **) &closure->tramp[0];
+
+ FFI_ASSERT (cif->abi == FFI_LINUX64);
+ /* Copy function address and TOC from ffi_closure_LINUX64. */
+ memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
+ tramp[2] = (void *) closure;
+#else
unsigned int *tramp;
FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
@@ -475,34 +755,25 @@ ffi_prep_closure (ffi_closure* closure,
*(void **) &tramp[2] = (void *)ffi_closure_SYSV; /* function */
*(void **) &tramp[3] = (void *)closure; /* context */
+ /* Flush the icache. */
+ flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
+#endif
+
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
- /* Flush the icache. */
- flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
-
return FFI_OK;
}
-
-#define MIN_CACHE_LINE_SIZE 8
-
-static void flush_icache(char * addr1, int size)
+typedef union
{
- int i;
- char * addr;
- for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) {
- addr = addr1 + i;
- __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory");
- }
- addr = addr1 + size - 1;
- __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : "memory");
-}
-
+ float f;
+ double d;
+} ffi_dblfl;
int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*,
- unsigned long*, unsigned long*);
+ ffi_dblfl*, unsigned long*);
/* Basically the trampoline invokes ffi_closure_SYSV, and on
* entry, r11 holds the address of the closure.
@@ -514,7 +785,7 @@ int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*,
int
ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue,
- unsigned long * pgr, unsigned long * pfr,
+ unsigned long * pgr, ffi_dblfl * pfr,
unsigned long * pst)
{
/* rvalue is the pointer to space for return value in closure assembly */
@@ -540,7 +811,7 @@ ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue,
returns the data directly to the caller. */
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
- rvalue = *pgr;
+ rvalue = (void *) *pgr;
ng++;
pgr++;
}
@@ -631,11 +902,11 @@ ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue,
/* there are 8 64bit floating point registers */
if (nf < 8) {
- temp = *(double*)pfr;
- *(float*)pfr = (float)temp;
+ temp = pfr->d;
+ pfr->f = (float)temp;
avalue[i] = pfr;
nf++;
- pfr+=2;
+ pfr++;
} else {
/* FIXME? here we are really changing the values
* stored in the original calling routines outgoing
@@ -655,7 +926,7 @@ ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue,
if (nf < 8) {
avalue[i] = pfr;
nf++;
- pfr+=2;
+ pfr++;
} else {
if (((long)pst) & 4) pst++;
avalue[i] = pst;
@@ -674,12 +945,148 @@ ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue,
(closure->fun) (cif, rvalue, avalue, closure->user_data);
- /* Tell ffi_closure_osf how to perform return type promotions. */
+ /* Tell ffi_closure_SYSV how to perform return type promotions. */
return cif->rtype->type;
}
+int hidden ffi_closure_helper_LINUX64 (ffi_closure*, void*, unsigned long*,
+ ffi_dblfl*);
+int 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;
+ long i, avn;
+ long nf; /* number of floating registers already used */
+ long ng; /* number of general registers already used */
+ ffi_cif * cif;
+ double temp;
+ cif = closure->cif;
+ avalue = alloca(cif->nargs * sizeof(void *));
+ nf = 0;
+ ng = 0;
+ /* 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)
+ {
+ rvalue = (void *) *pst;
+ ng++;
+ pst++;
+ }
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ while (i < avn)
+ {
+ switch (arg_types[i]->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ avalue[i] = (char *) pst + 7;
+ ng++;
+ pst++;
+ break;
+
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ avalue[i] = (char *) pst + 6;
+ ng++;
+ pst++;
+ break;
+
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ avalue[i] = (char *) pst + 4;
+ ng++;
+ pst++;
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ avalue[i] = pst;
+ ng++;
+ pst++;
+ break;
+
+ case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ /* Structures with 1, 2 and 4 byte sizes are passed left-padded
+ if they are in the first 8 arguments. */
+ if (ng < NUM_GPR_ARG_REGISTERS64
+ && arg_types[i]->size < 8
+ && ((arg_types[i]->size & ~(arg_types[i]->size - 1))
+ == arg_types[i]->size))
+ avalue[i] = (char *) pst + 8 - arg_types[i]->size;
+ else
+ avalue[i] = pst;
+ ng += (arg_types[i]->size + 7) / 8;
+ 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 (nf < NUM_FPR_ARG_REGISTERS64) {
+ temp = pfr->d;
+ pfr->f = (float)temp;
+ avalue[i] = pfr;
+ pfr++;
+ } else {
+ avalue[i] = pst;
+ }
+ nf++;
+ ng++;
+ pst++;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ /* On the outgoing stack all values are aligned to 8 */
+ /* there are 13 64bit floating point registers */
+
+ if (nf < NUM_FPR_ARG_REGISTERS64) {
+ avalue[i] = pfr;
+ pfr++;
+ } else {
+ avalue[i] = pst;
+ }
+ nf++;
+ ng++;
+ 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. */
+ return cif->rtype->type;
+
+}
diff --git a/libffi/src/powerpc/linux64.S b/libffi/src/powerpc/linux64.S
new file mode 100644
index 00000000000..9619c539223
--- /dev/null
+++ b/libffi/src/powerpc/linux64.S
@@ -0,0 +1,185 @@
+/* -----------------------------------------------------------------------
+ sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com>
+
+ PowerPC64 Assembly glue.
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <ffi.h>
+
+#ifdef __powerpc64__
+ .hidden ffi_call_LINUX64, .ffi_call_LINUX64
+ .globl ffi_call_LINUX64, .ffi_call_LINUX64
+ .section ".opd","aw"
+ .align 3
+ffi_call_LINUX64:
+ .quad .ffi_call_LINUX64,.TOC.@tocbase,0
+ .size ffi_call_LINUX64,24
+ .type .ffi_call_LINUX64,@function
+ .text
+.ffi_call_LINUX64:
+.LFB1:
+ mflr %r0
+ std %r28, -32(%r1)
+ std %r29, -24(%r1)
+ std %r30, -16(%r1)
+ std %r31, -8(%r1)
+ std %r0, 16(%r1)
+
+ mr %r28, %r1 /* our AP. */
+ stdux %r1, %r1, %r4
+.LCFI0:
+ mr %r31, %r5 /* flags, */
+ mr %r30, %r6 /* rvalue, */
+ mr %r29, %r7 /* function address. */
+ std %r2, 40(%r1)
+
+ /* Call ffi_prep_args64. */
+ mr %r4, %r1
+ bl .ffi_prep_args64
+
+ ld %r0, 0(%r29)
+ ld %r2, 8(%r29)
+ ld %r11, 16(%r29)
+
+ /* 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
+ /* Load all those argument registers. */
+ ld %r3, -32-(8*8)(%r28)
+ ld %r4, -32-(7*8)(%r28)
+ ld %r5, -32-(6*8)(%r28)
+ ld %r6, -32-(5*8)(%r28)
+ bf- 5, 1f
+ ld %r7, -32-(4*4)(%r28)
+ ld %r8, -32-(3*4)(%r28)
+ ld %r9, -32-(2*4)(%r28)
+ ld %r10, -32-(1*4)(%r28)
+1:
+
+ /* Load all the FP registers. */
+ bf- 6, 2f
+ lfd %f1, -32-(21*8)(%r28)
+ lfd %f2, -32-(20*8)(%r28)
+ lfd %f3, -32-(19*8)(%r28)
+ lfd %f4, -32-(18*8)(%r28)
+ lfd %f5, -32-(17*8)(%r28)
+ lfd %f6, -32-(16*8)(%r28)
+ lfd %f7, -32-(15*8)(%r28)
+ lfd %f8, -32-(14*8)(%r28)
+ lfd %f9, -32-(13*8)(%r28)
+ lfd %f10, -32-(12*8)(%r28)
+ lfd %f11, -32-(11*8)(%r28)
+ lfd %f12, -32-(10*8)(%r28)
+ lfd %f13, -32-(9*8)(%r28)
+2:
+ /* FIXME: Shouldn't gcc use %r3-%r10 in this case
+ and not the parm save area? */
+ std %r3, 48+(0*8)(%r1)
+ std %r4, 48+(1*8)(%r1)
+ std %r5, 48+(2*8)(%r1)
+ std %r6, 48+(3*8)(%r1)
+ std %r7, 48+(4*8)(%r1)
+ std %r8, 48+(5*8)(%r1)
+ std %r9, 48+(6*8)(%r1)
+ std %r10, 48+(7*8)(%r1)
+ /* end of FIXME. */
+
+ /* Make the call. */
+ bctrl
+
+ /* Now, deal with the return value. */
+ mtcrf 0x01, %r31
+ bt- 30, .Ldone_return_value
+ bt- 29, .Lfp_return_value
+ std %r3, 0(%r30)
+ /* Fall through... */
+
+.Ldone_return_value:
+ /* Restore the registers we used and return. */
+ ld %r2, 40(%r1)
+ mr %r1, %r28
+ ld %r0, 16(%r28)
+ ld %r28, -32(%r1)
+ mtlr %r0
+ ld %r29, -24(%r1)
+ ld %r30, -16(%r1)
+ ld %r31, -8(%r1)
+ blr
+
+.Lfp_return_value:
+ bf 28, .Lfloat_return_value
+ stfd %f1, 0(%r30)
+ b .Ldone_return_value
+.Lfloat_return_value:
+ stfs %f1, 0(%r30)
+ b .Ldone_return_value
+.LFE1:
+ .long 0
+ .byte 0,12,0,1,128,4,0,0
+ .size .ffi_call_LINUX64,.-.ffi_call_LINUX64
+
+ .section .eh_frame,"aw",@progbits
+.Lframe1:
+ .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
+.LSCIE1:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "zR\0" # CIE Augmentation
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 -8 # CIE Data Alignment Factor
+ .byte 0x41 # CIE RA Column
+ .uleb128 0x1 # Augmentation size
+ .byte 0x14 # FDE Encoding (pcrel udata8)
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1
+ .uleb128 0x0
+ .align 3
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 # FDE Length
+.LASFDE1:
+ .4byte .LASFDE1-.Lframe1 # FDE CIE offset
+ .8byte .LFB1-. # FDE initial location
+ .8byte .LFE1-.LFB1 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x2 # DW_CFA_advance_loc1
+ .byte .LCFI0-.LFB1
+ .byte 0xd # DW_CFA_def_cfa_register
+ .uleb128 0x1c
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x41
+ .sleb128 -2
+ .byte 0x9f # DW_CFA_offset, column 0x1f
+ .uleb128 0x1
+ .byte 0x9e # DW_CFA_offset, column 0x1e
+ .uleb128 0x2
+ .byte 0x9d # DW_CFA_offset, column 0x1d
+ .uleb128 0x3
+ .byte 0x9c # DW_CFA_offset, column 0x1c
+ .uleb128 0x4
+ .align 3
+.LEFDE1:
+#endif
diff --git a/libffi/src/powerpc/linux64_closure.S b/libffi/src/powerpc/linux64_closure.S
new file mode 100644
index 00000000000..d435e584fd5
--- /dev/null
+++ b/libffi/src/powerpc/linux64_closure.S
@@ -0,0 +1,210 @@
+ .file "linux64_closure.S"
+
+#ifdef __powerpc64__
+ .hidden ffi_closure_LINUX64, .ffi_closure_LINUX64
+ .globl ffi_closure_LINUX64, .ffi_closure_LINUX64
+ .section ".opd","aw"
+ .align 3
+ffi_closure_LINUX64:
+ .quad .ffi_closure_LINUX64,.TOC.@tocbase,0
+ .size ffi_closure_LINUX64,24
+ .type .ffi_closure_LINUX64,@function
+ .text
+.ffi_closure_LINUX64:
+.LFB1:
+ # save general regs into parm save area
+ std %r3, 48(%r1)
+ std %r4, 56(%r1)
+ std %r5, 64(%r1)
+ std %r6, 72(%r1)
+ mflr %r0
+
+ 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
+ # + 8 bytes retval area + 13*8 bytes fpr save area
+ stdu %r1, -224(%r1)
+.LCFI0:
+
+ # next save fpr 1 to fpr 13
+ stfd %f1, 120+(0*8)(%r1)
+ stfd %f2, 120+(1*8)(%r1)
+ stfd %f3, 120+(2*8)(%r1)
+ stfd %f4, 120+(3*8)(%r1)
+ stfd %f5, 120+(4*8)(%r1)
+ stfd %f6, 120+(5*8)(%r1)
+ stfd %f7, 120+(6*8)(%r1)
+ stfd %f8, 120+(7*8)(%r1)
+ stfd %f9, 120+(8*8)(%r1)
+ stfd %f10, 120+(9*8)(%r1)
+ stfd %f11, 120+(10*8)(%r1)
+ stfd %f12, 120+(11*8)(%r1)
+ stfd %f13, 120+(12*8)(%r1)
+
+ # set up registers for the routine that actually does the work
+ # get the context pointer from the trampoline
+ mr %r3, %r11
+
+ # now load up the pointer to the result storage
+ addi %r4, %r1, 112
+
+ # now load up the pointer to the parameter save area
+ # in the previous frame
+ addi %r5, %r1, 224 + 48
+
+ # now load up the pointer to the saved fpr registers */
+ addi %r6, %r1, 120
+
+ # make the call
+ bl .ffi_closure_helper_LINUX64
+
+ # now r3 contains the return type
+ # so use it to look up in a table
+ # so we know how to deal with each type
+
+ # look up the proper starting point in table
+ # by using return type as offset
+ addi %r5, %r1, 112 # get pointer to results area
+ bl .Lget_ret_type0_addr # get pointer to .Lret_type0 into LR
+ mflr %r4 # move to r4
+ sldi %r3, %r3, 4 # now multiply return type by 16
+ add %r3, %r3, %r4 # add contents of table to table address
+ mtctr %r3
+ bctr # jump to it
+
+# Each of the ret_typeX code fragments has to be exactly 16 bytes long
+# (4 instructions). For cache effectiveness we align to a 16 byte boundary
+# first.
+ .align 4
+
+ nop
+ nop
+ nop
+.Lget_ret_type0_addr:
+ blrl
+
+.Lret_type0:
+# case FFI_TYPE_VOID
+ b .Lfinish
+ nop
+ nop
+ nop
+# case FFI_TYPE_INT
+ lwa %r3, 4(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_FLOAT
+ lfs %f1, 4(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_DOUBLE
+ lfd %f1, 0(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_LONGDOUBLE
+ lfd %f1, 0(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_UINT8
+ lbz %r3, 7(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_SINT8
+ lbz %r3, 7(%r5)
+ extsb %r3,%r3
+ b .Lfinish
+ nop
+# case FFI_TYPE_UINT16
+ lhz %r3, 6(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_SINT16
+ lha %r3, 6(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_UINT32
+ lwz %r3, 4(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_SINT32
+ lwa %r3, 4(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_UINT64
+ ld %r3, 0(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_SINT64
+ ld %r3, 0(%r5)
+ b .Lfinish
+ nop
+ nop
+# case FFI_TYPE_STRUCT
+ b .Lfinish
+ nop
+ nop
+ nop
+# case FFI_TYPE_POINTER
+ ld %r3, 0(%r5)
+ b .Lfinish
+ nop
+ nop
+# esac
+.Lfinish:
+ ld %r0, 224+16(%r1)
+ mtlr %r0
+ addi %r1, %r1, 224
+ blr
+.LFE1:
+ .long 0
+ .byte 0,12,0,1,128,0,0,0
+ .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64
+
+ .section .eh_frame,"aw",@progbits
+.Lframe1:
+ .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
+.LSCIE1:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "zR\0" # CIE Augmentation
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 -8 # CIE Data Alignment Factor
+ .byte 0x41 # CIE RA Column
+ .uleb128 0x1 # Augmentation size
+ .byte 0x14 # FDE Encoding (pcrel udata8)
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1
+ .uleb128 0x0
+ .align 3
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 # FDE Length
+.LASFDE1:
+ .4byte .LASFDE1-.Lframe1 # FDE CIE offset
+ .8byte .LFB1-. # FDE initial location
+ .8byte .LFE1-.LFB1 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x2 # DW_CFA_advance_loc1
+ .byte .LCFI0-.LFB1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 224
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x41
+ .sleb128 -2
+ .align 3
+.LEFDE1:
+#endif
diff --git a/libffi/src/powerpc/ppc_closure.S b/libffi/src/powerpc/ppc_closure.S
index e402fb5cda3..4cfc8fda5ad 100644
--- a/libffi/src/powerpc/ppc_closure.S
+++ b/libffi/src/powerpc/ppc_closure.S
@@ -3,6 +3,8 @@
.file "ppc_closure.S"
+#ifndef __powerpc64__
+
ENTRY(ffi_closure_SYSV)
.LFB1:
stwu %r1,-144(%r1)
@@ -227,3 +229,5 @@ __FRAME_BEGIN__:
.byte 0x1 # uleb128 0x1
.align 2
.LEFDE1:
+
+#endif
diff --git a/libffi/src/powerpc/sysv.S b/libffi/src/powerpc/sysv.S
index 538ffa83bdb..c1e0d18461c 100644
--- a/libffi/src/powerpc/sysv.S
+++ b/libffi/src/powerpc/sysv.S
@@ -29,7 +29,8 @@
#include <ffi.h>
#include <powerpc/asm.h>
- .globl ffi_prep_args
+#ifndef __powerpc64__
+ .globl ffi_prep_args_SYSV
ENTRY(ffi_call_SYSV)
.LFB1:
/* Save the old stack pointer as AP. */
@@ -58,9 +59,9 @@ ENTRY(ffi_call_SYSV)
mr %r28,%r8 /* our AP. */
.LCFI6:
- /* Call ffi_prep_args. */
+ /* Call ffi_prep_args_SYSV. */
mr %r4,%r1
- bl JUMPTARGET(ffi_prep_args)
+ bl JUMPTARGET(ffi_prep_args_SYSV)
/* Now do the call. */
/* Set up cr1 with bits 4-7 of the flags. */
@@ -171,3 +172,4 @@ __FRAME_BEGIN__:
.byte 0x1c /* uleb128 0x1c */
.align 2
.LEFDE1:
+#endif