configure.in (powerpc64*-*-linux*): Remove.

* configure.in (powerpc64*-*-linux*): Remove.
	* configure: Rebuilt.
libffi/
	* 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.

From-SVN: r65781
This commit is contained in:
Jakub Jelinek 2003-04-18 14:32:36 +02:00 committed by Jakub Jelinek
parent 9c59483708
commit e9b841813c
15 changed files with 998 additions and 129 deletions

View File

@ -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

5
configure vendored
View File

@ -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}"
;;

View File

@ -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}"
;;

View File

@ -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.

View File

@ -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

View File

@ -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

2
libffi/configure vendored
View File

@ -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;;

View File

@ -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;;

View File

@ -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)

View File

@ -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);
}

View File

@ -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)
intarg_count++;
intarg_count += 2;
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))
intarg_count++;
intarg_count += 2;
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). */
/* 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++;
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;
}
}
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:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
#endif
intarg_count += ((*ptr)->size + 7) & ~7;
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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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