diff options
-rw-r--r-- | libffi/ChangeLog | 42 | ||||
-rw-r--r-- | libffi/Makefile.am | 6 | ||||
-rw-r--r-- | libffi/Makefile.in | 10 | ||||
-rwxr-xr-x | libffi/configure | 144 | ||||
-rw-r--r-- | libffi/configure.in | 2 | ||||
-rw-r--r-- | libffi/include/ffi.h.in | 9 | ||||
-rw-r--r-- | libffi/src/arm/ffi.c | 10 | ||||
-rw-r--r-- | libffi/src/ffitest.c | 279 | ||||
-rw-r--r-- | libffi/src/m68k/ffi.c | 10 | ||||
-rw-r--r-- | libffi/src/mips/ffi.c | 10 | ||||
-rw-r--r-- | libffi/src/prep_cif.c | 7 | ||||
-rw-r--r-- | libffi/src/sparc/ffi.c | 13 | ||||
-rw-r--r-- | libffi/src/types.c | 41 | ||||
-rw-r--r-- | libffi/src/x86/ffi.c | 4 | ||||
-rw-r--r-- | libffi/src/x86/ffi64.c | 575 | ||||
-rw-r--r-- | libffi/src/x86/sysv.S | 6 | ||||
-rw-r--r-- | libffi/src/x86/unix64.S | 166 |
17 files changed, 1174 insertions, 160 deletions
diff --git a/libffi/ChangeLog b/libffi/ChangeLog index fabe8c5..bee2111 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,40 @@ +2002-07-16 Bo Thorsen <bo@suse.de> + + * src/x86/ffi64.c: New file that adds x86-64 support. + * src/x86/unix64.S: New file that handles argument setup for + x86-64. + * src/x86/sysv.S: Don't use this on x86-64. + * src/x86/ffi.c: Don't use this on x86-64. + Remove unused vars. + * src/prep_cif.c (ffi_prep_cif): Don't do stack size calculation + for x86-64. + * src/ffitest.c (struct6): New test that tests a special case in + the x86-64 ABI. + (struct7): Likewise. + (struct8): Likewise. + (struct9): Likewise. + (closure_test_fn): Silence warning about this when it's not used. + (main): Add the new tests. + (main): Fix a couple of wrong casts and silence some compiler warnings. + * include/ffi.h.in: Add x86-64 ABI definition. + * fficonfig.h.in: Regenerate. + * Makefile.am: Add x86-64 support. + * configure.in: Likewise. + * Makefile.in: Regenerate. + * configure: Likewise. + +2002-06-24 Bo Thorsen <bo@suse.de> + + * src/types.c: Merge settings for similar architectures. + Add x86-64 sizes and alignments. + +2002-06-23 Bo Thorsen <bo@suse.de> + + * src/arm/ffi.c (ffi_prep_args): Remove unused vars. + * src/sparc/ffi.c (ffi_prep_args_v8): Likewise. + * src/mips/ffi.c (ffi_prep_args): Likewise. + * src/m68k/ffi.c (ffi_prep_args): Likewise. + 2002-07-18 H.J. Lu (hjl@gnu.org) * Makefile.am (TARGET_SRC_MIPS_LINUX): New. @@ -15,11 +52,6 @@ * src/s390/sysv.S: Save/restore %r6. Add DWARF-2 unwind info. -2002-05-28 Bo Thorsen <bo@suse.de> - - * src/x86/ffi.c (ffi_prep_incoming_args_SYSV): Remove - the same unused avn var from this one too. - 2002-05-27 Roger Sayle <roger@eyesopen.com> * src/x86/ffi.c (ffi_prep_args): Remove reference to avn. diff --git a/libffi/Makefile.am b/libffi/Makefile.am index 16febc6..d21c933 100644 --- a/libffi/Makefile.am +++ b/libffi/Makefile.am @@ -8,6 +8,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \ src/mips/n32.s src/mips/o32.S src/mips/o32.s \ src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S \ src/x86/ffi.c src/x86/sysv.S src/x86/win32.S \ + src/x86/ffi64.c src/x86/unix64.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 \ @@ -106,6 +107,7 @@ TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/ 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 TARGET_SRC_S390 = src/s390/sysv.S src/s390/ffi.c +TARGET_SRC_X86_64 = src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S ##libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c $(TARGET_SRC_@TARGET@) ## Work around automake deficiency @@ -167,6 +169,10 @@ if S390 libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_S390) libffi_convenience_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_S390) endif +if X86_64 +libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64) +libffi_convenience_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64) +endif AM_CFLAGS = -fexceptions diff --git a/libffi/Makefile.in b/libffi/Makefile.in index d1e37ff..793c3aa 100644 --- a/libffi/Makefile.in +++ b/libffi/Makefile.in @@ -89,6 +89,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \ src/mips/n32.s src/mips/o32.S src/mips/o32.s \ src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S \ src/x86/ffi.c src/x86/sysv.S src/x86/win32.S \ + src/x86/ffi64.c src/x86/unix64.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 \ @@ -177,6 +178,7 @@ TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/ 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 TARGET_SRC_S390 = src/s390/sysv.S src/s390/ffi.c +TARGET_SRC_X86_64 = src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \ src/raw_api.c src/java_raw_api.c @@ -195,6 +197,7 @@ libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \ @POWERPC_DARWIN_TRUE@libffi_la_SOURCES = @POWERPC_DARWIN_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC_DARWIN) @ARM_TRUE@libffi_la_SOURCES = @ARM_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ARM) @S390_TRUE@libffi_la_SOURCES = @S390_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_S390) +@X86_64_TRUE@libffi_la_SOURCES = @X86_64_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64) @MIPS_GCC_TRUE@libffi_convenience_la_SOURCES = @MIPS_GCC_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_GCC) @MIPS_LINUX_TRUE@libffi_convenience_la_SOURCES = @MIPS_LINUX_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_LINUX) @MIPS_SGI_TRUE@libffi_convenience_la_SOURCES = @MIPS_SGI_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_SGI) @@ -209,6 +212,7 @@ libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \ @POWERPC_DARWIN_TRUE@libffi_convenience_la_SOURCES = @POWERPC_DARWIN_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC_DARWIN) @ARM_TRUE@libffi_convenience_la_SOURCES = @ARM_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ARM) @S390_TRUE@libffi_convenience_la_SOURCES = @S390_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_S390) +@X86_64_TRUE@libffi_convenience_la_SOURCES = @X86_64_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64) AM_CFLAGS = -fexceptions @@ -304,6 +308,9 @@ libffi_la_LIBADD = @S390_TRUE@libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo \ @S390_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \ @S390_TRUE@src/s390/sysv.lo src/s390/ffi.lo +@X86_64_TRUE@libffi_convenience_la_OBJECTS = src/debug.lo src/prep_cif.lo \ +@X86_64_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \ +@X86_64_TRUE@src/x86/ffi.lo src/x86/sysv.lo src/x86/unix64.lo src/x86/ffi64.lo @X86_TRUE@libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo src/types.lo \ @X86_TRUE@src/raw_api.lo src/java_raw_api.lo src/x86/ffi.lo \ @X86_TRUE@src/x86/sysv.lo @@ -323,6 +330,9 @@ libffi_la_LIBADD = @M68K_TRUE@libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo \ @M68K_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \ @M68K_TRUE@src/m68k/ffi.lo src/m68k/sysv.lo +@X86_64_TRUE@libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo src/types.lo \ +@X86_64_TRUE@src/raw_api.lo src/java_raw_api.lo src/x86/ffi.lo \ +@X86_64_TRUE@src/x86/sysv.lo src/x86/unix64.lo src/x86/ffi64.lo noinst_PROGRAMS = ffitest$(EXEEXT) PROGRAMS = $(noinst_PROGRAMS) diff --git a/libffi/configure b/libffi/configure index 183c06b..d18f6dd 100755 --- a/libffi/configure +++ b/libffi/configure @@ -2395,6 +2395,7 @@ powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;; s390-*-linux-*) TARGET=S390; TARGETDIR=s390;; +x86_64-*-linux*) TARGET=X86_64; TARGETDIR=x86;; esac if test $TARGETDIR = unknown; then @@ -2528,12 +2529,21 @@ else S390_FALSE= fi + +if test x$TARGET = xX86_64; then + X86_64_TRUE= + X86_64_FALSE='#' +else + X86_64_TRUE='#' + X86_64_FALSE= +fi + if test x$TARGET = xMIPS_LINUX; then TARGET=MIPS fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:2537: checking how to run the C preprocessor" >&5 +echo "configure:2547: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -2548,13 +2558,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext <<EOF -#line 2552 "configure" +#line 2562 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2558: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2568: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2565,13 +2575,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext <<EOF -#line 2569 "configure" +#line 2579 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2575: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2585: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2582,13 +2592,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext <<EOF -#line 2586 "configure" +#line 2596 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2592: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2602: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2613,12 +2623,12 @@ fi echo "$ac_t""$CPP" 1>&6 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:2617: checking for ANSI C header files" >&5 +echo "configure:2627: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2622 "configure" +#line 2632 "configure" #include "confdefs.h" #include <stdlib.h> #include <stdarg.h> @@ -2626,7 +2636,7 @@ else #include <float.h> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2630: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2640: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -2643,7 +2653,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 2647 "configure" +#line 2657 "configure" #include "confdefs.h" #include <string.h> EOF @@ -2661,7 +2671,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 2665 "configure" +#line 2675 "configure" #include "confdefs.h" #include <stdlib.h> EOF @@ -2682,7 +2692,7 @@ if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext <<EOF -#line 2686 "configure" +#line 2696 "configure" #include "confdefs.h" #include <ctype.h> #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') @@ -2693,7 +2703,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -if { (eval echo configure:2697: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2707: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else @@ -2719,12 +2729,12 @@ fi for ac_func in memcpy do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2723: checking for $ac_func" >&5 +echo "configure:2733: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2728 "configure" +#line 2738 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2747,7 +2757,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2751: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2761: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2774,19 +2784,19 @@ done # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 -echo "configure:2778: checking for working alloca.h" >&5 +echo "configure:2788: checking for working alloca.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2783 "configure" +#line 2793 "configure" #include "confdefs.h" #include <alloca.h> int main() { char *p = alloca(2 * sizeof(int)); ; return 0; } EOF -if { (eval echo configure:2790: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2800: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_header_alloca_h=yes else @@ -2807,12 +2817,12 @@ EOF fi echo $ac_n "checking for alloca""... $ac_c" 1>&6 -echo "configure:2811: checking for alloca" >&5 +echo "configure:2821: checking for alloca" >&5 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2816 "configure" +#line 2826 "configure" #include "confdefs.h" #ifdef __GNUC__ @@ -2840,7 +2850,7 @@ int main() { char *p = (char *) alloca(1); ; return 0; } EOF -if { (eval echo configure:2844: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2854: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_func_alloca_works=yes else @@ -2872,12 +2882,12 @@ EOF echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 -echo "configure:2876: checking whether alloca needs Cray hooks" >&5 +echo "configure:2886: checking whether alloca needs Cray hooks" >&5 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2881 "configure" +#line 2891 "configure" #include "confdefs.h" #if defined(CRAY) && ! defined(CRAY2) webecray @@ -2902,12 +2912,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6 if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2906: checking for $ac_func" >&5 +echo "configure:2916: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2911 "configure" +#line 2921 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2930,7 +2940,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2934: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2944: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2957,7 +2967,7 @@ done fi echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 -echo "configure:2961: checking stack direction for C alloca" >&5 +echo "configure:2971: checking stack direction for C alloca" >&5 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2965,7 +2975,7 @@ else ac_cv_c_stack_direction=0 else cat > conftest.$ac_ext <<EOF -#line 2969 "configure" +#line 2979 "configure" #include "confdefs.h" find_stack_direction () { @@ -2984,7 +2994,7 @@ main () exit (find_stack_direction() < 0); } EOF -if { (eval echo configure:2988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2998: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_stack_direction=1 else @@ -3007,13 +3017,13 @@ fi echo $ac_n "checking size of short""... $ac_c" 1>&6 -echo "configure:3011: checking size of short" >&5 +echo "configure:3021: checking size of short" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 3017 "configure" +#line 3027 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -3023,7 +3033,7 @@ int main() { switch (0) case 0: case (sizeof (short) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:3027: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3037: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_short=$ac_size else @@ -3046,13 +3056,13 @@ EOF echo $ac_n "checking size of int""... $ac_c" 1>&6 -echo "configure:3050: checking size of int" >&5 +echo "configure:3060: checking size of int" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 3056 "configure" +#line 3066 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -3062,7 +3072,7 @@ int main() { switch (0) case 0: case (sizeof (int) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:3066: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3076: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_int=$ac_size else @@ -3085,13 +3095,13 @@ EOF echo $ac_n "checking size of long""... $ac_c" 1>&6 -echo "configure:3089: checking size of long" >&5 +echo "configure:3099: checking size of long" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 3095 "configure" +#line 3105 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -3101,7 +3111,7 @@ int main() { switch (0) case 0: case (sizeof (long) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:3105: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3115: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_long=$ac_size else @@ -3124,13 +3134,13 @@ EOF echo $ac_n "checking size of long long""... $ac_c" 1>&6 -echo "configure:3128: checking size of long long" >&5 +echo "configure:3138: checking size of long long" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 3134 "configure" +#line 3144 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -3140,7 +3150,7 @@ int main() { switch (0) case 0: case (sizeof (long long) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:3144: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3154: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_long_long=$ac_size else @@ -3163,13 +3173,13 @@ EOF echo $ac_n "checking size of float""... $ac_c" 1>&6 -echo "configure:3167: checking size of float" >&5 +echo "configure:3177: checking size of float" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_float'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 3173 "configure" +#line 3183 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -3179,7 +3189,7 @@ int main() { switch (0) case 0: case (sizeof (float) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:3183: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3193: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_float=$ac_size else @@ -3202,13 +3212,13 @@ EOF echo $ac_n "checking size of double""... $ac_c" 1>&6 -echo "configure:3206: checking size of double" >&5 +echo "configure:3216: checking size of double" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_double'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 3212 "configure" +#line 3222 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -3218,7 +3228,7 @@ int main() { switch (0) case 0: case (sizeof (double) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:3222: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3232: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_double=$ac_size else @@ -3241,13 +3251,13 @@ EOF echo $ac_n "checking size of long double""... $ac_c" 1>&6 -echo "configure:3245: checking size of long double" >&5 +echo "configure:3255: checking size of long double" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long_double'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 3251 "configure" +#line 3261 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -3257,7 +3267,7 @@ int main() { switch (0) case 0: case (sizeof (long double) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:3261: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3271: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_long_double=$ac_size else @@ -3281,13 +3291,13 @@ EOF echo $ac_n "checking size of void *""... $ac_c" 1>&6 -echo "configure:3285: checking size of void *" >&5 +echo "configure:3295: checking size of void *" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_void_p'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for ac_size in 4 8 1 2 16 12 ; do # List sizes in rough order of prevalence. cat > conftest.$ac_ext <<EOF -#line 3291 "configure" +#line 3301 "configure" #include "confdefs.h" #include "confdefs.h" #include <sys/types.h> @@ -3297,7 +3307,7 @@ int main() { switch (0) case 0: case (sizeof (void *) == $ac_size):; ; return 0; } EOF -if { (eval echo configure:3301: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3311: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sizeof_void_p=$ac_size else @@ -3320,14 +3330,14 @@ EOF echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 -echo "configure:3324: checking whether byte ordering is bigendian" >&5 +echo "configure:3334: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext <<EOF -#line 3331 "configure" +#line 3341 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/param.h> @@ -3338,11 +3348,11 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:3342: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3352: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext <<EOF -#line 3346 "configure" +#line 3356 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/param.h> @@ -3353,7 +3363,7 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:3357: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3367: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else @@ -3373,7 +3383,7 @@ if test "$cross_compiling" = yes; then echo $ac_n "cross-compiling... " 2>&6 else cat > conftest.$ac_ext <<EOF -#line 3377 "configure" +#line 3387 "configure" #include "confdefs.h" main () { /* Are we little or big endian? From Harbison&Steele. */ @@ -3386,7 +3396,7 @@ main () { exit (u.c[sizeof (long) - 1] == 1); } EOF -if { (eval echo configure:3390: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3400: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else @@ -3404,7 +3414,7 @@ fi echo "$ac_t""$ac_cv_c_bigendian" 1>&6 if test $ac_cv_c_bigendian = unknown; then echo $ac_n "checking to probe for byte ordering""... $ac_c" 1>&6 -echo "configure:3408: checking to probe for byte ordering" >&5 +echo "configure:3418: checking to probe for byte ordering" >&5 cat >conftest.c <<EOF short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; @@ -3454,7 +3464,7 @@ fi if test x$TARGET = xSPARC; then echo $ac_n "checking assembler and linker support unaligned pc related relocs""... $ac_c" 1>&6 -echo "configure:3458: checking assembler and linker support unaligned pc related relocs" >&5 +echo "configure:3468: checking assembler and linker support unaligned pc related relocs" >&5 if eval "test \"`echo '$''{'libffi_cv_as_sparc_ua_pcrel'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3464,14 +3474,14 @@ else CFLAGS="$CFLAGS -fpic" LDFLAGS="$LDFLAGS -shared" cat > conftest.$ac_ext <<EOF -#line 3468 "configure" +#line 3478 "configure" #include "confdefs.h" asm (".text; foo: nop; .data; .align 4; .byte 0; .uaword %r_disp32(foo); .text"); int main() { ; return 0; } EOF -if { (eval echo configure:3475: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3485: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* libffi_cv_as_sparc_ua_pcrel=yes else @@ -3756,6 +3766,8 @@ s%@ARM_TRUE@%$ARM_TRUE%g s%@ARM_FALSE@%$ARM_FALSE%g s%@S390_TRUE@%$S390_TRUE%g s%@S390_FALSE@%$S390_FALSE%g +s%@X86_64_TRUE@%$X86_64_TRUE%g +s%@X86_64_FALSE@%$X86_64_FALSE%g s%@CPP@%$CPP%g s%@ALLOCA@%$ALLOCA%g s%@TARGET@%$TARGET%g diff --git a/libffi/configure.in b/libffi/configure.in index 8e4cabf..7852a98 100644 --- a/libffi/configure.in +++ b/libffi/configure.in @@ -70,6 +70,7 @@ powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;; s390-*-linux-*) TARGET=S390; TARGETDIR=s390;; +x86_64-*-linux*) TARGET=X86_64; TARGETDIR=x86;; esac if test $TARGETDIR = unknown; then @@ -90,6 +91,7 @@ AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX) AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN) AM_CONDITIONAL(ARM, test x$TARGET = xARM) AM_CONDITIONAL(S390, test x$TARGET = xS390) +AM_CONDITIONAL(X86_64, test x$TARGET = xX86_64) if test x$TARGET = xMIPS_LINUX; then TARGET=MIPS diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in index 90dfa51..49e4570 100644 --- a/libffi/include/ffi.h.in +++ b/libffi/include/ffi.h.in @@ -189,10 +189,15 @@ typedef enum ffi_abi { #endif #endif - /* ---- Intel x86 ---------------- */ -#ifdef X86 + /* ---- Intel x86 and AMD x86-64 - */ +#if defined(X86) || defined(X86_64) FFI_SYSV, + FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */ +#ifdef X86 FFI_DEFAULT_ABI = FFI_SYSV, +#else + FFI_DEFAULT_ABI = FFI_UNIX64, +#endif #endif /* ---- Intel x86 Win32 ---------- */ diff --git a/libffi/src/arm/ffi.c b/libffi/src/arm/ffi.c index 0ede742..dcd9891 100644 --- a/libffi/src/arm/ffi.c +++ b/libffi/src/arm/ffi.c @@ -36,13 +36,10 @@ void ffi_prep_args(char *stack, extended_cif *ecif) /*@=exportheader@*/ { register unsigned int i; - register int tmp; - register unsigned int avn; register void **p_argv; register char *argp; register ffi_type **p_arg; - tmp = 0; argp = stack; if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) { @@ -50,11 +47,10 @@ void ffi_prep_args(char *stack, extended_cif *ecif) argp += 4; } - avn = ecif->cif->nargs; p_argv = ecif->avalue; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - (i != 0) && (avn != 0); + (i != 0); i--, p_arg++) { size_t z; @@ -64,9 +60,6 @@ void ffi_prep_args(char *stack, extended_cif *ecif) argp = (char *) ALIGN(argp, (*p_arg)->alignment); } - if (avn != 0) - { - avn--; z = (*p_arg)->size; if (z < sizeof(int)) { @@ -107,7 +100,6 @@ void ffi_prep_args(char *stack, extended_cif *ecif) } p_argv++; argp += z; - } } return; diff --git a/libffi/src/ffitest.c b/libffi/src/ffitest.c index ba47ba4..8d72df1 100644 --- a/libffi/src/ffitest.c +++ b/libffi/src/ffitest.c @@ -153,6 +153,33 @@ typedef struct char c2; } test_structure_5; +typedef struct +{ + float f; + double d; +} test_structure_6; + +typedef struct +{ + float f1; + float f2; + double d; +} test_structure_7; + +typedef struct +{ + float f1; + float f2; + float f3; + float f4; +} test_structure_8; + +typedef struct +{ + float f; + int i; +} test_structure_9; + static test_structure_1 struct1(test_structure_1 ts) { /*@-type@*/ @@ -194,15 +221,52 @@ static test_structure_5 struct5(test_structure_5 ts1, test_structure_5 ts2) return ts1; } +static test_structure_6 struct6 (test_structure_6 ts) +{ + ts.f += 1; + ts.d += 1; + + return ts; +} + +static test_structure_7 struct7 (test_structure_7 ts) +{ + ts.f1 += 1; + ts.f2 += 1; + ts.d += 1; + + return ts; +} + +static test_structure_8 struct8 (test_structure_8 ts) +{ + ts.f1 += 1; + ts.f2 += 1; + ts.f3 += 1; + ts.f4 += 1; + + return ts; +} + +static test_structure_9 struct9 (test_structure_9 ts) +{ + ts.f += 1; + ts.i += 1; + + return ts; +} + /* Take an int and a float argument, together with int userdata, and */ /* return the sum. */ -static void closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata) +#if FFI_CLOSURES +static void +closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata) { - *(int*)resp = - *(int *)args[0] + (int)(*(float *)args[1]) + (int)(long)userdata; + *(int*)resp = *(int*)args[0] + (int)(*(float*)args[1]) + (int)(long)userdata; } typedef int (*closure_test_type)(int, float); +#endif int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) { @@ -230,11 +294,19 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) ffi_type ts3_type; ffi_type ts4_type; ffi_type ts5_type; + ffi_type ts6_type; + ffi_type ts7_type; + ffi_type ts8_type; + ffi_type ts9_type; ffi_type *ts1_type_elements[4]; ffi_type *ts2_type_elements[3]; ffi_type *ts3_type_elements[2]; ffi_type *ts4_type_elements[4]; ffi_type *ts5_type_elements[3]; + ffi_type *ts6_type_elements[3]; + ffi_type *ts7_type_elements[4]; + ffi_type *ts8_type_elements[5]; + ffi_type *ts9_type_elements[3]; ts1_type.size = 0; ts1_type.alignment = 0; @@ -256,12 +328,32 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) ts5_type.alignment = 0; ts5_type.type = FFI_TYPE_STRUCT; + ts6_type.size = 0; + ts6_type.alignment = 0; + ts6_type.type = FFI_TYPE_STRUCT; + + ts7_type.size = 0; + ts7_type.alignment = 0; + ts7_type.type = FFI_TYPE_STRUCT; + + ts8_type.size = 0; + ts8_type.alignment = 0; + ts8_type.type = FFI_TYPE_STRUCT; + + ts9_type.size = 0; + ts9_type.alignment = 0; + ts9_type.type = FFI_TYPE_STRUCT; + /*@-immediatetrans@*/ ts1_type.elements = ts1_type_elements; ts2_type.elements = ts2_type_elements; ts3_type.elements = ts3_type_elements; ts4_type.elements = ts4_type_elements; ts5_type.elements = ts5_type_elements; + ts6_type.elements = ts6_type_elements; + ts7_type.elements = ts7_type_elements; + ts8_type.elements = ts8_type_elements; + ts9_type.elements = ts9_type_elements; /*@=immediatetrans@*/ ts1_type_elements[0] = &ffi_type_uchar; @@ -285,6 +377,25 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) ts5_type_elements[1] = &ffi_type_schar; ts5_type_elements[2] = NULL; + ts6_type_elements[0] = &ffi_type_float; + ts6_type_elements[1] = &ffi_type_double; + ts6_type_elements[2] = NULL; + + ts7_type_elements[0] = &ffi_type_float; + ts7_type_elements[1] = &ffi_type_float; + ts7_type_elements[2] = &ffi_type_double; + ts7_type_elements[3] = NULL; + + ts8_type_elements[0] = &ffi_type_float; + ts8_type_elements[1] = &ffi_type_float; + ts8_type_elements[2] = &ffi_type_float; + ts8_type_elements[3] = &ffi_type_float; + ts8_type_elements[4] = NULL; + + ts9_type_elements[0] = &ffi_type_float; + ts9_type_elements[1] = &ffi_type_sint; + ts9_type_elements[2] = NULL; + ul = 0; /* return value tests */ @@ -326,7 +437,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) { ul++; ffi_call(&cif, FFI_FN(return_sc), &rint, values); - CHECK(rint == (int) sc); + CHECK(rint == (ffi_arg) sc); } args[0] = &ffi_type_uchar; @@ -413,7 +524,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) ffi_call(&cif, FFI_FN(floating), &rint, values); - printf ("%d vs %d\n", rint, floating (si1, f, d, ld, si2)); + printf ("%d vs %d\n", (int)rint, floating (si1, f, d, ld, si2)); CHECK(rint == floating(si1, f, d, ld, si2)); @@ -483,7 +594,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) &ffi_type_float, args) == FFI_OK); /*@-usedef@*/ - ff = many(fa[0], fa[1], + ff = many (fa[0], fa[1], fa[2], fa[3], fa[4], fa[5], fa[6], fa[7], @@ -532,7 +643,8 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) { ul++; ffi_call(&cif, FFI_FN(promotion), &rint, values); - CHECK(rint == (int) sc + (int) ss + (int) uc + (int) us); + CHECK((int)rint == (signed char) sc + (signed short) ss + + (unsigned char) uc + (unsigned short) us); } printf("%lu promotion tests run\n", ul); } @@ -579,8 +691,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) values[0] = &ts2_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, - &ts2_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts2_type, args) == FFI_OK); ts2_arg.d1 = 5.55; ts2_arg.d2 = 6.66; @@ -647,8 +758,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) values[0] = &ts4_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, - &ts4_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts4_type, args) == FFI_OK); ts4_arg.ui1 = 2; ts4_arg.ui2 = 3; @@ -678,8 +788,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) values[1] = &ts5_arg2; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, - &ts5_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ts5_type, args) == FFI_OK); ts5_arg1.c1 = 2; ts5_arg1.c2 = 6; @@ -697,6 +806,150 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) free (ts5_result); } + /* struct tests */ + { + test_structure_6 ts6_arg; + + /* This is a hack to get a properly aligned result buffer */ + test_structure_6 *ts6_result = + (test_structure_6 *) malloc (sizeof(test_structure_6)); + + args[0] = &ts6_type; + values[0] = &ts6_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts6_type, args) == FFI_OK); + + ts6_arg.f = 5.55f; + ts6_arg.d = 6.66; + + printf ("%g\n", ts6_arg.f); + printf ("%g\n", ts6_arg.d); + + ffi_call(&cif, FFI_FN(struct6), ts6_result, values); + + printf ("%g\n", ts6_result->f); + printf ("%g\n", ts6_result->d); + + CHECK(ts6_result->f == 5.55f + 1); + CHECK(ts6_result->d == 6.66 + 1); + + printf("structure test 6 ok!\n"); + + free (ts6_result); + } + + /* struct tests */ + { + test_structure_7 ts7_arg; + + /* This is a hack to get a properly aligned result buffer */ + test_structure_7 *ts7_result = + (test_structure_7 *) malloc (sizeof(test_structure_7)); + + args[0] = &ts7_type; + values[0] = &ts7_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts7_type, args) == FFI_OK); + + ts7_arg.f1 = 5.55f; + ts7_arg.f2 = 55.5f; + ts7_arg.d = 6.66; + + printf ("%g\n", ts7_arg.f1); + printf ("%g\n", ts7_arg.f2); + printf ("%g\n", ts7_arg.d); + + ffi_call(&cif, FFI_FN(struct7), ts7_result, values); + + printf ("%g\n", ts7_result->f1); + printf ("%g\n", ts7_result->f2); + printf ("%g\n", ts7_result->d); + + CHECK(ts7_result->f1 == 5.55f + 1); + CHECK(ts7_result->f2 == 55.5f + 1); + CHECK(ts7_result->d == 6.66 + 1); + + printf("structure test 7 ok!\n"); + + free (ts7_result); + } + + /* struct tests */ + { + test_structure_8 ts8_arg; + + /* This is a hack to get a properly aligned result buffer */ + test_structure_8 *ts8_result = + (test_structure_8 *) malloc (sizeof(test_structure_8)); + + args[0] = &ts8_type; + values[0] = &ts8_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts8_type, args) == FFI_OK); + + ts8_arg.f1 = 5.55f; + ts8_arg.f2 = 55.5f; + ts8_arg.f3 = -5.55f; + ts8_arg.f4 = -55.5f; + + printf ("%g\n", ts8_arg.f1); + printf ("%g\n", ts8_arg.f2); + printf ("%g\n", ts8_arg.f3); + printf ("%g\n", ts8_arg.f4); + + ffi_call(&cif, FFI_FN(struct8), ts8_result, values); + + printf ("%g\n", ts8_result->f1); + printf ("%g\n", ts8_result->f2); + printf ("%g\n", ts8_result->f3); + printf ("%g\n", ts8_result->f4); + + CHECK(ts8_result->f1 == 5.55f + 1); + CHECK(ts8_result->f2 == 55.5f + 1); + CHECK(ts8_result->f3 == -5.55f + 1); + CHECK(ts8_result->f4 == -55.5f + 1); + + printf("structure test 8 ok!\n"); + + free (ts8_result); + } + + /* struct tests */ + { + test_structure_9 ts9_arg; + + /* This is a hack to get a properly aligned result buffer */ + test_structure_9 *ts9_result = + (test_structure_9 *) malloc (sizeof(test_structure_9)); + + args[0] = &ts9_type; + values[0] = &ts9_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts9_type, args) == FFI_OK); + + ts9_arg.f = 5.55f; + ts9_arg.i = 5; + + printf ("%g\n", ts9_arg.f); + printf ("%d\n", ts9_arg.i); + + ffi_call(&cif, FFI_FN(struct9), ts9_result, values); + + printf ("%g\n", ts9_result->f); + printf ("%d\n", ts9_result->i); + + CHECK(ts9_result->f == 5.55f + 1); + CHECK(ts9_result->i == 5 + 1); + + printf("structure test 9 ok!\n"); + + free (ts9_result); + } + #else printf("Structure passing doesn't work on Win32.\n"); #endif /* X86_WIN32 */ diff --git a/libffi/src/m68k/ffi.c b/libffi/src/m68k/ffi.c index c5d9507..55f3a98 100644 --- a/libffi/src/m68k/ffi.c +++ b/libffi/src/m68k/ffi.c @@ -16,14 +16,11 @@ static void * ffi_prep_args (void *stack, extended_cif *ecif) { unsigned int i; - int tmp; - unsigned int avn; void **p_argv; char *argp; ffi_type **p_arg; void *struct_value_ptr; - tmp = 0; argp = stack; if (ecif->cif->rtype->type == FFI_TYPE_STRUCT @@ -32,11 +29,10 @@ ffi_prep_args (void *stack, extended_cif *ecif) else struct_value_ptr = NULL; - avn = ecif->cif->nargs; p_argv = ecif->avalue; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - i != 0 && avn != 0; + i != 0; i--, p_arg++) { size_t z; @@ -45,9 +41,6 @@ ffi_prep_args (void *stack, extended_cif *ecif) if (((*p_arg)->alignment - 1) & (unsigned) argp) argp = (char *) ALIGN (argp, (*p_arg)->alignment); - if (avn != 0) - { - avn--; z = (*p_arg)->size; if (z < sizeof (int)) { @@ -82,7 +75,6 @@ ffi_prep_args (void *stack, extended_cif *ecif) memcpy (argp, *p_argv, z); p_argv++; argp += z; - } } return struct_value_ptr; diff --git a/libffi/src/mips/ffi.c b/libffi/src/mips/ffi.c index 6c41603..93f7923 100644 --- a/libffi/src/mips/ffi.c +++ b/libffi/src/mips/ffi.c @@ -51,7 +51,6 @@ static void ffi_prep_args(char *stack, int flags) { register int i; - register int avn; register void **p_argv; register char *argp; register ffi_type **p_arg; @@ -81,12 +80,9 @@ static void ffi_prep_args(char *stack, FIX_ARGP; } - avn = ecif->cif->nargs; p_argv = ecif->avalue; - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - i && avn; - i--, p_arg++) + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) { size_t z; @@ -102,9 +98,6 @@ static void ffi_prep_args(char *stack, #define OFFSET sizeof(int) #endif - if (avn) - { - avn--; z = (*p_arg)->size; if (z < sizeof(SLOT_TYPE_UNSIGNED)) { @@ -180,7 +173,6 @@ static void ffi_prep_args(char *stack, p_argv++; argp += z; FIX_ARGP; - } } return; diff --git a/libffi/src/prep_cif.c b/libffi/src/prep_cif.c index d53981a..9851364 100644 --- a/libffi/src/prep_cif.c +++ b/libffi/src/prep_cif.c @@ -103,7 +103,9 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, /* Perform a sanity check on the return type */ FFI_ASSERT(ffi_type_test(cif->rtype)); -#ifndef M68K + /* x86-64 and s390 stack space allocation is handled in prep_machdep. + TODO: Disable this for s390 too? */ +#if !defined M68K && !defined __x86_64__ /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT #ifdef SPARC @@ -122,6 +124,8 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; + /* TODO: Disable this calculation for s390 too? */ +#ifndef __x86_64__ #ifdef SPARC if (((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 16 || cif->abi != FFI_V9)) @@ -137,6 +141,7 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, bytes += STACK_ARG_SIZE((*ptr)->size); } +#endif } cif->bytes = bytes; diff --git a/libffi/src/sparc/ffi.c b/libffi/src/sparc/ffi.c index f557013..dc97535 100644 --- a/libffi/src/sparc/ffi.c +++ b/libffi/src/sparc/ffi.c @@ -34,14 +34,10 @@ void ffi_prep_args_v8(char *stack, extended_cif *ecif) { int i; - int tmp; - int avn; void **p_argv; char *argp; ffi_type **p_arg; - tmp = 0; - /* Skip 16 words for the window save area */ argp = stack + 16*sizeof(int); @@ -66,18 +62,12 @@ void ffi_prep_args_v8(char *stack, extended_cif *ecif) ((int*)argp)[5] = 0; #endif - avn = ecif->cif->nargs; p_argv = ecif->avalue; - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - i && avn; - i--, p_arg++) + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) { size_t z; - if (avn) - { - avn--; if ((*p_arg)->type == FFI_TYPE_STRUCT #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE || (*p_arg)->type == FFI_TYPE_LONGDOUBLE @@ -122,7 +112,6 @@ void ffi_prep_args_v8(char *stack, extended_cif *ecif) } p_argv++; argp += z; - } } return; diff --git a/libffi/src/types.c b/libffi/src/types.c index 5eba151..a4a2d06 100644 --- a/libffi/src/types.c +++ b/libffi/src/types.c @@ -42,7 +42,7 @@ FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32); FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32); FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); -#if defined ALPHA || defined SPARC64 +#if defined ALPHA || defined SPARC64 || defined X86_64 FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); @@ -52,22 +52,7 @@ FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); #endif -#ifdef X86 - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); - -#elif defined X86_WIN32 - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); - -#elif defined ARM - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); - -#elif defined M68K +#if defined X86 || defined X86_WIN32 || defined ARM || defined M68K FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); @@ -80,12 +65,7 @@ FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); #endif -#ifdef X86 - -FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); - -#elif defined X86_WIN32 +#if defined X86 || defined X86_WIN32 || defined M68K FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); @@ -95,25 +75,20 @@ FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE); -#elif defined M68K - -FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); - #elif defined SPARC FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); - #ifdef SPARC64 - FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); - #else - FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE); - #endif +#elif defined X86_64 + +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); + #else FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c index c2af395..2e47c5d 100644 --- a/libffi/src/x86/ffi.c +++ b/libffi/src/x86/ffi.c @@ -23,6 +23,8 @@ OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ +#ifndef __x86_64__ + #include <ffi.h> #include <ffi_common.h> @@ -491,3 +493,5 @@ ffi_raw_call(/*@dependent@*/ ffi_cif *cif, } #endif + +#endif /* __x86_64__ */ diff --git a/libffi/src/x86/ffi64.c b/libffi/src/x86/ffi64.c new file mode 100644 index 0000000..3dd8cbb --- /dev/null +++ b/libffi/src/x86/ffi64.c @@ -0,0 +1,575 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de> + + x86-64 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 CYGNUS SOLUTIONS 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> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +#ifdef __x86_64__ + +#define MAX_GPR_REGS 6 +#define MAX_SSE_REGS 8 +typedef struct +{ + /* Registers for argument passing. */ + long gpr[MAX_GPR_REGS]; + __int128_t sse[MAX_SSE_REGS]; + + /* Stack space for arguments. */ + char argspace[0]; +} stackLayout; + +/* All reference to register classes here is identical to the code in + gcc/config/i386/i386.c. Do *not* change one without the other. */ + +/* Register class used for passing given 64bit part of the argument. + These represent classes as documented by the PS ABI, with the exception + of SSESF, SSEDF classes, that are basically SSE class, just gcc will + use SF or DFmode move instead of DImode to avoid reformating penalties. + + Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves + whenever possible (upper half does contain padding). + */ +enum x86_64_reg_class + { + X86_64_NO_CLASS, + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS, + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS, + X86_64_X87_CLASS, + X86_64_X87UP_CLASS, + X86_64_MEMORY_CLASS + }; + +#define MAX_CLASSES 4 + +/* x86-64 register passing implementation. See x86-64 ABI for details. Goal + of this code is to classify each 8bytes of incoming argument by the register + class and assign registers accordingly. */ + +/* Return the union class of CLASS1 and CLASS2. + See the x86-64 PS ABI for details. */ + +static enum x86_64_reg_class +merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) +{ + /* Rule #1: If both classes are equal, this is the resulting class. */ + if (class1 == class2) + return class1; + + /* Rule #2: If one of the classes is NO_CLASS, the resulting class is + the other class. */ + if (class1 == X86_64_NO_CLASS) + return class2; + if (class2 == X86_64_NO_CLASS) + return class1; + + /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ + if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ + if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) + || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) + return X86_64_INTEGERSI_CLASS; + if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS + || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) + return X86_64_INTEGER_CLASS; + + /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ + if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS + || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #6: Otherwise class SSE is used. */ + return X86_64_SSE_CLASS; +} + +/* Classify the argument of type TYPE and mode MODE. + CLASSES will be filled by the register class used to pass each word + of the operand. The number of words is returned. In case the parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 is returned. + + See the x86-64 PS ABI for details. +*/ +static int +classify_argument (ffi_type *type, enum x86_64_reg_class classes[], + int *byte_offset) +{ + /* First, align to the right place. */ + *byte_offset = ALIGN(*byte_offset, type->alignment); + + switch (type->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + if (((*byte_offset) % 8 + type->size) <= 4) + classes[0] = X86_64_INTEGERSI_CLASS; + else + classes[0] = X86_64_INTEGER_CLASS; + return 1; + case FFI_TYPE_FLOAT: + if (((*byte_offset) % 8) == 0) + classes[0] = X86_64_SSESF_CLASS; + else + classes[0] = X86_64_SSE_CLASS; + return 1; + case FFI_TYPE_DOUBLE: + classes[0] = X86_64_SSEDF_CLASS; + return 1; + case FFI_TYPE_LONGDOUBLE: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + return 2; + case FFI_TYPE_STRUCT: + { + const int UNITS_PER_WORD = 8; + int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + ffi_type **ptr; + int i; + enum x86_64_reg_class subclasses[MAX_CLASSES]; + + /* If the struct is larger than 16 bytes, pass it on the stack. */ + if (type->size > 16) + return 0; + + for (i = 0; i < words; i++) + classes[i] = X86_64_NO_CLASS; + + /* Merge the fields of structure. */ + for (ptr=type->elements; (*ptr)!=NULL; ptr++) + { + int num; + + num = classify_argument (*ptr, subclasses, byte_offset); + if (num == 0) + return 0; + for (i = 0; i < num; i++) + { + int pos = *byte_offset / 8; + classes[i + pos] = + merge_classes (subclasses[i], classes[i + pos]); + } + + if ((*ptr)->type != FFI_TYPE_STRUCT) + *byte_offset += (*ptr)->size; + } + + /* Final merger cleanup. */ + for (i = 0; i < words; i++) + { + /* If one class is MEMORY, everything should be passed in + memory. */ + if (classes[i] == X86_64_MEMORY_CLASS) + return 0; + + /* The X86_64_SSEUP_CLASS should be always preceded by + X86_64_SSE_CLASS. */ + if (classes[i] == X86_64_SSEUP_CLASS + && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS)) + classes[i] = X86_64_SSE_CLASS; + + /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */ + if (classes[i] == X86_64_X87UP_CLASS + && (i == 0 || classes[i - 1] != X86_64_X87_CLASS)) + classes[i] = X86_64_SSE_CLASS; + } + return words; + } + + default: + FFI_ASSERT(0); + } + return 0; /* Never reached. */ +} + +/* Examine the argument and return set number of register required in each + class. Return 0 iff parameter should be passed in memory. */ +static int +examine_argument (ffi_type *type, int in_return, int *int_nregs,int *sse_nregs) +{ + enum x86_64_reg_class class[MAX_CLASSES]; + int offset = 0; + int n; + + n = classify_argument (type, class, &offset); + + if (n == 0) + return 0; + + *int_nregs = 0; + *sse_nregs = 0; + for (n--; n>=0; n--) + switch (class[n]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + (*int_nregs)++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + (*sse_nregs)++; + break; + case X86_64_NO_CLASS: + case X86_64_SSEUP_CLASS: + break; + case X86_64_X87_CLASS: + case X86_64_X87UP_CLASS: + if (!in_return) + return 0; + break; + default: + abort (); + } + return 1; +} + +/* Functions to load floats and double to an SSE register placeholder. */ +extern void float2sse (float, __int128_t *); +extern void double2sse (double, __int128_t *); +extern void floatfloat2sse (void *, __int128_t *); + +/* Functions to put the floats and doubles back. */ +extern float sse2float (__int128_t *); +extern double sse2double (__int128_t *); +extern void sse2floatfloat(__int128_t *, void *); + +/*@-exportheader@*/ +void +ffi_prep_args (stackLayout *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + int gprcount, ssecount, i, g, s; + void **p_argv; + void *argp = &stack->argspace; + ffi_type **p_arg; + + /* First check if the return value should be passed in memory. If so, + pass the pointer as the first argument. */ + gprcount = ssecount = 0; + if (examine_argument (ecif->cif->rtype, 1, &g, &s) == 0) + (void *)stack->gpr[gprcount++] = ecif->rvalue; + + for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue; + i!=0; i--, p_arg++, p_argv++) + { + int in_register = 0; + + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + if (gprcount < MAX_GPR_REGS) + { + stack->gpr[gprcount] = 0; + stack->gpr[gprcount++] = *(long long *)(*p_argv); + in_register = 1; + } + break; + + case FFI_TYPE_FLOAT: + if (ssecount < MAX_SSE_REGS) + { + float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]); + in_register = 1; + } + break; + + case FFI_TYPE_DOUBLE: + if (ssecount < MAX_SSE_REGS) + { + double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]); + in_register = 1; + } + break; + } + + if (in_register) + continue; + + /* Either all places in registers where filled, or this is a + type that potentially goes into a memory slot. */ + if (examine_argument (*p_arg, 0, &g, &s) == 0 + || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS) + { + /* Pass this argument in memory. */ + argp = (void *)ALIGN(argp, (*p_arg)->alignment); + memcpy (argp, *p_argv, (*p_arg)->size); + argp += (*p_arg)->size; + } + else + { + /* All easy cases are eliminated. Now fire the big guns. */ + + enum x86_64_reg_class classes[MAX_CLASSES]; + int offset = 0, j, num; + void *a; + + num = classify_argument (*p_arg, classes, &offset); + for (j=0, a=*p_argv; j<num; j++, a+=8) + { + switch (classes[j]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + stack->gpr[gprcount++] = *(long long *)a; + break; + case X86_64_SSE_CLASS: + floatfloat2sse (a, &stack->sse[ssecount++]); + break; + case X86_64_SSESF_CLASS: + float2sse (*(float *)a, &stack->sse[ssecount++]); + break; + case X86_64_SSEDF_CLASS: + double2sse (*(double *)a, &stack->sse[ssecount++]); + break; + default: + abort(); + } + } + } + } +} + +/* Perform machine dependent cif processing. */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + int gprcount, ssecount, i, g, s; + + gprcount = ssecount = 0; + + /* Reset the byte count. We handle this size estimation here. */ + cif->bytes = 0; + + /* If the return value should be passed in memory, pass the pointer + as the first argument. The actual memory isn't allocated here. */ + + if (examine_argument (cif->rtype, 1, &g, &s) == 0) + gprcount = 1; + + /* Go over all arguments and determine the way they should be passed. + If it's in a register and there is space for it, let that be so. If + not, add it's size to the stack byte count. */ + for (i=0; i<cif->nargs; i++) + { + if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0 + || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS) + { + /* This is passed in memory. First align to the basic type. */ + cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment); + + /* Stack arguments are *always* at least 8 byte aligned. */ + cif->bytes = ALIGN(cif->bytes, 8); + + /* Now add the size of this argument. */ + cif->bytes += cif->arg_types[i]->size; + } + else + { + gprcount += g; + ssecount += s; + } + } + + /* Set the flag for the closures return. */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: + cif->flags = FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + puts ("prep_machdep\n"); + + return FFI_OK; +} + +typedef struct +{ + long gpr[2]; + __int128_t sse[2]; + long double st0; +} return_value; + +void +ffi_fill_return_value (return_value *rv, extended_cif *ecif) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + int i = 0, num; + long *gpr = rv->gpr; + __int128_t *sse = rv->sse; + signed char sc; + signed short ss; + + /* This is needed because of the way x86-64 handles signed short + integers. */ + switch (ecif->cif->rtype->type) + { + case FFI_TYPE_SINT8: + sc = *(signed char *)gpr; + *(long long *)ecif->rvalue = (long long)sc; + return; + case FFI_TYPE_SINT16: + ss = *(signed short *)gpr; + *(long long *)ecif->rvalue = (long long)ss; + return; + default: + /* Just continue. */ + ; + } + + num = classify_argument (ecif->cif->rtype, classes, &i); + + if (num == 0) + /* Return in memory. */ + ecif->rvalue = (void *) rv->gpr[0]; + else if (num == 2 && classes[0] == X86_64_X87_CLASS && + classes[1] == X86_64_X87UP_CLASS) + /* This is a long double (this is easiest to handle this way instead + of an eightbyte at a time as in the loop below. */ + *((long double *)ecif->rvalue) = rv->st0; + else + { + void *a; + + for (i=0, a=ecif->rvalue; i<num; i++, a+=8) + { + switch (classes[i]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + *(long long *)a = *gpr; + gpr++; + break; + case X86_64_SSE_CLASS: + sse2floatfloat (sse++, a); + break; + case X86_64_SSESF_CLASS: + *(float *)a = sse2float (sse++); + break; + case X86_64_SSEDF_CLASS: + *(double *)a = sse2double (sse++); + break; + default: + abort(); + } + } + } +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_UNIX64(void (*)(stackLayout *, extended_cif *), + void (*) (return_value *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, /*@out@*/ unsigned *, void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + int dummy; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (examine_argument (cif->rtype, 1, &dummy, &dummy) == 0)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + /* Stack must always be 16byte aligned. Make it so. */ + cif->bytes = ALIGN(cif->bytes, 16); + + switch (cif->abi) + { + case FFI_SYSV: + /* Calling 32bit code from 64bit is not possible */ + FFI_ASSERT(0); + break; + + case FFI_UNIX64: + /*@-usedef@*/ + ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif, + cif->bytes, ecif.rvalue, fn); + /*@=usedef@*/ + break; + + default: + FFI_ASSERT(0); + break; + } +} + +#endif /* ifndef __x86_64__ */ diff --git a/libffi/src/x86/sysv.S b/libffi/src/x86/sysv.S index 32eb633..ad898ad 100644 --- a/libffi/src/x86/sysv.S +++ b/libffi/src/x86/sysv.S @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- - sysv.S - Copyright (c) 1996, 1998, 2001 Cygnus Solutions + sysv.S - Copyright (c) 1996, 1998, 2001, 2002 Cygnus Solutions X86 Foreign Function Interface @@ -23,6 +23,8 @@ OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ +#ifndef __x86_64__ + #define LIBFFI_ASM #include <ffi.h> @@ -163,3 +165,5 @@ __FRAME_BEGIN__: .align 4 .LEFDE1: .set .LLFDE1,.LEFDE1-.LSFDE1 + +#endif /* ifndef __x86_64__ */ diff --git a/libffi/src/x86/unix64.S b/libffi/src/x86/unix64.S new file mode 100644 index 0000000..2e64b41 --- /dev/null +++ b/libffi/src/x86/unix64.S @@ -0,0 +1,166 @@ +/* ----------------------------------------------------------------------- + unix64.S - Copyright (c) 2002 Bo Thorsen <bo@suse.de> + + x86-64 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 CYGNUS SOLUTIONS 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. + ----------------------------------------------------------------------- */ + +#ifdef __x86_64__ +#define LIBFFI_ASM +#include <ffi.h> + + .section .rodata +.LC0: + .string "asm in progress %lld\n" +.LC1: + .string "asm in progress\n" +.text + .align 2 +.globl ffi_call_UNIX64 + .type ffi_call_UNIX64,@function + +ffi_call_UNIX64: +.LFB1: + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + /* Save all arguments */ + subq $48, %rsp +.LCFI2: + movq %rdi, -8(%rbp) /* ffi_prep_args */ + movq %rsi, -16(%rbp) /* ffi_fill_return_value */ + movq %rdx, -24(%rbp) /* ecif */ + movq %rcx, -32(%rbp) /* cif->bytes */ + movq %r8, -40(%rbp) /* ecif.rvalue */ + movq %r9, -48(%rbp) /* fn */ + + /* Make room for all of the new args and the register args */ + addl $176, %ecx +.LCFI3: + subq %rcx, %rsp +.LCFI4: + /* Setup the call to ffi_prep_args. */ + movq %rdi, %rax /* &ffi_prep_args */ + movq %rsp, %rdi /* stackLayout */ + movq %rdx, %rsi /* ecif */ + call *%rax /* ffi_prep_args(stackLayout, ecif);*/ + + /* ffi_prep_args have put all the register contents into the */ + /* stackLayout struct. Now put the register values in place. */ + movq (%rsp), %rdi + movq 8(%rsp), %rsi + movq 16(%rsp), %rdx + movq 24(%rsp), %rcx + movq 32(%rsp), %r8 + movq 40(%rsp), %r9 + movaps 48(%rsp), %xmm0 + movaps 64(%rsp), %xmm1 + movaps 80(%rsp), %xmm2 + movaps 96(%rsp), %xmm3 + movaps 112(%rsp), %xmm4 + movaps 128(%rsp), %xmm5 + movaps 144(%rsp), %xmm6 + movaps 160(%rsp), %xmm7 + + /* Remove space for stackLayout so stack arguments are placed + correctly for the call. */ +.LCFI5: + addq $176, %rsp +.LCFI6: + /* Call the user function. */ + call *-48(%rbp) + + /* Make stack space for the return_value struct. */ + subq $64, %rsp + + /* Fill in all potential return values to this struct. */ + movq %rax, (%rsp) + movq %rdx, 8(%rsp) + movaps %xmm0, 16(%rsp) + movaps %xmm1, 32(%rsp) + fstpt 48(%rsp) + + /* Now call ffi_fill_return_value. */ + movq %rsp, %rdi /* struct return_value */ + movq -24(%rbp), %rsi /* ecif */ + movq -16(%rbp), %rax /* &ffi_fill_return_value */ + call *%rax /* call it */ + + /* And the work is done. */ + leave + ret +.LFE1: +.ffi_call_UNIX64_end: + .size ffi_call_UNIX64,.ffi_call_UNIX64_end-ffi_call_UNIX64 + +.text + .align 2 +.globl float2sse + .type float2sse,@function +float2sse: + /* Save the contents of this sse-float in a pointer. */ + movaps %xmm0, (%rdi) + ret + + .align 2 +.globl floatfloat2sse + .type floatfloat2sse,@function +floatfloat2sse: + /* Save the contents of these two sse-floats in a pointer. */ + movq (%rdi), %xmm0 + movaps %xmm0, (%rsi) + ret + + .align 2 +.globl double2sse + .type double2sse,@function +double2sse: + /* Save the contents of this sse-double in a pointer. */ + movaps %xmm0, (%rdi) + ret + + .align 2 +.globl sse2float + .type sse2float,@function +sse2float: + /* Save the contents of this sse-float in a pointer. */ + movaps (%rdi), %xmm0 + ret + + .align 2 +.globl sse2double + .type sse2double,@function +sse2double: + /* Save the contents of this pointer in a sse-double. */ + movaps (%rdi), %xmm0 + ret + + .align 2 +.globl sse2floatfloat + .type sse2floatfloat,@function +sse2floatfloat: + /* Save the contents of this pointer in two sse-floats. */ + movaps (%rdi), %xmm0 + movq %xmm0, (%rsi) + ret + +#endif /* __x86_64__ */ |