aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-06-21 14:50:42 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-06-21 14:50:42 +0000
commite15aeb042e63d6079534cc9cf0b4154a0a996f9d (patch)
tree9243fb80a4f9f9fccf873054ec277219c2b92d65
parent346fc30ba1b84cca643e0d970175358d79554d8c (diff)
parent4a02d39b203e353f4b915a08e1d45876f2f38097 (diff)
downloadlibffi-android12-mainline-cellbroadcast-release.tar.gz
Change-Id: I5e14f552d53ee85a733824e11e7c68bdd4410da4
-rw-r--r--.appveyor.yml66
-rw-r--r--.gitattributes4
-rw-r--r--.github/issue_template.md10
-rw-r--r--.gitignore37
-rw-r--r--.travis.yml75
-rwxr-xr-x.travis/ar-lib270
-rw-r--r--.travis/bfin-sim.exp58
-rwxr-xr-x.travis/build-cross-in-container.sh17
-rwxr-xr-x.travis/build-in-container.sh12
-rwxr-xr-x.travis/build.sh142
-rwxr-xr-x.travis/compile351
-rwxr-xr-x.travis/install.sh56
-rw-r--r--.travis/m32r-sim.exp58
-rw-r--r--.travis/moxie-sim.exp60
-rw-r--r--.travis/or1k-sim.exp58
-rw-r--r--.travis/site.exp27
-rw-r--r--.travis/wine-sim.exp55
-rw-r--r--Android.bp65
-rw-r--r--ChangeLog.old7407
-rw-r--r--LICENSE2
-rw-r--r--LICENSE-BUILDTOOLS353
-rw-r--r--METADATA20
-rw-r--r--Makefile.am333
-rw-r--r--NOTICE21
-rw-r--r--README.md477
-rw-r--r--acinclude.m4387
-rwxr-xr-xautogen.sh2
-rw-r--r--config.guess1466
-rw-r--r--config.sub1836
-rw-r--r--configure.ac389
-rw-r--r--configure.host303
-rw-r--r--doc/Makefile.am3
-rw-r--r--doc/libffi.texi309
-rw-r--r--doc/version.texi8
-rw-r--r--generate-darwin-source-and-headers.py34
-rw-r--r--include/Makefile.am6
-rw-r--r--include/ffi.h.in186
-rw-r--r--include/ffi_cfi.h55
-rw-r--r--include/ffi_common.h25
-rw-r--r--libffi.map.in80
-rw-r--r--libffi.pc.in2
-rw-r--r--libffi.xcodeproj/project.pbxproj524
-rw-r--r--libtool-version2
-rw-r--r--linux-arm/fficonfig.h6
-rw-r--r--linux-arm64/fficonfig.h6
-rw-r--r--linux-x86/ffi.h2
-rw-r--r--linux-x86/fficonfig.h10
-rw-r--r--m4/asmcfi.m42
-rw-r--r--m4/ax_append_flag.m461
-rw-r--r--m4/ax_cc_maxopt.m429
-rw-r--r--m4/ax_cflags_warn_all.m48
-rw-r--r--m4/ax_check_compile_flag.m443
-rw-r--r--m4/ax_compiler_vendor.m414
-rw-r--r--m4/ax_configure_args.m437
-rw-r--r--m4/ax_enable_builddir.m413
-rw-r--r--m4/ax_gcc_archflag.m4164
-rw-r--r--m4/ax_gcc_x86_cpuid.m426
-rw-r--r--m4/ax_require_defined.m437
-rw-r--r--make_sunver.pl333
-rw-r--r--msvc_build/aarch64/Ffi_staticLib.sln33
-rw-r--r--msvc_build/aarch64/Ffi_staticLib.vcxproj130
-rw-r--r--msvc_build/aarch64/Ffi_staticLib.vcxproj.filters57
-rw-r--r--msvc_build/aarch64/Ffi_staticLib.vcxproj.user4
-rw-r--r--msvc_build/aarch64/aarch64_include/ffi.h511
-rw-r--r--msvc_build/aarch64/aarch64_include/fficonfig.h219
-rwxr-xr-xmsvcc.sh128
-rw-r--r--src/aarch64/ffi.c1602
-rw-r--r--src/aarch64/ffitarget.h47
-rw-r--r--src/aarch64/internal.h67
-rw-r--r--src/aarch64/sysv.S625
-rw-r--r--src/aarch64/win64_armasm.S506
-rw-r--r--src/alpha/ffi.c429
-rw-r--r--src/alpha/ffitarget.h4
-rw-r--r--src/alpha/internal.h23
-rw-r--r--src/alpha/osf.S427
-rw-r--r--src/arc/ffi.c6
-rw-r--r--src/arm/ffi.c1281
-rw-r--r--src/arm/ffitarget.h32
-rw-r--r--src/arm/internal.h7
-rw-r--r--src/arm/sysv.S714
-rw-r--r--src/arm/sysv_msvc_arm32.S311
-rw-r--r--src/closures.c410
-rw-r--r--src/cris/ffi.c4
-rw-r--r--src/dlmalloc.c9
-rw-r--r--src/frv/ffi.c4
-rw-r--r--src/ia64/ffi.c30
-rw-r--r--src/ia64/ffitarget.h3
-rw-r--r--src/ia64/unix.S9
-rw-r--r--src/java_raw_api.c6
-rw-r--r--src/m32r/ffi.c2
-rw-r--r--src/m68k/ffi.c4
-rw-r--r--src/m68k/sysv.S29
-rw-r--r--src/m88k/ffi.c8
-rw-r--r--src/metag/ffi.c14
-rw-r--r--src/microblaze/ffi.c10
-rw-r--r--src/mips/ffi.c148
-rw-r--r--src/mips/ffitarget.h21
-rw-r--r--src/mips/n32.S151
-rw-r--r--src/mips/o32.S175
-rw-r--r--src/moxie/eabi.S2
-rw-r--r--src/moxie/ffi.c27
-rw-r--r--src/nios2/ffi.c4
-rw-r--r--src/pa/linux.S25
-rw-r--r--src/powerpc/aix.S240
-rw-r--r--src/powerpc/aix_closure.S253
-rw-r--r--src/powerpc/asm.h4
-rw-r--r--src/powerpc/darwin_closure.S6
-rw-r--r--src/powerpc/ffi.c50
-rw-r--r--src/powerpc/ffi_darwin.c125
-rw-r--r--src/powerpc/ffi_linux64.c330
-rw-r--r--src/powerpc/ffi_powerpc.h54
-rw-r--r--src/powerpc/ffi_sysv.c240
-rw-r--r--src/powerpc/ffitarget.h37
-rw-r--r--src/powerpc/linux64.S184
-rw-r--r--src/powerpc/linux64_closure.S272
-rw-r--r--src/powerpc/ppc_closure.S165
-rw-r--r--src/powerpc/sysv.S149
-rw-r--r--src/prep_cif.c52
-rw-r--r--src/raw_api.c10
-rw-r--r--src/riscv/ffi.c481
-rw-r--r--src/riscv/ffitarget.h69
-rw-r--r--src/riscv/sysv.S293
-rw-r--r--src/s390/ffi.c596
-rw-r--r--src/s390/ffitarget.h1
-rw-r--r--src/s390/internal.h11
-rw-r--r--src/s390/sysv.S623
-rw-r--r--src/sparc/ffi.c861
-rw-r--r--src/sparc/ffi64.c608
-rw-r--r--src/sparc/ffitarget.h20
-rw-r--r--src/sparc/internal.h26
-rw-r--r--src/sparc/v8.S613
-rw-r--r--src/sparc/v9.S547
-rw-r--r--src/types.c4
-rw-r--r--src/vax/ffi.c4
-rw-r--r--src/x86/asmnames.h30
-rw-r--r--src/x86/darwin.S444
-rw-r--r--src/x86/darwin64.S416
-rw-r--r--src/x86/ffi.c1380
-rw-r--r--src/x86/ffi64.c428
-rw-r--r--src/x86/ffitarget.h91
-rw-r--r--src/x86/ffiw64.c311
-rw-r--r--src/x86/internal.h29
-rw-r--r--src/x86/internal64.h22
-rw-r--r--src/x86/sysv.S1470
-rw-r--r--src/x86/sysv_intel.S995
-rw-r--r--src/x86/unix64.S738
-rw-r--r--src/x86/win32.S1351
-rw-r--r--src/x86/win64.S737
-rw-r--r--src/x86/win64_intel.S237
-rw-r--r--src/xtensa/ffi.c4
-rw-r--r--src/xtensa/sysv.S7
-rw-r--r--testsuite/Makefile.am191
-rw-r--r--testsuite/lib/libffi.exp317
-rw-r--r--testsuite/libffi.bhaible/Makefile28
-rw-r--r--testsuite/libffi.bhaible/README78
-rw-r--r--testsuite/libffi.bhaible/alignof.h50
-rw-r--r--testsuite/libffi.bhaible/bhaible.exp63
-rw-r--r--testsuite/libffi.bhaible/test-call.c1745
-rw-r--r--testsuite/libffi.bhaible/test-callback.c2885
-rw-r--r--testsuite/libffi.bhaible/testcases.c743
-rw-r--r--testsuite/libffi.call/align_mixed.c46
-rw-r--r--testsuite/libffi.call/align_stdcall.c46
-rw-r--r--testsuite/libffi.call/call.exp31
-rw-r--r--testsuite/libffi.call/ffitest.h5
-rw-r--r--testsuite/libffi.call/float1.c4
-rw-r--r--testsuite/libffi.call/float2.c27
-rw-r--r--testsuite/libffi.call/float3.c6
-rw-r--r--testsuite/libffi.call/offsets.c46
-rw-r--r--testsuite/libffi.call/pr1172638.c127
-rw-r--r--testsuite/libffi.call/return_ldl.c2
-rw-r--r--testsuite/libffi.call/struct10.c57
-rw-r--r--testsuite/libffi.call/va_1.c2
-rw-r--r--testsuite/libffi.closures/closure.exp67
-rw-r--r--testsuite/libffi.closures/closure_fn0.c89
-rw-r--r--testsuite/libffi.closures/closure_fn1.c81
-rw-r--r--testsuite/libffi.closures/closure_fn2.c81
-rw-r--r--testsuite/libffi.closures/closure_fn3.c82
-rw-r--r--testsuite/libffi.closures/closure_fn4.c89
-rw-r--r--testsuite/libffi.closures/closure_fn5.c92
-rw-r--r--testsuite/libffi.closures/closure_fn6.c90
-rw-r--r--testsuite/libffi.closures/closure_loc_fn0.c95
-rw-r--r--testsuite/libffi.closures/closure_simple.c55
-rw-r--r--testsuite/libffi.closures/cls_12byte.c94
-rw-r--r--testsuite/libffi.closures/cls_16byte.c95
-rw-r--r--testsuite/libffi.closures/cls_18byte.c96
-rw-r--r--testsuite/libffi.closures/cls_19byte.c102
-rw-r--r--testsuite/libffi.closures/cls_1_1byte.c89
-rw-r--r--testsuite/libffi.closures/cls_20byte.c91
-rw-r--r--testsuite/libffi.closures/cls_20byte1.c93
-rw-r--r--testsuite/libffi.closures/cls_24byte.c113
-rw-r--r--testsuite/libffi.closures/cls_2byte.c90
-rw-r--r--testsuite/libffi.closures/cls_3_1byte.c95
-rw-r--r--testsuite/libffi.closures/cls_3byte1.c90
-rw-r--r--testsuite/libffi.closures/cls_3byte2.c90
-rw-r--r--testsuite/libffi.closures/cls_3float.c95
-rw-r--r--testsuite/libffi.closures/cls_4_1byte.c98
-rw-r--r--testsuite/libffi.closures/cls_4byte.c90
-rw-r--r--testsuite/libffi.closures/cls_5_1_byte.c109
-rw-r--r--testsuite/libffi.closures/cls_5byte.c98
-rw-r--r--testsuite/libffi.closures/cls_64byte.c124
-rw-r--r--testsuite/libffi.closures/cls_6_1_byte.c113
-rw-r--r--testsuite/libffi.closures/cls_6byte.c99
-rw-r--r--testsuite/libffi.closures/cls_7_1_byte.c117
-rw-r--r--testsuite/libffi.closures/cls_7byte.c97
-rw-r--r--testsuite/libffi.closures/cls_8byte.c88
-rw-r--r--testsuite/libffi.closures/cls_9byte1.c90
-rw-r--r--testsuite/libffi.closures/cls_9byte2.c91
-rw-r--r--testsuite/libffi.closures/cls_align_double.c93
-rw-r--r--testsuite/libffi.closures/cls_align_float.c91
-rw-r--r--testsuite/libffi.closures/cls_align_longdouble.c92
-rw-r--r--testsuite/libffi.closures/cls_align_longdouble_split.c132
-rw-r--r--testsuite/libffi.closures/cls_align_longdouble_split2.c115
-rw-r--r--testsuite/libffi.closures/cls_align_pointer.c95
-rw-r--r--testsuite/libffi.closures/cls_align_sint16.c91
-rw-r--r--testsuite/libffi.closures/cls_align_sint32.c91
-rw-r--r--testsuite/libffi.closures/cls_align_sint64.c92
-rw-r--r--testsuite/libffi.closures/cls_align_uint16.c91
-rw-r--r--testsuite/libffi.closures/cls_align_uint32.c91
-rw-r--r--testsuite/libffi.closures/cls_align_uint64.c93
-rw-r--r--testsuite/libffi.closures/cls_dbls_struct.c66
-rw-r--r--testsuite/libffi.closures/cls_double.c43
-rw-r--r--testsuite/libffi.closures/cls_double_va.c61
-rw-r--r--testsuite/libffi.closures/cls_float.c42
-rw-r--r--testsuite/libffi.closures/cls_longdouble.c105
-rw-r--r--testsuite/libffi.closures/cls_longdouble_va.c61
-rw-r--r--testsuite/libffi.closures/cls_many_mixed_args.c70
-rw-r--r--testsuite/libffi.closures/cls_many_mixed_float_double.c55
-rw-r--r--testsuite/libffi.closures/cls_multi_schar.c74
-rw-r--r--testsuite/libffi.closures/cls_multi_sshort.c74
-rw-r--r--testsuite/libffi.closures/cls_multi_sshortchar.c86
-rw-r--r--testsuite/libffi.closures/cls_multi_uchar.c91
-rw-r--r--testsuite/libffi.closures/cls_multi_ushort.c74
-rw-r--r--testsuite/libffi.closures/cls_multi_ushortchar.c86
-rw-r--r--testsuite/libffi.closures/cls_pointer.c74
-rw-r--r--testsuite/libffi.closures/cls_pointer_stack.c142
-rw-r--r--testsuite/libffi.closures/cls_schar.c44
-rw-r--r--testsuite/libffi.closures/cls_sint.c42
-rw-r--r--testsuite/libffi.closures/cls_sshort.c42
-rw-r--r--testsuite/libffi.closures/cls_struct_va1.c114
-rw-r--r--testsuite/libffi.closures/cls_uchar.c42
-rw-r--r--testsuite/libffi.closures/cls_uchar_va.c44
-rw-r--r--testsuite/libffi.closures/cls_uint.c43
-rw-r--r--testsuite/libffi.closures/cls_uint_va.c45
-rw-r--r--testsuite/libffi.closures/cls_ulong_va.c45
-rw-r--r--testsuite/libffi.closures/cls_ulonglong.c47
-rw-r--r--testsuite/libffi.closures/cls_ushort.c43
-rw-r--r--testsuite/libffi.closures/cls_ushort_va.c44
-rw-r--r--testsuite/libffi.closures/err_bad_abi.c36
-rw-r--r--testsuite/libffi.closures/ffitest.h138
-rw-r--r--testsuite/libffi.closures/huge_struct.c341
-rw-r--r--testsuite/libffi.closures/nested_struct.c152
-rw-r--r--testsuite/libffi.closures/nested_struct1.c161
-rw-r--r--testsuite/libffi.closures/nested_struct10.c134
-rw-r--r--testsuite/libffi.closures/nested_struct11.c121
-rw-r--r--testsuite/libffi.closures/nested_struct2.c110
-rw-r--r--testsuite/libffi.closures/nested_struct3.c111
-rw-r--r--testsuite/libffi.closures/nested_struct4.c111
-rw-r--r--testsuite/libffi.closures/nested_struct5.c112
-rw-r--r--testsuite/libffi.closures/nested_struct6.c131
-rw-r--r--testsuite/libffi.closures/nested_struct7.c111
-rw-r--r--testsuite/libffi.closures/nested_struct8.c131
-rw-r--r--testsuite/libffi.closures/nested_struct9.c131
-rw-r--r--testsuite/libffi.closures/problem1.c90
-rw-r--r--testsuite/libffi.closures/stret_large.c145
-rw-r--r--testsuite/libffi.closures/stret_large2.c148
-rw-r--r--testsuite/libffi.closures/stret_medium.c124
-rw-r--r--testsuite/libffi.closures/stret_medium2.c125
-rw-r--r--testsuite/libffi.closures/testclosure.c70
-rw-r--r--testsuite/libffi.closures/unwindtest.cc117
-rw-r--r--testsuite/libffi.closures/unwindtest_ffi_call.cc54
-rw-r--r--testsuite/libffi.complex/cls_align_complex.inc91
-rw-r--r--testsuite/libffi.complex/cls_align_complex_double.c10
-rw-r--r--testsuite/libffi.complex/cls_align_complex_float.c10
-rw-r--r--testsuite/libffi.complex/cls_align_complex_longdouble.c10
-rw-r--r--testsuite/libffi.complex/cls_complex.inc42
-rw-r--r--testsuite/libffi.complex/cls_complex_double.c10
-rw-r--r--testsuite/libffi.complex/cls_complex_float.c10
-rw-r--r--testsuite/libffi.complex/cls_complex_longdouble.c10
-rw-r--r--testsuite/libffi.complex/cls_complex_struct.inc71
-rw-r--r--testsuite/libffi.complex/cls_complex_struct_double.c10
-rw-r--r--testsuite/libffi.complex/cls_complex_struct_float.c10
-rw-r--r--testsuite/libffi.complex/cls_complex_struct_longdouble.c10
-rw-r--r--testsuite/libffi.complex/cls_complex_va.inc80
-rw-r--r--testsuite/libffi.complex/cls_complex_va_double.c10
-rw-r--r--testsuite/libffi.complex/cls_complex_va_float.c16
-rw-r--r--testsuite/libffi.complex/cls_complex_va_longdouble.c10
-rw-r--r--testsuite/libffi.complex/complex.exp36
-rw-r--r--testsuite/libffi.complex/complex.inc51
-rw-r--r--testsuite/libffi.complex/complex_defs_double.inc7
-rw-r--r--testsuite/libffi.complex/complex_defs_float.inc7
-rw-r--r--testsuite/libffi.complex/complex_defs_longdouble.inc7
-rw-r--r--testsuite/libffi.complex/complex_double.c10
-rw-r--r--testsuite/libffi.complex/complex_float.c10
-rw-r--r--testsuite/libffi.complex/complex_int.c86
-rw-r--r--testsuite/libffi.complex/complex_longdouble.c10
-rw-r--r--testsuite/libffi.complex/ffitest.h1
-rw-r--r--testsuite/libffi.complex/many_complex.inc78
-rw-r--r--testsuite/libffi.complex/many_complex_double.c10
-rw-r--r--testsuite/libffi.complex/many_complex_float.c10
-rw-r--r--testsuite/libffi.complex/many_complex_longdouble.c10
-rw-r--r--testsuite/libffi.complex/return_complex.inc37
-rw-r--r--testsuite/libffi.complex/return_complex1.inc41
-rw-r--r--testsuite/libffi.complex/return_complex1_double.c10
-rw-r--r--testsuite/libffi.complex/return_complex1_float.c10
-rw-r--r--testsuite/libffi.complex/return_complex1_longdouble.c10
-rw-r--r--testsuite/libffi.complex/return_complex2.inc44
-rw-r--r--testsuite/libffi.complex/return_complex2_double.c10
-rw-r--r--testsuite/libffi.complex/return_complex2_float.c10
-rw-r--r--testsuite/libffi.complex/return_complex2_longdouble.c10
-rw-r--r--testsuite/libffi.complex/return_complex_double.c10
-rw-r--r--testsuite/libffi.complex/return_complex_float.c10
-rw-r--r--testsuite/libffi.complex/return_complex_longdouble.c10
-rw-r--r--testsuite/libffi.go/aa-direct.c34
-rw-r--r--testsuite/libffi.go/closure1.c28
-rw-r--r--testsuite/libffi.go/ffitest.h1
-rw-r--r--testsuite/libffi.go/go.exp36
-rw-r--r--testsuite/libffi.go/static-chain.h19
317 files changed, 46429 insertions, 10599 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 00000000..ece8a948
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,66 @@
+shallow_clone: true
+
+# We're currently only testing libffi built with Microsoft's
+# tools.
+# This matrix should be expanded to include at least:
+# 32- and 64-bit gcc/cygwin
+# 32- and 64-bit gcc/mingw
+# 32- and 64-bit clang/mingw
+# and perhaps more.
+
+image: Visual Studio 2017
+platform:
+ - x64
+ - x86
+ - arm
+ - arm64
+
+environment:
+ global:
+ CYG_ROOT: C:/cygwin
+ CYG_CACHE: C:/cygwin/var/cache/setup
+ CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin/
+ matrix:
+ - VSVER: 15
+
+install:
+ - ps: >-
+ If ($env:Platform -Match "x86") {
+ $env:VCVARS_PLATFORM="x86"
+ $env:BUILD="i686-pc-cygwin"
+ $env:HOST="i686-pc-cygwin"
+ $env:MSVCC="/cygdrive/c/projects/libffi/msvcc.sh"
+ $env:SRC_ARCHITECTURE="x86"
+ } ElseIf ($env:Platform -Match "arm64") {
+ $env:VCVARS_PLATFORM="x86_arm64"
+ $env:BUILD="i686-pc-cygwin"
+ $env:HOST="aarch64-w64-cygwin"
+ $env:MSVCC="/cygdrive/c/projects/libffi/msvcc.sh -marm64"
+ $env:SRC_ARCHITECTURE="aarch64"
+ } ElseIf ($env:Platform -Match "arm") {
+ $env:VCVARS_PLATFORM="x86_arm"
+ $env:BUILD="i686-pc-cygwin"
+ $env:HOST="arm-w32-cygwin"
+ $env:MSVCC="/cygdrive/c/projects/libffi/msvcc.sh -marm"
+ $env:SRC_ARCHITECTURE="arm"
+ } Else {
+ $env:VCVARS_PLATFORM="amd64"
+ $env:BUILD="x86_64-w64-cygwin"
+ $env:HOST="x86_64-w64-cygwin"
+ $env:MSVCC="/cygdrive/c/projects/libffi/msvcc.sh -m64"
+ $env:SRC_ARCHITECTURE="x86"
+ }
+ - 'appveyor DownloadFile https://cygwin.com/setup-x86.exe -FileName setup.exe'
+ - 'setup.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P dejagnu >NUL'
+ - '%CYG_ROOT%/bin/bash -lc "cygcheck -dc cygwin"'
+ - echo call VsDevCmd to set VS150COMNTOOLS
+ - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"
+ - ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS"))
+ - echo "Using Visual Studio %VSVER%.0 at %VSCOMNTOOLS%"
+ - call "%VSCOMNTOOLS%..\..\vc\Auxiliary\Build\vcvarsall.bat" %VCVARS_PLATFORM%
+
+build_script:
+ - c:\cygwin\bin\sh -lc "(cd $OLDPWD; ./autogen.sh;)"
+ - c:\cygwin\bin\sh -lc "(cd $OLDPWD; ./configure CC='%MSVCC%' CXX='%MSVCC%' LD='link' CPP='cl -nologo -EP' CXXCPP='cl -nologo -EP' CPPFLAGS='-DFFI_BUILDING_DLL' AR='/cygdrive/c/projects/libffi/.travis/ar-lib lib' NM='dumpbin -symbols' STRIP=':' --build=$BUILD --host=$HOST;)"
+ - c:\cygwin\bin\sh -lc "(cd $OLDPWD; cp src/%SRC_ARCHITECTURE%/ffitarget.h include; make; find .;)"
+ - c:\cygwin\bin\sh -lc "(cd $OLDPWD; cp `find . -name 'libffi-?.dll'` $HOST/testsuite/; make check; cat `find ./ -name libffi.log`)"
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..f7d3833e
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,4 @@
+* text=auto
+
+*.sln text eol=crlf
+*.vcxproj* text eol=crlf
diff --git a/.github/issue_template.md b/.github/issue_template.md
new file mode 100644
index 00000000..e197e2ce
--- /dev/null
+++ b/.github/issue_template.md
@@ -0,0 +1,10 @@
+## System Details
+
+<!--- What platform are you working with? eg. the output of config.guess -->
+<!--- Provide any toolchain details here. eg. compiler version -->
+
+## Problems Description
+
+<!--- Provide a description of the problem here -->
+<!--- If this is a configure-time problem, attach config.log -->
+<!--- If this is a testsuite problem, attach the relevant log output -->
diff --git a/.gitignore b/.gitignore
index 287489c5..5d396894 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,38 @@
+.libs
+.deps
+*.o
+*.lo
+.dirstamp
+*.la
+Makefile
+!testsuite/libffi.bhaible/Makefile
+Makefile.in
+aclocal.m4
+compile
+!.travis/compile
+configure
+depcomp
+doc/libffi.info
+*~
+fficonfig.h.in
+fficonfig.h
include/ffi.h
+include/ffitarget.h
+install-sh
+libffi.pc
+libtool
+libtool-ldflags
+ltmain.sh
+m4/libtool.m4
+m4/lt*.m4
+mdate-sh
+missing
+stamp-h1
+libffi*gz
+autom4te.cache
+libffi.xcodeproj/xcuserdata
+libffi.xcodeproj/project.xcworkspace
+build_*/
+darwin_*/
+src/arm/trampoline.S
+**/texinfo.tex
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..7cd3a186
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,75 @@
+---
+sudo: required
+
+language: cpp
+
+# For qemu-powered targets, get the list of supported processors from
+# travis by setting QEMU_CPU=help, then set -mcpu= for the compilers
+# accordingly.
+
+matrix:
+ include:
+ - os: linux
+ env: HOST=or1k-elf RUNTESTFLAGS="--target_board or1k-sim" DEJAGNU="/opt/.travis/site.exp"
+ - os: linux
+ env: HOST=m32r-elf RUNTESTFLAGS="--target_board m32r-sim" DEJAGNU="/opt/.travis/site.exp"
+ - os: linux
+ env: HOST=bfin-elf RUNTESTFLAGS="--target_board bfin-sim" DEJAGNU="/opt/.travis/site.exp"
+# This configuration is still using the native x86 toolchain?
+# - os: osx
+# env: HOST=aarch64-apple-darwin13
+ - os: osx
+ env: HOST=x86_64-apple-darwin10
+ - os: linux
+ env: HOST=x86_64-w64-mingw32 MEVAL='export CC="x86_64-w64-mingw32-gcc" && CXX="x86_64-w64-mingw32-g++" RUNTESTFLAGS="--target_board wine-sim" DEJAGNU="$TRAVIS_BUILD_DIR/.travis/site.exp" CONFIGURE_OPTIONS=--disable-shared LIBFFI_TEST_OPTIMIZATION="-O2"
+ - os: linux
+ env: HOST=sh4-linux-gnu CONFIGURE_OPTIONS=--disable-shared QEMU_LD_PREFIX=/usr/sh4-linux-gnu
+ - os: linux
+ env: HOST=alpha-linux-gnu CONFIGURE_OPTIONS=--disable-shared QEMU_LD_PREFIX=/usr/alpha-linux-gnu
+ - os: linux
+ env: HOST=m68k-linux-gnu MEVAL='export CC="m68k-linux-gnu-gcc-8 -mcpu=547x" && CXX="m68k-linux-gnu-g++-8 -mcpu=547x"' CONFIGURE_OPTIONS=--disable-shared QEMU_LD_PREFIX=/usr/m68k-linux-gnu QEMU_CPU=cfv4e
+ - os: linux
+ env: HOST=s390x-linux-gnu MEVAL='export CC="s390x-linux-gnu-gcc-8" && CXX="s390x-linux-gnu-g++-8"' CONFIGURE_OPTIONS=--disable-shared QEMU_LD_PREFIX=/usr/s390x-linux-gnu QEMU_CPU=max
+ - os: linux
+ env: HOST=arm32v7-linux-gnu LIBFFI_TEST_OPTIMIZATION="-O0"
+ - os: linux
+ env: HOST=arm32v7-linux-gnu LIBFFI_TEST_OPTIMIZATION="-O2"
+ - os: linux
+ env: HOST=arm32v7-linux-gnu LIBFFI_TEST_OPTIMIZATION="-O2 -fomit-frame-pointer"
+# The sparc64 linux system in the GCC compile farm is non-responsive.
+# - os: linux
+# env: HOST=sparc64-linux-gnu
+# Having problems getting logs for this one...
+# - os: linux
+# env: HOST=powerpc64le-unknown-linux-gnu
+# - os: linux
+# env: HOST=aarch64-linux-gnu
+# The mips64 linux system in the GCC compile farm is not allowing logins
+# - os: linux
+# env: HOST=mips64el-linux-gnu
+ - os: linux
+ compiler: gcc
+ env: HOST=i386-pc-linux-gnu MEVAL='export CC="$CC -m32" && CXX="$CXX -m32"'
+ - os: linux
+ compiler: gcc
+ - os: linux
+ compiler: gcc
+ env: CONFIGURE_OPTIONS=--disable-shared
+ - os: linux
+ compiler: clang
+ - os: linux
+ compiler: clang
+ env: CONFIGURE_OPTIONS=--disable-shared
+ - os: linux
+ env: HOST=moxie-elf MEVAL='export PATH=/opt/moxielogic/bin:$PATH && CC=moxie-elf-gcc && CXX=moxie-elf-g++' LDFLAGS=-Tsim.ld RUNTESTFLAGS="--target_board moxie-sim" DEJAGNU="$TRAVIS_BUILD_DIR/.travis/site.exp"
+
+before_install:
+ - if test x"$MEVAL" != x; then eval ${MEVAL}; fi
+
+install:
+ - travis_wait 30 ./.travis/install.sh
+
+script:
+ - if ! test x"$MEVAL" = x; then eval ${MEVAL}; fi
+ - travis_wait 115 sleep infinity &
+ - ./.travis/build.sh
diff --git a/.travis/ar-lib b/.travis/ar-lib
new file mode 100755
index 00000000..0baa4f60
--- /dev/null
+++ b/.travis/ar-lib
@@ -0,0 +1,270 @@
+#! /bin/sh
+# Wrapper for Microsoft lib.exe
+
+me=ar-lib
+scriptversion=2012-03-01.08; # UTC
+
+# Copyright (C) 2010-2018 Free Software Foundation, Inc.
+# Written by Peter Rosin <peda@lysator.liu.se>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+
+# func_error message
+func_error ()
+{
+ echo "$me: $1" 1>&2
+ exit 1
+}
+
+file_conv=
+
+# func_file_conv build_file
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv in
+ mingw)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_at_file at_file operation archive
+# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE
+# for each of them.
+# When interpreting the content of the @FILE, do NOT use func_file_conv,
+# since the user would need to supply preconverted file names to
+# binutils ar, at least for MinGW.
+func_at_file ()
+{
+ operation=$2
+ archive=$3
+ at_file_contents=`cat "$1"`
+ eval set x "$at_file_contents"
+ shift
+
+ for member
+ do
+ $AR -NOLOGO $operation:"$member" "$archive" || exit $?
+ done
+}
+
+case $1 in
+ '')
+ func_error "no command. Try '$0 --help' for more information."
+ ;;
+ -h | --h*)
+ cat <<EOF
+Usage: $me [--help] [--version] PROGRAM ACTION ARCHIVE [MEMBER...]
+
+Members may be specified in a file named with @FILE.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "$me, version $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test $# -lt 3; then
+ func_error "you must specify a program, an action and an archive"
+fi
+
+AR=$1
+shift
+while :
+do
+ if test $# -lt 2; then
+ func_error "you must specify a program, an action and an archive"
+ fi
+ case $1 in
+ -lib | -LIB \
+ | -ltcg | -LTCG \
+ | -machine* | -MACHINE* \
+ | -subsystem* | -SUBSYSTEM* \
+ | -verbose | -VERBOSE \
+ | -wx* | -WX* )
+ AR="$AR $1"
+ shift
+ ;;
+ *)
+ action=$1
+ shift
+ break
+ ;;
+ esac
+done
+orig_archive=$1
+shift
+func_file_conv "$orig_archive"
+archive=$file
+
+# strip leading dash in $action
+action=${action#-}
+
+delete=
+extract=
+list=
+quick=
+replace=
+index=
+create=
+
+while test -n "$action"
+do
+ case $action in
+ d*) delete=yes ;;
+ x*) extract=yes ;;
+ t*) list=yes ;;
+ q*) quick=yes ;;
+ r*) replace=yes ;;
+ s*) index=yes ;;
+ S*) ;; # the index is always updated implicitly
+ c*) create=yes ;;
+ u*) ;; # TODO: don't ignore the update modifier
+ v*) ;; # TODO: don't ignore the verbose modifier
+ *)
+ func_error "unknown action specified"
+ ;;
+ esac
+ action=${action#?}
+done
+
+case $delete$extract$list$quick$replace,$index in
+ yes,* | ,yes)
+ ;;
+ yesyes*)
+ func_error "more than one action specified"
+ ;;
+ *)
+ func_error "no action specified"
+ ;;
+esac
+
+if test -n "$delete"; then
+ if test ! -f "$orig_archive"; then
+ func_error "archive not found"
+ fi
+ for member
+ do
+ case $1 in
+ @*)
+ func_at_file "${1#@}" -REMOVE "$archive"
+ ;;
+ *)
+ func_file_conv "$1"
+ $AR -NOLOGO -REMOVE:"$file" "$archive" || exit $?
+ ;;
+ esac
+ done
+
+elif test -n "$extract"; then
+ if test ! -f "$orig_archive"; then
+ func_error "archive not found"
+ fi
+ if test $# -gt 0; then
+ for member
+ do
+ case $1 in
+ @*)
+ func_at_file "${1#@}" -EXTRACT "$archive"
+ ;;
+ *)
+ func_file_conv "$1"
+ $AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $?
+ ;;
+ esac
+ done
+ else
+ $AR -NOLOGO -LIST "$archive" | sed -e 's/\\/\\\\/g' | while read member
+ do
+ $AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $?
+ done
+ fi
+
+elif test -n "$quick$replace"; then
+ if test ! -f "$orig_archive"; then
+ if test -z "$create"; then
+ echo "$me: creating $orig_archive"
+ fi
+ orig_archive=
+ else
+ orig_archive=$archive
+ fi
+
+ for member
+ do
+ case $1 in
+ @*)
+ func_file_conv "${1#@}"
+ set x "$@" "@$file"
+ ;;
+ *)
+ func_file_conv "$1"
+ set x "$@" "$file"
+ ;;
+ esac
+ shift
+ shift
+ done
+
+ if test -n "$orig_archive"; then
+ $AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $?
+ else
+ $AR -NOLOGO -OUT:"$archive" "$@" || exit $?
+ fi
+
+elif test -n "$list"; then
+ if test ! -f "$orig_archive"; then
+ func_error "archive not found"
+ fi
+ $AR -NOLOGO -LIST "$archive" || exit $?
+fi
diff --git a/.travis/bfin-sim.exp b/.travis/bfin-sim.exp
new file mode 100644
index 00000000..13cd0ff8
--- /dev/null
+++ b/.travis/bfin-sim.exp
@@ -0,0 +1,58 @@
+# Copyright (C) 2010, 2019 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This is a list of toolchains that are supported on this board.
+set_board_info target_install {bfin-elf}
+
+# Load the generic configuration for this board. This will define a basic set
+# of routines needed by the tool to communicate with the board.
+load_generic_config "sim"
+
+# basic-sim.exp is a basic description for the standard Cygnus simulator.
+load_base_board_description "basic-sim"
+
+# "bfin" is the name of the sim subdir in devo/sim.
+setup_sim bfin
+
+# No multilib options needed by default.
+process_multilib_options ""
+
+# We only support newlib on this target. We assume that all multilib
+# options have been specified before we get here.
+
+set_board_info compiler "[find_gcc]"
+set_board_info cflags "[libgloss_include_flags] [newlib_include_flags]"
+set_board_info ldflags "[libgloss_link_flags] [newlib_link_flags]"
+
+# Configuration settings for testsuites
+set_board_info noargs 1
+set_board_info gdb,nosignals 1
+set_board_info gdb,noresults 1
+set_board_info gdb,cannot_call_functions 1
+set_board_info gdb,skip_float_tests 1
+set_board_info gdb,can_reverse 1
+set_board_info gdb,use_precord 1
+
+# More time is needed
+set_board_info gcc,timeout 800
+set_board_info gdb,timeout 60
+
+# Used by a few gcc.c-torture testcases to delimit how large the stack can
+# be.
+set_board_info gcc,stack_size 5000
+
diff --git a/.travis/build-cross-in-container.sh b/.travis/build-cross-in-container.sh
new file mode 100755
index 00000000..11447dbc
--- /dev/null
+++ b/.travis/build-cross-in-container.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+cd /opt
+
+set -x
+echo $PATH
+export PATH=/usr/local/bin:$PATH
+echo $PATH
+
+ls -l /usr/local/bin
+
+./configure --host=${HOST}
+make
+make dist
+make check RUNTESTFLAGS="-a $RUNTESTFLAGS" || true
+
+
diff --git a/.travis/build-in-container.sh b/.travis/build-in-container.sh
new file mode 100755
index 00000000..1a7fa76b
--- /dev/null
+++ b/.travis/build-in-container.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+cd /opt
+
+export QEMU_LD_PREFIX=/usr/${HOST}
+
+./configure ${HOST+--host=$HOST --disable-shared}
+make
+make dist
+make check RUNTESTFLAGS="-a $RUNTESTFLAGS" || true
+
+
diff --git a/.travis/build.sh b/.travis/build.sh
new file mode 100755
index 00000000..db596b3d
--- /dev/null
+++ b/.travis/build.sh
@@ -0,0 +1,142 @@
+#!/bin/bash
+
+set -x
+
+if [ -z ${QEMU_CPU+x} ]; then
+ export SET_QEMU_CPU=
+else
+ export SET_QEMU_CPU="-e QEMU_CPU=${QEMU_CPU}"
+fi
+
+# Default to podman where available, docker otherwise.
+# Override by setting the DOCKER environment variable.
+if test -z "$DOCKER"; then
+ which podman > /dev/null 2>&1
+ if [ $? != 0 ]; then
+ export DOCKER=docker
+ else
+ export DOCKER=podman
+ fi
+fi
+
+function build_cfarm()
+{
+ curl -u ${CFARM_AUTH} https://cfarm-test-libffi-libffi.apps.home.labdroid.net/test?host=${HOST}\&commit=${TRAVIS_COMMIT} | tee build.log
+ echo :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+ echo $(tail build.log | grep '^==LOGFILE==')
+ echo $(tail build.log | grep '^==LOGFILE==' | cut -b13-)
+ echo :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+ curl -u ${CFARM_AUTH} "$(tail build.log | grep '^==LOGFILE==' | cut -b13-)" > libffi.log
+
+ ./rlgl l https://rl.gl
+ ID=$(./rlgl start)
+ ./rlgl e --id=$ID --policy=https://github.com/libffi/rlgl-policy.git libffi.log
+ exit $?
+}
+
+function build_linux()
+{
+ ./autogen.sh
+ ./configure ${HOST+--host=$HOST} ${CONFIGURE_OPTIONS}
+ make
+ make dist
+ make check RUNTESTFLAGS="-a $RUNTESTFLAGS"
+
+ ./rlgl l https://rl.gl
+ ID=$(./rlgl start)
+ ./rlgl e --id=$ID --policy=https://github.com/libffi/rlgl-policy.git */testsuite/libffi.log
+ exit $?
+}
+
+function build_foreign_linux()
+{
+ ${DOCKER} run --rm -t -i -v `pwd`:/opt ${SET_QEMU_CPU} -e LIBFFI_TEST_OPTIMIZATION="${LIBFFI_TEST_OPTIMIZATION}" $2 bash -c /opt/.travis/build-in-container.sh
+
+ ./rlgl l https://rl.gl
+ ID=$(./rlgl start)
+ ./rlgl e --id=$ID --policy=https://github.com/libffi/rlgl-policy.git */testsuite/libffi.log
+ exit $?
+}
+
+function build_cross_linux()
+{
+ ${DOCKER} run --rm -t -i -v `pwd`:/opt ${SET_QEMU_CPU} -e HOST="${HOST}" -e CC="${HOST}-gcc-8 ${GCC_OPTIONS}" -e CXX="${HOST}-g++-8 ${GCC_OPTIONS}" -e LIBFFI_TEST_OPTIMIZATION="${LIBFFI_TEST_OPTIMIZATION}" moxielogic/cross-ci-build-container:latest bash -c /opt/.travis/build-in-container.sh
+
+ ./rlgl l https://rl.gl
+ ID=$(./rlgl start)
+ ./rlgl e --id=$ID --policy=https://github.com/libffi/rlgl-policy.git */testsuite/libffi.log
+ exit $?
+}
+
+function build_cross()
+{
+ ${DOCKER} pull quay.io/moxielogic/libffi-ci-${HOST}
+ ${DOCKER} run --rm -t -i -v `pwd`:/opt -e HOST="${HOST}" -e CC="${HOST}-gcc ${GCC_OPTIONS}" -e CXX="${HOST}-g++ ${GCC_OPTIONS}" -e TRAVIS_BUILD_DIR=/opt -e DEJAGNU="${DEJAGNU}" -e RUNTESTFLAGS="${RUNTESTFLAGS}" -e LIBFFI_TEST_OPTIMIZATION="${LIBFFI_TEST_OPTIMIZATION}" quay.io/moxielogic/libffi-ci-${HOST} bash -c /opt/.travis/build-cross-in-container.sh
+
+ ./rlgl l https://rl.gl
+ ID=$(./rlgl start)
+ ./rlgl e --id=$ID --policy=https://github.com/libffi/rlgl-policy.git */testsuite/libffi.log
+ exit $?
+}
+
+function build_ios()
+{
+ which python
+# export PYTHON_BIN=/usr/local/bin/python
+ ./generate-darwin-source-and-headers.py --only-ios
+ xcodebuild -showsdks
+ xcodebuild -project libffi.xcodeproj -target "libffi-iOS" -configuration Release -sdk iphoneos11.4
+ exit $?
+}
+
+function build_macosx()
+{
+ which python
+# export PYTHON_BIN=/usr/local/bin/python
+ ./generate-darwin-source-and-headers.py --only-osx
+ xcodebuild -showsdks
+ xcodebuild -project libffi.xcodeproj -target "libffi-Mac" -configuration Release -sdk macosx10.13
+ exit $?
+}
+
+case "$HOST" in
+ arm-apple-darwin*)
+ ./autogen.sh
+ build_ios
+ ;;
+ x86_64-apple-darwin*)
+ ./autogen.sh
+ build_macosx
+ ;;
+ arm32v7-linux-gnu)
+ ./autogen.sh
+ build_foreign_linux arm moxielogic/arm32v7-ci-build-container:latest
+ ;;
+ aarch64-linux-gnu| powerpc64le-unknown-linux-gnu | mips64el-linux-gnu | sparc64-linux-gnu)
+ build_cfarm
+ ;;
+ bfin-elf )
+ ./autogen.sh
+ GCC_OPTIONS=-msim build_cross
+ ;;
+ m32r-elf )
+ ./autogen.sh
+ build_cross
+ ;;
+ or1k-elf )
+ ./autogen.sh
+ build_cross
+ ;;
+ m68k-linux-gnu )
+ ./autogen.sh
+ GCC_OPTIONS=-mcpu=547x build_cross_linux
+ ;;
+ alpha-linux-gnu | sh4-linux-gnu | s390x-linux-gnu )
+ ./autogen.sh
+ build_cross_linux
+ ;;
+ *)
+ ./autogen.sh
+ build_linux
+ ;;
+esac
diff --git a/.travis/compile b/.travis/compile
new file mode 100755
index 00000000..655932a2
--- /dev/null
+++ b/.travis/compile
@@ -0,0 +1,351 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2018-03-27.18; # UTC
+
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" "" $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv/,$2, in
+ *,$file_conv,*)
+ ;;
+ mingw/*)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin/*)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine/*)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ if test -f "$dir/lib$lib.a"; then
+ found=yes
+ lib=$dir/lib$lib.a
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+ # Assume a capable shell
+ lib_path=
+ shared=:
+ linker_opts=
+ for arg
+ do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ eat=1
+ case $2 in
+ *.o | *.[oO][bB][jJ])
+ func_file_conv "$2"
+ set x "$@" -Fo"$file"
+ shift
+ ;;
+ *)
+ func_file_conv "$2"
+ set x "$@" -Fe"$file"
+ shift
+ ;;
+ esac
+ ;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -I*)
+ func_file_conv "${1#-I}" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -l*)
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
+ -L*)
+ func_cl_dashL "${1#-L}"
+ ;;
+ -static)
+ shared=false
+ ;;
+ -warn)
+ eat=1
+ ;;
+ -Wl,*)
+ arg=${1#-Wl,}
+ save_ifs="$IFS"; IFS=','
+ for flag in $arg; do
+ IFS="$save_ifs"
+ linker_opts="$linker_opts $flag"
+ done
+ IFS="$save_ifs"
+ ;;
+ -Xlinker)
+ eat=1
+ linker_opts="$linker_opts $2"
+ ;;
+ -*)
+ set x "$@" "$1"
+ shift
+ ;;
+ *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+ func_file_conv "$1"
+ set x "$@" -Tp"$file"
+ shift
+ ;;
+ *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+ func_file_conv "$1" mingw
+ set x "$@" "$file"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+ done
+ if test -n "$linker_opts"; then
+ linker_opts="-link$linker_opts"
+ fi
+ exec "$@" $linker_opts
+ exit 1
+}
+
+eat=
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
+ func_cl_wrapper "$@" # Doesn't return...
+ ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ # So we strip '-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no '-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # '.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/.travis/install.sh b/.travis/install.sh
new file mode 100755
index 00000000..eb7f80f3
--- /dev/null
+++ b/.travis/install.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+set -x
+
+if [[ $TRAVIS_OS_NAME != 'linux' ]]; then
+ brew update > brew-update.log 2>&1
+ # fix an issue with libtool on travis by reinstalling it
+ brew uninstall libtool;
+ brew install libtool dejagnu;
+
+ # Download and extract the rlgl client
+ wget -qO - https://rl.gl/cli/rlgl-darwin-amd64.tgz | \
+ tar --strip-components=2 -xvzf - ./rlgl/rlgl
+
+else
+
+ # Download and extract the rlgl client
+ wget -qO - http://rl.gl/cli/rlgl-linux-amd64.tgz | \
+ tar --strip-components=2 -xvzf - ./rlgl/rlgl
+
+ sudo apt-get clean # clear the cache
+ sudo apt-get update
+ case $HOST in
+ aarch64-linux-gnu | powerpc64le-unknown-linux-gnu | mips64el-linux-gnu | sparc64-linux-gnu)
+ ;;
+ alpha-linux-gnu | arm32v7-linux-gnu | m68k-linux-gnu | sh4-linux-gnu | s390x-linux-gnu )
+ sudo apt-get install qemu-user-static
+ ;;
+ hppa-linux-gnu )
+ sudo apt-get install -y qemu-user-static g++-5-hppa-linux-gnu
+ ;;
+ i386-pc-linux-gnu)
+ sudo apt-get install gcc-multilib g++-multilib;
+ ;;
+ moxie-elf)
+ echo 'deb https://repos.moxielogic.org:7114/MoxieLogic moxiedev main' | sudo tee -a /etc/apt/sources.list
+ sudo apt-get clean # clear the cache
+ sudo apt-get update ## -qq
+ sudo apt-get update
+ sudo apt-get install -y --allow-unauthenticated moxielogic-moxie-elf-gcc moxielogic-moxie-elf-gcc-c++ moxielogic-moxie-elf-gcc-libstdc++ moxielogic-moxie-elf-gdb-sim
+ ;;
+ x86_64-w64-mingw32)
+ sudo apt-get install gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 wine;
+ ;;
+ i686-w32-mingw32)
+ sudo apt-get install gcc-mingw-w64-i686 g++-mingw-w64-i686 wine;
+ ;;
+ esac
+ case $HOST in
+ arm32v7-linux-gnu | aarch64-linux-gnu | ppc64le-linux-gnu | s390x-linux-gnu)
+ # don't install host tools
+ ;;
+ *)
+ sudo apt-get install dejagnu texinfo sharutils
+ ;;
+ esac
+fi
diff --git a/.travis/m32r-sim.exp b/.travis/m32r-sim.exp
new file mode 100644
index 00000000..b3341f22
--- /dev/null
+++ b/.travis/m32r-sim.exp
@@ -0,0 +1,58 @@
+# Copyright (C) 2010, 2019 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This is a list of toolchains that are supported on this board.
+set_board_info target_install {m32r-elf}
+
+# Load the generic configuration for this board. This will define a basic set
+# of routines needed by the tool to communicate with the board.
+load_generic_config "sim"
+
+# basic-sim.exp is a basic description for the standard Cygnus simulator.
+load_base_board_description "basic-sim"
+
+# "m32r" is the name of the sim subdir in devo/sim.
+setup_sim m32r
+
+# No multilib options needed by default.
+process_multilib_options ""
+
+# We only support newlib on this target. We assume that all multilib
+# options have been specified before we get here.
+
+set_board_info compiler "[find_gcc]"
+set_board_info cflags "[libgloss_include_flags] [newlib_include_flags]"
+set_board_info ldflags "[libgloss_link_flags] [newlib_link_flags]"
+
+# Configuration settings for testsuites
+set_board_info noargs 1
+set_board_info gdb,nosignals 1
+set_board_info gdb,noresults 1
+set_board_info gdb,cannot_call_functions 1
+set_board_info gdb,skip_float_tests 1
+set_board_info gdb,can_reverse 1
+set_board_info gdb,use_precord 1
+
+# More time is needed
+set_board_info gcc,timeout 800
+set_board_info gdb,timeout 60
+
+# Used by a few gcc.c-torture testcases to delimit how large the stack can
+# be.
+set_board_info gcc,stack_size 5000
+
diff --git a/.travis/moxie-sim.exp b/.travis/moxie-sim.exp
new file mode 100644
index 00000000..3a6042ee
--- /dev/null
+++ b/.travis/moxie-sim.exp
@@ -0,0 +1,60 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This is a list of toolchains that are supported on this board.
+set_board_info target_install {moxie-elf}
+
+# Load the generic configuration for this board. This will define a basic set
+# of routines needed by the tool to communicate with the board.
+load_generic_config "sim"
+
+# basic-sim.exp is a basic description for the standard Cygnus simulator.
+load_base_board_description "basic-sim"
+
+# "moxie" is the name of the sim subdir in devo/sim.
+setup_sim moxie
+
+# No multilib options needed by default.
+process_multilib_options ""
+
+# We only support newlib on this target. We assume that all multilib
+# options have been specified before we get here.
+
+set_board_info compiler "[find_gcc]"
+set_board_info cflags "[libgloss_include_flags] [newlib_include_flags]"
+set_board_info ldflags "[libgloss_link_flags] [newlib_link_flags]"
+# No linker script needed.
+set_board_info ldscript "-Tsim.ld"
+
+# Configuration settings for testsuites
+set_board_info noargs 1
+set_board_info gdb,nosignals 1
+set_board_info gdb,noresults 1
+set_board_info gdb,cannot_call_functions 1
+set_board_info gdb,skip_float_tests 1
+set_board_info gdb,can_reverse 1
+set_board_info gdb,use_precord 1
+
+# More time is needed
+set_board_info gcc,timeout 800
+set_board_info gdb,timeout 60
+
+# Used by a few gcc.c-torture testcases to delimit how large the stack can
+# be.
+set_board_info gcc,stack_size 5000
+
diff --git a/.travis/or1k-sim.exp b/.travis/or1k-sim.exp
new file mode 100644
index 00000000..64e1444f
--- /dev/null
+++ b/.travis/or1k-sim.exp
@@ -0,0 +1,58 @@
+# Copyright (C) 2010, 2019 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This is a list of toolchains that are supported on this board.
+set_board_info target_install {or1k-elf}
+
+# Load the generic configuration for this board. This will define a basic set
+# of routines needed by the tool to communicate with the board.
+load_generic_config "sim"
+
+# basic-sim.exp is a basic description for the standard Cygnus simulator.
+load_base_board_description "basic-sim"
+
+# "or1k" is the name of the sim subdir in devo/sim.
+setup_sim or1k
+
+# No multilib options needed by default.
+process_multilib_options ""
+
+# We only support newlib on this target. We assume that all multilib
+# options have been specified before we get here.
+
+set_board_info compiler "[find_gcc]"
+set_board_info cflags "[libgloss_include_flags] [newlib_include_flags]"
+set_board_info ldflags "[libgloss_link_flags] [newlib_link_flags]"
+
+# Configuration settings for testsuites
+set_board_info noargs 1
+set_board_info gdb,nosignals 1
+set_board_info gdb,noresults 1
+set_board_info gdb,cannot_call_functions 1
+set_board_info gdb,skip_float_tests 1
+set_board_info gdb,can_reverse 1
+set_board_info gdb,use_precord 1
+
+# More time is needed
+set_board_info gcc,timeout 800
+set_board_info gdb,timeout 60
+
+# Used by a few gcc.c-torture testcases to delimit how large the stack can
+# be.
+set_board_info gcc,stack_size 5000
+
diff --git a/.travis/site.exp b/.travis/site.exp
new file mode 100644
index 00000000..644ec631
--- /dev/null
+++ b/.travis/site.exp
@@ -0,0 +1,27 @@
+# Copyright (C) 2008, 2010, 2018, 2019 Anthony Green
+
+# Make sure we look in the right place for the board description files.
+if ![info exists boards_dir] {
+ set boards_dir {}
+}
+
+lappend boards_dir $::env(TRAVIS_BUILD_DIR)/.travis
+
+verbose "Global Config File: target_triplet is $target_triplet" 2
+global target_list
+
+case "$target_triplet" in {
+ { "bfin-elf" } {
+ set target_list "bfin-sim"
+ }
+ { "m32r-elf" } {
+ set target_list "m32r-sim"
+ }
+ { "moxie-elf" } {
+ set target_list "moxie-sim"
+ }
+ { "or1k-elf" } {
+ set target_list "or1k-sim"
+ }
+}
+
diff --git a/.travis/wine-sim.exp b/.travis/wine-sim.exp
new file mode 100644
index 00000000..8bdab671
--- /dev/null
+++ b/.travis/wine-sim.exp
@@ -0,0 +1,55 @@
+# Copyright (C) 2010, 2019 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This is a list of toolchains that are supported on this board.
+set_board_info target_install {i686-w64-mingw32}
+
+# Load the generic configuration for this board. This will define a basic set
+# of routines needed by the tool to communicate with the board.
+load_generic_config "sim"
+
+set_board_info sim "wineconsole --backend=curses"
+set_board_info is_simulator 1
+
+# No multilib options needed by default.
+process_multilib_options ""
+
+# We only support newlib on this target. We assume that all multilib
+# options have been specified before we get here.
+
+set_board_info compiler "[find_gcc]"
+set_board_info cflags "[libgloss_include_flags] [newlib_include_flags]"
+set_board_info ldflags "[libgloss_link_flags] [newlib_link_flags]"
+
+# Configuration settings for testsuites
+set_board_info noargs 1
+set_board_info gdb,nosignals 1
+set_board_info gdb,noresults 1
+set_board_info gdb,cannot_call_functions 1
+set_board_info gdb,skip_float_tests 1
+set_board_info gdb,can_reverse 1
+set_board_info gdb,use_precord 1
+
+# More time is needed
+set_board_info gcc,timeout 800
+set_board_info gdb,timeout 60
+
+# Used by a few gcc.c-torture testcases to delimit how large the stack can
+# be.
+set_board_info gcc,stack_size 5000
+
diff --git a/Android.bp b/Android.bp
index 1c9a4ec9..32c473b3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,6 +12,49 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["external_libffi_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+// See: http://go/android-license-faq
+license {
+ name: "external_libffi_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-GPL",
+ "SPDX-license-identifier-GPL-2.0",
+ "SPDX-license-identifier-GPL-3.0",
+ "SPDX-license-identifier-LGPL",
+ "SPDX-license-identifier-LGPL-2.1",
+ "SPDX-license-identifier-MIT",
+ "SPDX-license-identifier-MPL",
+ "legacy_unencumbered",
+ ],
+ license_text: [
+ "LICENSE",
+ "LICENSE-BUILDTOOLS",
+ ],
+}
+
genrule {
name: "ffi_header",
cmd: "$(location gen_ffi_header.sh) < $(in) > $(out)",
@@ -20,15 +63,19 @@ genrule {
tool_files: ["gen_ffi_header.sh"],
}
-cc_library_static {
+cc_library {
name: "libffi",
host_supported: true,
vendor_available: true,
cflags: [
"-Wall",
"-Werror",
+
"-Wno-error=incompatible-pointer-types",
"-Wno-incompatible-pointer-types",
+
+ "-Wno-deprecated-declarations",
+ "-Wno-missing-field-initializers",
"-Wno-null-pointer-arithmetic",
"-Wno-pointer-arith",
"-Wno-sign-compare",
@@ -65,7 +112,6 @@ cc_library_static {
srcs: [
"src/x86/ffi.c",
"src/x86/sysv.S",
- "src/x86/win32.S",
],
asflags: [
"-DHAVE_AS_X86_PCREL",
@@ -76,7 +122,9 @@ cc_library_static {
x86_64: {
srcs: [
"src/x86/ffi64.c",
+ "src/x86/ffiw64.c",
"src/x86/unix64.S",
+ "src/x86/win64.S",
],
asflags: [
"-DHAVE_AS_X86_PCREL",
@@ -85,13 +133,8 @@ cc_library_static {
export_include_dirs: ["linux-x86_64"],
},
},
- target: {
- darwin_x86_64: {
- exclude_srcs: ["src/x86/unix64.S"],
- srcs: [
- "src/x86/darwin.S",
- "src/x86/darwin64.S",
- ],
- },
- },
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
diff --git a/ChangeLog.old b/ChangeLog.old
new file mode 100644
index 00000000..8de1ca75
--- /dev/null
+++ b/ChangeLog.old
@@ -0,0 +1,7407 @@
+Libffi change logs used to be maintained in separate ChangeLog files.
+These days we generate them directly from the git commit messages.
+The old ChangeLog files are saved here in order to maintain the historical
+record.
+
+=============================================================================
+From the old ChangeLog.libffi-3.1 file...
+
+2014-03-16 Josh Triplett <josh@joshtriplett.org>
+
+ * ChangeLog: Archive to ChangeLog.libffi-3.1 and delete. Future
+ changelogs will come from git, with autogenerated snapshots shipped in
+ distributed tarballs.
+
+2014-03-16 Josh Triplett <josh@joshtriplett.org>
+
+ Add support for stdcall, thiscall, and fastcall on non-Windows
+ x86-32.
+
+ Linux supports the stdcall calling convention, either via
+ functions explicitly declared with the stdcall attribute, or via
+ code compiled with -mrtd which effectively makes stdcall the
+ default.
+
+ This introduces FFI_STDCALL, FFI_THISCALL, and FFI_FASTCALL on
+ non-Windows x86-32 platforms, as non-default calling conventions.
+
+ * Makefile.am: Compile in src/x86/win32.S on non-Windows x86-32.
+ * src/x86/ffitarget.h: Add FFI_STDCALL, FFI_THISCALL, and
+ FFI_FASTCALL on non-Windows x86-32. Increase trampoline size to
+ accomodate these calling conventions, and unify some ifdeffery.
+ * src/x86/ffi.c: Add support for FFI_STDCALL, FFI_THISCALL, and
+ FFI_FASTCALL on non-Windows x86-32 platforms; update ifdeffery.
+ * src/x86/win32.S: Support compiling on non-Windows x86-32
+ platforms. On those platforms, avoid redefining the SYSV symbols
+ already provided by src/x86/sysv.S.
+ * testsuite/libffi.call/closure_stdcall.c: Run on non-Windows.
+ #define __stdcall if needed.
+ * testsuite/libffi.call/closure_thiscall.c: Run on non-Windows.
+ #define __fastcall if needed.
+ * testsuite/libffi.call/fastthis1_win32.c: Run on non-Windows.
+ * testsuite/libffi.call/fastthis2_win32.c: Ditto.
+ * testsuite/libffi.call/fastthis3_win32.c: Ditto.
+ * testsuite/libffi.call/many2_win32.c: Ditto.
+ * testsuite/libffi.call/many_win32.c: Ditto.
+ * testsuite/libffi.call/strlen2_win32.c: Ditto.
+ * testsuite/libffi.call/strlen_win32.c: Ditto.
+ * testsuite/libffi.call/struct1_win32.c: Ditto.
+ * testsuite/libffi.call/struct2_win32.c: Ditto.
+
+2014-03-16 Josh Triplett <josh@joshtriplett.org>
+
+ * prep_cif.c: Remove unnecessary ifdef for X86_WIN32.
+ ffi_prep_cif_core had a special case for X86_WIN32, checking for
+ FFI_THISCALL in addition to the FFI_FIRST_ABI-to-FFI_LAST_ABI
+ range before returning FFI_BAD_ABI. However, on X86_WIN32,
+ FFI_THISCALL already falls in that range, making the special case
+ unnecessary. Remove it.
+
+2014-03-16 Josh Triplett <josh@joshtriplett.org>
+
+ * testsuite/libffi.call/closure_stdcall.c,
+ testsuite/libffi.call/closure_thiscall.c: Remove fragile stack
+ pointer checks. These files included inline assembly to save the
+ stack pointer before and after the call, and compare the values.
+ However, compilers can and do leave the stack in different states
+ for these two pieces of inline assembly, such as by saving a
+ temporary value on the stack across the call; observed with gcc
+ -Os, and verified as spurious through careful inspection of
+ disassembly.
+
+2014-03-16 Josh Triplett <josh@joshtriplett.org>
+
+ * testsuite/libffi.call/many.c: Avoid spurious failure due to
+ excess floating-point precision.
+ * testsuite/libffi.call/many_win32.c: Ditto.
+
+2014-03-16 Josh Triplett <josh@joshtriplett.org>
+
+ * libtool-ldflags: Re-add.
+
+2014-03-16 Josh Triplett <josh@joshtriplett.org>
+
+ * Makefile.in, aclocal.m4, compile, config.guess, config.sub,
+ configure, depcomp, include/Makefile.in, install-sh,
+ libtool-ldflags, ltmain.sh, m4/libtool.m4, m4/ltoptions.m4,
+ m4/ltsugar.m4, m4/ltversion.m4, m4/lt~obsolete.m4,
+ man/Makefile.in, mdate-sh, missing, testsuite/Makefile.in: Delete
+ autogenerated files from version control.
+ * .gitignore: Add autogenerated files.
+ * autogen.sh: New script to generate the autogenerated files.
+ * README: Document requirement to run autogen.sh when building
+ directly from version control.
+ * .travis.yml: Run autogen.sh
+
+2014-03-14 Anthony Green <green@moxielogic.com>
+
+ * configure, Makefile.in: Rebuilt.
+
+2014-03-10 Mike Hommey <mh+mozilla@glandium.org>
+
+ * configure.ac: Allow building for mipsel with Android NDK r8.
+ * Makefile.am (AM_MAKEFLAGS): Replace double quotes with single
+ quotes.
+
+2014-03-10 Landry Breuil <landry@openbsd.org>
+
+ * configure.ac: Ensure the linker supports @unwind sections in libffi.
+
+2014-03-01 Anthony Green <green@moxielogic.com>
+
+ * Makefile.am (EXTRA_DIST): Replace old scripts with
+ generate-darwin-source-and-headers.py.
+ * Makefile.in: Rebuilt.
+
+2014-02-28 Anthony Green <green@moxielogic.com>
+
+ * Makefile.am (AM_CFLAGS): Reintroduce missing -DFFI_DEBUG for
+ --enable-debug builds.
+ * Makefile.in: Rebuilt.
+
+2014-02-28 Makoto Kato <m_kato@ga2.so-net.ne.jp>
+
+ * src/closures.c: Fix build failure when using clang for Android.
+
+2014-02-28 Marcin Wojdyr <wojdyr@gmail.com>
+
+ * libffi.pc.in (toolexeclibdir): use -L${toolexeclibdir} instead
+ of -L${libdir}.
+
+2014-02-28 Paulo Pizarro <paulo.pizarro@gmail.com>
+
+ * src/bfin/sysv.S: Calling functions in shared libraries requires
+ considering the GOT.
+
+2014-02-28 Josh Triplett <josh@joshtriplett.org>
+
+ * src/x86/ffi64.c (classify_argument): Handle case where
+ FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE.
+
+2014-02-28 Anthony Green <green@moxielogic.com>
+
+ * ltmain.sh: Generate with libtool-2.4.2.418.
+ * m4/libtool.m4, m4/ltoptions.m4, m4/ltversion.m4: Ditto.
+ * configure: Rebuilt.
+
+2014-02-28 Dominik Vogt <vogt@linux.vnet.ibm.com>
+
+ * configure.ac (AC_ARG_ENABLE struct): Fix typo in help
+ message.
+ (AC_ARG_ENABLE raw_api): Ditto.
+ * configure, fficonfig.h.in: Rebuilt.
+
+2014-02-28 Will Newton <will.newton@linaro.org>
+
+ * src/arm/sysv.S: Initialize IP register with FP.
+
+2014-02-28 Yufeng Zhang <yufeng.zhang@arm.com>
+
+ * src/aarch64/sysv.S (ffi_closure_SYSV): Use x29 as the
+ main CFA reg; update cfi_rel_offset.
+
+2014-02-15 Marcus Comstedt <marcus@mc.pp.se>
+
+ * src/powerpc/ffi_linux64.c, src/powerpc/linux64_closure.S: Remove
+ assumption on contents of r11 in closure.
+
+2014-02-09 Heiher <r@hev.cc>
+
+ * src/mips/n32.S: Fix call floating point va function.
+
+2014-01-21 Zachary Waldowski <zach@waldowski.me>
+
+ * src/aarch64/ffi.c: Fix missing semicolons on assertions under
+ debug mode.
+
+2013-12-30 Zachary Waldowski <zach@waldowski.me>
+
+ * .gitignore: Exclude darwin_* generated source and build_* trees.
+ * src/aarch64/ffi.c, src/arm/ffi.c, src/x86/ffi.c: Inhibit Clang
+ previous prototype warnings.
+ * src/arm/ffi.c: Prevent NULL dereference, fix short type warning
+ * src/dlmalloc.c: Fix warnings from set_segment_flags return type,
+ and the native use of size_t for malloc on platforms
+ * src/arm/sysv.S: Use unified syntax. Clang clean-ups for
+ ARM_FUNC_START.
+ * generate-osx-source-and-headers.py: Remove.
+ * build-ios.sh: Remove.
+ * libffi.xcodeproj/project.pbxproj: Rebuild targets. Include
+ x86_64+aarch64 pieces in library. Export headers properly.
+ * src/x86/ffi64.c: More Clang warning clean-ups.
+ * src/closures.c (open_temp_exec_file_dir): Use size_t.
+ * src/prep_cif.c (ffi_prep_cif_core): Cast ALIGN result.
+ * src/aarch64/sysv.S: Use CNAME for global symbols. Only use
+ .size for ELF targets.
+ * src/aarch64/ffi.c: Clean up for double == long double. Clean up
+ from Clang warnings. Use Clang cache invalidation builtin. Use
+ size_t in place of unsigned in many places. Accommodate for
+ differences in Apple AArch64 ABI.
+
+2013-12-02 Daniel Rodríguez Troitiño <drodrigueztroitino@yahoo.es>
+
+ * generate-darwin-source-and-headers.py: Clean up, modernize,
+ merged version of previous scripts.
+
+2013-11-21 Anthony Green <green@moxielogic.com>
+
+ * configure, Makefile.in, include/Makefile.in, include/ffi.h.in,
+ man/Makefile.in, testsuite/Makefile.in, fficonfig.h.in: Rebuilt.
+
+2013-11-21 Alan Modra <amodra@gmail.com>
+
+ * Makefile.am (EXTRA_DIST): Add new src/powerpc files.
+ (nodist_libffi_la_SOURCES <POWERPC, POWERPC_FREEBSD>): Likewise.
+ * configure.ac (HAVE_LONG_DOUBLE_VARIANT): Define for powerpc.
+ * include/ffi.h.in (ffi_prep_types): Declare.
+ * src/prep_cif.c (ffi_prep_cif_core): Call ffi_prep_types.
+ * src/types.c (FFI_NONCONST_TYPEDEF): Define and use for
+ HAVE_LONG_DOUBLE_VARIANT.
+ * src/powerpc/ffi_powerpc.h: New file.
+ * src/powerpc/ffi.c: Split into..
+ * src/powerpc/ffi_sysv.c: ..new file, and..
+ * src/powerpc/ffi_linux64.c: ..new file, rewriting parts.
+ * src/powerpc/ffitarget.h (enum ffi_abi): Rewrite powerpc ABI
+ selection as bits controlling features.
+ * src/powerpc/linux64.S: For consistency, use POWERPC64 rather
+ than __powerpc64__.
+ * src/powerpc/linux64_closure.S: Likewise.
+ * src/powerpc/ppc_closure.S: Likewise. Move .note.FNU-stack
+ inside guard.
+ * src/powerpc/sysv.S: Likewise.
+ * configure: Regenerate.
+ * fficonfig.h.in: Regenerate.
+ * Makefile.in: Regenerate.
+
+2013-11-20 Alan Modra <amodra@gmail.com>
+
+ * src/powerpc/ffi.c (ffi_prep_cif_machdep_core): Use
+ NUM_FPR_ARG_REGISTERS64 and NUM_GPR_ARG_REGISTERS64 not their
+ 32-bit versions for 64-bit code.
+ * src/powerpc/linux64_closure.S: Don't use the return value area
+ as a parameter save area on ELFv2.
+
+2013-11-18 Iain Sandoe <iain@codesourcery.com>
+
+ * src/powerpc/darwin.S (EH): Correct use of pcrel FDE encoding.
+ * src/powerpc/darwin_closure.S (EH): Likewise. Modernise picbase
+ labels.
+
+2013-11-18 Anthony Green <green@moxielogic.com>
+
+ * src/arm/ffi.c (ffi_call): Hoist declaration of temp to top of
+ function.
+ * src/arm/ffi.c (ffi_closure_inner): Moderize function declaration
+ to appease compiler.
+ Thanks for Gregory P. Smith <greg@krypto.org>.
+
+2013-11-18 Anthony Green <green@moxielogic.com>
+
+ * README (tested): Mention PowerPC ELFv2.
+
+2013-11-16 Alan Modra <amodra@gmail.com>
+
+ * src/powerpc/ppc_closure.S: Move errant #endif to where it belongs.
+ Don't bl .Luint128.
+
+2013-11-16 Alan Modra <amodra@gmail.com>
+
+ * src/powerpc/ffi.c (ffi_prep_cif_machdep_core): Use #if _CALL_ELF
+ test to select parameter save sizing for ELFv2 vs. ELFv1.
+ * src/powerpc/ffitarget.h (FFI_V2_TYPE_FLOAT_HOMOG,
+ FFI_V2_TYPE_DOUBLE_HOMOG, FFI_V2_TYPE_SMALL_STRUCT): Define.
+ (FFI_TRAMPOLINE_SIZE): Define variant for ELFv2.
+ * src/powerpc/ffi.c (FLAG_ARG_NEEDS_PSAVE): Define.
+ (discover_homogeneous_aggregate): New function.
+ (ffi_prep_args64): Adjust start of param save area for ELFv2.
+ Handle homogenous floating point struct parms.
+ (ffi_prep_cif_machdep_core): Adjust space calculation for ELFv2.
+ Handle ELFv2 return values. Set FLAG_ARG_NEEDS_PSAVE. Handle
+ homogenous floating point structs.
+ (ffi_call): Increase size of smst_buffer for ELFv2. Handle ELFv2.
+ (flush_icache): Compile for ELFv2.
+ (ffi_prep_closure_loc): Set up ELFv2 trampoline.
+ (ffi_closure_helper_LINUX64): Don't return all structs directly
+ to caller. Handle homogenous floating point structs. Handle
+ ELFv2 struct return values.
+ * src/powerpc/linux64.S (ffi_call_LINUX64): Set up r2 for
+ ELFv2. Adjust toc save location. Call function pointer using
+ r12. Handle FLAG_RETURNS_SMST. Don't predict branches.
+ * src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Set up r2
+ for ELFv2. Define ELFv2 versions of STACKFRAME, PARMSAVE, and
+ RETVAL. Handle possibly missing parameter save area. Handle
+ ELFv2 return values.
+ (.note.GNU-stack): Move inside outer #ifdef.
+
+2013-11-16 Alan Modra <amodra@gmail.com>
+
+ * src/powerpc/ffi.c (ffi_prep_cif_machdep): Revert 2013-02-08
+ change. Do not consume an int arg when returning a small struct
+ for FFI_SYSV ABI.
+ (ffi_call): Only use bounce buffer when FLAG_RETURNS_SMST.
+ Properly copy bounce buffer to destination.
+ * src/powerpc/sysv.S: Revert 2013-02-08 change.
+ * src/powerpc/ppc_closure.S: Remove stray '+'.
+
+2013-11-16 Alan Modra <amodra@gmail.com>
+
+ * src/powerpc/ffi.c (ffi_prep_args64): Align struct parameters
+ according to __STRUCT_PARM_ALIGN__.
+ (ffi_prep_cif_machdep_core): Likewise.
+ (ffi_closure_helper_LINUX64): Likewise.
+
+2013-11-16 Alan Modra <amodra@gmail.com>
+
+ * src/powerpc/linux64.S (ffi_call_LINUX64): Tweak restore of r28.
+ (.note.GNU-stack): Move inside outer #ifdef.
+ * src/powerpc/linux64_closure.S (STACKFRAME, PARMSAVE,
+ RETVAL): Define and use throughout.
+ (ffi_closure_LINUX64): Save fprs before buying stack.
+ (.note.GNU-stack): Move inside outer #ifdef.
+
+2013-11-16 Alan Modra <amodra@gmail.com>
+
+ * src/powerpc/ffitarget.h (FFI_TARGET_SPECIFIC_VARIADIC): Define.
+ (FFI_EXTRA_CIF_FIELDS): Define.
+ * src/powerpc/ffi.c (ffi_prep_args64): Save fprs as per the
+ ABI, not to both fpr and param save area.
+ (ffi_prep_cif_machdep_core): Renamed from ffi_prep_cif_machdep.
+ Keep initial flags. Formatting. Remove dead FFI_LINUX_SOFT_FLOAT
+ code.
+ (ffi_prep_cif_machdep, ffi_prep_cif_machdep_var): New functions.
+ (ffi_closure_helper_LINUX64): Pass floating point as per ABI,
+ not to both fpr and parameter save areas.
+
+ * libffi/testsuite/libffi.call/cls_double_va.c (main): Correct
+ function cast and don't call ffi_prep_cif.
+ * libffi/testsuite/libffi.call/cls_longdouble_va.c (main): Likewise.
+
+2013-11-15 Andrew Haley <aph@redhat.com>
+
+ * doc/libffi.texi (Closure Example): Fix the sample code.
+ * doc/libffi.info, doc/stamp-vti, doc/version.texi: Rebuilt.
+
+2013-11-15 Andrew Haley <aph@redhat.com>
+
+ * testsuite/libffi.call/va_struct1.c (main): Fix broken test.
+ * testsuite/libffi.call/cls_uint_va.c (cls_ret_T_fn): Likewise
+ * testsuite/libffi.call/cls_struct_va1.c (test_fn): Likewise.
+ * testsuite/libffi.call/va_1.c (main): Likewise.
+
+2013-11-14 David Schneider <david.schneider@bivab.de>
+
+ * src/arm/ffi.c: Fix register allocation for mixed float and
+ doubles.
+ * testsuite/libffi.call/cls_many_mixed_float_double.c: Testcase
+ for many mixed float and double arguments.
+
+2013-11-13 Alan Modra <amodra@gmail.com>
+
+ * doc/libffi.texi (Simple Example): Correct example code.
+ * doc/libffi.info, doc/stamp-vti, doc/version.texi: Rebuilt.
+
+2013-11-13 Anthony Green <green@moxielogic.com>
+
+ * include/ffi_common.h: Respect HAVE_ALLOCA_H for GNU compiler
+ based build. (Thanks to tmr111116 on github)
+
+2013-11-09 Anthony Green <green@moxielogic.com>
+
+ * m4/libtool.m4: Refresh.
+ * configure, Makefile.in: Rebuilt.
+ * README: Add more notes about next release.
+
+2013-11-09 Shigeharu TAKENO <shige@iee.niit.ac.jp>
+
+ * m4/ax_gcc_archflag.m4 (ax_gcc_arch): Don't recognize
+ UltraSPARC-IIi as ultrasparc3.
+
+2013-11-06 Mark Kettenis <kettenis@gnu.org>
+
+ * src/x86/freebsd.S (ffi_call_SYSV): Align the stack pointer to
+ 16-bytes.
+
+2013-11-06 Konstantin Belousov <kib@freebsd.org>
+
+ * src/x86/freebsd.S (ffi_closure_raw_SYSV): Mark the assembler
+ source as not requiring executable stack.
+
+2013-11-02 Anthony Green <green@moxielogic.com>
+
+ * doc/libffi.texi (The Basics): Clarify return value buffer size
+ requirements. Also, NULL result buffer pointers are no longer
+ supported.
+ * doc/libffi.info: Rebuilt.
+
+2013-11-02 Mischa Jonker <mjonker@synopsys.com>
+
+ * Makefile.am (nodist_libffi_la_SOURCES): Fix build error.
+ * Makefile.in: Rebuilt.
+
+2013-11-02 David Schneider <david.schneider@bivab.de>
+
+ * src/arm/ffi.c: more robust argument handling for closures on arm hardfloat
+ * testsuite/libffi.call/many_mixed.c: New file.
+ * testsuite/libffi.call/cls_many_mixed_args.c: More tests.
+
+2013-11-02 Vitaly Budovski
+
+ * src/x86/ffi.c (ffi_prep_cif_machdep): Don't align stack for win32.
+
+2013-10-23 Mark H Weaver <mhw@netris.org>
+
+ * src/mips/ffi.c: Fix handling of uint32_t arguments on the
+ MIPS N32 ABI.
+
+2013-10-13 Sandra Loosemore <sandra@codesourcery.com>
+
+ * README: Add Nios II to table of supported platforms.
+ * Makefile.am (EXTRA_DIST): Add nios2 files.
+ (nodist_libffi_la_SOURCES): Likewise.
+ * Makefile.in: Regenerated.
+ * configure.ac (nios2*-linux*): New host.
+ (NIOS2): Add AM_CONDITIONAL.
+ * configure: Regenerated.
+ * src/nios2/ffi.c: New.
+ * src/nios2/ffitarget.h: New.
+ * src/nios2/sysv.S: New.
+ * src/prep_cif.c (initialize_aggregate): Handle extra structure
+ alignment via FFI_AGGREGATE_ALIGNMENT.
+ (ffi_prep_cif_core): Conditionalize structure return for NIOS2.
+
+2013-10-10 Sandra Loosemore <sandra@codesourcery.com>
+
+ * testsuite/libffi.call/cls_many_mixed_args.c (cls_ret_double_fn):
+ Fix uninitialized variable.
+
+2013-10-11 Marcus Shawcroft <marcus.shawcroft@arm.com>
+
+ * testsuite/libffi.call/many.c (many): Replace * with +.
+
+2013-10-08 Ondřej Bílka <neleai@seznam.cz>
+
+ * src/aarch64/ffi.c, src/aarch64/sysv.S, src/arm/ffi.c,
+ src/arm/gentramp.sh, src/bfin/sysv.S, src/closures.c,
+ src/dlmalloc.c, src/ia64/ffi.c, src/microblaze/ffi.c,
+ src/microblaze/sysv.S, src/powerpc/darwin_closure.S,
+ src/powerpc/ffi.c, src/powerpc/ffi_darwin.c, src/sh/ffi.c,
+ src/tile/tile.S, testsuite/libffi.call/nested_struct11.c: Fix
+ spelling errors.
+
+2013-10-08 Anthony Green <green@moxielogic.com>
+
+ * aclocal.m4, compile, config.guess, config.sub, depcomp,
+ install-sh, mdate-sh, missing, texinfo.tex: Update from upstream.
+ * configure.ac: Update version to 3.0.14-rc0.
+ * Makefile.in, configure, Makefile.in, include/Makefile.in,
+ man/Makefile.in, testsuite/Makefile.in: Rebuilt.
+ * README: Mention M88K and VAX.
+
+2013-07-15 Miod Vallat <miod@openbsd.org>
+
+ * Makefile.am,
+ configure.ac,
+ src/m88k/ffi.c,
+ src/m88k/ffitarget.h,
+ src/m88k/obsd.S,
+ src/vax/elfbsd.S,
+ src/vax/ffi.c,
+ src/vax/ffitarget.h: Add m88k and vax support.
+
+2013-06-24 Alan Modra <amodra@gmail.com>
+
+ * src/powerpc/ffi.c (ffi_prep_args_SYSV): Move var declaration
+ before statements.
+ (ffi_prep_args64): Support little-endian.
+ (ffi_closure_helper_SYSV, ffi_closure_helper_LINUX64): Likewise.
+ * src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Likewise.
+ * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Likewise.
+
+2013-06-12 Mischa Jonker <mjonker@synopsys.com>
+
+ * configure.ac: Add support for ARC.
+ * Makefile.am: Likewise.
+ * README: Add ARC details.
+ * src/arc/arcompact.S: New.
+ * src/arc/ffi.c: Likewise.
+ * src/arc/ffitarget.h: Likewise.
+
+2013-03-28 David Schneider <david.schneider@bivab.de>
+
+ * src/arm/ffi.c: Fix support for ARM hard-float calling convention.
+ * src/arm/sysv.S: call different methods for SYSV and VFP ABIs.
+ * testsuite/libffi.call/cls_many_mixed_args.c: testcase for a closure with
+ mixed arguments, many doubles.
+ * testsuite/libffi.call/many_double.c: testcase for calling a function using
+ more than 8 doubles.
+ * testcase/libffi.call/many.c: use absolute value to check result against an
+ epsilon
+
+2013-03-17 Anthony Green <green@moxielogic.com>
+
+ * README: Update for 3.0.13.
+ * configure.ac: Ditto.
+ * configure: Rebuilt.
+ * doc/*: Update version.
+
+2013-03-17 Dave Korn <dave.korn.cygwin@gmail.com>
+
+ * src/closures.c (is_emutramp_enabled
+ [!FFI_MMAP_EXEC_EMUTRAMP_PAX]): Move default definition outside
+ enclosing #if scope.
+
+2013-03-17 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Only modify toolexecdir in certain cases.
+ * configure: Rebuilt.
+
+2013-03-16 Gilles Talis <gilles.talis@gmail.com>
+
+ * src/powerpc/ffi.c (ffi_prep_args_SYSV): Don't use
+ fparg_count,etc on __NO_FPRS__ targets.
+
+2013-03-16 Alan Hourihane <alanh@fairlite.co.uk>
+
+ * src/m68k/sysv.S (epilogue): Don't use extb instruction on
+ m680000 machines.
+
+2013-03-16 Alex Gaynor <alex.gaynor@gmail.com>
+
+ * src/x86/ffi.c (ffi_prep_cif_machdep): Always align stack.
+
+2013-03-13 Markos Chandras <markos.chandras@imgtec.com>
+
+ * configure.ac: Add support for Imagination Technologies Meta.
+ * Makefile.am: Likewise.
+ * README: Add Imagination Technologies Meta details.
+ * src/metag/ffi.c: New.
+ * src/metag/ffitarget.h: Likewise.
+ * src/metag/sysv.S: Likewise.
+
+2013-02-24 Andreas Schwab <schwab@linux-m68k.org>
+
+ * doc/libffi.texi (Structures): Fix missing category argument of
+ @deftp.
+
+2013-02-11 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Update release number to 3.0.12.
+ * configure: Rebuilt.
+ * README: Update release info.
+
+2013-02-10 Anthony Green <green@moxielogic.com>
+
+ * README: Add Moxie.
+ * src/moxie/ffi.c: Created.
+ * src/moxie/eabi.S: Created.
+ * src/moxie/ffitarget.h: Created.
+ * Makefile.am (nodist_libffi_la_SOURCES): Add Moxie.
+ * Makefile.in: Rebuilt.
+ * configure.ac: Add Moxie.
+ * configure: Rebuilt.
+ * testsuite/libffi.call/huge_struct.c: Disable format string
+ warnings for moxie*-*-elf tests.
+
+2013-02-10 Anthony Green <green@moxielogic.com>
+
+ * Makefile.am (LTLDFLAGS): Fix reference.
+ * Makefile.in: Rebuilt.
+
+2013-02-10 Anthony Green <green@moxielogic.com>
+
+ * README: Update supported platforms. Update test results link.
+
+2013-02-09 Anthony Green <green@moxielogic.com>
+
+ * testsuite/libffi.call/negint.c: Remove forced -O2.
+ * testsuite/libffi.call/many2.c (foo): Remove GCCism.
+ * testsuite/libffi.call/ffitest.h: Add default PRIuPTR definition.
+
+ * src/sparc/v8.S (ffi_closure_v8): Import ancient ulonglong
+ closure return type fix developed by Martin v. Löwis for cpython
+ fork.
+
+2013-02-08 Andreas Tobler <andreast@fgznet.ch>
+
+ * src/powerpc/ffi.c (ffi_prep_cif_machdep): Fix small struct
+ support.
+ * src/powerpc/sysv.S: Ditto.
+
+2013-02-08 Anthony Green <green@moxielogic.com>
+
+ * testsuite/libffi.call/cls_longdouble.c: Remove xfail for
+ arm*-*-*.
+
+2013-02-08 Anthony Green <green@moxielogic.com>
+
+ * src/sparc/ffi.c (ffi_prep_closure_loc): Fix cache flushing for GCC.
+
+2013-02-08 Matthias Klose <doko@ubuntu.com>
+
+ * man/ffi_prep_cif.3: Clean up for debian linter.
+
+2013-02-08 Peter Bergner <bergner@vnet.ibm.com>
+
+ * src/powerpc/ffi.c (ffi_prep_args_SYSV): Account for FP args pushed
+ on the stack.
+
+2013-02-08 Anthony Green <green@moxielogic.com>
+
+ * Makefile.am (EXTRA_DIST): Add missing files.
+ * testsuite/Makefile.am (EXTRA_DIST): Ditto.
+ * Makefile.in: Rebuilt.
+
+2013-02-08 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Move sparc asm config checks to within functions
+ for compatibility with sun tools.
+ * configure: Rebuilt.
+ * src/sparc/ffi.c (ffi_prep_closure_loc): Flush cache on v9
+ systems.
+ * src/sparc/v8.S (ffi_flush_icache): Implement a sparc v9 cache
+ flusher.
+
+2013-02-08 Nathan Rossi <nathan.rossi@xilinx.com>
+
+ * src/microblaze/ffi.c (ffi_closure_call_SYSV): Fix handling of
+ small big-endian structures.
+ (ffi_prep_args): Ditto.
+
+2013-02-07 Anthony Green <green@moxielogic.com>
+
+ * src/sparc/v8.S (ffi_call_v8): Fix typo from last patch
+ (effectively hiding ffi_call_v8).
+
+2013-02-07 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Update bug reporting address.
+ * configure.in: Rebuild.
+
+ * src/sparc/v8.S (ffi_flush_icache): Out-of-line cache flusher for
+ Sun compiler.
+ * src/sparc/ffi.c (ffi_call): Remove warning.
+ Call ffi_flush_icache for non-GCC builds.
+ (ffi_prep_closure_loc): Use ffi_flush_icache.
+
+ * Makefile.am (EXTRA_DIST): Add libtool-ldflags.
+ * Makefile.in: Rebuilt.
+ * libtool-ldflags: New file.
+
+2013-02-07 Daniel Schepler <dschepler@gmail.com>
+
+ * configure.ac: Correctly identify x32 systems as 64-bit.
+ * m4/libtool.m4: Remove libtool expr error.
+ * aclocal.m4, configure: Rebuilt.
+
+2013-02-07 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Fix GCC usage test.
+ * configure: Rebuilt.
+ * README: Mention LLVM/GCC x86_64 issue.
+ * testsuite/Makefile.in: Rebuilt.
+
+2013-02-07 Anthony Green <green@moxielogic.com>
+
+ * testsuite/libffi.call/cls_double_va.c (main): Replace // style
+ comments with /* */ for xlc compiler.
+ * testsuite/libffi.call/stret_large.c (main): Ditto.
+ * testsuite/libffi.call/stret_large2.c (main): Ditto.
+ * testsuite/libffi.call/nested_struct1.c (main): Ditto.
+ * testsuite/libffi.call/huge_struct.c (main): Ditto.
+ * testsuite/libffi.call/float_va.c (main): Ditto.
+ * testsuite/libffi.call/cls_struct_va1.c (main): Ditto.
+ * testsuite/libffi.call/cls_pointer_stack.c (main): Ditto.
+ * testsuite/libffi.call/cls_pointer.c (main): Ditto.
+ * testsuite/libffi.call/cls_longdouble_va.c (main): Ditto.
+
+2013-02-06 Anthony Green <green@moxielogic.com>
+
+ * man/ffi_prep_cif.3: Clean up for debian lintian checker.
+
+2013-02-06 Anthony Green <green@moxielogic.com>
+
+ * Makefile.am (pkgconfigdir): Add missing pkgconfig install bits.
+ * Makefile.in: Rebuild.
+
+2013-02-02 Mark H Weaver <mhw@netris.org>
+
+ * src/x86/ffi64.c (ffi_call): Sign-extend integer arguments passed
+ via general purpose registers.
+
+2013-01-21 Nathan Rossi <nathan.rossi@xilinx.com>
+
+ * README: Add MicroBlaze details.
+ * Makefile.am: Add MicroBlaze support.
+ * configure.ac: Likewise.
+ * src/microblaze/ffi.c: New.
+ * src/microblaze/ffitarget.h: Likewise.
+ * src/microblaze/sysv.S: Likewise.
+
+2013-01-21 Nathan Rossi <nathan.rossi@xilinx.com>
+ * testsuite/libffi.call/return_uc.c: Fixed issue.
+
+2013-01-21 Chris Zankel <chris@zankel.net>
+
+ * README: Add Xtensa support.
+ * Makefile.am: Likewise.
+ * configure.ac: Likewise.
+ * Makefile.in Regenerate.
+ * configure: Likewise.
+ * src/prep_cif.c: Handle Xtensa.
+ * src/xtensa: New directory.
+ * src/xtensa/ffi.c: New file.
+ * src/xtensa/ffitarget.h: Ditto.
+ * src/xtensa/sysv.S: Ditto.
+
+2013-01-11 Anthony Green <green@moxielogic.com>
+
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Replace // style
+ comments with /* */ for xlc compiler.
+ * src/powerpc/aix.S (ffi_call_AIX): Ditto.
+ * testsuite/libffi.call/ffitest.h (allocate_mmap): Delete
+ deprecated inline function.
+ * testsuite/libffi.special/ffitestcxx.h: Ditto.
+ * README: Add update for AIX support.
+
+2013-01-11 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Robustify pc relative reloc check.
+ * m4/ax_cc_maxopt.m4: Don't -malign-double. This is an ABI
+ changing option for 32-bit x86.
+ * aclocal.m4, configure: Rebuilt.
+ * README: Update supported target list.
+
+2013-01-10 Anthony Green <green@moxielogic.com>
+
+ * README (tested): Add Compiler column to table.
+
+2013-01-10 Anthony Green <green@moxielogic.com>
+
+ * src/x86/ffi64.c (struct register_args): Make sse array and array
+ of unions for sunpro compiler compatibility.
+
+2013-01-10 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Test target platform size_t size. Handle both 32
+ and 64-bit builds for x86_64-* and i?86-* targets (allowing for
+ CFLAG option to change default settings).
+ * configure, aclocal.m4: Rebuilt.
+
+2013-01-10 Anthony Green <green@moxielogic.com>
+
+ * testsuite/libffi.special/special.exp: Only run exception
+ handling tests when using GNU compiler.
+
+ * m4/ax_compiler_vendor.m4: New file.
+ * configure.ac: Test for compiler vendor and don't use
+ AX_CFLAGS_WARN_ALL with the sun compiler.
+ * aclocal.m4, configure: Rebuilt.
+
+2013-01-10 Anthony Green <green@moxielogic.com>
+
+ * include/ffi_common.h: Don't use GCCisms to define types when
+ building with the SUNPRO compiler.
+
+2013-01-10 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Put local.exp in the right place.
+ * configure: Rebuilt.
+
+ * src/x86/ffi.c: Update comment about regparm function attributes.
+ * src/x86/sysv.S (ffi_closure_SYSV): The SUNPRO compiler requires
+ that all function arguments be passed on the stack (no regparm
+ support).
+
+2013-01-08 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Generate local.exp. This sets CC_FOR_TARGET
+ when we are using the vendor compiler.
+ * testsuite/Makefile.am (EXTRA_DEJAGNU_SITE_CONFIG): Point to
+ ../local.exp.
+ * configure, testsuite/Makefile.in: Rebuilt.
+
+ * testsuite/libffi.call/call.exp: Run tests with different
+ options, depending on whether or not we are using gcc or the
+ vendor compiler.
+ * testsuite/lib/libffi.exp (libffi-init): Set using_gcc based on
+ whether or not we are building/testing with gcc.
+
+2013-01-08 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Switch x86 solaris target to X86 by default.
+ * configure: Rebuilt.
+
+2013-01-08 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Fix test for read-only eh_frame.
+ * configure: Rebuilt.
+
+2013-01-08 Anthony Green <green@moxielogic.com>
+
+ * src/x86/sysv.S, src/x86/unix64.S: Only emit DWARF unwind info
+ when building with the GNU toolchain.
+ * testsuite/libffi.call/ffitest.h (CHECK): Fix for Solaris vendor
+ compiler.
+
+2013-01-07 Thorsten Glaser <tg@mirbsd.org>
+
+ * testsuite/libffi.call/cls_uchar_va.c,
+ testsuite/libffi.call/cls_ushort_va.c,
+ testsuite/libffi.call/va_1.c: Testsuite fixes.
+
+2013-01-07 Thorsten Glaser <tg@mirbsd.org>
+
+ * src/m68k/ffi.c (CIF_FLAGS_SINT8, CIF_FLAGS_SINT16): Define.
+ (ffi_prep_cif_machdep): Fix 8-bit and 16-bit signed calls.
+ * src/m68k/sysv.S (ffi_call_SYSV, ffi_closure_SYSV): Ditto.
+
+2013-01-04 Anthony Green <green@moxielogic.com>
+
+ * Makefile.am (AM_CFLAGS): Don't automatically add -fexceptions
+ and -Wall. This is set in the configure script after testing for
+ GCC.
+ * Makefile.in: Rebuilt.
+
+2013-01-02 rofl0r <https://github.com/rofl0r>
+
+ * src/powerpc/ffi.c (ffi_prep_cif_machdep): Fix build error on ppc
+ when long double == double.
+
+2013-01-02 Reini Urban <rurban@x-ray.at>
+
+ * Makefile.am (libffi_la_LDFLAGS): Add -no-undefined to LDFLAGS
+ (required for shared libs on cygwin/mingw).
+ * Makefile.in: Rebuilt.
+
+2012-10-31 Alan Modra <amodra@gmail.co>
+
+ * src/powerpc/linux64_closure.S: Add new ABI support.
+ * src/powerpc/linux64.S: Likewise.
+
+2012-10-30 Magnus Granberg <zorry@gentoo.org>
+ Pavel Labushev <pavel.labushev@runbox.ru>
+
+ * configure.ac: New options pax_emutramp
+ * configure, fficonfig.h.in: Regenerated
+ * src/closures.c: New function emutramp_enabled_check() and
+ checks.
+
+2012-10-30 Frederick Cheung <frederick.cheung@gmail.com>
+
+ * configure.ac: Enable FFI_MAP_EXEC_WRIT for Darwin 12 (mountain
+ lion) and future version.
+ * configure: Rebuild.
+
+2012-10-30 James Greenhalgh <james.greenhalgh at arm.com>
+ Marcus Shawcroft <marcus.shawcroft at arm.com>
+
+ * README: Add details of aarch64 port.
+ * src/aarch64/ffi.c: New.
+ * src/aarch64/ffitarget.h: Likewise.
+ * src/aarch64/sysv.S: Likewise.
+ * Makefile.am: Support aarch64.
+ * configure.ac: Support aarch64.
+ * Makefile.in, configure: Rebuilt.
+
+2012-10-30 James Greenhalgh <james.greenhalgh at arm.com>
+ Marcus Shawcroft <marcus.shawcroft at arm.com>
+
+ * testsuite/lib/libffi.exp: Add support for aarch64.
+ * testsuite/libffi.call/cls_struct_va1.c: New.
+ * testsuite/libffi.call/cls_uchar_va.c: Likewise.
+ * testsuite/libffi.call/cls_uint_va.c: Likewise.
+ * testsuite/libffi.call/cls_ulong_va.c: Likewise.
+ * testsuite/libffi.call/cls_ushort_va.c: Likewise.
+ * testsuite/libffi.call/nested_struct11.c: Likewise.
+ * testsuite/libffi.call/uninitialized.c: Likewise.
+ * testsuite/libffi.call/va_1.c: Likewise.
+ * testsuite/libffi.call/va_struct1.c: Likewise.
+ * testsuite/libffi.call/va_struct2.c: Likewise.
+ * testsuite/libffi.call/va_struct3.c: Likewise.
+
+2012-10-12 Walter Lee <walt@tilera.com>
+
+ * Makefile.am: Add TILE-Gx/TILEPro support.
+ * configure.ac: Likewise.
+ * Makefile.in: Regenerate.
+ * configure: Likewise.
+ * src/prep_cif.c (ffi_prep_cif_core): Handle TILE-Gx/TILEPro.
+ * src/tile: New directory.
+ * src/tile/ffi.c: New file.
+ * src/tile/ffitarget.h: Ditto.
+ * src/tile/tile.S: Ditto.
+
+2012-10-12 Matthias Klose <doko@ubuntu.com>
+
+ * generate-osx-source-and-headers.py: Normalize whitespace.
+
+2012-09-14 David Edelsohn <dje.gcc@gmail.com>
+
+ * configure: Regenerated.
+
+2012-08-26 Andrew Pinski <apinski@cavium.com>
+
+ PR libffi/53014
+ * src/mips/ffi.c (ffi_prep_closure_loc): Allow n32 with soft-float and n64 with
+ soft-float.
+
+2012-08-08 Uros Bizjak <ubizjak@gmail.com>
+
+ * src/s390/ffi.c (ffi_prep_closure_loc): Don't ASSERT ABI test,
+ just return FFI_BAD_ABI when things are wrong.
+
+2012-07-18 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR libffi/53982
+ PR libffi/53973
+ * src/x86/ffitarget.h: Check __ILP32__ instead of __LP64__ for x32.
+ (FFI_SIZEOF_JAVA_RAW): Defined to 4 for x32.
+
+2012-05-16 H.J. Lu <hongjiu.lu@intel.com>
+
+ * configure: Regenerated.
+
+2012-05-05 Nicolas Lelong
+
+ * libffi.xcodeproj/project.pbxproj: Fixes.
+ * README: Update for iOS builds.
+
+2012-04-23 Alexandre Keunecke I. de Mendonca <alexandre.keunecke@gmail.com>
+
+ * configure.ac: Add Blackfin/sysv support
+ * Makefile.am: Add Blackfin/sysv support
+ * src/bfin/ffi.c: Add Blackfin/sysv support
+ * src/bfin/ffitarget.h: Add Blackfin/sysv support
+
+2012-04-11 Anthony Green <green@moxielogic.com>
+
+ * Makefile.am (EXTRA_DIST): Add new script.
+ * Makefile.in: Rebuilt.
+
+2012-04-11 Zachary Waldowski <zwaldowski@gmail.com>
+
+ * generate-ios-source-and-headers.py,
+ libffi.xcodeproj/project.pbxproj: Support a Mac static library via
+ Xcode. Set iOS compatibility to 4.0. Move iOS trampoline
+ generation into an Xcode "run script" phase. Include both as
+ Xcode build scripts. Don't always regenerate config files.
+
+2012-04-10 Anthony Green <green@moxielogic.com>
+
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Add missing semicolon.
+
+2012-04-06 Anthony Green <green@moxielogic.com>
+
+ * Makefile.am (EXTRA_DIST): Add new iOS/xcode files.
+ * Makefile.in: Rebuilt.
+
+2012-04-06 Mike Lewis <mikelikespie@gmail.com>
+
+ * generate-ios-source-and-headers.py: New file.
+ * libffi.xcodeproj/project.pbxproj: New file.
+ * README: Update instructions on building iOS binary.
+ * build-ios.sh: Delete.
+
+2012-04-06 Anthony Green <green@moxielogic.com>
+
+ * src/x86/ffi64.c (UINT128): Define differently for Intel and GNU
+ compilers, then use it.
+
+2012-04-06 H.J. Lu <hongjiu.lu@intel.com>
+
+ * m4/libtool.m4 (_LT_ENABLE_LOCK): Support x32.
+
+2012-04-06 Anthony Green <green@moxielogic.com>
+
+ * testsuite/Makefile.am (EXTRA_DIST): Add missing test cases.
+ * testsuite/Makefile.in: Rebuilt.
+
+2012-04-05 Zachary Waldowski <zwaldowski@gmail.com>
+
+ * include/ffi.h.in: Add missing trampoline table fields.
+ * src/arm/sysv.S: Fix ENTRY definition, and wrap symbol references
+ in CNAME.
+ * src/x86/ffi.c: Wrap Windows specific code in ifdefs.
+
+2012-04-02 Peter Bergner <bergner@vnet.ibm.com>
+
+ * src/powerpc/ffi.c (ffi_prep_args_SYSV): Declare double_tmp.
+ Silence casting pointer to integer of different size warning.
+ Delete goto to previously deleted label.
+ (ffi_call): Silence possibly undefined warning.
+ (ffi_closure_helper_SYSV): Declare variable type.
+
+2012-04-02 Peter Rosin <peda@lysator.liu.se>
+
+ * src/x86/win32.S (ffi_call_win32): Sign/zero extend the return
+ value in the Intel version as is already done for the AT&T version.
+ (ffi_closure_SYSV): Likewise.
+ (ffi_closure_raw_SYSV): Likewise.
+ (ffi_closure_STDCALL): Likewise.
+
+2012-03-29 Peter Rosin <peda@lysator.liu.se>
+
+ * src/x86/win32.S (ffi_closure_raw_THISCALL): Unify the frame
+ generation, fix the ENDP label and remove the surplus third arg
+ from the 'lea' insn.
+
+2012-03-29 Peter Rosin <peda@lysator.liu.se>
+
+ * src/x86/win32.S (ffi_closure_raw_SYSV): Make the 'stubraw' label
+ visible outside the PROC, so that ffi_closure_raw_THISCALL can see
+ it. Also instruct the assembler to add a frame to the function.
+
+2012-03-23 Peter Rosin <peda@lysator.liu.se>
+
+ * Makefile.am (AM_CPPFLAGS): Add -DFFI_BUILDING.
+ * Makefile.in: Rebuilt.
+ * include/ffi.h.in [MSVC]: Add __declspec(dllimport) decorations
+ to all data exports, when compiling libffi clients using MSVC.
+
+2012-03-29 Peter Rosin <peda@lysator.liu.se>
+
+ * src/x86/ffitarget.h (ffi_abi): Add new ABI FFI_MS_CDECL and
+ make it the default for MSVC.
+ (FFI_TYPE_MS_STRUCT): New structure return convention.
+ * src/x86/ffi.c (ffi_prep_cif_machdep): Tweak the structure
+ return convention for FFI_MS_CDECL to be FFI_TYPE_MS_STRUCT
+ instead of an ordinary FFI_TYPE_STRUCT.
+ (ffi_prep_args): Treat FFI_TYPE_MS_STRUCT as FFI_TYPE_STRUCT.
+ (ffi_call): Likewise.
+ (ffi_prep_incoming_args_SYSV): Likewise.
+ (ffi_raw_call): Likewise.
+ (ffi_prep_closure_loc): Treat FFI_MS_CDECL as FFI_SYSV.
+ * src/x86/win32.S (ffi_closure_SYSV): For FFI_TYPE_MS_STRUCT,
+ return a pointer to the result structure in eax and don't pop
+ that pointer from the stack, the caller takes care of it.
+ (ffi_call_win32): Treat FFI_TYPE_MS_STRUCT as FFI_TYPE_STRUCT.
+ (ffi_closure_raw_SYSV): Likewise.
+
+2012-03-22 Peter Rosin <peda@lysator.liu.se>
+
+ * testsuite/libffi.call/closure_stdcall.c [MSVC]: Add inline
+ assembly version with Intel syntax.
+ * testsuite/libffi.call/closure_thiscall.c [MSVC]: Likewise.
+
+2012-03-23 Peter Rosin <peda@lysator.liu.se>
+
+ * testsuite/libffi.call/ffitest.h: Provide abstration of
+ __attribute__((fastcall)) in the form of a __FASTCALL__
+ define. Define it to __fastcall for MSVC.
+ * testsuite/libffi.call/fastthis1_win32.c: Use the above.
+ * testsuite/libffi.call/fastthis2_win32.c: Likewise.
+ * testsuite/libffi.call/fastthis3_win32.c: Likewise.
+ * testsuite/libffi.call/strlen2_win32.c: Likewise.
+ * testsuite/libffi.call/struct1_win32.c: Likewise.
+ * testsuite/libffi.call/struct2_win32.c: Likewise.
+
+2012-03-22 Peter Rosin <peda@lysator.liu.se>
+
+ * src/x86/win32.S [MSVC] (ffi_closure_THISCALL): Remove the manual
+ frame on function entry, MASM adds one automatically.
+
+2012-03-22 Peter Rosin <peda@lysator.liu.se>
+
+ * testsuite/libffi.call/ffitest.h [MSVC]: Add kludge for missing
+ bits in the MSVC headers.
+
+2012-03-22 Peter Rosin <peda@lysator.liu.se>
+
+ * testsuite/libffi.call/cls_12byte.c: Adjust to the C89 style
+ with no declarations after statements.
+ * testsuite/libffi.call/cls_16byte.c: Likewise.
+ * testsuite/libffi.call/cls_18byte.c: Likewise.
+ * testsuite/libffi.call/cls_19byte.c: Likewise.
+ * testsuite/libffi.call/cls_1_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte1.c: Likewise.
+ * testsuite/libffi.call/cls_24byte.c: Likewise.
+ * testsuite/libffi.call/cls_2byte.c: Likewise.
+ * testsuite/libffi.call/cls_3_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_3byte1.c: Likewise.
+ * testsuite/libffi.call/cls_3byte2.c: Likewise.
+ * testsuite/libffi.call/cls_4_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_4byte.c: Likewise.
+ * testsuite/libffi.call/cls_5_1_byte.c: Likewise.
+ * testsuite/libffi.call/cls_5byte.c: Likewise.
+ * testsuite/libffi.call/cls_64byte.c: Likewise.
+ * testsuite/libffi.call/cls_6_1_byte.c: Likewise.
+ * testsuite/libffi.call/cls_6byte.c: Likewise.
+ * testsuite/libffi.call/cls_7_1_byte.c: Likewise.
+ * testsuite/libffi.call/cls_7byte.c: Likewise.
+ * testsuite/libffi.call/cls_8byte.c: Likewise.
+ * testsuite/libffi.call/cls_9byte1.c: Likewise.
+ * testsuite/libffi.call/cls_9byte2.c: Likewise.
+ * testsuite/libffi.call/cls_align_double.c: Likewise.
+ * testsuite/libffi.call/cls_align_float.c: Likewise.
+ * testsuite/libffi.call/cls_align_longdouble.c: Likewise.
+ * testsuite/libffi.call/cls_align_longdouble_split.c: Likewise.
+ * testsuite/libffi.call/cls_align_longdouble_split2.c: Likewise.
+ * testsuite/libffi.call/cls_align_pointer.c: Likewise.
+ * testsuite/libffi.call/cls_align_sint16.c: Likewise.
+ * testsuite/libffi.call/cls_align_sint32.c: Likewise.
+ * testsuite/libffi.call/cls_align_sint64.c: Likewise.
+ * testsuite/libffi.call/cls_align_uint16.c: Likewise.
+ * testsuite/libffi.call/cls_align_uint32.c: Likewise.
+ * testsuite/libffi.call/cls_align_uint64.c: Likewise.
+ * testsuite/libffi.call/cls_dbls_struct.c: Likewise.
+ * testsuite/libffi.call/cls_pointer_stack.c: Likewise.
+ * testsuite/libffi.call/err_bad_typedef.c: Likewise.
+ * testsuite/libffi.call/huge_struct.c: Likewise.
+ * testsuite/libffi.call/nested_struct.c: Likewise.
+ * testsuite/libffi.call/nested_struct1.c: Likewise.
+ * testsuite/libffi.call/nested_struct10.c: Likewise.
+ * testsuite/libffi.call/nested_struct2.c: Likewise.
+ * testsuite/libffi.call/nested_struct3.c: Likewise.
+ * testsuite/libffi.call/nested_struct4.c: Likewise.
+ * testsuite/libffi.call/nested_struct5.c: Likewise.
+ * testsuite/libffi.call/nested_struct6.c: Likewise.
+ * testsuite/libffi.call/nested_struct7.c: Likewise.
+ * testsuite/libffi.call/nested_struct8.c: Likewise.
+ * testsuite/libffi.call/nested_struct9.c: Likewise.
+ * testsuite/libffi.call/stret_large.c: Likewise.
+ * testsuite/libffi.call/stret_large2.c: Likewise.
+ * testsuite/libffi.call/stret_medium.c: Likewise.
+ * testsuite/libffi.call/stret_medium2.c: Likewise.
+ * testsuite/libffi.call/struct1.c: Likewise.
+ * testsuite/libffi.call/struct1_win32.c: Likewise.
+ * testsuite/libffi.call/struct2.c: Likewise.
+ * testsuite/libffi.call/struct2_win32.c: Likewise.
+ * testsuite/libffi.call/struct3.c: Likewise.
+ * testsuite/libffi.call/struct4.c: Likewise.
+ * testsuite/libffi.call/struct5.c: Likewise.
+ * testsuite/libffi.call/struct6.c: Likewise.
+ * testsuite/libffi.call/struct7.c: Likewise.
+ * testsuite/libffi.call/struct8.c: Likewise.
+ * testsuite/libffi.call/struct9.c: Likewise.
+ * testsuite/libffi.call/testclosure.c: Likewise.
+
+2012-03-21 Peter Rosin <peda@lysator.liu.se>
+
+ * testsuite/libffi.call/float_va.c (float_va_fn): Use %f when
+ printing doubles (%lf is for long doubles).
+ (main): Likewise.
+
+2012-03-21 Peter Rosin <peda@lysator.liu.se>
+
+ * testsuite/lib/target-libpath.exp [*-*-cygwin*, *-*-mingw*]
+ (set_ld_library_path_env_vars): Add the library search dir to PATH
+ (and save PATH for later).
+ (restore_ld_library_path_env_vars): Restore PATH.
+
+2012-03-21 Peter Rosin <peda@lysator.liu.se>
+
+ * testsuite/lib/target-libpath.exp [*-*-cygwin*, *-*-mingw*]
+ (set_ld_library_path_env_vars): Add the library search dir to PATH
+ (and save PATH for later).
+ (restore_ld_library_path_env_vars): Restore PATH.
+
+2012-03-20 Peter Rosin <peda@lysator.liu.se>
+
+ * testsuite/libffi.call/strlen2_win32.c (main): Remove bug.
+ * src/x86/win32.S [MSVC] (ffi_closure_SYSV): Make the 'stub' label
+ visible outside the PROC, so that ffi_closure_THISCALL can see it.
+
+2012-03-20 Peter Rosin <peda@lysator.liu.se>
+
+ * testsuite/libffi.call/strlen2_win32.c (main): Remove bug.
+ * src/x86/win32.S [MSVC] (ffi_closure_SYSV): Make the 'stub' label
+ visible outside the PROC, so that ffi_closure_THISCALL can see it.
+
+2012-03-19 Alan Hourihane <alanh@fairlite.co.uk>
+
+ * src/m68k/ffi.c: Add MINT support.
+ * src/m68k/sysv.S: Ditto.
+
+2012-03-06 Chung-Lin Tang <cltang@codesourcery.com>
+
+ * src/arm/ffi.c (ffi_call): Add __ARM_EABI__ guard around call to
+ ffi_call_VFP().
+ (ffi_prep_closure_loc): Add __ARM_EABI__ guard around use of
+ ffi_closure_VFP.
+ * src/arm/sysv.S: Add __ARM_EABI__ guard around VFP code.
+
+2012-03-19 chennam <csit@axway.com>
+
+ * src/powerpc/ffi_darwin.c (ffi_prep_closure_loc): Fix AIX closure
+ support.
+
+2012-03-13 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/ffi.c (ffi_prep_closure_loc): Don't ASSERT ABI test,
+ just return FFI_BAD_ABI when things are wrong.
+ * src/sh64/ffi.c (ffi_prep_closure_loc): Ditto.
+
+2012-03-09 David Edelsohn <dje.gcc@gmail.com>
+
+ * src/powerpc/aix_closure.S (ffi_closure_ASM): Adjust for Darwin64
+ change to return value of ffi_closure_helper_DARWIN and load type
+ from return type.
+
+2012-03-03 H.J. Lu <hongjiu.lu@intel.com>
+
+ * src/x86/ffi64.c (ffi_call): Cast the return value to unsigned
+ long.
+ (ffi_prep_closure_loc): Cast to 64bit address in trampoline.
+ (ffi_closure_unix64_inner): Cast return pointer to unsigned long
+ first.
+
+ * src/x86/ffitarget.h (FFI_SIZEOF_ARG): Defined to 8 for x32.
+ (ffi_arg): Set to unsigned long long for x32.
+ (ffi_sarg): Set to long long for x32.
+
+2012-03-03 H.J. Lu <hongjiu.lu@intel.com>
+
+ * src/prep_cif.c (ffi_prep_cif_core): Properly check bad ABI.
+
+2012-03-03 Andoni Morales Alastruey <ylatuya@gmail.com>
+
+ * configure.ac: Add -no-undefined for both 32- and 64-bit x86
+ windows-like hosts.
+ * configure: Rebuilt.
+
+2012-02-27 Mikael Pettersson <mikpe@it.uu.se>
+
+ PR libffi/52223
+ * Makefile.am (FLAGS_TO_PASS): Define.
+ * Makefile.in: Regenerate.
+
+2012-02-23 Anthony Green <green@moxielogic.com>
+
+ * src/*/ffitarget.h: Ensure that users never include ffitarget.h
+ directly.
+
+2012-02-23 Kai Tietz <ktietz@redhat.com>
+
+ PR libffi/52221
+ * src/x86/ffi.c (ffi_closure_raw_THISCALL): New
+ prototype.
+ (ffi_prep_raw_closure_loc): Use ffi_closure_raw_THISCALL for
+ thiscall-convention.
+ (ffi_raw_call): Use ffi_prep_args_raw.
+ * src/x86/win32.S (ffi_closure_raw_THISCALL): Add
+ implementation for stub.
+
+2012-02-10 Kai Tietz <ktietz@redhat.com>
+
+ * configure.ac (AM_LTLDFLAGS): Add -no-undefine for x64
+ windows target.
+ * configure: Regenerated.
+
+2012-02-08 Kai Tietz <ktietz@redhat.com>
+
+ * src/prep_cif.c (ffi_prep_cif): Allow for X86_WIN32
+ also FFI_THISCALL.
+ * src/x86/ffi.c (ffi_closure_THISCALL): Add prototype.
+ (FFI_INIT_TRAMPOLINE_THISCALL): New trampoline code.
+ (ffi_prep_closure_loc): Add FFI_THISCALL support.
+ * src/x86/ffitarget.h (FFI_TRAMPOLINE_SIZE): Adjust size.
+ * src/x86/win32.S (ffi_closure_THISCALL): New closure code
+ for thiscall-calling convention.
+ * testsuite/libffi.call/closure_thiscall.c: New test.
+
+2012-01-28 Kai Tietz <ktietz@redhat.com>
+
+ * src/libffi/src/x86/ffi.c (ffi_call_win32): Add new
+ argument to prototype for specify calling-convention.
+ (ffi_call): Add support for stdcall/thiscall convention.
+ (ffi_prep_args): Likewise.
+ (ffi_raw_call): Likewise.
+ * src/x86/ffitarget.h (ffi_abi): Add FFI_THISCALL and
+ FFI_FASTCALL.
+ * src/x86/win32.S (_ffi_call_win32): Add support for
+ fastcall/thiscall calling-convention calls.
+ * testsuite/libffi.call/fastthis1_win32.c: New test.
+ * testsuite/libffi.call/fastthis2_win32.c: New test.
+ * testsuite/libffi.call/fastthis3_win32.c: New test.
+ * testsuite/libffi.call/strlen2_win32.c: New test.
+ * testsuite/libffi.call/many2_win32.c: New test.
+ * testsuite/libffi.call/struct1_win32.c: New test.
+ * testsuite/libffi.call/struct2_win32.c: New test.
+
+2012-01-23 Uros Bizjak <ubizjak@gmail.com>
+
+ * src/alpha/ffi.c (ffi_prep_closure_loc): Check for bad ABI.
+
+2012-01-23 Anthony Green <green@moxielogic.com>
+ Chris Young <cdyoung@ntlworld.com>
+
+ * configure.ac: Add Amiga support.
+ * configure: Rebuilt.
+
+2012-01-23 Dmitry Nadezhin <dmitry.nadezhin@gmail.com>
+
+ * include/ffi_common.h (LIKELY, UNLIKELY): Fix definitions.
+
+2012-01-23 Andreas Schwab <schwab@linux-m68k.org>
+
+ * src/m68k/sysv.S (ffi_call_SYSV): Properly test for plain
+ mc68000. Test for __HAVE_68881__ in addition to __MC68881__.
+
+2012-01-19 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/48496
+ * src/ia64/ffi.c (ffi_call): Fix up aliasing violations.
+
+2012-01-09 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * configure.ac (i?86-*-*): Set TARGET to X86_64.
+ * configure: Regenerate.
+
+2011-12-07 Andrew Pinski <apinski@cavium.com>
+
+ PR libffi/50051
+ * src/mips/n32.S: Add ".set mips4".
+
+2011-11-21 Andreas Tobler <andreast@fgznet.ch>
+
+ * configure: Regenerate.
+
+2011-11-12 David Gilbert <david.gilbert@linaro.org>
+
+ * doc/libffi.texi, include/ffi.h.in, include/ffi_common.h,
+ man/Makefile.am, man/ffi.3, man/ffi_prep_cif.3,
+ man/ffi_prep_cif_var.3, src/arm/ffi.c, src/arm/ffitarget.h,
+ src/cris/ffi.c, src/prep_cif.c,
+ testsuite/libffi.call/cls_double_va.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/float_va.c: Many changes to support variadic
+ function calls.
+
+2011-11-12 Kyle Moffett <Kyle.D.Moffett@boeing.com>
+
+ * src/powerpc/ffi.c, src/powerpc/ffitarget.h,
+ src/powerpc/ppc_closure.S, src/powerpc/sysv.S: Many changes for
+ softfloat powerpc variants.
+
+2011-11-12 Petr Salinger <Petr.Salinger@seznam.cz>
+
+ * configure.ac (FFI_EXEC_TRAMPOLINE_TABLE): Fix kfreebsd support.
+ * configure: Rebuilt.
+
+2011-11-12 Timothy Wall <twall@users.sf.net>
+
+ * src/arm/ffi.c (ffi_prep_args, ffi_prep_incoming_args_SYSV): Max
+ alignment of 4 for wince on ARM.
+
+2011-11-12 Kyle Moffett <Kyle.D.Moffett@boeing.com>
+ Anthony Green <green@moxielogic.com>
+
+ * src/ppc/sysv.S, src/ppc/ffi.c: Remove use of ppc string
+ instructions (not available on some cores, like the PPC440).
+
+2011-11-12 Kimura Wataru <kimuraw@i.nifty.jp>
+
+ * m4/ax_enable_builddir: Change from string comparison to numeric
+ comparison for wc output.
+ * configure.ac: Enable FFI_MMAP_EXEC_WRIT for darwin11 aka Mac OS
+ X 10.7.
+ * configure: Rebuilt.
+
+2011-11-12 Anthony Green <green@moxielogic.com>
+
+ * Makefile.am (AM_CCASFLAGS): Add -g option to build assembly
+ files with debug info.
+ * Makefile.in: Rebuilt.
+
+2011-11-12 Jasper Lievisse Adriaanse <jasper@openbsd.org>
+
+ * README: Update list of supported OpenBSD systems.
+
+2011-11-12 Anthony Green <green@moxielogic.com>
+
+ * libtool-version: Update.
+ * Makefile.am (nodist_libffi_la_SOURCES): Add src/debug.c if
+ FFI_DEBUG.
+ (libffi_la_SOURCES): Remove src/debug.c
+ (EXTRA_DIST): Add src/debug.c
+ * Makefile.in: Rebuilt.
+ * README: Update for 3.0.11.
+
+2011-11-10 Richard Henderson <rth@redhat.com>
+
+ * configure.ac (GCC_AS_CFI_PSEUDO_OP): Use it instead of inline check.
+ * configure, aclocal.m4: Rebuild.
+
+2011-09-04 Iain Sandoe <iains@gcc.gnu.org>
+
+ PR libffi/49594
+ * src/powerpc/darwin_closure.S (stubs): Make the stub binding
+ helper reference track the architecture pointer size.
+
+2011-08-25 Andrew Haley <aph@redhat.com>
+
+ * src/arm/ffi.c (FFI_INIT_TRAMPOLINE): Remove hard-coded assembly
+ instructions.
+ * src/arm/sysv.S (ffi_arm_trampoline): Put them here instead.
+
+2011-07-11 Andrew Haley <aph@redhat.com>
+
+ * src/arm/ffi.c (FFI_INIT_TRAMPOLINE): Clear icache.
+
+2011-06-29 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * testsuite/libffi.call/cls_double_va.c: Move PR number to comment.
+ * testsuite/libffi.call/cls_longdouble_va.c: Likewise.
+
+2011-06-29 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ PR libffi/46660
+ * testsuite/libffi.call/cls_double_va.c: xfail dg-output on
+ mips-sgi-irix6*.
+ * testsuite/libffi.call/cls_longdouble_va.c: Likewise.
+
+2011-06-14 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * testsuite/libffi.call/huge_struct.c (test_large_fn): Use PRIu8,
+ PRId8 instead of %hhu, %hhd.
+ * testsuite/libffi.call/ffitest.h [__alpha__ && __osf__] (PRId8,
+ PRIu8): Define.
+ [__sgi__] (PRId8, PRIu8): Define.
+
+2011-04-29 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * src/alpha/osf.S (UA_SI, FDE_ENCODING, FDE_ENCODE, FDE_ARANGE):
+ Define.
+ Use them to handle ELF vs. ECOFF differences.
+ [__osf__] (_GLOBAL__F_ffi_call_osf): Define.
+
+2011-03-30 Timothy Wall <twall@users.sf.net>
+
+ * src/powerpc/darwin.S: Fix unknown FDE encoding.
+ * src/powerpc/darwin_closure.S: ditto.
+
+2011-02-25 Anthony Green <green@moxielogic.com>
+
+ * src/powerpc/ffi.c (ffi_prep_closure_loc): Allow for more
+ 32-bit ABIs.
+
+2011-02-15 Anthony Green <green@moxielogic.com>
+
+ * m4/ax_cc_maxopt.m4: Don't -malign-double or use -ffast-math.
+ * configure: Rebuilt.
+
+2011-02-13 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * configure: Regenerate.
+
+2011-02-13 Anthony Green <green@moxielogic.com>
+
+ * include/ffi_common.h (UNLIKELY, LIKELY): Define.
+ * src/x86/ffi64.c (UNLIKELY, LIKELY): Remove definition.
+ * src/prep_cif.c (UNLIKELY, LIKELY): Remove definition.
+
+ * src/prep_cif.c (initialize_aggregate): Convert assertion into
+ FFI_BAD_TYPEDEF return. Initialize arg size and alignment to 0.
+
+ * src/pa/ffi.c (ffi_prep_closure_loc): Don't ASSERT ABI test,
+ just return FFI_BAD_ABI when things are wrong.
+ * src/arm/ffi.c (ffi_prep_closure_loc): Ditto.
+ * src/powerpc/ffi.c (ffi_prep_closure_loc): Ditto.
+ * src/mips/ffi.c (ffi_prep_closure_loc): Ditto.
+ * src/ia64/ffi.c (ffi_prep_closure_loc): Ditto.
+ * src/avr32/ffi.c (ffi_prep_closure_loc): Ditto.
+
+2011-02-11 Anthony Green <green@moxielogic.com>
+
+ * src/sparc/ffi.c (ffi_prep_closure_loc): Don't ASSERT ABI test,
+ just return FFI_BAD_ABI when things are wrong.
+
+2012-02-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * src/sparc/v9.S (STACKFRAME): Bump to 176.
+
+2011-02-09 Stuart Shelton <srcshelton@gmail.com>
+
+ http://bugs.gentoo.org/show_bug.cgi?id=286911
+ * src/mips/ffitarget.h: Clean up error messages.
+ * src/java_raw_api.c (ffi_java_translate_args): Cast raw arg to
+ ffi_raw*.
+ * include/ffi.h.in: Add pragma for SGI compiler.
+
+2011-02-09 Anthony Green <green@moxielogic.com>
+
+ * configure.ac: Add powerpc64-*-darwin* support.
+
+2011-02-09 Anthony Green <green@moxielogic.com>
+
+ * README: Mention Interix.
+
+2011-02-09 Jonathan Callen <abcd@gentoo.org>
+
+ * configure.ac: Add Interix to win32/cygwin/mingw case.
+ * configure: Ditto.
+ * src/closures.c: Treat Interix like Cygwin, instead of as a
+ generic win32.
+
+2011-02-09 Anthony Green <green@moxielogic.com>
+
+ * testsuite/libffi.call/err_bad_typedef.c: Remove xfail.
+ * testsuite/libffi.call/err_bad_abi.c: Remove xfail.
+ * src/x86/ffi64.c (UNLIKELY, LIKELY): Define.
+ (ffi_prep_closure_loc): Check for bad ABI.
+ * src/prep_cif.c (UNLIKELY, LIKELY): Define.
+ (initialize_aggregate): Check for bad types.
+
+2011-02-09 Landon Fuller <landonf@plausible.coop>
+
+ * Makefile.am (EXTRA_DIST): Add build-ios.sh, src/arm/gentramp.sh,
+ src/arm/trampoline.S.
+ (nodist_libffi_la_SOURCES): Add src/arc/trampoline.S.
+ * configure.ac (FFI_EXEC_TRAMPOLINE_TABLE): Define.
+ * src/arm/ffi.c (ffi_trampoline_table)
+ (ffi_closure_trampoline_table_page, ffi_trampoline_table_entry)
+ (FFI_TRAMPOLINE_CODELOC_CONFIG, FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET)
+ (FFI_TRAMPOLINE_COUNT, ffi_trampoline_lock, ffi_trampoline_tables)
+ (ffi_trampoline_table_alloc, ffi_closure_alloc, ffi_closure_free):
+ Define for FFI_EXEC_TRAMPOLINE_TABLE case (iOS).
+ (ffi_prep_closure_loc): Handl FFI_EXEC_TRAMPOLINE_TABLE case
+ separately.
+ * src/arm/sysv.S: Handle Apple iOS host.
+ * src/closures.c: Handle FFI_EXEC_TRAMPOLINE_TABLE case.
+ * build-ios.sh: New file.
+ * fficonfig.h.in, configure, Makefile.in: Rebuilt.
+ * README: Mention ARM iOS.
+
+2011-02-08 Oren Held <orenhe@il.ibm.com>
+
+ * src/dlmalloc.c (_STRUCT_MALLINFO): Define in order to avoid
+ redefinition of mallinfo on HP-UX.
+
+2011-02-08 Ginn Chen <ginn.chen@oracle.com>
+
+ * src/sparc/ffi.c (ffi_call): Make compatible with Solaris Studio
+ aggregate return ABI. Flush cache.
+ (ffi_prep_closure_loc): Flush cache.
+
+2011-02-11 Anthony Green <green@moxielogic.com>
+
+ From Tom Honermann <tom.honermann@oracle.com>:
+ * src/powerpc/aix.S (ffi_call_AIX): Support for xlc toolchain on
+ AIX. Declare .ffi_prep_args. Insert nops after branch
+ instructions so that the AIX linker can insert TOC reload
+ instructions.
+ * src/powerpc/aix_closure.S: Declare .ffi_closure_helper_DARWIN.
+
+2011-02-08 Ed <ed@kdtc.net>
+
+ * src/powerpc/asm.h: Fix grammar nit in comment.
+
+2011-02-08 Uli Link <ul.mcamafia@linkitup.de>
+
+ * include/ffi.h.in (FFI_64_BIT_MAX): Define and use.
+
+2011-02-09 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ PR libffi/46661
+ * testsuite/libffi.call/cls_pointer.c (main): Cast void * to
+ uintptr_t first.
+ * testsuite/libffi.call/cls_pointer_stack.c (main): Likewise.
+
+2011-02-08 Rafael Avila de Espindola <respindola@mozilla.com>
+
+ * configure.ac: Fix x86 test for pc related relocs.
+ * configure: Rebuilt.
+
+2011-02-07 Joel Sherrill <joel.sherrill@oarcorp.com>
+
+ * libffi/src/m68k/ffi.c: Add RTEMS support for cache flushing.
+ Handle case when CPU variant does not have long double support.
+ * libffi/src/m68k/sysv.S: Add support for mc68000, Coldfire,
+ and cores with soft floating point.
+
+2011-02-07 Joel Sherrill <joel.sherrill@oarcorp.com>
+
+ * configure.ac: Add mips*-*-rtems* support.
+ * configure: Regenerate.
+ * src/mips/ffitarget.h: Ensure needed constants are available
+ for targets which do not have sgidefs.h.
+
+2011-01-26 Dave Korn <dave.korn.cygwin@gmail.com>
+
+ PR target/40125
+ * configure.ac (AM_LTLDFLAGS): Add -bindir option for windows DLLs.
+ * configure: Regenerate.
+
+2010-12-18 Iain Sandoe <iains@gcc.gnu.org>
+
+ PR libffi/29152
+ PR libffi/42378
+ * src/powerpc/darwin_closure.S: Provide Darwin64 implementation,
+ update comments.
+ * src/powerpc/ffitarget.h (POWERPC_DARWIN64): New,
+ (FFI_TRAMPOLINE_SIZE): Update for Darwin64.
+ * src/powerpc/darwin.S: Provide Darwin64 implementation,
+ update comments.
+ * src/powerpc/ffi_darwin.c: Likewise.
+
+2010-12-06 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * configure.ac (libffi_cv_as_ascii_pseudo_op): Use double
+ backslashes.
+ (libffi_cv_as_string_pseudo_op): Likewise.
+ * configure: Regenerate.
+
+2010-12-03 Chung-Lin Tang <cltang@codesourcery.com>
+
+ * src/arm/sysv.S (ffi_closure_SYSV): Add UNWIND to .pad directive.
+ (ffi_closure_VFP): Same.
+ (ffi_call_VFP): Move down to before ffi_closure_VFP. Add '.fpu vfp'
+ directive.
+
+2010-12-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * testsuite/libffi.call/ffitest.h [__sgi] (PRId64, PRIu64): Define.
+ (PRIuPTR): Define.
+
+2010-11-29 Richard Henderson <rth@redhat.com>
+ Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * src/x86/sysv.S (FDE_ENCODING, FDE_ENCODE): Define.
+ (.eh_frame): Use FDE_ENCODING.
+ (.LASFDE1, .LASFDE2, LASFDE3): Simplify with FDE_ENCODE.
+
+2010-11-22 Jacek Caban <jacek@codeweavers.com>
+
+ * configure.ac: Check for symbol underscores on mingw-w64.
+ * configure: Rebuilt.
+ * src/x86/win64.S: Correctly access extern symbols in respect to
+ underscores.
+
+2010-11-15 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * testsuite/lib/libffi-dg.exp: Rename ...
+ * testsuite/lib/libffi.exp: ... to this.
+ * libffi/testsuite/libffi.call/call.exp: Don't load libffi-dg.exp.
+ * libffi/testsuite/libffi.special/special.exp: Likewise.
+
+2010-10-28 Chung-Lin Tang <cltang@codesourcery.com>
+
+ * src/arm/ffi.c (ffi_prep_args): Add VFP register argument handling
+ code, new parameter, and return value. Update comments.
+ (ffi_prep_cif_machdep): Add case for VFP struct return values. Add
+ call to layout_vfp_args().
+ (ffi_call_SYSV): Update declaration.
+ (ffi_call_VFP): New declaration.
+ (ffi_call): Add VFP struct return conditions. Call ffi_call_VFP()
+ when ABI is FFI_VFP.
+ (ffi_closure_VFP): New declaration.
+ (ffi_closure_SYSV_inner): Add new vfp_args parameter, update call to
+ ffi_prep_incoming_args_SYSV().
+ (ffi_prep_incoming_args_SYSV): Update parameters. Add VFP argument
+ case handling.
+ (ffi_prep_closure_loc): Pass ffi_closure_VFP to trampoline
+ construction under VFP hard-float.
+ (rec_vfp_type_p): New function.
+ (vfp_type_p): Same.
+ (place_vfp_arg): Same.
+ (layout_vfp_args): Same.
+ * src/arm/ffitarget.h (ffi_abi): Add FFI_VFP. Define FFI_DEFAULT_ABI
+ based on __ARM_PCS_VFP.
+ (FFI_EXTRA_CIF_FIELDS): Define for adding VFP hard-float specific
+ fields.
+ (FFI_TYPE_STRUCT_VFP_FLOAT): Define internally used type code.
+ (FFI_TYPE_STRUCT_VFP_DOUBLE): Same.
+ * src/arm/sysv.S (ffi_call_SYSV): Change call of ffi_prep_args() to
+ direct call. Move function pointer load upwards.
+ (ffi_call_VFP): New function.
+ (ffi_closure_VFP): Same.
+
+ * testsuite/lib/libffi-dg.exp (check-flags): New function.
+ (dg-skip-if): New function.
+ * testsuite/libffi.call/cls_double_va.c: Skip if target is arm*-*-*
+ and compiler options include -mfloat-abi=hard.
+ * testsuite/libffi.call/cls_longdouble_va.c: Same.
+
+2010-10-01 Jakub Jelinek <jakub@redhat.com>
+
+ PR libffi/45677
+ * src/x86/ffi64.c (ffi_prep_cif_machdep): Ensure cif->bytes is
+ a multiple of 8.
+ * testsuite/libffi.call/many2.c: New test.
+
+2010-08-20 Mark Wielaard <mjw@redhat.com>
+
+ * src/closures.c (open_temp_exec_file_mnt): Check if getmntent_r
+ returns NULL.
+
+2010-08-09 Andreas Tobler <andreast@fgznet.ch>
+
+ * configure.ac: Add target powerpc64-*-freebsd*.
+ * configure: Regenerate.
+ * testsuite/libffi.call/cls_align_longdouble_split.c: Pass
+ -mlong-double-128 only to linux targets.
+ * testsuite/libffi.call/cls_align_longdouble_split2.c: Likewise.
+ * testsuite/libffi.call/cls_longdouble.c: Likewise.
+ * testsuite/libffi.call/huge_struct.c: Likewise.
+
+2010-08-05 Dan Witte <dwitte@mozilla.com>
+
+ * Makefile.am: Pass FFI_DEBUG define to msvcc.sh for linking to the
+ debug CRT when --enable-debug is given.
+ * configure.ac: Define it.
+ * msvcc.sh: Translate -g and -DFFI_DEBUG appropriately.
+
+2010-08-04 Dan Witte <dwitte@mozilla.com>
+
+ * src/x86/ffitarget.h: Add X86_ANY define for all x86/x86_64
+ platforms.
+ * src/x86/ffi.c: Remove redundant ifdef checks.
+ * src/prep_cif.c: Push stack space computation into src/x86/ffi.c
+ for X86_ANY so return value space doesn't get added twice.
+
+2010-08-03 Neil Rashbrooke <neil@parkwaycc.co.uk>
+
+ * msvcc.sh: Don't pass -safeseh to ml64 because behavior is buggy.
+
+2010-07-22 Dan Witte <dwitte@mozilla.com>
+
+ * src/*/ffitarget.h: Make FFI_LAST_ABI one past the last valid ABI.
+ * src/prep_cif.c: Fix ABI assertion.
+ * src/cris/ffi.c: Ditto.
+
+2010-07-10 Evan Phoenix <evan@fallingsnow.net>
+
+ * src/closures.c (selinux_enabled_check): Fix strncmp usage bug.
+
+2010-07-07 Dan Horák <dan@danny.cz>
+
+ * include/ffi.h.in: Protect #define with #ifndef.
+ * src/powerpc/ffitarget.h: Ditto.
+ * src/s390/ffitarget.h: Ditto.
+ * src/sparc/ffitarget.h: Ditto.
+
+2010-07-07 Neil Roberts <neil@linux.intel.com>
+
+ * src/x86/sysv.S (ffi_call_SYSV): Align the stack pointer to
+ 16-bytes.
+
+2010-07-02 Jakub Jelinek <jakub@redhat.com>
+
+ * Makefile.am (AM_MAKEFLAGS): Pass also mandir to submakes.
+ * Makefile.in: Regenerated.
+
+2010-05-19 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * configure.ac (libffi_cv_as_x86_pcrel): Check for illegal in as
+ output, too.
+ (libffi_cv_as_ascii_pseudo_op): Check for .ascii.
+ (libffi_cv_as_string_pseudo_op): Check for .string.
+ * configure: Regenerate.
+ * fficonfig.h.in: Regenerate.
+ * src/x86/sysv.S (.eh_frame): Use .ascii, .string or error.
+
+2010-05-11 Dan Witte <dwitte@mozilla.com>
+
+ * doc/libffi.tex: Document previous change.
+
+2010-05-11 Makoto Kato <m_kato@ga2.so-net.ne.jp>
+
+ * src/x86/ffi.c (ffi_call): Don't copy structs passed by value.
+
+2010-05-05 Michael Kohler <michaelkohler@live.com>
+
+ * src/dlmalloc.c (dlfree): Fix spelling.
+ * src/ia64/ffi.c (ffi_prep_cif_machdep): Ditto.
+ * configure.ac: Ditto.
+ * configure: Rebuilt.
+
+2010-04-13 Dan Witte <dwitte@mozilla.com>
+
+ * msvcc.sh: Build with -W3 instead of -Wall.
+ * src/powerpc/ffi_darwin.c: Remove build warnings.
+ * src/x86/ffi.c: Ditto.
+ * src/x86/ffitarget.h: Ditto.
+
+2010-04-12 Dan Witte <dwitte@mozilla.com>
+ Walter Meinl <wuno@lsvw.de>
+
+ * configure.ac: Add OS/2 support.
+ * configure: Rebuilt.
+ * src/closures.c: Ditto.
+ * src/dlmalloc.c: Ditto.
+ * src/x86/win32.S: Ditto.
+
+2010-04-07 Jakub Jelinek <jakub@redhat.com>
+
+ * testsuite/libffi.call/err_bad_abi.c: Remove unused args variable.
+
+2010-04-02 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * Makefile.in: Regenerate.
+ * aclocal.m4: Regenerate.
+ * include/Makefile.in: Regenerate.
+ * man/Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2010-03-30 Dan Witte <dwitte@mozilla.com>
+
+ * msvcc.sh: Disable build warnings.
+ * README (tested): Clarify windows build procedure.
+
+2010-03-15 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * configure.ac (libffi_cv_as_x86_64_unwind_section_type): New test.
+ * configure: Regenerate.
+ * fficonfig.h.in: Regenerate.
+ * libffi/src/x86/unix64.S (.eh_frame)
+ [HAVE_AS_X86_64_UNWIND_SECTION_TYPE]: Use @unwind section type.
+
+2010-03-14 Matthias Klose <doko@ubuntu.com>
+
+ * src/x86/ffi64.c: Fix typo in comment.
+ * src/x86/ffi.c: Use /* ... */ comment style.
+
+2010-02-24 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * doc/libffi.texi (The Closure API): Fix typo.
+ * doc/libffi.info: Remove.
+
+2010-02-15 Matthias Klose <doko@ubuntu.com>
+
+ * src/arm/sysv.S (__ARM_ARCH__): Define for processor
+ __ARM_ARCH_7EM__.
+
+2010-01-15 Anthony Green <green@redhat.com>
+
+ * README: Add notes on building with Microsoft Visual C++.
+
+2010-01-15 Daniel Witte <dwitte@mozilla.com>
+
+ * msvcc.sh: New file.
+
+ * src/x86/win32.S: Port assembly routines to MSVC and #ifdef.
+ * src/x86/ffi.c: Tweak function declaration and remove excess
+ parens.
+ * include/ffi.h.in: Add __declspec(align(8)) to typedef struct
+ ffi_closure.
+
+ * src/x86/ffi.c: Merge ffi_call_SYSV and ffi_call_STDCALL into new
+ function ffi_call_win32 on X86_WIN32.
+ * src/x86/win32.S (ffi_call_SYSV): Rename to ffi_call_win32.
+ (ffi_call_STDCALL): Remove.
+
+ * src/prep_cif.c (ffi_prep_cif): Move stack space allocation code
+ to ffi_prep_cif_machdep for x86.
+ * src/x86/ffi.c (ffi_prep_cif_machdep): To here.
+
+2010-01-15 Oliver Kiddle <okiddle@yahoo.co.uk>
+
+ * src/x86/ffitarget.h (ffi_abi): Check for __i386 and __amd64 for
+ Sun Studio compiler compatibility.
+
+2010-01-12 Conrad Irwin <conrad.irwin@gmail.com>
+
+ * doc/libffi.texi: Add closure example.
+
+2010-01-07 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ PR libffi/40701
+ * testsuite/libffi.call/ffitest.h [__alpha__ && __osf__] (PRIdLL,
+ PRIuLL, PRId64, PRIu64, PRIuPTR): Define.
+ * testsuite/libffi.call/cls_align_sint64.c: Add -Wno-format on
+ alpha*-dec-osf*.
+ * testsuite/libffi.call/cls_align_uint64.c: Likewise.
+ * testsuite/libffi.call/cls_ulonglong.c: Likewise.
+ * testsuite/libffi.call/return_ll1.c: Likewise.
+ * testsuite/libffi.call/stret_medium2.c: Likewise.
+ * testsuite/libffi.special/ffitestcxx.h (allocate_mmap): Cast
+ MAP_FAILED to char *.
+
+2010-01-06 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * src/mips/n32.S: Use .abicalls and .eh_frame with __GNUC__.
+
+2009-12-31 Anthony Green <green@redhat.com>
+
+ * README: Update for libffi 3.0.9.
+
+2009-12-27 Matthias Klose <doko@ubuntu.com>
+
+ * configure.ac (HAVE_LONG_DOUBLE): Define for mips when
+ appropriate.
+ * configure: Rebuilt.
+
+2009-12-26 Anthony Green <green@redhat.com>
+
+ * testsuite/libffi.call/cls_longdouble_va.c: Mark as xfail for
+ avr32*-*-*.
+ * testsuite/libffi.call/cls_double_va.c: Ditto.
+
+2009-12-26 Andreas Tobler <a.tobler@schweiz.org>
+
+ * testsuite/libffi.call/ffitest.h: Conditionally include stdint.h
+ and inttypes.h.
+ * testsuite/libffi.special/unwindtest.cc: Ditto.
+
+2009-12-26 Andreas Tobler <a.tobler@schweiz.org>
+
+ * configure.ac: Add amd64-*-openbsd*.
+ * configure: Rebuilt.
+ * testsuite/lib/libffi-dg.exp (libffi_target_compile): Link
+ openbsd programs with -lpthread.
+
+2009-12-26 Anthony Green <green@redhat.com>
+
+ * testsuite/libffi.call/cls_double_va.c,
+ testsuite/libffi.call/cls_longdouble.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/cls_pointer.c,
+ testsuite/libffi.call/cls_pointer_stack.c: Remove xfail for
+ mips*-*-* and arm*-*-*.
+ * testsuite/libffi.call/cls_align_longdouble_split.c,
+ testsuite/libffi.call/cls_align_longdouble_split2.c,
+ testsuite/libffi.call/stret_medium2.c,
+ testsuite/libffi.call/stret_medium.c,
+ testsuite/libffi.call/stret_large.c,
+ testsuite/libffi.call/stret_large2.c: Remove xfail for arm*-*-*.
+
+2009-12-31 Kay Tietz <ktietz70@googlemail.com>
+
+ * testsuite/libffi.call/ffitest.h,
+ testsuite/libffi.special/ffitestcxx.h (PRIdLL, PRuLL): Fix
+ definitions.
+
+2009-12-31 Carlo Bramini <carlo.bramix@libero.it>
+
+ * configure.ac (AM_LTLDFLAGS): Define for windows hosts.
+ * Makefile.am (libffi_la_LDFLAGS): Add AM_LTLDFLAGS.
+ * configure: Rebuilt.
+ * Makefile.in: Rebuilt.
+
+2009-12-31 Anthony Green <green@redhat.com>
+ Blake Chaffin.
+
+ * testsuite/libffi.call/huge_struct.c: New test case from Blake
+ Chaffin @ Apple.
+
+2009-12-28 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Copy abi and nargs to
+ local variables.
+ (aix_adjust_aggregate_sizes): New function.
+ (ffi_prep_cif_machdep): Call it.
+
+2009-12-26 Andreas Tobler <a.tobler@schweiz.org>
+
+ * configure.ac: Define FFI_MMAP_EXEC_WRIT for the given targets.
+ * configure: Regenerate.
+ * fficonfig.h.in: Likewise.
+ * src/closures.c: Remove the FFI_MMAP_EXEC_WRIT definition for
+ Solaris/x86.
+
+2009-12-26 Andreas Schwab <schwab@linux-m68k.org>
+
+ * src/powerpc/ffi.c (ffi_prep_args_SYSV): Advance intarg_count
+ when a float arguments is passed in memory.
+ (ffi_closure_helper_SYSV): Mark general registers as used up when
+ a 64bit or soft-float long double argument is passed in memory.
+
+2009-12-25 Matthias Klose <doko@ubuntu.com>
+
+ * man/ffi_call.3: Fix #include in examples.
+ * doc/libffi.texi: Add dircategory.
+
+2009-12-25 Frank Everdij <f.p.x.everdij@tudelft.nl>
+
+ * include/ffi.h.in: Placed '__GNUC__' ifdef around
+ '__attribute__((aligned(8)))' in ffi_closure, fixes compile for
+ IRIX MIPSPro c99.
+ * include/ffi_common.h: Added '__sgi' define to non
+ '__attribute__((__mode__()))' integer typedefs.
+ * src/mips/ffi.c (ffi_call, ffi_closure_mips_inner_O32,
+ ffi_closure_mips_inner_N32): Added 'defined(_MIPSEB)' to BE check.
+ (ffi_closure_mips_inner_O32, ffi_closure_mips_inner_N32): Added
+ FFI_LONGDOUBLE support and alignment(N32 only).
+ * src/mips/ffitarget.h: Corrected '#include <sgidefs.h>' for IRIX and
+ fixed non '__attribute__((__mode__()))' integer typedefs.
+ * src/mips/n32.S: Put '#ifdef linux' around '.abicalls' and '.eh_frame'
+ since they are Linux/GNU Assembler specific.
+
+2009-12-25 Bradley Smith <brad@brad-smith.co.uk>
+
+ * configure.ac, Makefile.am, src/avr32/ffi.c,
+ src/avr32/ffitarget.h,
+ src/avr32/sysv.S: Add AVR32 port.
+ * configure, Makefile.in: Rebuilt.
+
+2009-12-21 Andreas Tobler <a.tobler@schweiz.org>
+
+ * configure.ac: Make i?86 build on FreeBSD and OpenBSD.
+ * configure: Regenerate.
+
+2009-12-15 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
+
+ * testsuite/libffi.call/ffitest.h: Define PRIuPTR on PA HP-UX.
+
+2009-12-13 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
+
+ * src/pa/ffi.c (ffi_closure_inner_pa32): Handle FFI_TYPE_LONGDOUBLE
+ type on HP-UX.
+
+2012-02-13 Kai Tietz <ktietz@redhat.com>
+
+ PR libffi/52221
+ * src/x86/ffi.c (ffi_prep_raw_closure_loc): Add thiscall
+ support for X86_WIN32.
+ (FFI_INIT_TRAMPOLINE_THISCALL): Fix displacement.
+
+2009-12-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * src/sparc/ffi.c (ffi_closure_sparc_inner_v9): Properly align 'long
+ double' arguments.
+
+2009-12-11 Eric Botcazou <ebotcazou@adacore.com>
+
+ * testsuite/libffi.call/ffitest.h: Define PRIuPTR on Solaris < 10.
+
+2009-12-10 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ PR libffi/40700
+ * src/closures.c [X86_64 && __sun__ && __svr4__]
+ (FFI_MMAP_EXEC_WRIT): Define.
+
+2009-12-08 David Daney <ddaney@caviumnetworks.com>
+
+ * testsuite/libffi.call/stret_medium.c: Remove xfail for mips*-*-*
+ * testsuite/libffi.call/cls_align_longdouble_split2.c: Same.
+ * testsuite/libffi.call/stret_large.c: Same.
+ * testsuite/libffi.call/cls_align_longdouble_split.c: Same.
+ * testsuite/libffi.call/stret_large2.c: Same.
+ * testsuite/libffi.call/stret_medium2.c: Same.
+
+2009-12-07 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/aix_closure.S (libffi_closure_ASM): Fix tablejump
+ typo.
+
+2009-12-05 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/aix.S: Update AIX32 code to be consistent with AIX64
+ code.
+ * src/powerpc/aix_closure.S: Same.
+
+2009-12-05 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * Makefile.in: Regenerate.
+ * configure: Regenerate.
+ * include/Makefile.in: Regenerate.
+ * man/Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2009-12-04 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/aix_closure.S: Reorganize 64-bit code to match
+ linux64_closure.S.
+
+2009-12-04 Uros Bizjak <ubizjak@gmail.com>
+
+ PR libffi/41908
+ * src/x86/ffi64.c (classify_argument): Update from
+ gcc/config/i386/i386.c.
+ (ffi_closure_unix64_inner): Do not use the address of two consecutive
+ SSE registers directly.
+ * testsuite/libffi.call/cls_dbls_struct.c (main): Remove xfail
+ for x86_64 linux targets.
+
+2009-12-04 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/ffi_darwin.c (ffi_closure_helper_DARWIN): Increment
+ pfr for long double split between fpr13 and stack.
+
+2009-12-03 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Increment next_arg and
+ fparg_count twice for long double.
+
+2009-12-03 David Edelsohn <edelsohn@gnu.org>
+
+ PR libffi/42243
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Remove extra parentheses.
+
+2009-12-03 Uros Bizjak <ubizjak@gmail.com>
+
+ * testsuite/libffi.call/cls_longdouble_va.c (main): Fix format string.
+ Remove xfails for x86 linux targets.
+
+2009-12-02 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Fix typo in INT64
+ case.
+
+2009-12-01 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/aix.S (ffi_call_AIX): Convert to more standard
+ register usage. Call ffi_prep_args directly. Add long double
+ return value support.
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Double arg increment
+ applies to FFI_TYPE_DOUBLE. Correct fpr_base increment typo.
+ Separate FFI_TYPE_SINT32 and FFI_TYPE_UINT32 cases.
+ (ffi_prep_cif_machdep): Only 16 byte stack alignment in 64 bit
+ mode.
+ (ffi_closure_helper_DARWIN): Remove nf and ng counters. Move temp
+ into case.
+ * src/powerpc/aix_closure.S: Maintain 16 byte stack alignment.
+ Allocate result area between params and FPRs.
+
+2009-11-30 David Edelsohn <edelsohn@gnu.org>
+
+ PR target/35484
+ * src/powerpc/ffitarget.h (POWERPC64): Define for PPC64 Linux and
+ AIX64.
+ * src/powerpc/aix.S: Implement AIX64 version.
+ * src/powerpc/aix_closure.S: Implement AIX64 version.
+ (ffi_closure_ASM): Use extsb, lha and displament addresses.
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Implement AIX64
+ support.
+ (ffi_prep_cif_machdep): Same.
+ (ffi_call): Same.
+ (ffi_closure_helper_DARWIN): Same.
+
+2009-11-02 Andreas Tobler <a.tobler@schweiz.org>
+
+ PR libffi/41908
+ * testsuite/libffi.call/testclosure.c: New test.
+
+2009-09-28 Kai Tietz <kai.tietz@onevision.com>
+
+ * src/x86/win64.S (_ffi_call_win64 stack): Remove for gnu
+ assembly version use of ___chkstk.
+
+2009-09-23 Matthias Klose <doko@ubuntu.com>
+
+ PR libffi/40242, PR libffi/41443
+ * src/arm/sysv.S (__ARM_ARCH__): Define for processors
+ __ARM_ARCH_6T2__, __ARM_ARCH_6M__, __ARM_ARCH_7__,
+ __ARM_ARCH_7A__, __ARM_ARCH_7R__, __ARM_ARCH_7M__.
+ Change the conditionals to __SOFTFP__ || __ARM_EABI__
+ for -mfloat-abi=softfp to work.
+
+2009-09-17 Loren J. Rittle <ljrittle@acm.org>
+
+ PR testsuite/32843 (strikes again)
+ * src/x86/ffi.c (ffi_prep_cif_machdep): Add X86_FREEBSD to
+ enable proper extension on char and short.
+
+2009-09-15 David Daney <ddaney@caviumnetworks.com>
+
+ * src/java_raw_api.c (ffi_java_raw_to_rvalue): Remove special
+ handling for FFI_TYPE_POINTER.
+ * src/mips/ffitarget.h (FFI_TYPE_STRUCT_D_SOFT,
+ FFI_TYPE_STRUCT_F_SOFT, FFI_TYPE_STRUCT_DD_SOFT,
+ FFI_TYPE_STRUCT_FF_SOFT, FFI_TYPE_STRUCT_FD_SOFT,
+ FFI_TYPE_STRUCT_DF_SOFT, FFI_TYPE_STRUCT_SOFT): New defines.
+ (FFI_N32_SOFT_FLOAT, FFI_N64_SOFT_FLOAT): New ffi_abi enumerations.
+ (enum ffi_abi): Set FFI_DEFAULT_ABI for soft-float.
+ * src/mips/n32.S (ffi_call_N32): Add handling for soft-float
+ structure and pointer returns.
+ (ffi_closure_N32): Add handling for pointer returns.
+ * src/mips/ffi.c (ffi_prep_args, calc_n32_struct_flags,
+ calc_n32_return_struct_flags): Handle soft-float.
+ (ffi_prep_cif_machdep): Handle soft-float, fix pointer handling.
+ (ffi_call_N32): Declare proper argument types.
+ (ffi_call, copy_struct_N32, ffi_closure_mips_inner_N32): Handle
+ soft-float.
+
+2009-08-24 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * configure.ac (AC_PREREQ): Bump to 2.64.
+
+2009-08-22 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * Makefile.am (install-html, install-pdf): Remove.
+ * Makefile.in: Regenerate.
+
+ * Makefile.in: Regenerate.
+ * aclocal.m4: Regenerate.
+ * configure: Regenerate.
+ * fficonfig.h.in: Regenerate.
+ * include/Makefile.in: Regenerate.
+ * man/Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2011-08-22 Jasper Lievisse Adriaanse <jasper@openbsd.org>
+
+ * configure.ac: Add OpenBSD/hppa and OpenBSD/powerpc support.
+ * configure: Rebuilt.
+
+2009-07-30 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * configure.ac (_AC_ARG_VAR_PRECIOUS): Use m4_rename_force.
+
+2009-07-24 Dave Korn <dave.korn.cygwin@gmail.com>
+
+ PR libffi/40807
+ * src/x86/ffi.c (ffi_prep_cif_machdep): Also use sign/zero-extending
+ return types for X86_WIN32.
+ * src/x86/win32.S (_ffi_call_SYSV): Handle omitted return types.
+ (_ffi_call_STDCALL, _ffi_closure_SYSV, _ffi_closure_raw_SYSV,
+ _ffi_closure_STDCALL): Likewise.
+
+ * src/closures.c (is_selinux_enabled): Define to const 0 for Cygwin.
+ (dlmmap, dlmunmap): Also use these functions on Cygwin.
+
+2009-07-11 Richard Sandiford <rdsandiford@googlemail.com>
+
+ PR testsuite/40699
+ PR testsuite/40707
+ PR testsuite/40709
+ * testsuite/lib/libffi-dg.exp: Revert 2009-07-02, 2009-07-01 and
+ 2009-06-30 commits.
+
+2009-07-01 Richard Sandiford <r.sandiford@uk.ibm.com>
+
+ * testsuite/lib/libffi-dg.exp (libffi-init): Set ld_library_path
+ to "" before adding paths. (This reinstates an assignment that
+ was removed by my 2009-06-30 commit, but changes the initial
+ value from "." to "".)
+
+2009-07-01 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR testsuite/40601
+ * testsuite/lib/libffi-dg.exp (libffi-init): Properly set
+ gccdir. Adjust ld_library_path for gcc only if gccdir isn't
+ empty.
+
+2009-06-30 Richard Sandiford <r.sandiford@uk.ibm.com>
+
+ * testsuite/lib/libffi-dg.exp (libffi-init): Don't add "."
+ to ld_library_path. Use add_path. Add just find_libgcc_s
+ to ld_library_path, not every libgcc multilib directory.
+
+2009-06-16 Wim Lewis <wiml@hhhh.org>
+
+ * src/powerpc/ffi.c: Avoid clobbering cr3 and cr4, which are
+ supposed to be callee-saved.
+ * src/powerpc/sysv.S (small_struct_return_value): Fix overrun of
+ return buffer for odd-size structs.
+
+2009-06-16 Andreas Tobler <a.tobler@schweiz.org>
+
+ PR libffi/40444
+ * testsuite/lib/libffi-dg.exp (libffi_target_compile): Add
+ allow_stack_execute for Darwin.
+
+2009-06-16 Andrew Haley <aph@redhat.com>
+
+ * configure.ac (TARGETDIR): Add missing blank lines.
+ * configure: Regenerate.
+
+2009-06-16 Andrew Haley <aph@redhat.com>
+
+ * testsuite/libffi.call/cls_align_sint64.c,
+ testsuite/libffi.call/cls_align_uint64.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/cls_ulonglong.c,
+ testsuite/libffi.call/return_ll1.c,
+ testsuite/libffi.call/stret_medium2.c: Fix printf format
+ specifiers.
+ * testsuite/libffi.call/ffitest.h,
+ testsuite/libffi.special/ffitestcxx.h (PRIdLL, PRIuLL): Define.
+
+2009-06-15 Andrew Haley <aph@redhat.com>
+
+ * testsuite/libffi.call/err_bad_typedef.c: xfail everywhere.
+ * testsuite/libffi.call/err_bad_abi.c: Likewise.
+
+2009-06-12 Andrew Haley <aph@redhat.com>
+
+ * Makefile.am: Remove info_TEXINFOS.
+
+2009-06-12 Andrew Haley <aph@redhat.com>
+
+ * ChangeLog.libffi: testsuite/libffi.call/cls_align_sint64.c,
+ testsuite/libffi.call/cls_align_uint64.c,
+ testsuite/libffi.call/cls_ulonglong.c,
+ testsuite/libffi.call/return_ll1.c,
+ testsuite/libffi.call/stret_medium2.c: Fix printf format
+ specifiers.
+ testsuite/libffi.special/unwindtest.cc: include stdint.h.
+
+2009-06-11 Timothy Wall <twall@users.sf.net>
+
+ * Makefile.am,
+ configure.ac,
+ include/ffi.h.in,
+ include/ffi_common.h,
+ src/closures.c,
+ src/dlmalloc.c,
+ src/x86/ffi.c,
+ src/x86/ffitarget.h,
+ src/x86/win64.S (new),
+ README: Added win64 support (mingw or MSVC)
+ * Makefile.in,
+ include/Makefile.in,
+ man/Makefile.in,
+ testsuite/Makefile.in,
+ configure,
+ aclocal.m4: Regenerated
+ * ltcf-c.sh: properly escape cygwin/w32 path
+ * man/ffi_call.3: Clarify size requirements for return value.
+ * src/x86/ffi64.c: Fix filename in comment.
+ * src/x86/win32.S: Remove unused extern.
+
+ * testsuite/libffi.call/closure_fn0.c,
+ testsuite/libffi.call/closure_fn1.c,
+ testsuite/libffi.call/closure_fn2.c,
+ testsuite/libffi.call/closure_fn3.c,
+ testsuite/libffi.call/closure_fn4.c,
+ testsuite/libffi.call/closure_fn5.c,
+ testsuite/libffi.call/closure_fn6.c,
+ testsuite/libffi.call/closure_stdcall.c,
+ testsuite/libffi.call/cls_12byte.c,
+ testsuite/libffi.call/cls_16byte.c,
+ testsuite/libffi.call/cls_18byte.c,
+ testsuite/libffi.call/cls_19byte.c,
+ testsuite/libffi.call/cls_1_1byte.c,
+ testsuite/libffi.call/cls_20byte.c,
+ testsuite/libffi.call/cls_20byte1.c,
+ testsuite/libffi.call/cls_24byte.c,
+ testsuite/libffi.call/cls_2byte.c,
+ testsuite/libffi.call/cls_3_1byte.c,
+ testsuite/libffi.call/cls_3byte1.c,
+ testsuite/libffi.call/cls_3byte2.c,
+ testsuite/libffi.call/cls_4_1byte.c,
+ testsuite/libffi.call/cls_4byte.c,
+ testsuite/libffi.call/cls_5_1_byte.c,
+ testsuite/libffi.call/cls_5byte.c,
+ testsuite/libffi.call/cls_64byte.c,
+ testsuite/libffi.call/cls_6_1_byte.c,
+ testsuite/libffi.call/cls_6byte.c,
+ testsuite/libffi.call/cls_7_1_byte.c,
+ testsuite/libffi.call/cls_7byte.c,
+ testsuite/libffi.call/cls_8byte.c,
+ testsuite/libffi.call/cls_9byte1.c,
+ testsuite/libffi.call/cls_9byte2.c,
+ testsuite/libffi.call/cls_align_double.c,
+ testsuite/libffi.call/cls_align_float.c,
+ testsuite/libffi.call/cls_align_longdouble.c,
+ testsuite/libffi.call/cls_align_longdouble_split.c,
+ testsuite/libffi.call/cls_align_longdouble_split2.c,
+ testsuite/libffi.call/cls_align_pointer.c,
+ testsuite/libffi.call/cls_align_sint16.c,
+ testsuite/libffi.call/cls_align_sint32.c,
+ testsuite/libffi.call/cls_align_sint64.c,
+ testsuite/libffi.call/cls_align_uint16.c,
+ testsuite/libffi.call/cls_align_uint32.c,
+ testsuite/libffi.call/cls_align_uint64.c,
+ testsuite/libffi.call/cls_dbls_struct.c,
+ testsuite/libffi.call/cls_double.c,
+ testsuite/libffi.call/cls_double_va.c,
+ testsuite/libffi.call/cls_float.c,
+ testsuite/libffi.call/cls_longdouble.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/cls_multi_schar.c,
+ testsuite/libffi.call/cls_multi_sshort.c,
+ testsuite/libffi.call/cls_multi_sshortchar.c,
+ testsuite/libffi.call/cls_multi_uchar.c,
+ testsuite/libffi.call/cls_multi_ushort.c,
+ testsuite/libffi.call/cls_multi_ushortchar.c,
+ testsuite/libffi.call/cls_pointer.c,
+ testsuite/libffi.call/cls_pointer_stack.c,
+ testsuite/libffi.call/cls_schar.c,
+ testsuite/libffi.call/cls_sint.c,
+ testsuite/libffi.call/cls_sshort.c,
+ testsuite/libffi.call/cls_uchar.c,
+ testsuite/libffi.call/cls_uint.c,
+ testsuite/libffi.call/cls_ulonglong.c,
+ testsuite/libffi.call/cls_ushort.c,
+ testsuite/libffi.call/err_bad_abi.c,
+ testsuite/libffi.call/err_bad_typedef.c,
+ testsuite/libffi.call/float2.c,
+ testsuite/libffi.call/huge_struct.c,
+ testsuite/libffi.call/nested_struct.c,
+ testsuite/libffi.call/nested_struct1.c,
+ testsuite/libffi.call/nested_struct10.c,
+ testsuite/libffi.call/nested_struct2.c,
+ testsuite/libffi.call/nested_struct3.c,
+ testsuite/libffi.call/nested_struct4.c,
+ testsuite/libffi.call/nested_struct5.c,
+ testsuite/libffi.call/nested_struct6.c,
+ testsuite/libffi.call/nested_struct7.c,
+ testsuite/libffi.call/nested_struct8.c,
+ testsuite/libffi.call/nested_struct9.c,
+ testsuite/libffi.call/problem1.c,
+ testsuite/libffi.call/return_ldl.c,
+ testsuite/libffi.call/return_ll1.c,
+ testsuite/libffi.call/stret_large.c,
+ testsuite/libffi.call/stret_large2.c,
+ testsuite/libffi.call/stret_medium.c,
+ testsuite/libffi.call/stret_medium2.c,
+ testsuite/libffi.special/unwindtest.cc: use ffi_closure_alloc instead
+ of checking for MMAP. Use intptr_t instead of long casts.
+
+2009-06-11 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * testsuite/libffi.call/cls_longdouble_va.c: Add xfail sh*-*-linux-*.
+ * testsuite/libffi.call/err_bad_abi.c: Add xfail sh*-*-*.
+ * testsuite/libffi.call/err_bad_typedef.c: Likewise.
+
+2009-06-09 Andrew Haley <aph@redhat.com>
+
+ * src/x86/freebsd.S: Add missing file.
+
+2009-06-08 Andrew Haley <aph@redhat.com>
+
+ Import from libffi 3.0.8:
+
+ * doc/libffi.texi: New file.
+ * doc/libffi.info: Likewise.
+ * doc/stamp-vti: Likewise.
+ * man/Makefile.am: New file.
+ * man/ffi_call.3: New file.
+
+ * Makefile.am (EXTRA_DIST): Add src/x86/darwin64.S,
+ src/dlmalloc.c.
+ (nodist_libffi_la_SOURCES): Add X86_FREEBSD.
+
+ * configure.ac: Bump version to 3.0.8.
+ parisc*-*-linux*: Add.
+ i386-*-freebsd* | i386-*-openbsd*: Add.
+ powerpc-*-beos*: Add.
+ AM_CONDITIONAL X86_FREEBSD: Add.
+ AC_CONFIG_FILES: Add man/Makefile.
+
+ * include/ffi.h.in (FFI_FN): Change void (*)() to void (*)(void).
+
+2009-06-08 Andrew Haley <aph@redhat.com>
+
+ * README: Import from libffi 3.0.8.
+
+2009-06-08 Andrew Haley <aph@redhat.com>
+
+ * testsuite/libffi.call/err_bad_abi.c: Add xfails.
+ * testsuite/libffi.call/cls_longdouble_va.c: Add xfails.
+ * testsuite/libffi.call/cls_dbls_struct.c: Add xfail x86_64-*-linux-*.
+ * testsuite/libffi.call/err_bad_typedef.c: Add xfails.
+
+ * testsuite/libffi.call/stret_medium2.c: Add __UNUSED__ to args.
+ * testsuite/libffi.call/stret_medium.c: Likewise.
+ * testsuite/libffi.call/stret_large2.c: Likewise.
+ * testsuite/libffi.call/stret_large.c: Likewise.
+
+2008-12-26 Timothy Wall <twall@users.sf.net>
+
+ * testsuite/libffi.call/cls_longdouble.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/cls_align_longdouble.c,
+ testsuite/libffi.call/cls_align_longdouble_split.c,
+ testsuite/libffi.call/cls_align_longdouble_split2.c: mark expected
+ failures on x86_64 cygwin/mingw.
+
+2008-12-22 Timothy Wall <twall@users.sf.net>
+
+ * testsuite/libffi.call/closure_fn0.c,
+ testsuite/libffi.call/closure_fn1.c,
+ testsuite/libffi.call/closure_fn2.c,
+ testsuite/libffi.call/closure_fn3.c,
+ testsuite/libffi.call/closure_fn4.c,
+ testsuite/libffi.call/closure_fn5.c,
+ testsuite/libffi.call/closure_fn6.c,
+ testsuite/libffi.call/closure_loc_fn0.c,
+ testsuite/libffi.call/closure_stdcall.c,
+ testsuite/libffi.call/cls_align_pointer.c,
+ testsuite/libffi.call/cls_pointer.c,
+ testsuite/libffi.call/cls_pointer_stack.c: use portable cast from
+ pointer to integer (intptr_t).
+ * testsuite/libffi.call/cls_longdouble.c: disable for win64.
+
+2008-07-24 Anthony Green <green@redhat.com>
+
+ * testsuite/libffi.call/cls_dbls_struct.c,
+ testsuite/libffi.call/cls_double_va.c,
+ testsuite/libffi.call/cls_longdouble.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/cls_pointer.c,
+ testsuite/libffi.call/cls_pointer_stack.c,
+ testsuite/libffi.call/err_bad_abi.c: Clean up failures from
+ compiler warnings.
+
+2008-03-04 Anthony Green <green@redhat.com>
+ Blake Chaffin
+ hos@tamanegi.org
+
+ * testsuite/libffi.call/cls_align_longdouble_split2.c
+ testsuite/libffi.call/cls_align_longdouble_split.c
+ testsuite/libffi.call/cls_dbls_struct.c
+ testsuite/libffi.call/cls_double_va.c
+ testsuite/libffi.call/cls_longdouble.c
+ testsuite/libffi.call/cls_longdouble_va.c
+ testsuite/libffi.call/cls_pointer.c
+ testsuite/libffi.call/cls_pointer_stack.c
+ testsuite/libffi.call/err_bad_abi.c
+ testsuite/libffi.call/err_bad_typedef.c
+ testsuite/libffi.call/stret_large2.c
+ testsuite/libffi.call/stret_large.c
+ testsuite/libffi.call/stret_medium2.c
+ testsuite/libffi.call/stret_medium.c: New tests from Apple.
+
+2009-06-05 Andrew Haley <aph@redhat.com>
+
+ * src/x86/ffitarget.h, src/x86/ffi.c: Merge stdcall changes from
+ libffi.
+
+2009-06-04 Andrew Haley <aph@redhat.com>
+
+ * src/x86/ffitarget.h, src/x86/win32.S, src/x86/ffi.c: Back out
+ stdcall changes.
+
+2008-02-26 Anthony Green <green@redhat.com>
+ Thomas Heller <theller@ctypes.org>
+
+ * src/x86/ffi.c (ffi_closure_SYSV_inner): Change C++ comment to C
+ comment.
+
+2008-02-03 Timothy Wall <twall@users.sf.net>
+
+ * src/x86/ffi.c (FFI_INIT_TRAMPOLINE_STDCALL): Calculate jump return
+ offset based on code pointer, not data pointer.
+
+2008-01-31 Timothy Wall <twall@users.sf.net>
+
+ * testsuite/libffi.call/closure_stdcall.c: Add test for stdcall
+ closures.
+ * src/x86/ffitarget.h: Increase size of trampoline for stdcall
+ closures.
+ * src/x86/win32.S: Add assembly for stdcall closure.
+ * src/x86/ffi.c: Initialize stdcall closure trampoline.
+
+2009-06-04 Andrew Haley <aph@redhat.com>
+
+ * include/ffi.h.in: Change void (*)() to void (*)(void).
+ * src/x86/ffi.c: Likewise.
+
+2009-06-04 Andrew Haley <aph@redhat.com>
+
+ * src/powerpc/ppc_closure.S: Insert licence header.
+ * src/powerpc/linux64_closure.S: Likewise.
+ * src/m68k/sysv.S: Likewise.
+
+ * src/sh64/ffi.c: Change void (*)() to void (*)(void).
+ * src/powerpc/ffi.c: Likewise.
+ * src/powerpc/ffi_darwin.c: Likewise.
+ * src/m32r/ffi.c: Likewise.
+ * src/sh64/ffi.c: Likewise.
+ * src/x86/ffi64.c: Likewise.
+ * src/alpha/ffi.c: Likewise.
+ * src/alpha/osf.S: Likewise.
+ * src/frv/ffi.c: Likewise.
+ * src/s390/ffi.c: Likewise.
+ * src/pa/ffi.c: Likewise.
+ * src/pa/hpux32.S: Likewise.
+ * src/ia64/unix.S: Likewise.
+ * src/ia64/ffi.c: Likewise.
+ * src/sparc/ffi.c: Likewise.
+ * src/mips/ffi.c: Likewise.
+ * src/sh/ffi.c: Likewise.
+
+2008-02-15 David Daney <ddaney@avtrex.com>
+
+ * src/mips/ffi.c (USE__BUILTIN___CLEAR_CACHE):
+ Define (conditionally), and use it to include cachectl.h.
+ (ffi_prep_closure_loc): Fix cache flushing.
+ * src/mips/ffitarget.h (_ABIN32, _ABI64, _ABIO32): Define.
+
+2009-06-04 Andrew Haley <aph@redhat.com>
+
+ include/ffi.h.in,
+ src/arm/ffitarget.h,
+ src/arm/ffi.c,
+ src/arm/sysv.S,
+ src/powerpc/ffitarget.h,
+ src/closures.c,
+ src/sh64/ffitarget.h,
+ src/sh64/ffi.c,
+ src/sh64/sysv.S,
+ src/types.c,
+ src/x86/ffi64.c,
+ src/x86/ffitarget.h,
+ src/x86/win32.S,
+ src/x86/darwin.S,
+ src/x86/ffi.c,
+ src/x86/sysv.S,
+ src/x86/unix64.S,
+ src/alpha/ffitarget.h,
+ src/alpha/ffi.c,
+ src/alpha/osf.S,
+ src/m68k/ffitarget.h,
+ src/frv/ffitarget.h,
+ src/frv/ffi.c,
+ src/s390/ffitarget.h,
+ src/s390/sysv.S,
+ src/cris/ffitarget.h,
+ src/pa/linux.S,
+ src/pa/ffitarget.h,
+ src/pa/ffi.c,
+ src/raw_api.c,
+ src/ia64/ffitarget.h,
+ src/ia64/unix.S,
+ src/ia64/ffi.c,
+ src/ia64/ia64_flags.h,
+ src/java_raw_api.c,
+ src/debug.c,
+ src/sparc/v9.S,
+ src/sparc/ffitarget.h,
+ src/sparc/ffi.c,
+ src/sparc/v8.S,
+ src/mips/ffitarget.h,
+ src/mips/n32.S,
+ src/mips/o32.S,
+ src/mips/ffi.c,
+ src/prep_cif.c,
+ src/sh/ffitarget.h,
+ src/sh/ffi.c,
+ src/sh/sysv.S: Update license text.
+
+2009-05-22 Dave Korn <dave.korn.cygwin@gmail.com>
+
+ * src/x86/win32.S (_ffi_closure_STDCALL): New function.
+ (.eh_frame): Add FDE for it.
+
+2009-05-22 Dave Korn <dave.korn.cygwin@gmail.com>
+
+ * configure.ac: Also check if assembler supports pc-relative
+ relocs on X86_WIN32 targets.
+ * configure: Regenerate.
+ * src/x86/win32.S (ffi_prep_args): Declare extern, not global.
+ (_ffi_call_SYSV): Add missing function type symbol .def and
+ add EH markup labels.
+ (_ffi_call_STDCALL): Likewise.
+ (_ffi_closure_SYSV): Likewise.
+ (_ffi_closure_raw_SYSV): Likewise.
+ (.eh_frame): Add hand-crafted EH data.
+
+2009-04-09 Jakub Jelinek <jakub@redhat.com>
+
+ * testsuite/lib/libffi-dg.exp: Change copyright header to refer to
+ version 3 of the GNU General Public License and to point readers
+ at the COPYING3 file and the FSF's license web page.
+ * testsuite/libffi.call/call.exp: Likewise.
+ * testsuite/libffi.special/special.exp: Likewise.
+
+2009-03-01 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * configure: Regenerate.
+
+2008-12-18 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ PR libffi/26048
+ * configure.ac (HAVE_AS_X86_PCREL): New test.
+ * configure: Regenerate.
+ * fficonfig.h.in: Regenerate.
+ * src/x86/sysv.S [!FFI_NO_RAW_API]: Precalculate
+ RAW_CLOSURE_CIF_OFFSET, RAW_CLOSURE_FUN_OFFSET,
+ RAW_CLOSURE_USER_DATA_OFFSET for the Solaris 10/x86 assembler.
+ (.eh_frame): Only use SYMBOL-. iff HAVE_AS_X86_PCREL.
+ * src/x86/unix64.S (.Lstore_table): Move to .text section.
+ (.Lload_table): Likewise.
+ (.eh_frame): Only use SYMBOL-. iff HAVE_AS_X86_PCREL.
+
+2008-12-18 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * configure: Regenerate.
+
+2008-11-21 Eric Botcazou <ebotcazou@adacore.com>
+
+ * src/sparc/ffi.c (ffi_prep_cif_machdep): Add support for
+ signed/unsigned int8/16 return values.
+ * src/sparc/v8.S (ffi_call_v8): Likewise.
+ (ffi_closure_v8): Likewise.
+
+2008-09-26 Peter O'Gorman <pogma@thewrittenword.com>
+ Steve Ellcey <sje@cup.hp.com>
+
+ * configure: Regenerate for new libtool.
+ * Makefile.in: Ditto.
+ * include/Makefile.in: Ditto.
+ * aclocal.m4: Ditto.
+
+2008-08-25 Andreas Tobler <a.tobler@schweiz.org>
+
+ * src/powerpc/ffitarget.h (ffi_abi): Add FFI_LINUX and
+ FFI_LINUX_SOFT_FLOAT to the POWERPC_FREEBSD enum.
+ Add note about flag bits used for FFI_SYSV_TYPE_SMALL_STRUCT.
+ Adjust copyright notice.
+ * src/powerpc/ffi.c: Add two new flags to indicate if we have one
+ register or two register to use for FFI_SYSV structs.
+ (ffi_prep_cif_machdep): Pass the right register flag introduced above.
+ (ffi_closure_helper_SYSV): Fix the return type for
+ FFI_SYSV_TYPE_SMALL_STRUCT. Comment.
+ Adjust copyright notice.
+
+2008-07-16 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/ffi.c (ffi_prep_closure_loc): Turn INSN into an unsigned
+ int.
+
+2008-06-17 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * configure: Regenerate.
+ * include/Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2008-06-07 Joseph Myers <joseph@codesourcery.com>
+
+ * configure.ac (parisc*-*-linux*, powerpc-*-sysv*,
+ powerpc-*-beos*): Remove.
+ * configure: Regenerate.
+
+2008-05-09 Julian Brown <julian@codesourcery.com>
+
+ * Makefile.am (LTLDFLAGS): New.
+ (libffi_la_LDFLAGS): Use above.
+ * Makefile.in: Regenerate.
+
+2008-04-18 Paolo Bonzini <bonzini@gnu.org>
+
+ PR bootstrap/35457
+ * aclocal.m4: Regenerate.
+ * configure: Regenerate.
+
+2008-03-26 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/sysv.S: Add .note.GNU-stack on Linux.
+ * src/sh64/sysv.S: Likewise.
+
+2008-03-26 Daniel Jacobowitz <dan@debian.org>
+
+ * src/arm/sysv.S: Fix ARM comment marker.
+
+2008-03-26 Jakub Jelinek <jakub@redhat.com>
+
+ * src/alpha/osf.S: Add .note.GNU-stack on Linux.
+ * src/s390/sysv.S: Likewise.
+ * src/powerpc/ppc_closure.S: Likewise.
+ * src/powerpc/sysv.S: Likewise.
+ * src/x86/unix64.S: Likewise.
+ * src/x86/sysv.S: Likewise.
+ * src/sparc/v8.S: Likewise.
+ * src/sparc/v9.S: Likewise.
+ * src/m68k/sysv.S: Likewise.
+ * src/arm/sysv.S: Likewise.
+
+2008-03-16 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * aclocal.m4: Regenerate.
+ * configure: Likewise.
+ * Makefile.in: Likewise.
+ * include/Makefile.in: Likewise.
+ * testsuite/Makefile.in: Likewise.
+
+2008-02-12 Bjoern Koenig <bkoenig@alpha-tierchen.de>
+ Andreas Tobler <a.tobler@schweiz.org>
+
+ * configure.ac: Add amd64-*-freebsd* target.
+ * configure: Regenerate.
+
+2008-01-30 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR libffi/34612
+ * src/x86/sysv.S (ffi_closure_SYSV): Pop 4 byte from stack when
+ returning struct.
+
+ * testsuite/libffi.call/call.exp: Add "-O2 -fomit-frame-pointer"
+ tests.
+
+2008-01-24 David Edelsohn <edelsohn@gnu.org>
+
+ * configure: Regenerate.
+
+2008-01-06 Andreas Tobler <a.tobler@schweiz.org>
+
+ * src/x86/ffi.c (ffi_prep_cif_machdep): Fix thinko.
+
+2008-01-05 Andreas Tobler <a.tobler@schweiz.org>
+
+ PR testsuite/32843
+ * src/x86/ffi.c (ffi_prep_cif_machdep): Add code for
+ signed/unsigned int8/16 for X86_DARWIN.
+ Updated copyright info.
+ Handle one and two byte structs with special cif->flags.
+ * src/x86/ffitarget.h: Add special types for one and two byte structs.
+ Updated copyright info.
+ * src/x86/darwin.S (ffi_call_SYSV): Rewrite to use a jump table like
+ sysv.S
+ Remove code to pop args from the stack after call.
+ Special-case signed/unsigned for int8/16, one and two byte structs.
+ (ffi_closure_raw_SYSV): Handle FFI_TYPE_UINT8,
+ FFI_TYPE_SINT8, FFI_TYPE_UINT16, FFI_TYPE_SINT16, FFI_TYPE_UINT32,
+ FFI_TYPE_SINT32.
+ Updated copyright info.
+
+2007-12-08 David Daney <ddaney@avtrex.com>
+
+ * src/mips/n32.S (ffi_call_N32): Replace dadd with ADDU, dsub with
+ SUBU, add with ADDU and use smaller code sequences.
+
+2007-12-07 David Daney <ddaney@avtrex.com>
+
+ * src/mips/ffi.c (ffi_prep_cif_machdep): Handle long double return
+ type.
+
+2007-12-06 David Daney <ddaney@avtrex.com>
+
+ * include/ffi.h.in (FFI_SIZEOF_JAVA_RAW): Define if not already
+ defined.
+ (ffi_java_raw): New typedef.
+ (ffi_java_raw_call, ffi_java_ptrarray_to_raw,
+ ffi_java_raw_to_ptrarray): Change parameter types from ffi_raw to
+ ffi_java_raw.
+ (ffi_java_raw_closure) : Same.
+ (ffi_prep_java_raw_closure, ffi_prep_java_raw_closure_loc): Change
+ parameter types.
+ * src/java_raw_api.c (ffi_java_raw_size): Replace FFI_SIZEOF_ARG with
+ FFI_SIZEOF_JAVA_RAW.
+ (ffi_java_raw_to_ptrarray): Change type of raw to ffi_java_raw.
+ Replace FFI_SIZEOF_ARG with FFI_SIZEOF_JAVA_RAW. Use
+ sizeof(ffi_java_raw) for alignment calculations.
+ (ffi_java_ptrarray_to_raw): Same.
+ (ffi_java_rvalue_to_raw): Add special handling for FFI_TYPE_POINTER
+ if FFI_SIZEOF_JAVA_RAW == 4.
+ (ffi_java_raw_to_rvalue): Same.
+ (ffi_java_raw_call): Change type of raw to ffi_java_raw.
+ (ffi_java_translate_args): Same.
+ (ffi_prep_java_raw_closure_loc, ffi_prep_java_raw_closure): Change
+ parameter types.
+ * src/mips/ffitarget.h (FFI_SIZEOF_JAVA_RAW): Define for N32 ABI.
+
+2007-12-06 David Daney <ddaney@avtrex.com>
+
+ * src/mips/n32.S (ffi_closure_N32): Use 64-bit add instruction on
+ pointer values.
+
+2007-12-01 Andreas Tobler <a.tobler@schweiz.org>
+
+ PR libffi/31937
+ * src/powerpc/ffitarget.h: Introduce new ABI FFI_LINUX_SOFT_FLOAT.
+ Add local FFI_TYPE_UINT128 to handle soft-float long-double-128.
+ * src/powerpc/ffi.c: Distinguish between __NO_FPRS__ and not and
+ set the NUM_FPR_ARG_REGISTERS according to.
+ Add support for potential soft-float support under hard-float
+ architecture.
+ (ffi_prep_args_SYSV): Set NUM_FPR_ARG_REGISTERS to 0 in case of
+ FFI_LINUX_SOFT_FLOAT, handle float, doubles and long-doubles according
+ to the FFI_LINUX_SOFT_FLOAT ABI.
+ (ffi_prep_cif_machdep): Likewise.
+ (ffi_closure_helper_SYSV): Likewise.
+ * src/powerpc/ppc_closure.S: Make sure not to store float/double
+ on archs where __NO_FPRS__ is true.
+ Add FFI_TYPE_UINT128 support.
+ * src/powerpc/sysv.S: Add support for soft-float long-double-128.
+ Adjust copyright notice.
+
+2007-11-25 Andreas Tobler <a.tobler@schweiz.org>
+
+ * src/closures.c: Move defintion of MAYBE_UNUSED from here to ...
+ * include/ffi_common.h: ... here.
+ Update copyright.
+
+2007-11-17 Andreas Tobler <a.tobler@schweiz.org>
+
+ * src/powerpc/sysv.S: Load correct cr to compare if we have long double.
+ * src/powerpc/linux64.S: Likewise.
+ * src/powerpc/ffi.c: Add a comment to show which part goes into cr6.
+ * testsuite/libffi.call/return_ldl.c: New test.
+
+2007-09-04 <aph@redhat.com>
+
+ * src/arm/sysv.S (UNWIND): New.
+ (Whole file): Conditionally compile unwinder directives.
+ * src/arm/sysv.S: Add unwinder directives.
+
+ * src/arm/ffi.c (ffi_prep_args): Align structs by at least 4 bytes.
+ Only treat r0 as a struct address if we're actually returning a
+ struct by address.
+ Only copy the bytes that are actually within a struct.
+ (ffi_prep_cif_machdep): A Composite Type not larger than 4 bytes
+ is returned in r0, not passed by address.
+ (ffi_call): Allocate a word-sized temporary for the case where
+ a composite is returned in r0.
+ (ffi_prep_incoming_args_SYSV): Align as necessary.
+
+2007-08-05 Steven Newbury <s_j_newbury@yahoo.co.uk>
+
+ * src/arm/ffi.c (FFI_INIT_TRAMPOLINE): Use __clear_cache instead of
+ directly using the sys_cacheflush syscall.
+
+2007-07-27 Andrew Haley <aph@redhat.com>
+
+ * src/arm/sysv.S (ffi_closure_SYSV): Add soft-float.
+
+2007-09-03 Maciej W. Rozycki <macro@linux-mips.org>
+
+ * Makefile.am: Unify MIPS_IRIX and MIPS_LINUX into MIPS.
+ * configure.ac: Likewise.
+ * Makefile.in: Regenerate.
+ * include/Makefile.in: Likewise.
+ * testsuite/Makefile.in: Likewise.
+ * configure: Likewise.
+
+2007-08-24 David Daney <ddaney@avtrex.com>
+
+ * testsuite/libffi.call/return_sl.c: New test.
+
+2007-08-10 David Daney <ddaney@avtrex.com>
+
+ * testsuite/libffi.call/cls_multi_ushort.c,
+ testsuite/libffi.call/cls_align_uint16.c,
+ testsuite/libffi.call/nested_struct1.c,
+ testsuite/libffi.call/nested_struct3.c,
+ testsuite/libffi.call/cls_7_1_byte.c,
+ testsuite/libffi.call/nested_struct5.c,
+ testsuite/libffi.call/cls_double.c,
+ testsuite/libffi.call/nested_struct7.c,
+ testsuite/libffi.call/cls_sint.c,
+ testsuite/libffi.call/nested_struct9.c,
+ testsuite/libffi.call/cls_20byte1.c,
+ testsuite/libffi.call/cls_multi_sshortchar.c,
+ testsuite/libffi.call/cls_align_sint64.c,
+ testsuite/libffi.call/cls_3byte2.c,
+ testsuite/libffi.call/cls_multi_schar.c,
+ testsuite/libffi.call/cls_multi_uchar.c,
+ testsuite/libffi.call/cls_19byte.c,
+ testsuite/libffi.call/cls_9byte1.c,
+ testsuite/libffi.call/cls_align_float.c,
+ testsuite/libffi.call/closure_fn1.c,
+ testsuite/libffi.call/problem1.c,
+ testsuite/libffi.call/closure_fn3.c,
+ testsuite/libffi.call/cls_sshort.c,
+ testsuite/libffi.call/closure_fn5.c,
+ testsuite/libffi.call/cls_align_double.c,
+ testsuite/libffi.call/nested_struct.c,
+ testsuite/libffi.call/cls_2byte.c,
+ testsuite/libffi.call/nested_struct10.c,
+ testsuite/libffi.call/cls_4byte.c,
+ testsuite/libffi.call/cls_6byte.c,
+ testsuite/libffi.call/cls_8byte.c,
+ testsuite/libffi.call/cls_multi_sshort.c,
+ testsuite/libffi.call/cls_align_sint16.c,
+ testsuite/libffi.call/cls_align_uint32.c,
+ testsuite/libffi.call/cls_20byte.c,
+ testsuite/libffi.call/cls_float.c,
+ testsuite/libffi.call/nested_struct2.c,
+ testsuite/libffi.call/cls_5_1_byte.c,
+ testsuite/libffi.call/nested_struct4.c,
+ testsuite/libffi.call/cls_24byte.c,
+ testsuite/libffi.call/nested_struct6.c,
+ testsuite/libffi.call/cls_64byte.c,
+ testsuite/libffi.call/nested_struct8.c,
+ testsuite/libffi.call/cls_uint.c,
+ testsuite/libffi.call/cls_multi_ushortchar.c,
+ testsuite/libffi.call/cls_schar.c,
+ testsuite/libffi.call/cls_uchar.c,
+ testsuite/libffi.call/cls_align_uint64.c,
+ testsuite/libffi.call/cls_ulonglong.c,
+ testsuite/libffi.call/cls_align_longdouble.c,
+ testsuite/libffi.call/cls_1_1byte.c,
+ testsuite/libffi.call/cls_12byte.c,
+ testsuite/libffi.call/cls_3_1byte.c,
+ testsuite/libffi.call/cls_3byte1.c,
+ testsuite/libffi.call/cls_4_1byte.c,
+ testsuite/libffi.call/cls_6_1_byte.c,
+ testsuite/libffi.call/cls_16byte.c,
+ testsuite/libffi.call/cls_18byte.c,
+ testsuite/libffi.call/closure_fn0.c,
+ testsuite/libffi.call/cls_9byte2.c,
+ testsuite/libffi.call/closure_fn2.c,
+ testsuite/libffi.call/closure_fn4.c,
+ testsuite/libffi.call/cls_ushort.c,
+ testsuite/libffi.call/closure_fn6.c,
+ testsuite/libffi.call/cls_5byte.c,
+ testsuite/libffi.call/cls_align_pointer.c,
+ testsuite/libffi.call/cls_7byte.c,
+ testsuite/libffi.call/cls_align_sint32.c,
+ testsuite/libffi.special/unwindtest_ffi_call.cc,
+ testsuite/libffi.special/unwindtest.cc: Remove xfail for mips64*-*-*.
+
+2007-08-10 David Daney <ddaney@avtrex.com>
+
+ PR libffi/28313
+ * configure.ac: Don't treat mips64 as a special case.
+ * Makefile.am (nodist_libffi_la_SOURCES): Add n32.S.
+ * configure: Regenerate
+ * Makefile.in: Ditto.
+ * fficonfig.h.in: Ditto.
+ * src/mips/ffitarget.h (REG_L, REG_S, SUBU, ADDU, SRL, LI): Indent.
+ (LA, EH_FRAME_ALIGN, FDE_ADDR_BYTES): New preprocessor macros.
+ (FFI_DEFAULT_ABI): Set for n64 case.
+ (FFI_CLOSURES, FFI_TRAMPOLINE_SIZE): Define for n32 and n64 cases.
+ * src/mips/n32.S (ffi_call_N32): Add debug macros and labels for FDE.
+ (ffi_closure_N32): New function.
+ (.eh_frame): New section
+ * src/mips/o32.S: Clean up comments.
+ (ffi_closure_O32): Pass ffi_closure parameter in $12.
+ * src/mips/ffi.c: Use FFI_MIPS_N32 instead of
+ _MIPS_SIM == _ABIN32 throughout.
+ (FFI_MIPS_STOP_HERE): New, use in place of
+ ffi_stop_here.
+ (ffi_prep_args): Use unsigned long to hold pointer values. Rewrite
+ to support n32/n64 ABIs.
+ (calc_n32_struct_flags): Rewrite.
+ (calc_n32_return_struct_flags): Remove unused variable. Reverse
+ position of flag bits.
+ (ffi_prep_cif_machdep): Rewrite n32 portion.
+ (ffi_call): Enable for n64. Add special handling for small structure
+ return values.
+ (ffi_prep_closure_loc): Add n32 and n64 support.
+ (ffi_closure_mips_inner_O32): Add cast to silence warning.
+ (copy_struct_N32, ffi_closure_mips_inner_N32): New functions.
+
+2007-08-08 David Daney <ddaney@avtrex.com>
+
+ * testsuite/libffi.call/ffitest.h (ffi_type_mylong): Remove definition.
+ * testsuite/libffi.call/cls_align_uint16.c (main): Use correct type
+ specifiers.
+ * testsuite/libffi.call/nested_struct1.c (main): Ditto.
+ * testsuite/libffi.call/cls_sint.c (main): Ditto.
+ * testsuite/libffi.call/nested_struct9.c (main): Ditto.
+ * testsuite/libffi.call/cls_20byte1.c (main): Ditto.
+ * testsuite/libffi.call/cls_9byte1.c (main): Ditto.
+ * testsuite/libffi.call/closure_fn1.c (main): Ditto.
+ * testsuite/libffi.call/closure_fn3.c (main): Ditto.
+ * testsuite/libffi.call/return_dbl2.c (main): Ditto.
+ * testsuite/libffi.call/cls_sshort.c (main): Ditto.
+ * testsuite/libffi.call/return_fl3.c (main): Ditto.
+ * testsuite/libffi.call/closure_fn5.c (main): Ditto.
+ * testsuite/libffi.call/nested_struct.c (main): Ditto.
+ * testsuite/libffi.call/nested_struct10.c (main): Ditto.
+ * testsuite/libffi.call/return_ll1.c (main): Ditto.
+ * testsuite/libffi.call/cls_8byte.c (main): Ditto.
+ * testsuite/libffi.call/cls_align_uint32.c (main): Ditto.
+ * testsuite/libffi.call/cls_align_sint16.c (main): Ditto.
+ * testsuite/libffi.call/cls_20byte.c (main): Ditto.
+ * testsuite/libffi.call/nested_struct2.c (main): Ditto.
+ * testsuite/libffi.call/cls_24byte.c (main): Ditto.
+ * testsuite/libffi.call/nested_struct6.c (main): Ditto.
+ * testsuite/libffi.call/cls_uint.c (main): Ditto.
+ * testsuite/libffi.call/cls_12byte.c (main): Ditto.
+ * testsuite/libffi.call/cls_16byte.c (main): Ditto.
+ * testsuite/libffi.call/closure_fn0.c (main): Ditto.
+ * testsuite/libffi.call/cls_9byte2.c (main): Ditto.
+ * testsuite/libffi.call/closure_fn2.c (main): Ditto.
+ * testsuite/libffi.call/return_dbl1.c (main): Ditto.
+ * testsuite/libffi.call/closure_fn4.c (main): Ditto.
+ * testsuite/libffi.call/closure_fn6.c (main): Ditto.
+ * testsuite/libffi.call/cls_align_sint32.c (main): Ditto.
+
+2007-08-07 Andrew Haley <aph@redhat.com>
+
+ * src/x86/sysv.S (ffi_closure_raw_SYSV): Fix typo in previous
+ checkin.
+
+2007-08-06 Andrew Haley <aph@redhat.com>
+
+ PR testsuite/32843
+ * src/x86/sysv.S (ffi_closure_raw_SYSV): Handle FFI_TYPE_UINT8,
+ FFI_TYPE_SINT8, FFI_TYPE_UINT16, FFI_TYPE_SINT16, FFI_TYPE_UINT32,
+ FFI_TYPE_SINT32.
+
+2007-08-02 David Daney <ddaney@avtrex.com>
+
+ * testsuite/libffi.call/return_ul.c (main): Define return type as
+ ffi_arg. Use proper printf conversion specifier.
+
+2007-07-30 Andrew Haley <aph@redhat.com>
+
+ PR testsuite/32843
+ * src/x86/ffi.c (ffi_prep_cif_machdep): in x86 case, add code for
+ signed/unsigned int8/16.
+ * src/x86/sysv.S (ffi_call_SYSV): Rewrite to:
+ Use a jump table.
+ Remove code to pop args from the stack after call.
+ Special-case signed/unsigned int8/16.
+ * testsuite/libffi.call/return_sc.c (main): Revert.
+
+2007-07-26 Richard Guenther <rguenther@suse.de>
+
+ PR testsuite/32843
+ * testsuite/libffi.call/return_sc.c (main): Verify call
+ result as signed char, not ffi_arg.
+
+2007-07-16 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * configure.ac (i?86-*-solaris2.1[0-9]): Set TARGET to X86_64.
+ * configure: Regenerate.
+
+2007-07-11 David Daney <ddaney@avtrex.com>
+
+ * src/mips/ffi.c: Don't include sys/cachectl.h.
+ (ffi_prep_closure_loc): Use __builtin___clear_cache() instead of
+ cacheflush().
+
+2007-05-18 Aurelien Jarno <aurelien@aurel32.net>
+
+ * src/arm/ffi.c (ffi_prep_closure_loc): Renamed and ajusted
+ from (ffi_prep_closure): ... this.
+ (FFI_INIT_TRAMPOLINE): Adjust.
+
+2005-12-31 Phil Blundell <pb@reciva.com>
+
+ * src/arm/ffi.c (ffi_prep_incoming_args_SYSV,
+ ffi_closure_SYSV_inner, ffi_prep_closure): New, add closure support.
+ * src/arm/sysv.S(ffi_closure_SYSV): Likewise.
+ * src/arm/ffitarget.h (FFI_TRAMPOLINE_SIZE): Likewise.
+ (FFI_CLOSURES): Enable closure support.
+
+2007-07-03 Andrew Haley <aph@hedges.billgatliff.com>
+
+ * testsuite/libffi.call/cls_multi_ushort.c,
+ testsuite/libffi.call/cls_align_uint16.c,
+ testsuite/libffi.call/nested_struct1.c,
+ testsuite/libffi.call/nested_struct3.c,
+ testsuite/libffi.call/cls_7_1_byte.c,
+ testsuite/libffi.call/cls_double.c,
+ testsuite/libffi.call/nested_struct5.c,
+ testsuite/libffi.call/nested_struct7.c,
+ testsuite/libffi.call/cls_sint.c,
+ testsuite/libffi.call/nested_struct9.c,
+ testsuite/libffi.call/cls_20byte1.c,
+ testsuite/libffi.call/cls_multi_sshortchar.c,
+ testsuite/libffi.call/cls_align_sint64.c,
+ testsuite/libffi.call/cls_3byte2.c,
+ testsuite/libffi.call/cls_multi_schar.c,
+ testsuite/libffi.call/cls_multi_uchar.c,
+ testsuite/libffi.call/cls_19byte.c,
+ testsuite/libffi.call/cls_9byte1.c,
+ testsuite/libffi.call/cls_align_float.c,
+ testsuite/libffi.call/closure_fn1.c,
+ testsuite/libffi.call/problem1.c,
+ testsuite/libffi.call/closure_fn3.c,
+ testsuite/libffi.call/cls_sshort.c,
+ testsuite/libffi.call/closure_fn5.c,
+ testsuite/libffi.call/cls_align_double.c,
+ testsuite/libffi.call/cls_2byte.c,
+ testsuite/libffi.call/nested_struct.c,
+ testsuite/libffi.call/nested_struct10.c,
+ testsuite/libffi.call/cls_4byte.c,
+ testsuite/libffi.call/cls_6byte.c,
+ testsuite/libffi.call/cls_8byte.c,
+ testsuite/libffi.call/cls_multi_sshort.c,
+ testsuite/libffi.call/cls_align_uint32.c,
+ testsuite/libffi.call/cls_align_sint16.c,
+ testsuite/libffi.call/cls_float.c,
+ testsuite/libffi.call/cls_20byte.c,
+ testsuite/libffi.call/cls_5_1_byte.c,
+ testsuite/libffi.call/nested_struct2.c,
+ testsuite/libffi.call/cls_24byte.c,
+ testsuite/libffi.call/nested_struct4.c,
+ testsuite/libffi.call/nested_struct6.c,
+ testsuite/libffi.call/cls_64byte.c,
+ testsuite/libffi.call/nested_struct8.c,
+ testsuite/libffi.call/cls_uint.c,
+ testsuite/libffi.call/cls_multi_ushortchar.c,
+ testsuite/libffi.call/cls_schar.c,
+ testsuite/libffi.call/cls_uchar.c,
+ testsuite/libffi.call/cls_align_uint64.c,
+ testsuite/libffi.call/cls_ulonglong.c,
+ testsuite/libffi.call/cls_align_longdouble.c,
+ testsuite/libffi.call/cls_1_1byte.c,
+ testsuite/libffi.call/cls_12byte.c,
+ testsuite/libffi.call/cls_3_1byte.c,
+ testsuite/libffi.call/cls_3byte1.c,
+ testsuite/libffi.call/cls_4_1byte.c,
+ testsuite/libffi.call/cls_6_1_byte.c,
+ testsuite/libffi.call/cls_16byte.c,
+ testsuite/libffi.call/cls_18byte.c,
+ testsuite/libffi.call/closure_fn0.c,
+ testsuite/libffi.call/cls_9byte2.c,
+ testsuite/libffi.call/closure_fn2.c,
+ testsuite/libffi.call/closure_fn4.c,
+ testsuite/libffi.call/cls_ushort.c,
+ testsuite/libffi.call/closure_fn6.c,
+ testsuite/libffi.call/cls_5byte.c,
+ testsuite/libffi.call/cls_align_pointer.c,
+ testsuite/libffi.call/cls_7byte.c,
+ testsuite/libffi.call/cls_align_sint32.c,
+ testsuite/libffi.special/unwindtest_ffi_call.cc,
+ testsuite/libffi.special/unwindtest.cc: Enable for ARM.
+
+2007-07-05 H.J. Lu <hongjiu.lu@intel.com>
+
+ * aclocal.m4: Regenerated.
+
+2007-06-02 Paolo Bonzini <bonzini@gnu.org>
+
+ * configure: Regenerate.
+
+2007-05-23 Steve Ellcey <sje@cup.hp.com>
+
+ * Makefile.in: Regenerate.
+ * configure: Regenerate.
+ * aclocal.m4: Regenerate.
+ * include/Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2007-05-10 Roman Zippel <zippel@linux-m68k.org>
+
+ * src/m68k/ffi.c (ffi_prep_incoming_args_SYSV,
+ ffi_closure_SYSV_inner,ffi_prep_closure): New, add closure support.
+ * src/m68k/sysv.S(ffi_closure_SYSV,ffi_closure_struct_SYSV): Likewise.
+ * src/m68k/ffitarget.h (FFI_TRAMPOLINE_SIZE): Likewise.
+ (FFI_CLOSURES): Enable closure support.
+
+2007-05-10 Roman Zippel <zippel@linux-m68k.org>
+
+ * configure.ac (HAVE_AS_CFI_PSEUDO_OP): New test.
+ * configure: Regenerate.
+ * fficonfig.h.in: Regenerate.
+ * src/m68k/sysv.S (CFI_STARTPROC,CFI_ENDPROC,
+ CFI_OFFSET,CFI_DEF_CFA): New macros.
+ (ffi_call_SYSV): Add callframe annotation.
+
+2007-05-10 Roman Zippel <zippel@linux-m68k.org>
+
+ * src/m68k/ffi.c (ffi_prep_args,ffi_prep_cif_machdep): Fix
+ numerous test suite failures.
+ * src/m68k/sysv.S (ffi_call_SYSV): Likewise.
+
+2007-04-11 Paolo Bonzini <bonzini@gnu.org>
+
+ * Makefile.am (EXTRA_DIST): Bring up to date.
+ * Makefile.in: Regenerate.
+ * src/frv/eabi.S: Remove RCS keyword.
+
+2007-04-06 Richard Henderson <rth@redhat.com>
+
+ * configure.ac: Tidy target case.
+ (HAVE_LONG_DOUBLE): Allow the target to override.
+ * configure: Regenerate.
+ * include/ffi.h.in: Don't define ffi_type_foo if
+ LIBFFI_HIDE_BASIC_TYPES is defined.
+ (ffi_type_longdouble): If not HAVE_LONG_DOUBLE, define
+ to ffi_type_double.
+ * types.c (LIBFFI_HIDE_BASIC_TYPES): Define.
+ (FFI_TYPEDEF, ffi_type_void): Mark the data const.
+ (ffi_type_longdouble): Special case for Alpha. Don't define
+ if long double == double.
+
+ * src/alpha/ffi.c (FFI_TYPE_LONGDOUBLE): Assert unique value.
+ (ffi_prep_cif_machdep): Handle it as the 128-bit type.
+ (ffi_call, ffi_closure_osf_inner): Likewise.
+ (ffi_closure_osf_inner): Likewise. Mark hidden.
+ (ffi_call_osf, ffi_closure_osf): Mark hidden.
+ * src/alpha/ffitarget.h (FFI_LAST_ABI): Tidy definition.
+ * src/alpha/osf.S (ffi_call_osf, ffi_closure_osf): Mark hidden.
+ (load_table): Handle 128-bit long double.
+
+ * testsuite/libffi.call/float4.c: Add -mieee for alpha.
+
+2007-04-06 Tom Tromey <tromey@redhat.com>
+
+ PR libffi/31491:
+ * README: Fixed bug in example.
+
+2007-04-03 Jakub Jelinek <jakub@redhat.com>
+
+ * src/closures.c: Include sys/statfs.h.
+ (_GNU_SOURCE): Define on Linux.
+ (FFI_MMAP_EXEC_SELINUX): Define.
+ (selinux_enabled): New variable.
+ (selinux_enabled_check): New function.
+ (is_selinux_enabled): Define.
+ (dlmmap): Use it.
+
+2007-03-24 Uros Bizjak <ubizjak@gmail.com>
+
+ * testsuite/libffi.call/return_fl2.c (return_fl): Mark as static.
+ Use 'volatile float sum' to create sum of floats to avoid false
+ negative due to excess precision on ix86 targets.
+ (main): Ditto.
+
+2007-03-08 Alexandre Oliva <aoliva@redhat.com>
+
+ * src/powerpc/ffi.c (flush_icache): Fix left-over from previous
+ patch.
+ (ffi_prep_closure_loc): Remove unneeded casts. Add needed ones.
+
+2007-03-07 Alexandre Oliva <aoliva@redhat.com>
+
+ * include/ffi.h.in (ffi_closure_alloc, ffi_closure_free): New.
+ (ffi_prep_closure_loc): New.
+ (ffi_prep_raw_closure_loc): New.
+ (ffi_prep_java_raw_closure_loc): New.
+ * src/closures.c: New file.
+ * src/dlmalloc.c [FFI_MMAP_EXEC_WRIT] (struct malloc_segment):
+ Replace sflags with exec_offset.
+ [FFI_MMAP_EXEC_WRIT] (mmap_exec_offset, add_segment_exec_offset,
+ sub_segment_exec_offset): New macros.
+ (get_segment_flags, set_segment_flags, check_segment_merge): New
+ macros.
+ (is_mmapped_segment, is_extern_segment): Use get_segment_flags.
+ (add_segment, sys_alloc, create_mspace, create_mspace_with_base,
+ destroy_mspace): Use new macros.
+ (sys_alloc): Silence warning.
+ * Makefile.am (libffi_la_SOURCES): Add src/closures.c.
+ * Makefile.in: Rebuilt.
+ * src/prep_cif [FFI_CLOSURES] (ffi_prep_closure): Implement in
+ terms of ffi_prep_closure_loc.
+ * src/raw_api.c (ffi_prep_raw_closure_loc): Renamed and adjusted
+ from...
+ (ffi_prep_raw_closure): ... this. Re-implement in terms of the
+ renamed version.
+ * src/java_raw_api (ffi_prep_java_raw_closure_loc): Renamed and
+ adjusted from...
+ (ffi_prep_java_raw_closure): ... this. Re-implement in terms of
+ the renamed version.
+ * src/alpha/ffi.c (ffi_prep_closure_loc): Renamed from
+ (ffi_prep_closure): ... this.
+ * src/pa/ffi.c: Likewise.
+ * src/cris/ffi.c: Likewise. Adjust.
+ * src/frv/ffi.c: Likewise.
+ * src/ia64/ffi.c: Likewise.
+ * src/mips/ffi.c: Likewise.
+ * src/powerpc/ffi_darwin.c: Likewise.
+ * src/s390/ffi.c: Likewise.
+ * src/sh/ffi.c: Likewise.
+ * src/sh64/ffi.c: Likewise.
+ * src/sparc/ffi.c: Likewise.
+ * src/x86/ffi64.c: Likewise.
+ * src/x86/ffi.c: Likewise.
+ (FFI_INIT_TRAMPOLINE): Adjust.
+ (ffi_prep_raw_closure_loc): Renamed and adjusted from...
+ (ffi_prep_raw_closure): ... this.
+ * src/powerpc/ffi.c (ffi_prep_closure_loc): Renamed from
+ (ffi_prep_closure): ... this.
+ (flush_icache): Adjust.
+
+2007-03-07 Alexandre Oliva <aoliva@redhat.com>
+
+ * src/dlmalloc.c: New file, imported version 2.8.3 of Doug
+ Lea's malloc.
+
+2007-03-01 Brooks Moses <brooks.moses@codesourcery.com>
+
+ * Makefile.am: Add dummy install-pdf target.
+ * Makefile.in: Regenerate
+
+2007-02-13 Andreas Krebbel <krebbel1@de.ibm.com>
+
+ * src/s390/ffi.c (ffi_prep_args, ffi_prep_cif_machdep,
+ ffi_closure_helper_SYSV): Add long double handling.
+
+2007-02-02 Jakub Jelinek <jakub@redhat.com>
+
+ * src/powerpc/linux64.S (ffi_call_LINUX64): Move restore of r2
+ immediately after bctrl instruction.
+
+2007-01-18 Alexandre Oliva <aoliva@redhat.com>
+
+ * Makefile.am (all-recursive, install-recursive,
+ mostlyclean-recursive, clean-recursive, distclean-recursive,
+ maintainer-clean-recursive): Add missing targets.
+ * Makefile.in: Rebuilt.
+
+2006-12-14 Andreas Tobler <a.tobler@schweiz.org>
+
+ * configure.ac: Add TARGET for x86_64-*-darwin*.
+ * Makefile.am (nodist_libffi_la_SOURCES): Add rules for 64-bit sources
+ for X86_DARWIN.
+ * src/x86/ffitarget.h: Set trampoline size for x86_64-*-darwin*.
+ * src/x86/darwin64.S: New file for x86_64-*-darwin* support.
+ * configure: Regenerate.
+ * Makefile.in: Regenerate.
+ * include/Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+ * testsuite/libffi.special/unwindtest_ffi_call.cc: New test case for
+ ffi_call only.
+
+2006-12-13 Andreas Tobler <a.tobler@schweiz.org>
+
+ * aclocal.m4: Regenerate with aclocal -I .. as written in the
+ Makefile.am.
+
+2006-10-31 Geoffrey Keating <geoffk@apple.com>
+
+ * src/powerpc/ffi_darwin.c (darwin_adjust_aggregate_sizes): New.
+ (ffi_prep_cif_machdep): Call darwin_adjust_aggregate_sizes for
+ Darwin.
+ * testsuite/libffi.call/nested_struct4.c: Remove Darwin XFAIL.
+ * testsuite/libffi.call/nested_struct6.c: Remove Darwin XFAIL.
+
+2006-10-10 Paolo Bonzini <bonzini@gnu.org>
+ Sandro Tolaini <tolaini@libero.it>
+
+ * configure.ac [i*86-*-darwin*]: Set X86_DARWIN symbol and
+ conditional.
+ * configure: Regenerated.
+ * Makefile.am (nodist_libffi_la_SOURCES) [X86_DARWIN]: New case.
+ (EXTRA_DIST): Add src/x86/darwin.S.
+ * Makefile.in: Regenerated.
+ * include/Makefile.in: Regenerated.
+ * testsuite/Makefile.in: Regenerated.
+
+ * src/x86/ffi.c (ffi_prep_cif_machdep) [X86_DARWIN]: Treat like
+ X86_WIN32, and additionally align stack to 16 bytes.
+ * src/x86/darwin.S: New, based on sysv.S.
+ * src/prep_cif.c (ffi_prep_cif) [X86_DARWIN]: Align > 8-byte structs.
+
+2006-09-12 David Daney <ddaney@avtrex.com>
+
+ PR libffi/23935
+ * include/Makefile.am: Install both ffi.h and ffitarget.h in
+ $(libdir)/gcc/$(target_alias)/$(gcc_version)/include.
+ * aclocal.m4: Regenerated for automake 1.9.6.
+ * Makefile.in: Regenerated.
+ * include/Makefile.in: Regenerated.
+ * testsuite/Makefile.in: Regenerated.
+
+2006-08-17 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * include/ffi_common.h (struct): Revert accidental commit.
+
+2006-08-15 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * include/ffi_common.h: Remove lint directives.
+ * include/ffi.h.in: Likewise.
+
+2006-07-25 Torsten Schoenfeld <kaffeetisch@gmx.de>
+
+ * include/ffi.h.in (ffi_type_ulong, ffi_type_slong): Define correctly
+ for 32-bit architectures.
+ * testsuite/libffi.call/return_ul.c: New test case.
+
+2006-07-19 David Daney <ddaney@avtrex.com>
+
+ * testsuite/libffi.call/closure_fn6.c: Remove xfail for mips,
+ xfail remains for mips64.
+
+2006-05-23 Carlos O'Donell <carlos@codesourcery.com>
+
+ * Makefile.am: Add install-html target. Add install-html to .PHONY
+ * Makefile.in: Regenerate.
+ * aclocal.m4: Regenerate.
+ * include/Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2006-05-18 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
+
+ * pa/ffi.c (ffi_prep_args_pa32): Load floating point arguments from
+ stack slot.
+
+2006-04-22 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * README: Remove notice about 'Crazy Comments'.
+ * src/debug.c: Remove lint directives. Cleanup white spaces.
+ * src/java_raw_api.c: Likewise.
+ * src/prep_cif.c: Likewise.
+ * src/raw_api.c: Likewise.
+ * src/ffitest.c: Delete. No longer needed, all test cases migrated
+ to the testsuite.
+ * src/arm/ffi.c: Remove lint directives.
+ * src/m32r/ffi.c: Likewise.
+ * src/pa/ffi.c: Likewise.
+ * src/powerpc/ffi.c: Likewise.
+ * src/powerpc/ffi_darwin.c: Likewise.
+ * src/sh/ffi.c: Likewise.
+ * src/sh64/ffi.c: Likewise.
+ * src/x86/ffi.c: Likewise.
+ * testsuite/libffi.call/float2.c: Likewise.
+ * testsuite/libffi.call/promotion.c: Likewise.
+ * testsuite/libffi.call/struct1.c: Likewise.
+
+2006-04-13 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/pa/hpux32.S: Correct unwind offset calculation for
+ ffi_closure_pa32.
+ * src/pa/linux.S: Likewise.
+
+2006-04-12 James E Wilson <wilson@specifix.com>
+
+ PR libgcj/26483
+ * src/ia64/ffi.c (stf_spill, ldf_fill): Rewrite as macros.
+ (hfa_type_load): Call stf_spill.
+ (hfa_type_store): Call ldf_fill.
+ (ffi_call): Adjust calls to above routines. Add local temps for
+ macro result.
+
+2006-04-10 Matthias Klose <doko@debian.org>
+
+ * testsuite/lib/libffi-dg.exp (libffi-init): Recognize multilib
+ directory names containing underscores.
+
+2006-04-07 James E Wilson <wilson@specifix.com>
+
+ * testsuite/libffi.call/float4.c: New testcase.
+
+2006-04-05 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
+ Andreas Tobler <a.tobler@schweiz.ch>
+
+ * Makefile.am: Add PA_HPUX port.
+ * Makefile.in: Regenerate.
+ * include/Makefile.in: Likewise.
+ * testsuite/Makefile.in: Likewise.
+ * configure.ac: Add PA_HPUX rules.
+ * configure: Regenerate.
+ * src/pa/ffitarget.h: Rename linux target to PA_LINUX.
+ Add PA_HPUX and PA64_HPUX.
+ Rename FFI_LINUX ABI to FFI_PA32 ABI.
+ (FFI_TRAMPOLINE_SIZE): Define for 32-bit HP-UX targets.
+ (FFI_TYPE_SMALL_STRUCT2): Define.
+ (FFI_TYPE_SMALL_STRUCT4): Likewise.
+ (FFI_TYPE_SMALL_STRUCT8): Likewise.
+ (FFI_TYPE_SMALL_STRUCT3): Redefine.
+ (FFI_TYPE_SMALL_STRUCT5): Likewise.
+ (FFI_TYPE_SMALL_STRUCT6): Likewise.
+ (FFI_TYPE_SMALL_STRUCT7): Likewise.
+ * src/pa/ffi.c (ROUND_DOWN): Delete.
+ (fldw, fstw, fldd, fstd): Use '__asm__'.
+ (ffi_struct_type): Add support for FFI_TYPE_SMALL_STRUCT2,
+ FFI_TYPE_SMALL_STRUCT4 and FFI_TYPE_SMALL_STRUCT8.
+ (ffi_prep_args_LINUX): Rename to ffi_prep_args_pa32. Update comment.
+ Simplify incrementing of stack slot variable. Change type of local
+ 'n' to unsigned int.
+ (ffi_size_stack_LINUX): Rename to ffi_size_stack_pa32. Handle long
+ double on PA_HPUX.
+ (ffi_prep_cif_machdep): Likewise.
+ (ffi_call): Likewise.
+ (ffi_closure_inner_LINUX): Rename to ffi_closure_inner_pa32. Change
+ return type to ffi_status. Simplify incrementing of stack slot
+ variable. Only copy floating point argument registers when PA_LINUX
+ is true. Reformat debug statement.
+ Add support for FFI_TYPE_SMALL_STRUCT2, FFI_TYPE_SMALL_STRUCT4 and
+ FFI_TYPE_SMALL_STRUCT8.
+ (ffi_closure_LINUX): Rename to ffi_closure_pa32. Add 'extern' to
+ declaration.
+ (ffi_prep_closure): Make linux trampoline conditional on PA_LINUX.
+ Add nops to cache flush. Add trampoline for PA_HPUX.
+ * src/pa/hpux32.S: New file.
+ * src/pa/linux.S (ffi_call_LINUX): Rename to ffi_call_pa32. Rename
+ ffi_prep_args_LINUX to ffi_prep_args_pa32.
+ Localize labels. Add support for 2, 4 and 8-byte small structs. Handle
+ unaligned destinations in 3, 5, 6 and 7-byte small structs. Order
+ argument type checks so that common argument types appear first.
+ (ffi_closure_LINUX): Rename to ffi_closure_pa32. Rename
+ ffi_closure_inner_LINUX to ffi_closure_inner_pa32.
+
+2006-03-24 Alan Modra <amodra@bigpond.net.au>
+
+ * src/powerpc/ffitarget.h (enum ffi_abi): Add FFI_LINUX. Default
+ for 32-bit using IBM extended double format. Fix FFI_LAST_ABI.
+ * src/powerpc/ffi.c (ffi_prep_args_SYSV): Handle linux variant of
+ FFI_TYPE_LONGDOUBLE.
+ (ffi_prep_args64): Assert using IBM extended double.
+ (ffi_prep_cif_machdep): Don't munge FFI_TYPE_LONGDOUBLE type.
+ Handle FFI_LINUX FFI_TYPE_LONGDOUBLE return and args.
+ (ffi_call): Handle FFI_LINUX.
+ (ffi_closure_helper_SYSV): Non FFI_LINUX long double return needs
+ gpr3 return pointer as for struct return. Handle FFI_LINUX
+ FFI_TYPE_LONGDOUBLE return and args. Don't increment "nf"
+ unnecessarily.
+ * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Load both f1 and f2
+ for FFI_TYPE_LONGDOUBLE. Move epilogue insns into case table.
+ Don't use r6 as pointer to results, instead use sp offset. Don't
+ make a special call to load lr with case table address, instead
+ use offset from previous call.
+ * src/powerpc/sysv.S (ffi_call_SYSV): Save long double return.
+ * src/powerpc/linux64.S (ffi_call_LINUX64): Simplify long double
+ return.
+
+2006-03-15 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh64/ffi.c (ffi_prep_cif_machdep): Handle float arguments
+ passed with FP registers correctly.
+ (ffi_closure_helper_SYSV): Likewise.
+ * src/sh64/sysv.S: Likewise.
+
+2006-03-01 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.special/unwindtest.cc (closure_test_fn): Mark cif,
+ args and userdata unused.
+ (closure_test_fn1): Mark cif and userdata unused.
+ (main): Remove unused res.
+
+2006-02-28 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/call.exp: Adjust FSF address. Add test runs for
+ -O2, -O3, -Os and the warning flags -W -Wall.
+ * testsuite/libffi.special/special.exp: Likewise.
+ * testsuite/libffi.call/ffitest.h: Add an __UNUSED__ macro to mark
+ unused parameter unused for gcc or else do nothing.
+ * testsuite/libffi.special/ffitestcxx.h: Likewise.
+ * testsuite/libffi.call/cls_12byte.c (cls_struct_12byte_gn): Mark cif
+ and userdata unused.
+ * testsuite/libffi.call/cls_16byte.c (cls_struct_16byte_gn): Likewise.
+ * testsuite/libffi.call/cls_18byte.c (cls_struct_18byte_gn): Likewise.
+ * testsuite/libffi.call/cls_19byte.c (cls_struct_19byte_gn): Likewise.
+ * testsuite/libffi.call/cls_1_1byte.c (cls_struct_1_1byte_gn): Likewise.
+ * testsuite/libffi.call/cls_20byte.c (cls_struct_20byte_gn): Likewise.
+ * testsuite/libffi.call/cls_20byte1.c (cls_struct_20byte_gn): Likewise.
+ * testsuite/libffi.call/cls_24byte.c (cls_struct_24byte_gn): Likewise.
+ * testsuite/libffi.call/cls_2byte.c (cls_struct_2byte_gn): Likewise.
+ * testsuite/libffi.call/cls_3_1byte.c (cls_struct_3_1byte_gn): Likewise.
+ * testsuite/libffi.call/cls_3byte1.c (cls_struct_3byte_gn): Likewise.
+ * testsuite/libffi.call/cls_3byte2.c (cls_struct_3byte_gn1): Likewise.
+ * testsuite/libffi.call/cls_4_1byte.c (cls_struct_4_1byte_gn): Likewise.
+ * testsuite/libffi.call/cls_4byte.c (cls_struct_4byte_gn): Likewise.
+ * testsuite/libffi.call/cls_5_1_byte.c (cls_struct_5byte_gn): Likewise.
+ * testsuite/libffi.call/cls_5byte.c (cls_struct_5byte_gn): Likewise.
+ * testsuite/libffi.call/cls_64byte.c (cls_struct_64byte_gn): Likewise.
+ * testsuite/libffi.call/cls_6_1_byte.c (cls_struct_6byte_gn): Likewise.
+ * testsuite/libffi.call/cls_6byte.c (cls_struct_6byte_gn): Likewise.
+ * testsuite/libffi.call/cls_7_1_byte.c (cls_struct_7byte_gn): Likewise.
+ * testsuite/libffi.call/cls_7byte.c (cls_struct_7byte_gn): Likewise.
+ * testsuite/libffi.call/cls_8byte.c (cls_struct_8byte_gn): Likewise.
+ * testsuite/libffi.call/cls_9byte1.c (cls_struct_9byte_gn): Likewise.
+ * testsuite/libffi.call/cls_9byte2.c (cls_struct_9byte_gn): Likewise.
+ * testsuite/libffi.call/cls_align_double.c (cls_struct_align_gn):
+ Likewise.
+ * testsuite/libffi.call/cls_align_float.c (cls_struct_align_gn):
+ Likewise.
+ * testsuite/libffi.call/cls_align_longdouble.c (cls_struct_align_gn):
+ Likewise.
+ * testsuite/libffi.call/cls_align_pointer.c (cls_struct_align_fn): Cast
+ void* to avoid compiler warning.
+ (main): Likewise.
+ (cls_struct_align_gn): Mark cif and userdata unused.
+ * testsuite/libffi.call/cls_align_sint16.c (cls_struct_align_gn):
+ Likewise.
+ * testsuite/libffi.call/cls_align_sint32.c (cls_struct_align_gn):
+ Likewise.
+ * testsuite/libffi.call/cls_align_sint64.c (cls_struct_align_gn):
+ Likewise.
+ * testsuite/libffi.call/cls_align_uint16.c (cls_struct_align_gn):
+ Likewise.
+ * testsuite/libffi.call/cls_align_uint32.c (cls_struct_align_gn):
+ Likewise.
+ * testsuite/libffi.call/cls_double.c (cls_ret_double_fn): Likewise.
+ * testsuite/libffi.call/cls_float.c (cls_ret_float_fn): Likewise.
+ * testsuite/libffi.call/cls_multi_schar.c (test_func_gn): Mark cif and
+ data unused.
+ (main): Cast res_call to silence gcc.
+ * testsuite/libffi.call/cls_multi_sshort.c (test_func_gn): Mark cif and
+ data unused.
+ (main): Cast res_call to silence gcc.
+ * testsuite/libffi.call/cls_multi_sshortchar.c (test_func_gn): Mark cif
+ and data unused.
+ (main): Cast res_call to silence gcc.
+ * testsuite/libffi.call/cls_multi_uchar.c (test_func_gn): Mark cif and
+ data unused.
+ (main): Cast res_call to silence gcc.
+ * testsuite/libffi.call/cls_multi_ushort.c (test_func_gn): Mark cif and
+ data unused.
+ (main): Cast res_call to silence gcc.
+ * testsuite/libffi.call/cls_multi_ushortchar.c (test_func_gn): Mark cif
+ and data unused.
+ (main): Cast res_call to silence gcc.
+ * testsuite/libffi.call/cls_schar.c (cls_ret_schar_fn): Mark cif and
+ userdata unused.
+ (cls_ret_schar_fn): Cast printf parameter to silence gcc.
+ * testsuite/libffi.call/cls_sint.c (cls_ret_sint_fn): Mark cif and
+ userdata unused.
+ (cls_ret_sint_fn): Cast printf parameter to silence gcc.
+ * testsuite/libffi.call/cls_sshort.c (cls_ret_sshort_fn): Mark cif and
+ userdata unused.
+ (cls_ret_sshort_fn): Cast printf parameter to silence gcc.
+ * testsuite/libffi.call/cls_uchar.c (cls_ret_uchar_fn): Mark cif and
+ userdata unused.
+ (cls_ret_uchar_fn): Cast printf parameter to silence gcc.
+ * testsuite/libffi.call/cls_uint.c (cls_ret_uint_fn): Mark cif and
+ userdata unused.
+ (cls_ret_uint_fn): Cast printf parameter to silence gcc.
+ * testsuite/libffi.call/cls_ulonglong.c (cls_ret_ulonglong_fn): Mark cif
+ and userdata unused.
+ * testsuite/libffi.call/cls_ushort.c (cls_ret_ushort_fn): Mark cif and
+ userdata unused.
+ (cls_ret_ushort_fn): Cast printf parameter to silence gcc.
+ * testsuite/libffi.call/float.c (floating): Remove unused parameter e.
+ * testsuite/libffi.call/float1.c (main): Remove unused variable i.
+ Cleanup white spaces.
+ * testsuite/libffi.call/negint.c (checking): Remove unused variable i.
+ * testsuite/libffi.call/nested_struct.c (cls_struct_combined_gn): Mark
+ cif and userdata unused.
+ * testsuite/libffi.call/nested_struct1.c (cls_struct_combined_gn):
+ Likewise.
+ * testsuite/libffi.call/nested_struct10.c (B_gn): Likewise.
+ * testsuite/libffi.call/nested_struct2.c (B_fn): Adjust printf
+ formatters to silence gcc.
+ (B_gn): Mark cif and userdata unused.
+ * testsuite/libffi.call/nested_struct3.c (B_gn): Mark cif and userdata
+ unused.
+ * testsuite/libffi.call/nested_struct4.c: Mention related PR.
+ (B_gn): Mark cif and userdata unused.
+ * testsuite/libffi.call/nested_struct5.c (B_gn): Mark cif and userdata
+ unused.
+ * testsuite/libffi.call/nested_struct6.c: Mention related PR.
+ (B_gn): Mark cif and userdata unused.
+ * testsuite/libffi.call/nested_struct7.c (B_gn): Mark cif and userdata
+ unused.
+ * testsuite/libffi.call/nested_struct8.c (B_gn): Likewise.
+ * testsuite/libffi.call/nested_struct9.c (B_gn): Likewise.
+ * testsuite/libffi.call/problem1.c (stub): Likewise.
+ * testsuite/libffi.call/pyobjc-tc.c (main): Cast the result to silence
+ gcc.
+ * testsuite/libffi.call/return_fl2.c (return_fl): Add the note mentioned
+ in the last commit for this test case in the test case itself.
+ * testsuite/libffi.call/closure_fn0.c (closure_test_fn0): Mark cif as
+ unused.
+ * testsuite/libffi.call/closure_fn1.c (closure_test_fn1): Likewise.
+ * testsuite/libffi.call/closure_fn2.c (closure_test_fn2): Likewise.
+ * testsuite/libffi.call/closure_fn3.c (closure_test_fn3): Likewise.
+ * testsuite/libffi.call/closure_fn4.c (closure_test_fn0): Likewise.
+ * testsuite/libffi.call/closure_fn5.c (closure_test_fn5): Likewise.
+ * testsuite/libffi.call/closure_fn6.c (closure_test_fn0): Likewise.
+
+2006-02-22 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/sysv.S: Fix register numbers in the FDE for
+ ffi_closure_SYSV.
+
+2006-02-20 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/return_fl2.c (return_fl): Remove static
+ declaration to avoid a false negative on ix86. See PR323.
+
+2006-02-18 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/ffi.c (ffi_closure_helper_SYSV): Remove unused variable
+ and cast integer to void * if needed. Update the pointer to
+ the FP register saved area correctly.
+
+2006-02-17 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/nested_struct6.c: XFAIL this test until PR25630
+ is fixed.
+ * testsuite/libffi.call/nested_struct4.c: Likewise.
+
+2006-02-16 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/return_dbl.c: New test case.
+ * testsuite/libffi.call/return_dbl1.c: Likewise.
+ * testsuite/libffi.call/return_dbl2.c: Likewise.
+ * testsuite/libffi.call/return_fl.c: Likewise.
+ * testsuite/libffi.call/return_fl1.c: Likewise.
+ * testsuite/libffi.call/return_fl2.c: Likewise.
+ * testsuite/libffi.call/return_fl3.c: Likewise.
+ * testsuite/libffi.call/closure_fn6.c: Likewise.
+
+ * testsuite/libffi.call/nested_struct2.c: Remove ffi_type_mylong
+ definition.
+ * testsuite/libffi.call/ffitest.h: Add ffi_type_mylong definition
+ here to be used by other test cases too.
+
+ * testsuite/libffi.call/nested_struct10.c: New test case.
+ * testsuite/libffi.call/nested_struct9.c: Likewise.
+ * testsuite/libffi.call/nested_struct8.c: Likewise.
+ * testsuite/libffi.call/nested_struct7.c: Likewise.
+ * testsuite/libffi.call/nested_struct6.c: Likewise.
+ * testsuite/libffi.call/nested_struct5.c: Likewise.
+ * testsuite/libffi.call/nested_struct4.c: Likewise.
+
+2006-01-21 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * configure.ac: Enable libffi for sparc64-*-freebsd*.
+ * configure: Rebuilt.
+
+2006-01-18 Jakub Jelinek <jakub@redhat.com>
+
+ * src/powerpc/sysv.S (smst_two_register): Don't call __ashldi3,
+ instead do the shifting inline.
+ * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Don't compute %r5
+ shift count unconditionally. Simplify load sequences for 1, 2, 3, 4
+ and 8 byte structs, for the remaining struct sizes don't call
+ __lshrdi3, instead do the shifting inline.
+
+2005-12-07 Thiemo Seufer <ths@networkno.de>
+
+ * src/mips/ffitarget.h: Remove obsolete sgidefs.h include. Add
+ missing parentheses.
+ * src/mips/o32.S (ffi_call_O32): Code formatting. Define
+ and use A3_OFF, FP_OFF, RA_OFF. Micro-optimizations.
+ (ffi_closure_O32): Likewise, but with newly defined A3_OFF2,
+ A2_OFF2, A1_OFF2, A0_OFF2, RA_OFF2, FP_OFF2, S0_OFF2, GP_OFF2,
+ V1_OFF2, V0_OFF2, FA_1_1_OFF2, FA_1_0_OFF2, FA_0_1_OFF2,
+ FA_0_0_OFF2.
+ * src/mips/ffi.c (ffi_prep_args): Code formatting. Fix
+ endianness bugs.
+ (ffi_prep_closure): Improve trampoline instruction scheduling.
+ (ffi_closure_mips_inner_O32): Fix endianness bugs.
+
+2005-12-03 Alan Modra <amodra@bigpond.net.au>
+
+ * src/powerpc/ffi.c: Formatting.
+ (ffi_prep_args_SYSV): Avoid possible aliasing problems by using unions.
+ (ffi_prep_args64): Likewise.
+
+2005-09-30 Geoffrey Keating <geoffk@apple.com>
+
+ * testsuite/lib/libffi-dg.exp (libffi_target_compile): For
+ darwin, use -shared-libgcc not -lgcc_s, and explain why.
+
+2005-09-26 Tom Tromey <tromey@redhat.com>
+
+ * testsuite/libffi.call/float1.c (value_type): New typedef.
+ (CANARY): New define.
+ (main): Check for result buffer overflow.
+ * src/powerpc/linux64.S: Handle linux64 long double returns.
+ * src/powerpc/ffi.c (FLAG_RETURNS_128BITS): New constant.
+ (ffi_prep_cif_machdep): Handle linux64 long double returns.
+
+2005-08-25 Alan Modra <amodra@bigpond.net.au>
+
+ PR target/23404
+ * src/powerpc/ffi.c (ffi_prep_args_SYSV): Correct placement of stack
+ homed fp args.
+ (ffi_status ffi_prep_cif_machdep): Correct stack sizing for same.
+
+2005-08-11 Jakub Jelinek <jakub@redhat.com>
+
+ * configure.ac (HAVE_HIDDEN_VISIBILITY_ATTRIBUTE): New test.
+ (AH_BOTTOM): Add FFI_HIDDEN definition.
+ * configure: Rebuilt.
+ * fficonfig.h.in: Rebuilt.
+ * src/powerpc/ffi.c (hidden): Remove.
+ (ffi_closure_LINUX64, ffi_prep_args64, ffi_call_LINUX64,
+ ffi_closure_helper_LINUX64): Use FFI_HIDDEN instead of hidden.
+ * src/powerpc/linux64_closure.S (ffi_closure_LINUX64,
+ .ffi_closure_LINUX64): Use FFI_HIDDEN instead of .hidden.
+ * src/x86/ffi.c (ffi_closure_SYSV, ffi_closure_raw_SYSV): Remove,
+ add FFI_HIDDEN to its prototype.
+ (ffi_closure_SYSV_inner): New.
+ * src/x86/sysv.S (ffi_closure_SYSV, ffi_closure_raw_SYSV): New.
+ * src/x86/win32.S (ffi_closure_SYSV, ffi_closure_raw_SYSV): New.
+
+2005-08-10 Alfred M. Szmidt <ams@gnu.org>
+
+ PR libffi/21819:
+ * configure: Rebuilt.
+ * configure.ac: Handle i*86-*-gnu*.
+
+2005-08-09 Jakub Jelinek <jakub@redhat.com>
+
+ * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Use
+ DW_CFA_offset_extended_sf rather than
+ DW_CFA_GNU_negative_offset_extended.
+ * src/powerpc/sysv.S (ffi_call_SYSV): Likewise.
+
+2005-07-22 SUGIOKA Toshinobu <sugioka@itonet.co.jp>
+
+ * src/sh/sysv.S (ffi_call_SYSV): Stop argument popping correctly
+ on sh3.
+ (ffi_closure_SYSV): Change the stack layout for sh3 struct argument.
+ * src/sh/ffi.c (ffi_prep_args): Fix sh3 argument copy, when it is
+ partially on register.
+ (ffi_closure_helper_SYSV): Likewise.
+ (ffi_prep_cif_machdep): Don't set too many cif->flags.
+
+2005-07-20 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/ffi.c (ffi_call): Handle small structures correctly.
+ Remove empty line.
+ * src/sh64/ffi.c (simple_type): Remove.
+ (return_type): Handle small structures correctly.
+ (ffi_prep_args): Likewise.
+ (ffi_call): Likewise.
+ (ffi_closure_helper_SYSV): Likewise.
+ * src/sh64/sysv.S (ffi_call_SYSV): Handle 1, 2 and 4-byte return.
+ Emit position independent code if PIC and remove wrong datalabel
+ prefixes from EH data.
+
+2005-07-19 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * Makefile.am (nodist_libffi_la_SOURCES): Add POWERPC_FREEBSD.
+ * Makefile.in: Regenerate.
+ * include/Makefile.in: Likewise.
+ * testsuite/Makefile.in: Likewise.
+ * configure.ac: Add POWERPC_FREEBSD rules.
+ * configure: Regenerate.
+ * src/powerpc/ffitarget.h: Add POWERPC_FREEBSD rules.
+ (FFI_SYSV_TYPE_SMALL_STRUCT): Define.
+ * src/powerpc/ffi.c: Add flags to handle small structure returns
+ in ffi_call_SYSV.
+ (ffi_prep_cif_machdep): Handle small structures for SYSV 4 ABI.
+ Aka FFI_SYSV.
+ (ffi_closure_helper_SYSV): Likewise.
+ * src/powerpc/ppc_closure.S: Add return types for small structures.
+ * src/powerpc/sysv.S: Add bits to handle small structures for
+ final SYSV 4 ABI.
+
+2005-07-10 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/cls_5_1_byte.c: New test file.
+ * testsuite/libffi.call/cls_6_1_byte.c: Likewise.
+ * testsuite/libffi.call/cls_7_1_byte.c: Likewise.
+
+2005-07-05 Randolph Chung <tausq@debian.org>
+
+ * src/pa/ffi.c (ffi_struct_type): Rename FFI_TYPE_SMALL_STRUCT1
+ as FFI_TYPE_SMALL_STRUCT3. Break out handling for 5-7 byte
+ structures. Kill compilation warnings.
+ (ffi_closure_inner_LINUX): Print return values as hex in debug
+ message. Rename FFI_TYPE_SMALL_STRUCT1 as FFI_TYPE_SMALL_STRUCT3.
+ Properly handle 5-7 byte structure returns.
+ * src/pa/ffitarget.h (FFI_TYPE_SMALL_STRUCT1)
+ (FFI_TYPE_SMALL_STRUCT2): Remove.
+ (FFI_TYPE_SMALL_STRUCT3, FFI_TYPE_SMALL_STRUCT5)
+ (FFI_TYPE_SMALL_STRUCT6, FFI_TYPE_SMALL_STRUCT7): Define.
+ * src/pa/linux.S: Mark source file as using PA1.1 assembly.
+ (checksmst1, checksmst2): Remove.
+ (checksmst3): Optimize handling of 3-byte struct returns.
+ (checksmst567): Properly handle 5-7 byte struct returns.
+
+2005-06-15 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ PR libgcj/21943
+ * src/mips/n32.S: Enforce PIC code.
+ * src/mips/o32.S: Likewise.
+
+2005-06-15 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * configure.ac: Treat i*86-*-solaris2.10 and up as X86_64.
+ * configure: Regenerate.
+
+2005-06-01 Alan Modra <amodra@bigpond.net.au>
+
+ * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Don't use JUMPTARGET
+ to call ffi_closure_helper_SYSV. Append @local instead.
+ * src/powerpc/sysv.S (ffi_call_SYSV): Likewise for ffi_prep_args_SYSV.
+
+2005-05-17 Kelley Cook <kcook@gcc.gnu.org>
+
+ * configure.ac: Use AC_C_BIGENDIAN instead of AC_C_BIGENDIAN_CROSS.
+ Use AC_CHECK_SIZEOF instead of AC_COMPILE_CHECK_SIZEOF.
+ * Makefile.am (ACLOCAL_AMFLAGS): Remove -I ../config.
+ * aclocal.m4, configure, fficonfig.h.in, Makefile.in,
+ include/Makefile.in, testsuite/Makefile.in: Regenerate.
+
+2005-05-09 Mike Stump <mrs@apple.com>
+
+ * configure: Regenerate.
+
+2005-05-08 Richard Henderson <rth@redhat.com>
+
+ PR libffi/21285
+ * src/alpha/osf.S: Update unwind into to match code.
+
+2005-05-04 Andreas Degert <ad@papyrus-gmbh.de>
+ Richard Henderson <rth@redhat.com>
+
+ * src/x86/ffi64.c (ffi_prep_cif_machdep): Save sse-used flag in
+ bit 11 of flags.
+ (ffi_call): Mask return type field. Pass ssecount to ffi_call_unix64.
+ (ffi_prep_closure): Set carry bit if sse-used flag set.
+ * src/x86/unix64.S (ffi_call_unix64): Add ssecount argument.
+ Only load sse registers if ssecount non-zero.
+ (ffi_closure_unix64): Only save sse registers if carry set on entry.
+
+2005-04-29 Ralf Corsepius <ralf.corsepius@rtems.org>
+
+ * configure.ac: Add i*86-*-rtems*, sparc*-*-rtems*,
+ powerpc-*rtems*, arm*-*-rtems*, sh-*-rtems*.
+ * configure: Regenerate.
+
+2005-04-20 Hans-Peter Nilsson <hp@axis.com>
+
+ * testsuite/lib/libffi-dg.exp (libffi-dg-test-1): In regsub use,
+ have Tcl8.3-compatible intermediate variable.
+
+2005-04-18 Simon Posnjak <simon.posnjak@siol.net>
+ Hans-Peter Nilsson <hp@axis.com>
+
+ * Makefile.am: Add CRIS support.
+ * configure.ac: Likewise.
+ * Makefile.in, configure, testsuite/Makefile.in,
+ include/Makefile.in: Regenerate.
+ * src/cris: New directory.
+ * src/cris/ffi.c, src/cris/sysv.S, src/cris/ffitarget.h: New files.
+ * src/prep_cif.c (ffi_prep_cif): Wrap in #ifndef __CRIS__.
+
+ * testsuite/lib/libffi-dg.exp (libffi-dg-test-1): Replace \n with
+ \r?\n in output tests.
+
+2005-04-12 Mike Stump <mrs@apple.com>
+
+ * configure: Regenerate.
+
+2005-03-30 Hans Boehm <Hans.Boehm@hp.com>
+
+ * src/ia64/ffitarget.h (ffi_arg): Use long long instead of DI.
+
+2005-03-30 Steve Ellcey <sje@cup.hp.com>
+
+ * src/ia64/ffitarget.h (ffi_arg) ADD DI attribute.
+ (ffi_sarg) Ditto.
+ * src/ia64/unix.S (ffi_closure_unix): Extend gp
+ to 64 bits in ILP32 mode.
+ Load 64 bits even for short data.
+
+2005-03-23 Mike Stump <mrs@apple.com>
+
+ * src/powerpc/darwin.S: Update for -m64 multilib.
+ * src/powerpc/darwin_closure.S: Likewise.
+
+2005-03-21 Zack Weinberg <zack@codesourcery.com>
+
+ * configure.ac: Do not invoke TL_AC_GCC_VERSION.
+ Do not set tool_include_dir.
+ * aclocal.m4, configure, Makefile.in, testsuite/Makefile.in:
+ Regenerate.
+ * include/Makefile.am: Set gcc_version and toollibffidir.
+ * include/Makefile.in: Regenerate.
+
+2005-02-22 Andrew Haley <aph@redhat.com>
+
+ * src/powerpc/ffi.c (ffi_prep_cif_machdep): Bump alignment to
+ odd-numbered register pairs for 64-bit integer types.
+
+2005-02-23 Andreas Tobler <a.tobler@schweiz.ch>
+
+ PR libffi/20104
+ * testsuite/libffi.call/return_ll1.c: New test case.
+
+2005-02-11 Janis Johnson <janis187@us.ibm.com>
+
+ * testsuite/libffi.call/cls_align_longdouble.c: Remove dg-options.
+ * testsuite/libffi.call/float.c: Ditto.
+ * testsuite/libffi.call/float2.c: Ditto.
+ * testsuite/libffi.call/float3.c: Ditto.
+
+2005-02-08 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/frv/ffitarget.h: Remove PPC stuff which does not belong to frv.
+
+2005-01-12 Eric Botcazou <ebotcazou@libertysurf.fr>
+
+ * testsuite/libffi.special/special.exp (cxx_options): Add
+ -shared-libgcc.
+
+2004-12-31 Richard Henderson <rth@redhat.com>
+
+ * src/types.c (FFI_AGGREGATE_TYPEDEF): Remove.
+ (FFI_TYPEDEF): Rename from FFI_INTEGRAL_TYPEDEF. Replace size and
+ offset parameters with a type parameter; deduce size and structure
+ alignment. Update all users.
+
+2004-12-31 Richard Henderson <rth@redhat.com>
+
+ * src/types.c (FFI_TYPE_POINTER): Define with sizeof.
+ (FFI_TYPE_LONGDOUBLE): Fix for ia64.
+ * src/ia64/ffitarget.h (struct ffi_ia64_trampoline_struct): Move
+ into ffi_prep_closure.
+ * src/ia64/ia64_flags.h, src/ia64/ffi.c, src/ia64/unix.S: Rewrite
+ from scratch.
+
+2004-12-27 Richard Henderson <rth@redhat.com>
+
+ * src/x86/unix64.S: Fix typo in unwind info.
+
+2004-12-25 Richard Henderson <rth@redhat.com>
+
+ * src/x86/ffi64.c (struct register_args): Rename from stackLayout.
+ (enum x86_64_reg_class): Add X86_64_COMPLEX_X87_CLASS.
+ (merge_classes): Check for it.
+ (SSE_CLASS_P): New.
+ (classify_argument): Pass byte_offset by value; perform all updates
+ inside struct case.
+ (examine_argument): Add classes argument; handle
+ X86_64_COMPLEX_X87_CLASS.
+ (ffi_prep_args): Merge into ...
+ (ffi_call): ... here. Share stack frame with ffi_call_unix64.
+ (ffi_prep_cif_machdep): Setup cif->flags for proper structure return.
+ (ffi_fill_return_value): Remove.
+ (ffi_prep_closure): Remove dead assert.
+ (ffi_closure_unix64_inner): Rename from ffi_closure_UNIX64_inner.
+ Rewrite to use struct register_args instead of va_list. Create
+ flags for handling structure returns.
+ * src/x86/unix64.S: Remove dead strings.
+ (ffi_call_unix64): Rename from ffi_call_UNIX64. Rewrite to share
+ stack frame with ffi_call. Handle structure returns properly.
+ (float2sse, floatfloat2sse, double2sse): Remove.
+ (sse2float, sse2double, sse2floatfloat): Remove.
+ (ffi_closure_unix64): Rename from ffi_closure_UNIX64. Rewrite
+ to handle structure returns properly.
+
+2004-12-08 David Edelsohn <edelsohn@gnu.org>
+
+ * Makefile.am (AM_MAKEFLAGS): Remove duplicate LIBCFLAGS and
+ PICFLAG.
+ * Makefile.in: Regenerated.
+
+2004-12-02 Richard Sandiford <rsandifo@redhat.com>
+
+ * configure.ac: Use TL_AC_GCC_VERSION to set gcc_version.
+ * configure, aclocal.m4, Makefile.in: Regenerate.
+ * include/Makefile.in, testsuite/Makefile.in: Regenerate.
+
+2004-11-29 Kelley Cook <kcook@gcc.gnu.org>
+
+ * configure: Regenerate for libtool change.
+
+2004-11-25 Kelley Cook <kcook@gcc.gnu.org>
+
+ * configure: Regenerate for libtool reversion.
+
+2004-11-24 Kelley Cook <kcook@gcc.gnu.org>
+
+ * configure: Regenerate for libtool change.
+
+2004-11-23 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
+
+ * testsuite/lib/libffi-dg.exp: Use new procs in target-libpath.exp.
+
+2004-11-23 Richard Sandiford <rsandifo@redhat.com>
+
+ * src/mips/o32.S (ffi_call_O32, ffi_closure_O32): Use jalr instead
+ of jal. Use an absolute encoding for the frame information.
+
+2004-11-23 Kelley Cook <kcook@gcc.gnu.org>
+
+ * Makefile.am: Remove no-dependencies. Add ACLOCAL_AMFLAGS.
+ * acinclude.m4: Delete logic for sincludes.
+ * aclocal.m4, Makefile.in, configure: Regenerate.
+ * include/Makefile: Likewise.
+ * testsuite/Makefile: Likewise.
+
+2004-11-22 Eric Botcazou <ebotcazou@libertysurf.fr>
+
+ * src/sparc/ffi.c (ffi_prep_closure): Align doubles and 64-bit integers
+ on a 8-byte boundary.
+ * src/sparc/v8.S (ffi_closure_v8): Reserve frame space for arguments.
+
+2004-10-27 Richard Earnshaw <rearnsha@arm.com>
+
+ * src/arm/ffi.c (ffi_prep_cif_machdep): Handle functions that return
+ long long values. Round stack allocation to a multiple of 8 bytes
+ for ATPCS compatibility.
+ * src/arm/sysv.S (ffi_call_SYSV): Rework to avoid use of APCS register
+ names. Handle returning long long types. Add Thumb and interworking
+ support. Improve soft-float code.
+
+2004-10-27 Richard Earnshaw <rearnsha@arm.com>
+
+ * testsuite/lib/libffi-db.exp (load_gcc_lib): New function.
+ (libffi_exit): New function.
+ (libffi_init): Build the testglue wrapper if needed.
+
+2004-10-25 Eric Botcazou <ebotcazou@libertysurf.fr>
+
+ PR other/18138
+ * testsuite/lib/libffi-dg.exp: Accept more than one multilib libgcc.
+
+2004-10-25 Kazuhiro Inaoka <inaoka.kazuhiro@renesas.com>
+
+ * src/m32r/libffitarget.h (FFI_CLOSURES): Set to 0.
+
+2004-10-20 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/sysv.S (ffi_call_SYSV): Don't align for double data.
+ * testsuite/libffi.call/float3.c: New test case.
+
+2004-10-18 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/ffi.c (ffi_prep_closure): Set T bit in trampoline for
+ the function returning a structure pointed with R2.
+ * src/sh/sysv.S (ffi_closure_SYSV): Use R2 as the pointer to
+ the structure return value if T bit set. Emit position
+ independent code and EH data if PIC.
+
+2004-10-13 Kazuhiro Inaoka <inaoka.kazuhiro@renesas.com>
+
+ * Makefile.am: Add m32r support.
+ * configure.ac: Likewise.
+ * Makefile.in: Regenerate.
+ * confiugre: Regenerate.
+ * src/types.c: Add m32r port to FFI_INTERNAL_TYPEDEF
+ (uint64, sint64, double, longdouble)
+ * src/m32r: New directory.
+ * src/m32r/ffi.c: New file.
+ * src/m32r/sysv.S: Likewise.
+ * src/m32r/ffitarget.h: Likewise.
+
+2004-10-02 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * testsuite/libffi.call/negint.c: New test case.
+
+2004-09-14 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR libgcj/17465
+ * testsuite/lib/libffi-dg.exp: Don't use global ld_library_path.
+ Set up LD_LIBRARY_PATH, SHLIB_PATH, LD_LIBRARYN32_PATH,
+ LD_LIBRARY64_PATH, LD_LIBRARY_PATH_32, LD_LIBRARY_PATH_64 and
+ DYLD_LIBRARY_PATH.
+
+2004-09-05 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/many_win32.c: Remove whitespaces.
+ * testsuite/libffi.call/promotion.c: Likewise.
+ * testsuite/libffi.call/return_ll.c: Remove unused var. Cleanup
+ whitespaces.
+ * testsuite/libffi.call/return_sc.c: Likewise.
+ * testsuite/libffi.call/return_uc.c: Likewise.
+
+2004-09-05 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/powerpc/darwin.S: Fix comments and identation.
+ * src/powerpc/darwin_closure.S: Likewise.
+
+2004-09-02 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/powerpc/ffi_darwin.c: Add flag for longdouble return values.
+ (ffi_prep_args): Handle longdouble arguments.
+ (ffi_prep_cif_machdep): Set flags for longdouble. Calculate space for
+ longdouble.
+ (ffi_closure_helper_DARWIN): Add closure handling for longdouble.
+ * src/powerpc/darwin.S (_ffi_call_DARWIN): Add handling of longdouble
+ values.
+ * src/powerpc/darwin_closure.S (_ffi_closure_ASM): Likewise.
+ * src/types.c: Defined longdouble size and alignment for darwin.
+
+2004-09-02 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/powerpc/aix.S: Remove whitespaces.
+ * src/powerpc/aix_closure.S: Likewise.
+ * src/powerpc/asm.h: Likewise.
+ * src/powerpc/ffi.c: Likewise.
+ * src/powerpc/ffitarget.h: Likewise.
+ * src/powerpc/linux64.S: Likewise.
+ * src/powerpc/linux64_closure.S: Likewise.
+ * src/powerpc/ppc_closure.S: Likewise.
+ * src/powerpc/sysv.S: Likewise.
+
+2004-08-30 Anthony Green <green@redhat.com>
+
+ * Makefile.am: Add frv support.
+ * Makefile.in, testsuite/Makefile.in: Rebuilt.
+ * configure.ac: Read configure.host.
+ * configure.in: Read configure.host.
+ * configure.host: New file. frv-elf needs libgloss.
+ * include/ffi.h.in: Force ffi_closure to have a nice big (8)
+ alignment. This is needed to frv and shouldn't harm the others.
+ * include/ffi_common.h (ALIGN_DOWN): New macro.
+ * src/frv/ffi.c, src/frv/ffitarget.h, src/frv/eabi.S: New files.
+
+2004-08-24 David Daney <daney@avtrex.com>
+
+ * testsuite/libffi.call/closure_fn0.c: Xfail mips64* instead of mips*.
+ * testsuite/libffi.call/closure_fn1.c: Likewise.
+ * testsuite/libffi.call/closure_fn2.c Likewise.
+ * testsuite/libffi.call/closure_fn3.c: Likewise.
+ * testsuite/libffi.call/closure_fn4.c: Likewise.
+ * testsuite/libffi.call/closure_fn5.c: Likewise.
+ * testsuite/libffi.call/cls_18byte.c: Likewise.
+ * testsuite/libffi.call/cls_19byte.c: Likewise.
+ * testsuite/libffi.call/cls_1_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte1.c: Likewise.
+ * testsuite/libffi.call/cls_24byte.c: Likewise.
+ * testsuite/libffi.call/cls_2byte.c: Likewise.
+ * testsuite/libffi.call/cls_3_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_3byte1.c: Likewise.
+ * testsuite/libffi.call/cls_3byte2.c: Likewise.
+ * testsuite/libffi.call/cls_4_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_4byte.c: Likewise.
+ * testsuite/libffi.call/cls_64byte.c: Likewise.
+ * testsuite/libffi.call/cls_6byte.c: Likewise.
+ * testsuite/libffi.call/cls_7byte.c: Likewise.
+ * testsuite/libffi.call/cls_8byte.c: Likewise.
+ * testsuite/libffi.call/cls_9byte1.c: Likewise.
+ * testsuite/libffi.call/cls_9byte2.c: Likewise.
+ * testsuite/libffi.call/cls_align_double.c: Likewise.
+ * testsuite/libffi.call/cls_align_float.c: Likewise.
+ * testsuite/libffi.call/cls_align_longdouble.c: Likewise.
+ * testsuite/libffi.call/cls_align_pointer.c: Likewise.
+ * testsuite/libffi.call/cls_align_sint16.c: Likewise.
+ * testsuite/libffi.call/cls_align_sint32.c: Likewise.
+ * testsuite/libffi.call/cls_align_sint64.c: Likewise.
+ * testsuite/libffi.call/cls_align_uint16.c: Likewise.
+ * testsuite/libffi.call/cls_align_uint32.c: Likewise.
+ * testsuite/libffi.call/cls_align_uint64.c: Likewise.
+ * testsuite/libffi.call/cls_double.c: Likewise.
+ * testsuite/libffi.call/cls_float.c: Likewise.
+ * testsuite/libffi.call/cls_multi_schar.c: Likewise.
+ * testsuite/libffi.call/cls_multi_sshort.c: Likewise.
+ * testsuite/libffi.call/cls_multi_sshortchar.c: Likewise.
+ * testsuite/libffi.call/cls_multi_uchar.c: Likewise.
+ * testsuite/libffi.call/cls_multi_ushort.c: Likewise.
+ * testsuite/libffi.call/cls_multi_ushortchar.c: Likewise.
+ * testsuite/libffi.call/cls_schar.c: Likewise.
+ * testsuite/libffi.call/cls_sint.c: Likewise.
+ * testsuite/libffi.call/cls_sshort.c: Likewise.
+ * testsuite/libffi.call/cls_uchar.c: Likewise.
+ * testsuite/libffi.call/cls_uint.c: Likewise.
+ * testsuite/libffi.call/cls_ulonglong.c: Likewise.
+ * testsuite/libffi.call/cls_ushort.c: Likewise.
+ * testsuite/libffi.call/nested_struct.c: Likewise.
+ * testsuite/libffi.call/nested_struct1.c: Likewise.
+ * testsuite/libffi.call/nested_struct2.c: Likewise.
+ * testsuite/libffi.call/nested_struct3.c: Likewise.
+ * testsuite/libffi.call/problem1.c: Likewise.
+ * testsuite/libffi.special/unwindtest.cc: Likewise.
+ * testsuite/libffi.call/cls_12byte.c: Likewise and set return value
+ to zero.
+ * testsuite/libffi.call/cls_16byte.c: Likewise.
+ * testsuite/libffi.call/cls_5byte.c: Likewise.
+
+2004-08-23 David Daney <daney@avtrex.com>
+
+ PR libgcj/13141
+ * src/mips/ffitarget.h (FFI_O32_SOFT_FLOAT): New ABI.
+ * src/mips/ffi.c (ffi_prep_args): Fix alignment calculation.
+ (ffi_prep_cif_machdep): Handle FFI_O32_SOFT_FLOAT floating point
+ parameters and return types.
+ (ffi_call): Handle FFI_O32_SOFT_FLOAT ABI.
+ (ffi_prep_closure): Ditto.
+ (ffi_closure_mips_inner_O32): Handle FFI_O32_SOFT_FLOAT ABI, fix
+ alignment calculations.
+ * src/mips/o32.S (ffi_closure_O32): Don't use floating point
+ instructions if FFI_O32_SOFT_FLOAT, make stack frame ABI compliant.
+
+2004-08-14 Casey Marshall <csm@gnu.org>
+
+ * src/mips/ffi.c (ffi_pref_cif_machdep): set `cif->flags' to
+ contain `FFI_TYPE_UINT64' as return type for any 64-bit
+ integer (O32 ABI only).
+ (ffi_prep_closure): new function.
+ (ffi_closure_mips_inner_O32): new function.
+ * src/mips/ffitarget.h: Define `FFI_CLOSURES' and
+ `FFI_TRAMPOLINE_SIZE' appropriately if the ABI is o32.
+ * src/mips/o32.S (ffi_call_O32): add labels for .eh_frame. Return
+ 64 bit integers correctly.
+ (ffi_closure_O32): new function.
+ Added DWARF-2 unwind info for both functions.
+
+2004-08-10 Andrew Haley <aph@redhat.com>
+
+ * src/x86/ffi64.c (ffi_prep_args ): 8-align all stack arguments.
+
+2004-08-01 Robert Millan <robertmh@gnu.org>
+
+ * configure.ac: Detect knetbsd-gnu and kfreebsd-gnu.
+ * configure: Regenerate.
+
+2004-07-30 Maciej W. Rozycki <macro@linux-mips.org>
+
+ * acinclude.m4 (AC_FUNC_MMAP_BLACKLIST): Check for <sys/mman.h>
+ and mmap() explicitly instead of relying on preset autoconf cache
+ variables.
+ * aclocal.m4: Regenerate.
+ * configure: Regenerate.
+
+2004-07-11 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * src/s390/ffi.c (ffi_prep_args): Fix C aliasing violation.
+ (ffi_check_float_struct): Remove unused prototype.
+
+2004-06-30 Geoffrey Keating <geoffk@apple.com>
+
+ * src/powerpc/ffi_darwin.c (flush_icache): ';' is a comment
+ character on Darwin, use '\n\t' instead.
+
+2004-06-26 Matthias Klose <doko@debian.org>
+
+ * libtool-version: Fix typo in revision/age.
+
+2004-06-17 Matthias Klose <doko@debian.org>
+
+ * libtool-version: New.
+ * Makefile.am (libffi_la_LDFLAGS): Use -version-info for soname.
+ * Makefile.in: Regenerate.
+
+2004-06-15 Paolo Bonzini <bonzini@gnu.org>
+
+ * Makefile.am: Remove useless multilib rules.
+ * Makefile.in: Regenerate.
+ * aclocal.m4: Regenerate with automake 1.8.5.
+ * configure.ac: Remove useless multilib configury.
+ * configure: Regenerate.
+
+2004-06-15 Paolo Bonzini <bonzini@gnu.org>
+
+ * .cvsignore: New file.
+
+2004-06-10 Jakub Jelinek <jakub@redhat.com>
+
+ * src/ia64/unix.S (ffi_call_unix): Insert group barrier break
+ fp_done.
+ (ffi_closure_UNIX): Fix f14/f15 adjustment if FLOAT_SZ is ever
+ changed from 8.
+
+2004-06-06 Sean McNeil <sean@mcneil.com>
+
+ * configure.ac: Add x86_64-*-freebsd* support.
+ * configure: Regenerate.
+
+2004-04-26 Joe Buck <jbuck@welsh-buck.org>
+
+ Bug 15093
+ * configure.ac: Test for existence of mmap and sys/mman.h before
+ checking blacklist. Fix suggested by Jim Wilson.
+ * configure: Regenerate.
+
+2004-04-26 Matt Austern <austern@apple.com>
+
+ * src/powerpc/darwin.S: Go through a non-lazy pointer for initial
+ FDE location.
+ * src/powerpc/darwin_closure.S: Likewise.
+
+2004-04-24 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/cls_multi_schar.c (main): Fix initialization
+ error. Reported by Thomas Heller <theller@python.net>.
+ * testsuite/libffi.call/cls_multi_sshort.c (main): Likewise.
+ * testsuite/libffi.call/cls_multi_ushort.c (main): Likewise.
+
+2004-03-20 Matthias Klose <doko@debian.org>
+
+ * src/pa/linux.S: Fix typo.
+
+2004-03-19 Matthias Klose <doko@debian.org>
+
+ * Makefile.am: Update.
+ * Makefile.in: Regenerate.
+ * src/pa/ffi.h.in: Remove.
+ * src/pa/ffitarget.h: New file.
+
+2004-02-10 Randolph Chung <tausq@debian.org>
+
+ * Makefile.am: Add PA support.
+ * Makefile.in: Regenerate.
+ * include/Makefile.in: Regenerate.
+ * configure.ac: Add PA target.
+ * configure: Regenerate.
+ * src/pa/ffi.c: New file.
+ * src/pa/ffi.h.in: Add PA support.
+ * src/pa/linux.S: New file.
+ * prep_cif.c: Add PA support.
+
+2004-03-16 Hosaka Yuji <hos@tamanegi.org>
+
+ * src/types.c: Fix alignment size of X86_WIN32 case int64 and
+ double.
+ * src/x86/ffi.c (ffi_prep_args): Replace ecif->cif->rtype->type
+ with ecif->cif->flags.
+ (ffi_call, ffi_prep_incoming_args_SYSV): Replace cif->rtype->type
+ with cif->flags.
+ (ffi_prep_cif_machdep): Add X86_WIN32 struct case.
+ (ffi_closure_SYSV): Add 1 or 2-bytes struct case for X86_WIN32.
+ * src/x86/win32.S (retstruct1b, retstruct2b, sc_retstruct1b,
+ sc_retstruct2b): Add for 1 or 2-bytes struct case.
+
+2004-03-15 Kelley Cook <kcook@gcc.gnu.org>
+
+ * configure.in: Rename file to ...
+ * configure.ac: ... this.
+ * fficonfig.h.in: Regenerate.
+ * Makefile.in: Regenerate.
+ * include/Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2004-03-12 Matt Austern <austern@apple.com>
+
+ * src/powerpc/darwin.S: Fix EH information so it corresponds to
+ changes in EH format resulting from addition of linkonce support.
+ * src/powerpc/darwin_closure.S: Likewise.
+
+2004-03-11 Andreas Tobler <a.tobler@schweiz.ch>
+ Paolo Bonzini <bonzini@gnu.org>
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Set them.
+ Remove VPATH. Remove rules for object files. Remove multilib support.
+ (AM_CCASFLAGS): Add.
+ * configure.in (AC_CONFIG_HEADERS): Relace AM_CONFIG_HEADER.
+ (AC_PREREQ): Bump version to 2.59.
+ (AC_INIT): Fill with version info and bug address.
+ (ORIGINAL_LD_FOR_MULTILIBS): Remove.
+ (AM_ENABLE_MULTILIB): Use this instead of AC_ARG_ENABLE.
+ De-precious CC so that the right flags are passed down to multilibs.
+ (AC_MSG_ERROR): Replace obsolete macro AC_ERROR.
+ (AC_CONFIG_FILES): Replace obsolete macro AC_LINK_FILES.
+ (AC_OUTPUT): Reorganize the output with AC_CONFIG_COMMANDS.
+ * configure: Rebuilt.
+ * aclocal.m4: Likewise.
+ * Makefile.in, include/Makefile.in, testsuite/Makefile.in: Likewise.
+ * fficonfig.h.in: Likewise.
+
+2004-03-11 Andreas Schwab <schwab@suse.de>
+
+ * src/ia64/ffi.c (ffi_prep_incoming_args_UNIX): Get floating point
+ arguments from fp registers only for the first 8 parameter slots.
+ Don't convert a float parameter when passed in memory.
+
+2004-03-09 Hans-Peter Nilsson <hp@axis.com>
+
+ * configure: Regenerate for config/accross.m4 correction.
+
+2004-02-25 Matt Kraai <kraai@alumni.cmu.edu>
+
+ * src/powerpc/ffi.c (ffi_prep_args_SYSV): Change
+ ecif->cif->bytes to bytes.
+ (ffi_prep_cif_machdep): Add braces around nested if statement.
+
+2004-02-09 Alan Modra <amodra@bigpond.net.au>
+
+ * src/types.c (pointer): POWERPC64 has 8 byte pointers.
+
+ * src/powerpc/ffi.c (ffi_prep_args64): Correct long double handling.
+ (ffi_closure_helper_LINUX64): Fix typo.
+ * testsuite/libffi.call/cls_align_longdouble.c: Pass -mlong-double-128
+ for powerpc64-*-*.
+ * testsuite/libffi.call/float.c: Likewise.
+ * testsuite/libffi.call/float2.c: Likewise.
+
+2004-02-08 Alan Modra <amodra@bigpond.net.au>
+
+ * src/powerpc/ffi.c (ffi_prep_cif_machdep <FFI_LINUX64>): Correct
+ long double function return and long double arg handling.
+ (ffi_closure_helper_LINUX64): Formatting. Delete unused "ng" var.
+ Use "end_pfr" instead of "nf". Correct long double handling.
+ Localise "temp".
+ * src/powerpc/linux64.S (ffi_call_LINUX64): Save f2 long double
+ return value.
+ * src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Allocate
+ space for long double return value. Adjust stack frame and offsets.
+ Load f2 long double return.
+
+2004-02-07 Alan Modra <amodra@bigpond.net.au>
+
+ * src/types.c: Use 16 byte long double for POWERPC64.
+
+2004-01-25 Eric Botcazou <ebotcazou@libertysurf.fr>
+
+ * src/sparc/ffi.c (ffi_prep_args_v9): Shift the parameter array
+ when the structure return address is passed in %o0.
+ (ffi_V9_return_struct): Rename into ffi_v9_layout_struct.
+ (ffi_v9_layout_struct): Align the field following a nested structure
+ on a word boundary. Use memmove instead of memcpy.
+ (ffi_call): Update call to ffi_V9_return_struct.
+ (ffi_prep_closure): Define 'ctx' only for V8.
+ (ffi_closure_sparc_inner): Clone into ffi_closure_sparc_inner_v8
+ and ffi_closure_sparc_inner_v9.
+ (ffi_closure_sparc_inner_v8): Return long doubles by reference.
+ Always skip the structure return address. For structures and long
+ doubles, copy the argument directly.
+ (ffi_closure_sparc_inner_v9): Skip the structure return address only
+ if required. Shift the maximum floating-point slot accordingly. For
+ big structures, copy the argument directly; otherwise, left-justify the
+ argument and call ffi_v9_layout_struct to lay out the structure on
+ the stack.
+ * src/sparc/v8.S: Undef STACKFRAME before defining it.
+ (ffi_closure_v8): Pass the structure return address. Update call to
+ ffi_closure_sparc_inner_v8. Short-circuit FFI_TYPE_INT handling.
+ Skip the 'unimp' insn when returning long doubles and structures.
+ * src/sparc/v9.S: Undef STACKFRAME before defining it.
+ (ffi_closure_v9): Increase the frame size by 2 words. Short-circuit
+ FFI_TYPE_INT handling. Load structures both in integers and
+ floating-point registers on return.
+ * README: Update status of the SPARC port.
+
+2004-01-24 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/pyobjc-tc.c (main): Treat result value
+ as of type ffi_arg.
+ * testsuite/libffi.call/struct3.c (main): Fix CHECK.
+
+2004-01-22 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * testsuite/libffi.call/cls_uint.c (cls_ret_uint_fn): Treat result
+ value as of type ffi_arg, not unsigned int.
+
+2004-01-21 Michael Ritzert <ritzert@t-online.de>
+
+ * ffi64.c (ffi_prep_args): Cast the RHS of an assignment instead
+ of the LHS.
+
+2004-01-12 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/lib/libffi-dg.exp: Set LD_LIBRARY_PATH_32 for
+ Solaris.
+
+2004-01-08 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * testsuite/libffi.call/ffitest.h (allocate_mmap): Cast MAP_FAILED
+ to void *.
+
+2003-12-10 Richard Henderson <rth@redhat.com>
+
+ * testsuite/libffi.call/cls_align_pointer.c: Cast pointers to
+ size_t instead of int.
+
+2003-12-04 Hosaka Yuji <hos@tamanegi.org>
+
+ * testsuite/libffi.call/many_win32.c: Include <float.h>.
+ * testsuite/libffi.call/many_win32.c (main): Replace variable
+ int i with unsigned long ul.
+
+ * testsuite/libffi.call/cls_align_uint64.c: New test case.
+ * testsuite/libffi.call/cls_align_sint64.c: Likewise.
+ * testsuite/libffi.call/cls_align_uint32.c: Likewise.
+ * testsuite/libffi.call/cls_align_sint32.c: Likewise.
+ * testsuite/libffi.call/cls_align_uint16.c: Likewise.
+ * testsuite/libffi.call/cls_align_sint16.c: Likewise.
+ * testsuite/libffi.call/cls_align_float.c: Likewise.
+ * testsuite/libffi.call/cls_align_double.c: Likewise.
+ * testsuite/libffi.call/cls_align_longdouble.c: Likewise.
+ * testsuite/libffi.call/cls_align_pointer.c: Likewise.
+
+2003-12-02 Hosaka Yuji <hos@tamanegi.org>
+
+ PR other/13221
+ * src/x86/ffi.c (ffi_prep_args, ffi_prep_incoming_args_SYSV):
+ Align arguments to 32 bits.
+
+2003-12-01 Andreas Tobler <a.tobler@schweiz.ch>
+
+ PR other/13221
+ * testsuite/libffi.call/cls_multi_sshort.c: New test case.
+ * testsuite/libffi.call/cls_multi_sshortchar.c: Likewise.
+ * testsuite/libffi.call/cls_multi_uchar.c: Likewise.
+ * testsuite/libffi.call/cls_multi_schar.c: Likewise.
+ * testsuite/libffi.call/cls_multi_ushortchar.c: Likewise.
+ * testsuite/libffi.call/cls_multi_ushort.c: Likewise.
+
+ * testsuite/libffi.special/unwindtest.cc: Cosmetics.
+
+2003-11-26 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * testsuite/libffi.call/ffitest.h: Include <fcntl.h>.
+ * testsuite/libffi.special/ffitestcxx.h: Likewise.
+
+2003-11-22 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * Makefile.in: Rebuilt.
+ * configure: Likewise.
+ * testsuite/libffi.special/unwindtest.cc: Convert the mmap to
+ the right type.
+
+2003-11-21 Andreas Jaeger <aj@suse.de>
+ Andreas Tobler <a.tobler@schweiz.ch>
+
+ * acinclude.m4: Add AC_FUNC_MMAP_BLACKLIST.
+ * configure.in: Call AC_FUNC_MMAP_BLACKLIST.
+ * Makefile.in: Rebuilt.
+ * aclocal.m4: Likewise.
+ * configure: Likewise.
+ * fficonfig.h.in: Likewise.
+ * testsuite/lib/libffi-dg.exp: Add include dir.
+ * testsuite/libffi.call/ffitest.h: Add MMAP definitions.
+ * testsuite/libffi.special/ffitestcxx.h: Likewise.
+ * testsuite/libffi.call/closure_fn0.c: Use MMAP functionality
+ for ffi_closure if available.
+ * testsuite/libffi.call/closure_fn1.c: Likewise.
+ * testsuite/libffi.call/closure_fn2.c: Likewise.
+ * testsuite/libffi.call/closure_fn3.c: Likewise.
+ * testsuite/libffi.call/closure_fn4.c: Likewise.
+ * testsuite/libffi.call/closure_fn5.c: Likewise.
+ * testsuite/libffi.call/cls_12byte.c: Likewise.
+ * testsuite/libffi.call/cls_16byte.c: Likewise.
+ * testsuite/libffi.call/cls_18byte.c: Likewise.
+ * testsuite/libffi.call/cls_19byte.c: Likewise.
+ * testsuite/libffi.call/cls_1_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte1.c: Likewise.
+ * testsuite/libffi.call/cls_24byte.c: Likewise.
+ * testsuite/libffi.call/cls_2byte.c: Likewise.
+ * testsuite/libffi.call/cls_3_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_3byte1.c: Likewise.
+ * testsuite/libffi.call/cls_3byte2.c: Likewise.
+ * testsuite/libffi.call/cls_4_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_4byte.c: Likewise.
+ * testsuite/libffi.call/cls_5byte.c: Likewise.
+ * testsuite/libffi.call/cls_64byte.c: Likewise.
+ * testsuite/libffi.call/cls_6byte.c: Likewise.
+ * testsuite/libffi.call/cls_7byte.c: Likewise.
+ * testsuite/libffi.call/cls_8byte.c: Likewise.
+ * testsuite/libffi.call/cls_9byte1.c: Likewise.
+ * testsuite/libffi.call/cls_9byte2.c: Likewise.
+ * testsuite/libffi.call/cls_double.c: Likewise.
+ * testsuite/libffi.call/cls_float.c: Likewise.
+ * testsuite/libffi.call/cls_schar.c: Likewise.
+ * testsuite/libffi.call/cls_sint.c: Likewise.
+ * testsuite/libffi.call/cls_sshort.c: Likewise.
+ * testsuite/libffi.call/cls_uchar.c: Likewise.
+ * testsuite/libffi.call/cls_uint.c: Likewise.
+ * testsuite/libffi.call/cls_ulonglong.c: Likewise.
+ * testsuite/libffi.call/cls_ushort.c: Likewise.
+ * testsuite/libffi.call/nested_struct.c: Likewise.
+ * testsuite/libffi.call/nested_struct1.c: Likewise.
+ * testsuite/libffi.call/nested_struct2.c: Likewise.
+ * testsuite/libffi.call/nested_struct3.c: Likewise.
+ * testsuite/libffi.call/problem1.c: Likewise.
+ * testsuite/libffi.special/unwindtest.cc: Likewise.
+
+2003-11-20 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/lib/libffi-dg.exp: Make the -lgcc_s conditional.
+
+2003-11-19 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/lib/libffi-dg.exp: Add DYLD_LIBRARY_PATH for darwin.
+ Add -lgcc_s to additional flags.
+
+2003-11-12 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * configure.in, include/Makefile.am: PR libgcj/11147, install
+ the ffitarget.h header file in a gcc versioned and target
+ dependent place.
+ * configure: Regenerated.
+ * Makefile.in, include/Makefile.in: Likewise.
+ * testsuite/Makefile.in: Likewise.
+
+2003-11-09 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/closure_fn0.c: Print result and check
+ with dg-output to make debugging easier.
+ * testsuite/libffi.call/closure_fn1.c: Likewise.
+ * testsuite/libffi.call/closure_fn2.c: Likewise.
+ * testsuite/libffi.call/closure_fn3.c: Likewise.
+ * testsuite/libffi.call/closure_fn4.c: Likewise.
+ * testsuite/libffi.call/closure_fn5.c: Likewise.
+ * testsuite/libffi.call/cls_12byte.c: Likewise.
+ * testsuite/libffi.call/cls_16byte.c: Likewise.
+ * testsuite/libffi.call/cls_18byte.c: Likewise.
+ * testsuite/libffi.call/cls_19byte.c: Likewise.
+ * testsuite/libffi.call/cls_1_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte1.c: Likewise.
+ * testsuite/libffi.call/cls_24byte.c: Likewise.
+ * testsuite/libffi.call/cls_2byte.c: Likewise.
+ * testsuite/libffi.call/cls_3_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_3byte1.c: Likewise.
+ * testsuite/libffi.call/cls_3byte2.c: Likewise.
+ * testsuite/libffi.call/cls_4_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_4byte.c: Likewise.
+ * testsuite/libffi.call/cls_5byte.c: Likewise.
+ * testsuite/libffi.call/cls_64byte.c: Likewise.
+ * testsuite/libffi.call/cls_6byte.c: Likewise.
+ * testsuite/libffi.call/cls_7byte.c: Likewise.
+ * testsuite/libffi.call/cls_8byte.c: Likewise.
+ * testsuite/libffi.call/cls_9byte1.c: Likewise.
+ * testsuite/libffi.call/cls_9byte2.c: Likewise.
+ * testsuite/libffi.call/cls_double.c: Likewise.
+ * testsuite/libffi.call/cls_float.c: Likewise.
+ * testsuite/libffi.call/cls_schar.c: Likewise.
+ * testsuite/libffi.call/cls_sint.c: Likewise.
+ * testsuite/libffi.call/cls_sshort.c: Likewise.
+ * testsuite/libffi.call/cls_uchar.c: Likewise.
+ * testsuite/libffi.call/cls_uint.c: Likewise.
+ * testsuite/libffi.call/cls_ulonglong.c: Likewise.
+ * testsuite/libffi.call/cls_ushort.c: Likewise.
+ * testsuite/libffi.call/problem1.c: Likewise.
+
+ * testsuite/libffi.special/unwindtest.cc: Make ffi_closure
+ static.
+
+2003-11-08 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/cls_9byte2.c: New test case.
+ * testsuite/libffi.call/cls_9byte1.c: Likewise.
+ * testsuite/libffi.call/cls_64byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte1.c: Likewise.
+ * testsuite/libffi.call/cls_19byte.c: Likewise.
+ * testsuite/libffi.call/cls_18byte.c: Likewise.
+ * testsuite/libffi.call/closure_fn4.c: Likewise.
+ * testsuite/libffi.call/closure_fn5.c: Likewise.
+ * testsuite/libffi.call/cls_schar.c: Likewise.
+ * testsuite/libffi.call/cls_sint.c: Likewise.
+ * testsuite/libffi.call/cls_sshort.c: Likewise.
+ * testsuite/libffi.call/nested_struct2.c: Likewise.
+ * testsuite/libffi.call/nested_struct3.c: Likewise.
+
+2003-11-08 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/cls_double.c: Do a check on the result.
+ * testsuite/libffi.call/cls_uchar.c: Likewise.
+ * testsuite/libffi.call/cls_uint.c: Likewise.
+ * testsuite/libffi.call/cls_ulonglong.c: Likewise.
+ * testsuite/libffi.call/cls_ushort.c: Likewise.
+ * testsuite/libffi.call/return_sc.c: Cleanup whitespaces.
+
+2003-11-06 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/prep_cif.c (ffi_prep_cif): Move the validity check after
+ the initialization.
+
+2003-10-23 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/java_raw_api.c (ffi_java_ptrarray_to_raw): Replace
+ FFI_ASSERT(FALSE) with FFI_ASSERT(0).
+
+2003-10-22 David Daney <ddaney@avtrex.com>
+
+ * src/mips/ffitarget.h: Replace undefined UINT32 and friends with
+ __attribute__((__mode__(__SI__))) and friends.
+
+2003-10-22 Andreas Schwab <schwab@suse.de>
+
+ * src/ia64/ffi.c: Replace FALSE/TRUE with false/true.
+
+2003-10-21 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * configure.in: AC_LINK_FILES(ffitarget.h).
+ * configure: Regenerate.
+ * Makefile.in: Likewise.
+ * include/Makefile.in: Likewise.
+ * testsuite/Makefile.in: Likewise.
+ * fficonfig.h.in: Likewise.
+
+2003-10-21 Paolo Bonzini <bonzini@gnu.org>
+ Richard Henderson <rth@redhat.com>
+
+ Avoid that ffi.h includes fficonfig.h.
+
+ * Makefile.am (EXTRA_DIST): Include ffitarget.h files
+ (TARGET_SRC_MIPS_GCC): Renamed to TARGET_SRC_MIPS_IRIX.
+ (TARGET_SRC_MIPS_SGI): Removed.
+ (MIPS_GCC): Renamed to TARGET_SRC_MIPS_IRIX.
+ (MIPS_SGI): Removed.
+ (CLEANFILES): Removed.
+ (mostlyclean-am, clean-am, mostlyclean-sub, clean-sub): New
+ targets.
+ * acconfig.h: Removed.
+ * configure.in: Compute sizeofs only for double and long double.
+ Use them to define and subst HAVE_LONG_DOUBLE. Include comments
+ into AC_DEFINE instead of using acconfig.h. Create
+ include/ffitarget.h instead of include/fficonfig.h. Rename
+ MIPS_GCC to MIPS_IRIX, drop MIPS_SGI since we are in gcc's tree.
+ AC_DEFINE EH_FRAME_FLAGS.
+ * include/Makefile.am (DISTCLEANFILES): New automake macro.
+ (hack_DATA): Add ffitarget.h.
+ * include/ffi.h.in: Remove all system specific definitions.
+ Declare raw API even if it is not installed, why bother?
+ Use limits.h instead of SIZEOF_* to define ffi_type_*. Do
+ not define EH_FRAME_FLAGS, it is in fficonfig.h now. Include
+ ffitarget.h instead of fficonfig.h. Remove ALIGN macro.
+ (UINT_ARG, INT_ARG): Removed, use ffi_arg and ffi_sarg instead.
+ * include/ffi_common.h (bool): Do not define.
+ (ffi_assert): Accept failed assertion.
+ (ffi_type_test): Return void and accept file/line.
+ (FFI_ASSERT): Pass stringized failed assertion.
+ (FFI_ASSERT_AT): New macro.
+ (FFI_ASSERT_VALID_TYPE): New macro.
+ (UINT8, SINT8, UINT16, SINT16, UINT32, SINT32,
+ UINT64, SINT64): Define here with gcc's __attribute__ macro
+ instead of in ffi.h
+ (FLOAT32, ALIGN): Define here instead of in ffi.h
+ * include/ffi-mips.h: Removed. Its content moved to
+ src/mips/ffitarget.h after separating assembly and C sections.
+ * src/alpha/ffi.c, src/alpha/ffi.c, src/java_raw_api.c
+ src/prep_cif.c, src/raw_api.c, src/ia64/ffi.c,
+ src/mips/ffi.c, src/mips/n32.S, src/mips/o32.S,
+ src/mips/ffitarget.h, src/sparc/ffi.c, src/x86/ffi64.c:
+ SIZEOF_ARG -> FFI_SIZEOF_ARG.
+ * src/ia64/ffi.c: Include stdbool.h (provided by GCC 2.95+).
+ * src/debug.c (ffi_assert): Accept stringized failed assertion.
+ (ffi_type_test): Rewritten.
+ * src/prep-cif.c (initialize_aggregate, ffi_prep_cif): Call
+ FFI_ASSERT_VALID_TYPE.
+ * src/alpha/ffitarget.h, src/arm/ffitarget.h,
+ src/ia64/ffitarget.h, src/m68k/ffitarget.h,
+ src/mips/ffitarget.h, src/powerpc/ffitarget.h,
+ src/s390/ffitarget.h, src/sh/ffitarget.h,
+ src/sh64/ffitarget.h, src/sparc/ffitarget.h,
+ src/x86/ffitarget.h: New files.
+ * src/alpha/osf.S, src/arm/sysv.S, src/ia64/unix.S,
+ src/m68k/sysv.S, src/mips/n32.S, src/mips/o32.S,
+ src/powerpc/aix.S, src/powerpc/darwin.S,
+ src/powerpc/ffi_darwin.c, src/powerpc/linux64.S,
+ src/powerpc/linux64_closure.S, src/powerpc/ppc_closure.S,
+ src/powerpc/sysv.S, src/s390/sysv.S, src/sh/sysv.S,
+ src/sh64/sysv.S, src/sparc/v8.S, src/sparc/v9.S,
+ src/x86/sysv.S, src/x86/unix64.S, src/x86/win32.S:
+ include fficonfig.h
+
+2003-10-20 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * src/mips/ffi.c: Use _ABIN32, _ABIO32 instead of external
+ _MIPS_SIM_NABI32, _MIPS_SIM_ABI32.
+
+2003-10-19 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Declare bytes again.
+ Used when FFI_DEBUG = 1.
+
+2003-10-14 Alan Modra <amodra@bigpond.net.au>
+
+ * src/types.c (double, longdouble): Default POWERPC64 to 8 byte size
+ and align.
+
+2003-10-06 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * include/ffi_mips.h: Define FFI_MIPS_N32 for N32/N64 ABIs,
+ FFI_MIPS_O32 for O32 ABI.
+
+2003-10-01 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/lib/libffi-dg.exp: Set LD_LIBRARY_PATH_64 for
+ SPARC64. Cleanup whitespaces.
+
+2003-09-19 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * testsuite/libffi.call/closure_fn0.c: Xfail mips, arm,
+ strongarm, xscale. Cleanup whitespaces.
+ * testsuite/libffi.call/closure_fn1.c: Likewise.
+ * testsuite/libffi.call/closure_fn2.c: Likewise.
+ * testsuite/libffi.call/closure_fn3.c: Likewise.
+ * testsuite/libffi.call/cls_12byte.c: Likewise.
+ * testsuite/libffi.call/cls_16byte.c: Likewise.
+ * testsuite/libffi.call/cls_1_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte.c: Likewise.
+ * testsuite/libffi.call/cls_24byte.c: Likewise.
+ * testsuite/libffi.call/cls_2byte.c: Likewise.
+ * testsuite/libffi.call/cls_3_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_3byte1.c: Likewise.
+ * testsuite/libffi.call/cls_3byte2.c: Likewise.
+ * testsuite/libffi.call/cls_4_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_4byte.c: Likewise.
+ * testsuite/libffi.call/cls_5byte.c: Likewise.
+ * testsuite/libffi.call/cls_6byte.c: Likewise.
+ * testsuite/libffi.call/cls_7byte.c: Likewise.
+ * testsuite/libffi.call/cls_8byte.c: Likewise.
+ * testsuite/libffi.call/cls_double.c: Likewise.
+ * testsuite/libffi.call/cls_float.c: Likewise.
+ * testsuite/libffi.call/cls_uchar.c: Likewise.
+ * testsuite/libffi.call/cls_uint.c: Likewise.
+ * testsuite/libffi.call/cls_ulonglong.c: Likewise.
+ * testsuite/libffi.call/cls_ushort.c: Likewise.
+ * testsuite/libffi.call/nested_struct.c: Likewise.
+ * testsuite/libffi.call/nested_struct1.c: Likewise.
+ * testsuite/libffi.call/problem1.c: Likewise.
+ * testsuite/libffi.special/unwindtest.cc: Likewise.
+ * testsuite/libffi.call/pyobjc-tc.c: Cleanup whitespaces.
+
+2003-09-18 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/aix.S: Cleanup whitespaces.
+ * src/powerpc/aix_closure.S: Likewise.
+
+2003-09-18 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/powerpc/darwin.S: Cleanup whitespaces, comment formatting.
+ * src/powerpc/darwin_closure.S: Likewise.
+ * src/powerpc/ffi_darwin.c: Likewise.
+
+2003-09-18 Andreas Tobler <a.tobler@schweiz.ch>
+ David Edelsohn <edelsohn@gnu.org>
+
+ * src/types.c (double): Add AIX and Darwin to the right TYPEDEF.
+ * src/powerpc/aix_closure.S: Remove the pointer to the outgoing
+ parameter stack.
+ * src/powerpc/darwin_closure.S: Likewise.
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Handle structures
+ according to the Darwin/AIX ABI.
+ (ffi_prep_cif_machdep): Likewise.
+ (ffi_closure_helper_DARWIN): Likewise.
+ Remove the outgoing parameter stack logic. Simplify the evaluation
+ of the different CASE types.
+ (ffi_prep_clousure): Avoid the casts on lvalues. Change the branch
+ statement in the trampoline code.
+
+2003-09-18 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/ffi.c (ffi_prep_args): Take account into the alignement
+ for the register size.
+ (ffi_closure_helper_SYSV): Handle the structure return value
+ address correctly.
+ (ffi_closure_helper_SYSV): Return the appropriate type when
+ the registers are used for the structure return value.
+ * src/sh/sysv.S (ffi_closure_SYSV): Fix the stack layout for
+ the 64-bit return value. Update copyright years.
+
+2003-09-17 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * testsuite/lib/libffi-dg.exp (libffi_target_compile): Search in
+ srcdir for ffi_mips.h.
+
+2003-09-12 Alan Modra <amodra@bigpond.net.au>
+
+ * src/prep_cif.c (initialize_aggregate): Include tail padding in
+ structure size.
+ * src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Correct
+ placement of float result.
+ * testsuite/libffi.special/unwindtest.cc (closure_test_fn1): Correct
+ cast of "resp" for big-endian 64 bit machines.
+
+2003-09-11 Alan Modra <amodra@bigpond.net.au>
+
+ * src/types.c (double, longdouble): Merge identical SH and ARM
+ typedefs, and add POWERPC64.
+ * src/powerpc/ffi.c (ffi_prep_args64): Correct next_arg calc for
+ struct split over gpr and rest.
+ (ffi_prep_cif_machdep): Correct intarg_count for structures.
+ * src/powerpc/linux64.S (ffi_call_LINUX64): Fix gpr offsets.
+
+2003-09-09 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/powerpc/ffi.c (ffi_closure_helper_SYSV) Handle struct
+ passing correctly.
+
+2003-09-09 Alan Modra <amodra@bigpond.net.au>
+
+ * configure: Regenerate.
+
+2003-09-04 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * Makefile.am: Remove build rules for ffitest.
+ * Makefile.in: Rebuilt.
+
+2003-09-04 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/java_raw_api.c: Include <stdlib.h> to fix compiler warning
+ about implicit declaration of abort().
+
+2003-09-04 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * Makefile.am: Add dejagnu test framework. Fixes PR other/11411.
+ * Makefile.in: Rebuilt.
+ * configure.in: Add dejagnu test framework.
+ * configure: Rebuilt.
+
+ * testsuite/Makefile.am: New file.
+ * testsuite/Makefile.in: Built
+ * testsuite/lib/libffi-dg.exp: New file.
+ * testsuite/config/default.exp: Likewise.
+ * testsuite/libffi.call/call.exp: Likewise.
+ * testsuite/libffi.call/ffitest.h: Likewise.
+ * testsuite/libffi.call/closure_fn0.c: Likewise.
+ * testsuite/libffi.call/closure_fn1.c: Likewise.
+ * testsuite/libffi.call/closure_fn2.c: Likewise.
+ * testsuite/libffi.call/closure_fn3.c: Likewise.
+ * testsuite/libffi.call/cls_1_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_3_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_4_1byte.c: Likewise.
+ * testsuite/libffi.call/cls_2byte.c: Likewise.
+ * testsuite/libffi.call/cls_3byte1.c: Likewise.
+ * testsuite/libffi.call/cls_3byte2.c: Likewise.
+ * testsuite/libffi.call/cls_4byte.c: Likewise.
+ * testsuite/libffi.call/cls_5byte.c: Likewise.
+ * testsuite/libffi.call/cls_6byte.c: Likewise.
+ * testsuite/libffi.call/cls_7byte.c: Likewise.
+ * testsuite/libffi.call/cls_8byte.c: Likewise.
+ * testsuite/libffi.call/cls_12byte.c: Likewise.
+ * testsuite/libffi.call/cls_16byte.c: Likewise.
+ * testsuite/libffi.call/cls_20byte.c: Likewise.
+ * testsuite/libffi.call/cls_24byte.c: Likewise.
+ * testsuite/libffi.call/cls_double.c: Likewise.
+ * testsuite/libffi.call/cls_float.c: Likewise.
+ * testsuite/libffi.call/cls_uchar.c: Likewise.
+ * testsuite/libffi.call/cls_uint.c: Likewise.
+ * testsuite/libffi.call/cls_ulonglong.c: Likewise.
+ * testsuite/libffi.call/cls_ushort.c: Likewise.
+ * testsuite/libffi.call/float.c: Likewise.
+ * testsuite/libffi.call/float1.c: Likewise.
+ * testsuite/libffi.call/float2.c: Likewise.
+ * testsuite/libffi.call/many.c: Likewise.
+ * testsuite/libffi.call/many_win32.c: Likewise.
+ * testsuite/libffi.call/nested_struct.c: Likewise.
+ * testsuite/libffi.call/nested_struct1.c: Likewise.
+ * testsuite/libffi.call/pyobjc-tc.c: Likewise.
+ * testsuite/libffi.call/problem1.c: Likewise.
+ * testsuite/libffi.call/promotion.c: Likewise.
+ * testsuite/libffi.call/return_ll.c: Likewise.
+ * testsuite/libffi.call/return_sc.c: Likewise.
+ * testsuite/libffi.call/return_uc.c: Likewise.
+ * testsuite/libffi.call/strlen.c: Likewise.
+ * testsuite/libffi.call/strlen_win32.c: Likewise.
+ * testsuite/libffi.call/struct1.c: Likewise.
+ * testsuite/libffi.call/struct2.c: Likewise.
+ * testsuite/libffi.call/struct3.c: Likewise.
+ * testsuite/libffi.call/struct4.c: Likewise.
+ * testsuite/libffi.call/struct5.c: Likewise.
+ * testsuite/libffi.call/struct6.c: Likewise.
+ * testsuite/libffi.call/struct7.c: Likewise.
+ * testsuite/libffi.call/struct8.c: Likewise.
+ * testsuite/libffi.call/struct9.c: Likewise.
+ * testsuite/libffi.special/special.exp: New file.
+ * testsuite/libffi.special/ffitestcxx.h: Likewise.
+ * testsuite/libffi.special/unwindtest.cc: Likewise.
+
+
+2003-08-13 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/ffi.c (OFS_INT16): Set 0 for little endian case. Update
+ copyright years.
+
+2003-08-02 Alan Modra <amodra@bigpond.net.au>
+
+ * src/powerpc/ffi.c (ffi_prep_args64): Modify for changed gcc
+ structure passing.
+ (ffi_closure_helper_LINUX64): Likewise.
+ * src/powerpc/linux64.S: Remove code writing to parm save area.
+ * src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Use return
+ address in lr from ffi_closure_helper_LINUX64 call to calculate
+ table address. Optimize function tail.
+
+2003-07-28 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/sparc/ffi.c: Handle all floating point registers.
+ * src/sparc/v9.S: Likewise. Fixes second part of PR target/11410.
+
+2003-07-11 Gerald Pfeifer <pfeifer@dbai.tuwien.ac.at>
+
+ * README: Note that libffi is not part of GCC. Update the project
+ URL and status.
+
+2003-06-19 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+
+ * src/powerpc/ppc_closure.S: Include ffi.h.
+
+2003-06-13 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * src/x86/sysv.S: Avoid gas-only .uleb128/.sleb128 directives.
+ Use C style comments.
+
+2003-06-13 Kaz Kojima <kkojima@rr.iij4u.or.jp>
+
+ * Makefile.am: Add SHmedia support. Fix a typo of SH support.
+ * Makefile.in: Regenerate.
+ * configure.in (sh64-*-linux*, sh5*-*-linux*): Add target.
+ * configure: Regenerate.
+ * include/ffi.h.in: Add SHmedia support.
+ * src/sh64/ffi.c: New file.
+ * src/sh64/sysv.S: New file.
+
+2003-05-16 Jakub Jelinek <jakub@redhat.com>
+
+ * configure.in (HAVE_RO_EH_FRAME): Check whether .eh_frame section
+ should be read-only.
+ * configure: Rebuilt.
+ * fficonfig.h.in: Rebuilt.
+ * include/ffi.h.in (EH_FRAME_FLAGS): Define.
+ * src/alpha/osf.S: Use EH_FRAME_FLAGS.
+ * src/powerpc/linux64.S: Likewise.
+ * src/powerpc/linux64_closure.S: Likewise. Include ffi.h.
+ * src/powerpc/sysv.S: Use EH_FRAME_FLAGS. Use pcrel encoding
+ if -fpic/-fPIC/-mrelocatable.
+ * src/powerpc/powerpc_closure.S: Likewise.
+ * src/sparc/v8.S: If HAVE_RO_EH_FRAME is defined, don't include
+ #write in .eh_frame flags.
+ * src/sparc/v9.S: Likewise.
+ * src/x86/unix64.S: Use EH_FRAME_FLAGS.
+ * src/x86/sysv.S: Likewise. Use pcrel encoding if -fpic/-fPIC.
+ * src/s390/sysv.S: Use EH_FRAME_FLAGS. Include ffi.h.
+
+2003-05-07 Jeff Sturm <jsturm@one-point.com>
+
+ Fixes PR bootstrap/10656
+ * configure.in (HAVE_AS_REGISTER_PSEUDO_OP): Test assembler
+ support for .register pseudo-op.
+ * src/sparc/v8.S: Use it.
+ * fficonfig.h.in: Rebuilt.
+ * configure: Rebuilt.
+
+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.
+ (configure): Regenerated.
+
+2003-04-04 Loren J. Rittle <ljrittle@acm.org>
+
+ * include/Makefile.in: Regenerate.
+
+2003-03-21 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
+
+ * libffi/include/ffi.h.in: Define X86 instead of X86_64 in 32
+ bit mode.
+ * libffi/src/x86/ffi.c (ffi_closure_SYSV, ffi_closure_raw_SYSV):
+ Receive closure pointer through parameter, read args using
+ __builtin_dwarf_cfa.
+ (FFI_INIT_TRAMPOLINE): Send closure reference through eax.
+
+2003-03-12 Andreas Schwab <schwab@suse.de>
+
+ * configure.in: Avoid trailing /. in toolexeclibdir.
+ * configure: Rebuilt.
+
+2003-03-03 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/powerpc/darwin_closure.S: Recode to fit dynamic libraries.
+
+2003-02-06 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * libffi/src/powerpc/darwin_closure.S:
+ Fix alignement bug, allocate 8 bytes for the result.
+ * libffi/src/powerpc/aix_closure.S:
+ Likewise.
+ * libffi/src/powerpc/ffi_darwin.c:
+ Update stackframe description for aix/darwin_closure.S.
+
+2003-02-06 Jakub Jelinek <jakub@redhat.com>
+
+ * src/s390/ffi.c (ffi_closure_helper_SYSV): Add hidden visibility
+ attribute.
+
+2003-01-31 Christian Cornelssen <ccorn@cs.tu-berlin.de>,
+ Andreas Schwab <schwab@suse.de>
+
+ * configure.in: Adjust command to source config-ml.in to account
+ for changes to the libffi_basedir definition.
+ (libffi_basedir): Remove ${srcdir} from value and include trailing
+ slash if nonempty.
+
+ * configure: Regenerate.
+
+2003-01-29 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+
+ * src/powerpc/ppc_closure.S: Recode to fit shared libs.
+
+2003-01-28 Andrew Haley <aph@redhat.com>
+
+ * include/ffi.h.in: Enable FFI_CLOSURES for x86_64.
+ * src/x86/ffi64.c (ffi_prep_closure): New.
+ (ffi_closure_UNIX64_inner): New.
+ * src/x86/unix64.S (ffi_closure_UNIX64): New.
+
+2003-01-27 Alexandre Oliva <aoliva@redhat.com>
+
+ * configure.in (toolexecdir, toolexeclibdir): Set and AC_SUBST.
+ Remove USE_LIBDIR conditional.
+ * Makefile.am (toolexecdir, toolexeclibdir): Don't override.
+ * Makefile.in, configure: Rebuilt.
+
+2003-01027 David Edelsohn <edelsohn@gnu.org>
+
+ * Makefile.am (TARGET_SRC_POWERPC_AIX): Fix typo.
+ * Makefile.in: Regenerate.
+
+2003-01-22 Andrew Haley <aph@redhat.com>
+
+ * src/powerpc/darwin.S (_ffi_call_AIX): Add Augmentation size to
+ unwind info.
+
+2003-01-21 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/powerpc/darwin.S: Add unwind info.
+ * src/powerpc/darwin_closure.S: Likewise.
+
+2003-01-14 Andrew Haley <aph@redhat.com>
+
+ * src/x86/ffi64.c (ffi_prep_args): Check for void retval.
+ (ffi_prep_cif_machdep): Likewise.
+ * src/x86/unix64.S: Add unwind info.
+
+2003-01-14 Andreas Jaeger <aj@suse.de>
+
+ * src/ffitest.c (main): Only use ffi_closures if those are
+ supported.
+
+2003-01-13 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * libffi/src/ffitest.c
+ add closure testcases
+
+2003-01-13 Kevin B. Hendricks <khendricks@ivey.uwo.ca>
+
+ * libffi/src/powerpc/ffi.c
+ fix alignment bug for float (4 byte aligned iso 8 byte)
+
+2003-01-09 Geoffrey Keating <geoffk@apple.com>
+
+ * src/powerpc/ffi_darwin.c: Remove RCS version string.
+ * src/powerpc/darwin.S: Remove RCS version string.
+
+2003-01-03 Jeff Sturm <jsturm@one-point.com>
+
+ * include/ffi.h.in: Add closure defines for SPARC, SPARC64.
+ * src/ffitest.c (main): Use static storage for closure.
+ * src/sparc/ffi.c (ffi_prep_closure, ffi_closure_sparc_inner): New.
+ * src/sparc/v8.S (ffi_closure_v8): New.
+ * src/sparc/v9.S (ffi_closure_v9): New.
+
+2002-11-10 Ranjit Mathew <rmathew@hotmail.com>
+
+ * include/ffi.h.in: Added FFI_STDCALL ffi_type
+ enumeration for X86_WIN32.
+ * src/x86/win32.S: Added ffi_call_STDCALL function
+ definition.
+ * src/x86/ffi.c (ffi_call/ffi_raw_call): Added
+ switch cases for recognising FFI_STDCALL and
+ calling ffi_call_STDCALL if target is X86_WIN32.
+ * src/ffitest.c (my_stdcall_strlen/stdcall_many):
+ stdcall versions of the "my_strlen" and "many"
+ test functions (for X86_WIN32).
+ Added test cases to test stdcall invocation using
+ these functions.
+
+2002-12-02 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/sysv.S: Add DWARF2 unwind info.
+
+2002-11-27 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * src/s390/sysv.S (.eh_frame section): Make section read-only.
+
+2002-11-26 Jim Wilson <wilson@redhat.com>
+
+ * src/types.c (FFI_TYPE_POINTER): Has size 8 on IA64.
+
+2002-11-23 H.J. Lu <hjl@gnu.org>
+
+ * acinclude.m4: Add dummy AM_PROG_LIBTOOL.
+ Include ../config/accross.m4.
+ * aclocal.m4; Rebuild.
+ * configure: Likewise.
+
+2002-11-15 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * src/s390/sysv.S (.eh_frame section): Adapt to pcrel FDE encoding.
+
+2002-11-11 DJ Delorie <dj@redhat.com>
+
+ * configure.in: Look for common files in the right place.
+
+2002-10-08 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * src/java_raw_api.c (ffi_java_raw_to_ptrarray): Interpret
+ raw data as _Jv_word values, not ffi_raw.
+ (ffi_java_ptrarray_to_raw): Likewise.
+ (ffi_java_rvalue_to_raw): New function.
+ (ffi_java_raw_call): Call it.
+ (ffi_java_raw_to_rvalue): New function.
+ (ffi_java_translate_args): Call it.
+ * src/ffitest.c (closure_test_fn): Interpret return value
+ as ffi_arg, not int.
+ * src/s390/ffi.c (ffi_prep_cif_machdep): Add missing
+ FFI_TYPE_POINTER case.
+ (ffi_closure_helper_SYSV): Likewise. Also, assume return
+ values extended to word size.
+
+2002-10-02 Andreas Jaeger <aj@suse.de>
+
+ * src/x86/ffi64.c (ffi_prep_cif_machdep): Remove debug output.
+
+2002-10-01 Bo Thorsen <bo@smetana.suse.de>
+
+ * include/ffi.h.in: Fix i386 win32 compilation.
+
+2002-09-30 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * configure.in: Add s390x-*-linux-* target.
+ * configure: Regenerate.
+ * include/ffi.h.in: Define S390X for s390x targets.
+ (FFI_CLOSURES): Define for s390/s390x.
+ (FFI_TRAMPOLINE_SIZE): Likewise.
+ (FFI_NATIVE_RAW_API): Likewise.
+ * src/prep_cif.c (ffi_prep_cif): Do not compute stack space for s390.
+ * src/types.c (FFI_TYPE_POINTER): Use 8-byte pointers on s390x.
+ * src/s390/ffi.c: Major rework of existing code. Add support for
+ s390x targets. Add closure support.
+ * src/s390/sysv.S: Likewise.
+
+2002-09-29 Richard Earnshaw <rearnsha@arm.com>
+
+ * src/arm/sysv.S: Fix typo.
+
+2002-09-28 Richard Earnshaw <rearnsha@arm.com>
+
+ * src/arm/sysv.S: If we don't have machine/asm.h and the pre-processor
+ has defined __USER_LABEL_PREFIX__, then use it in CNAME.
+ (ffi_call_SYSV): Handle soft-float.
+
+2002-09-27 Bo Thorsen <bo@suse.de>
+
+ * include/ffi.h.in: Fix multilib x86-64 support.
+
+2002-09-22 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.am (all-multi): Fix multilib parallel build.
+
+2002-07-19 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * configure.in (sh[34]*-*-linux*): Add brackets.
+ * configure: Regenerate.
+
+2002-07-18 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * Makefile.am: Add SH support.
+ * Makefile.in: Regenerate.
+ * configure.in (sh-*-linux*, sh[34]*-*-linux*): Add target.
+ * configure: Regenerate.
+ * include/ffi.h.in: Add SH support.
+ * src/sh/ffi.c: New file.
+ * src/sh/sysv.S: New file.
+ * src/types.c: Add SH support.
+
+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.
+ (libffi_la_SOURCES): Support MIPS_LINUX.
+ (libffi_convenience_la_SOURCES): Likewise.
+ * Makefile.in: Regenerated.
+
+ * configure.in (mips64*-*): Skip.
+ (mips*-*-linux*): New.
+ * configure: Regenerated.
+
+ * src/mips/ffi.c: Include <sgidefs.h>.
+
+2002-06-06 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * src/s390/sysv.S: Save/restore %r6. Add DWARF-2 unwind info.
+
+2002-05-27 Roger Sayle <roger@eyesopen.com>
+
+ * src/x86/ffi.c (ffi_prep_args): Remove reference to avn.
+
+2002-05-27 Bo Thorsen <bo@suse.de>
+
+ * src/x86/ffi.c (ffi_prep_args): Remove unused variable and
+ fix formatting.
+
+2002-05-13 Andreas Tobler <a.tobler@schweiz.ch>
+
+ * src/powerpc/ffi_darwin.c (ffi_prep_closure): Declare fd at
+ beginning of function (for older apple cc).
+
+2002-05-08 Alexandre Oliva <aoliva@redhat.com>
+
+ * configure.in (ORIGINAL_LD_FOR_MULTILIBS): Preserve LD at
+ script entry, and set LD to it when configuring multilibs.
+ * configure: Rebuilt.
+
+2002-05-05 Jason Thorpe <thorpej@wasabisystems.com>
+
+ * configure.in (sparc64-*-netbsd*): Add target.
+ (sparc-*-netbsdelf*): Likewise.
+ * configure: Regenerate.
+
+2002-04-28 David S. Miller <davem@redhat.com>
+
+ * configure.in, configure: Fix SPARC test in previous change.
+
+2002-04-29 Gerhard Tonn <GerhardTonn@swol.de>
+
+ * Makefile.am: Add Linux for S/390 support.
+ * Makefile.in: Regenerate.
+ * configure.in: Add Linux for S/390 support.
+ * configure: Regenerate.
+ * include/ffi.h.in: Add Linux for S/390 support.
+ * src/s390/ffi.c: New file from libffi CVS tree.
+ * src/s390/sysv.S: New file from libffi CVS tree.
+
+2002-04-28 Jakub Jelinek <jakub@redhat.com>
+
+ * configure.in (HAVE_AS_SPARC_UA_PCREL): Check for working
+ %r_disp32().
+ * src/sparc/v8.S: Use it.
+ * src/sparc/v9.S: Likewise.
+ * fficonfig.h.in: Rebuilt.
+ * configure: Rebuilt.
+
+2002-04-08 Hans Boehm <Hans_Boehm@hp.com>
+
+ * src/java_raw_api.c (ffi_java_raw_size): Handle FFI_TYPE_DOUBLE
+ correctly.
+ * src/ia64/unix.S: Add unwind information. Fix comments.
+ Save sp in a way that's compatible with unwind info.
+ (ffi_call_unix): Correctly restore sp in all cases.
+ * src/ia64/ffi.c: Add, fix comments.
+
+2002-04-08 Jakub Jelinek <jakub@redhat.com>
+
+ * src/sparc/v8.S: Make .eh_frame dependent on target word size.
+
+2002-04-06 Jason Thorpe <thorpej@wasabisystems.com>
+
+ * configure.in (alpha*-*-netbsd*): Add target.
+ * configure: Regenerate.
+
+2002-04-04 Jeff Sturm <jsturm@one-point.com>
+
+ * src/sparc/v8.S: Add unwind info.
+ * src/sparc/v9.S: Likewise.
+
+2002-03-30 Krister Walfridsson <cato@df.lth.se>
+
+ * configure.in: Enable i*86-*-netbsdelf*.
+ * configure: Rebuilt.
+
+2002-03-29 David Billinghurst <David.Billinghurst@riotinto.com>
+
+ PR other/2620
+ * src/mips/n32.s: Delete
+ * src/mips/o32.s: Delete
+
+2002-03-21 Loren J. Rittle <ljrittle@acm.org>
+
+ * configure.in: Enable alpha*-*-freebsd*.
+ * configure: Rebuilt.
+
+2002-03-17 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
+
+ * Makefile.am: libfficonvenience -> libffi_convenience.
+ * Makefile.in: Rebuilt.
+
+ * Makefile.am: Define ffitest_OBJECTS.
+ * Makefile.in: Rebuilt.
+
+2002-03-07 Andreas Tobler <toa@pop.agri.ch>
+ David Edelsohn <edelsohn@gnu.org>
+
+ * Makefile.am (EXTRA_DIST): Add Darwin and AIX closure files.
+ (TARGET_SRC_POWERPC_AIX): Add aix_closure.S.
+ (TARGET_SRC_POWERPC_DARWIN): Add darwin_closure.S.
+ * Makefile.in: Regenerate.
+ * include/ffi.h.in: Add AIX and Darwin closure definitions.
+ * src/powerpc/ffi_darwin.c (ffi_prep_closure): New function.
+ (flush_icache, flush_range): New functions.
+ (ffi_closure_helper_DARWIN): New function.
+ * src/powerpc/aix_closure.S: New file.
+ * src/powerpc/darwin_closure.S: New file.
+
+2002-02-24 Jeff Sturm <jsturm@one-point.com>
+
+ * include/ffi.h.in: Add typedef for ffi_arg.
+ * src/ffitest.c (main): Declare rint with ffi_arg.
+
+2002-02-21 Andreas Tobler <toa@pop.agri.ch>
+
+ * src/powerpc/ffi_darwin.c (ffi_prep_args): Skip appropriate
+ number of GPRs for floating-point arguments.
+
+2002-01-31 Anthony Green <green@redhat.com>
+
+ * configure: Rebuilt.
+ * configure.in: Replace CHECK_SIZEOF and endian tests with
+ cross-compiler friendly macros.
+ * aclocal.m4 (AC_COMPILE_CHECK_SIZEOF, AC_C_BIGENDIAN_CROSS): New
+ macros.
+
+2002-01-18 David Edelsohn <edelsohn@gnu.org>
+
+ * src/powerpc/darwin.S (_ffi_call_AIX): New.
+ * src/powerpc/aix.S (ffi_call_DARWIN): New.
+
+2002-01-17 David Edelsohn <edelsohn@gnu.org>
+
+ * Makefile.am (EXTRA_DIST): Add Darwin and AIX files.
+ (TARGET_SRC_POWERPC_AIX): New.
+ (POWERPC_AIX): New stanza.
+ * Makefile.in: Regenerate.
+ * configure.in: Add AIX case.
+ * configure: Regenerate.
+ * include/ffi.h.in (ffi_abi): Add FFI_AIX.
+ * src/powerpc/ffi_darwin.c (ffi_status): Use "long" to scale frame
+ size. Fix "long double" support.
+ (ffi_call): Add FFI_AIX case.
+ * src/powerpc/aix.S: New.
+
+2001-10-09 John Hornkvist <john@toastedmarshmallow.com>
+
+ Implement Darwin PowerPC ABI.
+ * configure.in: Handle powerpc-*-darwin*.
+ * Makefile.am: Set source files for POWERPC_DARWIN.
+ * configure: Rebuilt.
+ * Makefile.in: Rebuilt.
+ * include/ffi.h.in: Define FFI_DARWIN and FFI_DEFAULT_ABI for
+ POWERPC_DARWIN.
+ * src/powerpc/darwin.S: New file.
+ * src/powerpc/ffi_darwin.c: New file.
+
+2001-10-07 Joseph S. Myers <jsm28@cam.ac.uk>
+
+ * src/x86/ffi.c: Fix spelling error of "separate" as "seperate".
+
+2001-07-16 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * src/x86/sysv.S: Avoid gas-only .balign directive.
+ Use C style comments.
+
+2001-07-16 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * src/alpha/ffi.c (ffi_prep_closure): Avoid gas-only mnemonic.
+ Fixes PR bootstrap/3563.
+
+2001-06-26 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * src/alpha/osf.S (ffi_closure_osf): Use .rdata for ECOFF.
+
+2001-06-25 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * configure.in: Recognize sparc*-sun-* host.
+ * configure: Regenerate.
+
+2001-06-06 Andrew Haley <aph@redhat.com>
+
+ * src/alpha/osf.S (__FRAME_BEGIN__): Conditionalize for ELF.
+
+2001-06-03 Andrew Haley <aph@redhat.com>
+
+ * src/alpha/osf.S: Add unwind info.
+ * src/powerpc/sysv.S: Add unwind info.
+ * src/powerpc/ppc_closure.S: Likewise.
+
+2000-05-31 Jeff Sturm <jsturm@one-point.com>
+
+ * configure.in: Fix AC_ARG_ENABLE usage.
+ * configure: Rebuilt.
+
+2001-05-06 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
+
+ * configure.in: Remove warning about beta code.
+ * configure: Rebuilt.
+
+2001-04-25 Hans Boehm <Hans_Boehm@hp.com>
+
+ * src/ia64/unix.S: Restore stack pointer when returning from
+ ffi_closure_UNIX.
+ * src/ia64/ffi.c: Fix typo in comment.
+
+2001-04-18 Jim Wilson <wilson@redhat.com>
+
+ * src/ia64/unix.S: Delete unnecessary increment and decrement of loc2
+ to eliminate RAW DV.
+
+2001-04-12 Bryce McKinlay <bryce@albatross.co.nz>
+
+ * Makefile.am: Make a libtool convenience library.
+ * Makefile.in: Rebuilt.
+
+2001-03-29 Bryce McKinlay <bryce@albatross.co.nz>
+
+ * configure.in: Use different syntax for subdirectory creation.
+ * configure: Rebuilt.
+
+2001-03-27 Jon Beniston <jon@beniston.com>
+
+ * configure.in: Added X86_WIN32 target (Win32, CygWin, MingW).
+ * configure: Rebuilt.
+ * Makefile.am: Added X86_WIN32 target support.
+ * Makefile.in: Rebuilt.
+
+ * include/ffi.h.in: Added X86_WIN32 target support.
+
+ * src/ffitest.c: Doesn't run structure tests for X86_WIN32 targets.
+ * src/types.c: Added X86_WIN32 target support.
+
+ * src/x86/win32.S: New file. Based on sysv.S, but with EH
+ stuff removed and made to work with CygWin's gas.
+
+2001-03-26 Bryce McKinlay <bryce@albatross.co.nz>
+
+ * configure.in: Make target subdirectory in build dir.
+ * Makefile.am: Override suffix based rules to specify correct output
+ subdirectory.
+ * Makefile.in: Rebuilt.
+ * configure: Rebuilt.
+
+2001-03-23 Kevin B Hendricks <khendricks@ivey.uwo.ca>
+
+ * src/powerpc/ppc_closure.S: New file.
+ * src/powerpc/ffi.c (ffi_prep_args): Fixed ABI compatibility bug
+ involving long long and register pairs.
+ (ffi_prep_closure): New function.
+ (flush_icache): Likewise.
+ (ffi_closure_helper_SYSV): Likewise.
+ * include/ffi.h.in (FFI_CLOSURES): Define on PPC.
+ (FFI_TRAMPOLINE_SIZE): Likewise.
+ (FFI_NATIVE_RAW_API): Likewise.
+ * Makefile.in: Rebuilt.
+ * Makefile.am (EXTRA_DIST): Added src/powerpc/ppc_closure.S.
+ (TARGET_SRC_POWERPC): Likewise.
+
+2001-03-19 Tom Tromey <tromey@redhat.com>
+
+ * Makefile.in: Rebuilt.
+ * Makefile.am (ffitest_LDFLAGS): New macro.
+
+2001-03-02 Nick Clifton <nickc@redhat.com>
+
+ * include/ffi.h.in: Remove RCS ident string.
+ * include/ffi_mips.h: Remove RCS ident string.
+ * src/debug.c: Remove RCS ident string.
+ * src/ffitest.c: Remove RCS ident string.
+ * src/prep_cif.c: Remove RCS ident string.
+ * src/types.c: Remove RCS ident string.
+ * src/alpha/ffi.c: Remove RCS ident string.
+ * src/alpha/osf.S: Remove RCS ident string.
+ * src/arm/ffi.c: Remove RCS ident string.
+ * src/arm/sysv.S: Remove RCS ident string.
+ * src/mips/ffi.c: Remove RCS ident string.
+ * src/mips/n32.S: Remove RCS ident string.
+ * src/mips/o32.S: Remove RCS ident string.
+ * src/sparc/ffi.c: Remove RCS ident string.
+ * src/sparc/v8.S: Remove RCS ident string.
+ * src/sparc/v9.S: Remove RCS ident string.
+ * src/x86/ffi.c: Remove RCS ident string.
+ * src/x86/sysv.S: Remove RCS ident string.
+
+2001-02-08 Joseph S. Myers <jsm28@cam.ac.uk>
+
+ * include/ffi.h.in: Change sourceware.cygnus.com references to
+ gcc.gnu.org.
+
+2000-12-09 Richard Henderson <rth@redhat.com>
+
+ * src/alpha/ffi.c (ffi_call): Simplify struct return test.
+ (ffi_closure_osf_inner): Index rather than increment avalue
+ and arg_types. Give ffi_closure_osf the raw return value type.
+ * src/alpha/osf.S (ffi_closure_osf): Handle return value type
+ promotion.
+
+2000-12-07 Richard Henderson <rth@redhat.com>
+
+ * src/raw_api.c (ffi_translate_args): Fix typo.
+ (ffi_prep_closure): Likewise.
+
+ * include/ffi.h.in [ALPHA]: Define FFI_CLOSURES and
+ FFI_TRAMPOLINE_SIZE.
+ * src/alpha/ffi.c (ffi_prep_cif_machdep): Adjust minimal
+ cif->bytes for new ffi_call_osf implementation.
+ (ffi_prep_args): Absorb into ...
+ (ffi_call): ... here. Do all stack allocation here and
+ avoid a callback function.
+ (ffi_prep_closure, ffi_closure_osf_inner): New.
+ * src/alpha/osf.S (ffi_call_osf): Reimplement with no callback.
+ (ffi_closure_osf): New.
+
+2000-09-10 Alexandre Oliva <aoliva@redhat.com>
+
+ * config.guess, config.sub, install-sh: Removed.
+ * ltconfig, ltmain.sh, missing, mkinstalldirs: Likewise.
+ * Makefile.in: Rebuilt.
+
+ * acinclude.m4: Include libtool macros from the top level.
+ * aclocal.m4, configure: Rebuilt.
+
+2000-08-22 Alexandre Oliva <aoliva@redhat.com>
+
+ * configure.in [i*86-*-freebsd*] (TARGET, TARGETDIR): Set.
+ * configure: Rebuilt.
+
+2000-05-11 Scott Bambrough <scottb@netwinder.org>
+
+ * libffi/src/arm/sysv.S (ffi_call_SYSV): Doubles are not saved to
+ memory correctly. Use conditional instructions, not branches where
+ possible.
+
+2000-05-04 Tom Tromey <tromey@cygnus.com>
+
+ * configure: Rebuilt.
+ * configure.in: Match `arm*-*-linux-*'.
+ From Chris Dornan <cdornan@arm.com>.
+
+2000-04-28 Jakub Jelinek <jakub@redhat.com>
+
+ * Makefile.am (SUBDIRS): Define.
+ (AM_MAKEFLAGS): Likewise.
+ (Multilib support.): Add section.
+ * Makefile.in: Rebuilt.
+ * ltconfig (extra_compiler_flags, extra_compiler_flags_value):
+ New variables. Set for gcc using -print-multi-lib. Export them
+ to libtool.
+ (sparc64-*-linux-gnu*): Use libsuff 64 for search paths.
+ * ltmain.sh (B|b|V): Don't throw away gcc's -B, -b and -V options
+ for -shared links.
+ (extra_compiler_flags_value, extra_compiler_flags): Check these
+ for extra compiler options which need to be passed down in
+ compiler_flags.
+
+2000-04-16 Anthony Green <green@redhat.com>
+
+ * configure: Rebuilt.
+ * configure.in: Change i*86-pc-linux* to i*86-*-linux*.
+
+2000-04-14 Jakub Jelinek <jakub@redhat.com>
+
+ * include/ffi.h.in (SPARC64): Define for 64bit SPARC builds.
+ Set SPARC FFI_DEFAULT_ABI based on SPARC64 define.
+ * src/sparc/ffi.c (ffi_prep_args_v8): Renamed from ffi_prep_args.
+ Replace all void * sizeofs with sizeof(int).
+ Only compare type with FFI_TYPE_LONGDOUBLE if LONGDOUBLE is
+ different than DOUBLE.
+ Remove FFI_TYPE_SINT32 and FFI_TYPE_UINT32 cases (handled elsewhere).
+ (ffi_prep_args_v9): New function.
+ (ffi_prep_cif_machdep): Handle V9 ABI and long long on V8.
+ (ffi_V9_return_struct): New function.
+ (ffi_call): Handle FFI_V9 ABI from 64bit code and FFI_V8 ABI from
+ 32bit code (not yet cross-arch calls).
+ * src/sparc/v8.S: Add struct return delay nop.
+ Handle long long.
+ * src/sparc/v9.S: New file.
+ * src/prep_cif.c (ffi_prep_cif): Return structure pointer
+ is used on sparc64 only for structures larger than 32 bytes.
+ Pass by reference for structures is done for structure arguments
+ larger than 16 bytes.
+ * src/ffitest.c (main): Use 64bit rint on sparc64.
+ Run long long tests on sparc.
+ * src/types.c (FFI_TYPE_POINTER): Pointer is 64bit on alpha and
+ sparc64.
+ (FFI_TYPE_LONGDOUBLE): long double is 128 bit aligned to 128 bits
+ on sparc64.
+ * configure.in (sparc-*-linux*): New supported target.
+ (sparc64-*-linux*): Likewise.
+ * configure: Rebuilt.
+ * Makefile.am: Add v9.S to SPARC files.
+ * Makefile.in: Likewise.
+ (LINK): Surround $(CCLD) into double quotes, so that multilib
+ compiles work correctly.
+
+2000-04-04 Alexandre Petit-Bianco <apbianco@cygnus.com>
+
+ * configure: Rebuilt.
+ * configure.in: (i*86-*-solaris*): New libffi target. Patch
+ proposed by Bryce McKinlay.
+
+2000-03-20 Tom Tromey <tromey@cygnus.com>
+
+ * Makefile.in: Hand edit for java_raw_api.lo.
+
+2000-03-08 Bryce McKinlay <bryce@albatross.co.nz>
+
+ * config.guess, config.sub: Update from the gcc tree.
+ Fix for PR libgcj/168.
+
+2000-03-03 Tom Tromey <tromey@cygnus.com>
+
+ * Makefile.in: Fixed ia64 by hand.
+
+ * configure: Rebuilt.
+ * configure.in (--enable-multilib): New option.
+ (libffi_basedir): New subst.
+ (AC_OUTPUT): Added multilib code.
+
+2000-03-02 Tom Tromey <tromey@cygnus.com>
+
+ * Makefile.in: Rebuilt.
+ * Makefile.am (TARGET_SRC_IA64): Use `ia64', not `alpha', as
+ directory name.
+
+2000-02-25 Hans Boehm <boehm@acm.org>
+
+ * src/ia64/ffi.c, src/ia64/ia64_flags.h, src/ia64/unix.S: New
+ files.
+ * src/raw_api.c (ffi_translate_args): Fixed typo in argument
+ list.
+ (ffi_prep_raw_closure): Use ffi_translate_args, not
+ ffi_closure_translate.
+ * src/java_raw_api.c: New file.
+ * src/ffitest.c (closure_test_fn): New function.
+ (main): Define `rint' as long long on IA64. Added new test when
+ FFI_CLOSURES is defined.
+ * include/ffi.h.in (ALIGN): Use size_t, not unsigned.
+ (ffi_abi): Recognize IA64.
+ (ffi_raw): Added `flt' field.
+ Added "Java raw API" code.
+ * configure.in: Recognize ia64.
+ * Makefile.am (TARGET_SRC_IA64): New macro.
+ (libffi_la_common_SOURCES): Added java_raw_api.c.
+ (libffi_la_SOURCES): Define in IA64 case.
+
+2000-01-04 Tom Tromey <tromey@cygnus.com>
+
+ * Makefile.in: Rebuilt with newer automake.
+
+1999-12-31 Tom Tromey <tromey@cygnus.com>
+
+ * Makefile.am (INCLUDES): Added -I$(top_srcdir)/src.
+
+1999-09-01 Tom Tromey <tromey@cygnus.com>
+
+ * include/ffi.h.in: Removed PACKAGE and VERSION defines and
+ undefs.
+ * fficonfig.h.in: Rebuilt.
+ * configure: Rebuilt.
+ * configure.in: Pass 3rd argument to AM_INIT_AUTOMAKE.
+ Use AM_PROG_LIBTOOL (automake 1.4 compatibility).
+ * acconfig.h: Don't #undef PACKAGE or VERSION.
+
+1999-08-09 Anthony Green <green@cygnus.com>
+
+ * include/ffi.h.in: Try to work around messy header problem
+ with PACKAGE and VERSION.
+
+ * configure: Rebuilt.
+ * configure.in: Change version to 2.00-beta.
+
+ * fficonfig.h.in: Rebuilt.
+ * acconfig.h (FFI_NO_STRUCTS, FFI_NO_RAW_API): Define.
+
+ * src/x86/ffi.c (ffi_raw_call): Rename.
+
+1999-08-02 Kresten Krab Thorup <krab@dominiq.is.s.u-tokyo.ac.jp>
+
+ * src/x86/ffi.c (ffi_closure_SYSV): New function.
+ (ffi_prep_incoming_args_SYSV): Ditto.
+ (ffi_prep_closure): Ditto.
+ (ffi_closure_raw_SYSV): Ditto.
+ (ffi_prep_raw_closure): More ditto.
+ (ffi_call_raw): Final ditto.
+
+ * include/ffi.h.in: Add definitions for closure and raw API.
+
+ * src/x86/ffi.c (ffi_prep_cif_machdep): Added case for
+ FFI_TYPE_UINT64.
+
+ * Makefile.am (libffi_la_common_SOURCES): Added raw_api.c
+
+ * src/raw_api.c: New file.
+
+ * include/ffi.h.in (ffi_raw): New type.
+ (UINT_ARG, SINT_ARG): New defines.
+ (ffi_closure, ffi_raw_closure): New types.
+ (ffi_prep_closure, ffi_prep_raw_closure): New declarations.
+
+ * configure.in: Add check for endianness and sizeof void*.
+
+ * src/x86/sysv.S (ffi_call_SYSV): Call fixup routine via argument,
+ instead of directly.
+
+ * configure: Rebuilt.
+
+Thu Jul 8 14:28:42 1999 Anthony Green <green@cygnus.com>
+
+ * configure.in: Add x86 and powerpc BeOS configurations.
+ From Makoto Kato <m_kato@ga2.so-net.ne.jp>.
+
+1999-05-09 Anthony Green <green@cygnus.com>
+
+ * configure.in: Add warning about this being beta code.
+ Remove src/Makefile.am from the picture.
+ * configure: Rebuilt.
+
+ * Makefile.am: Move logic from src/Makefile.am. Add changes
+ to support libffi as a target library.
+ * Makefile.in: Rebuilt.
+
+ * aclocal.m4, config.guess, config.sub, ltconfig, ltmain.sh:
+ Upgraded to new autoconf, automake, libtool.
+
+ * README: Tweaks.
+
+ * LICENSE: Update copyright date.
+
+ * src/Makefile.am, src/Makefile.in: Removed.
+
+1998-11-29 Anthony Green <green@cygnus.com>
+
+ * include/ChangeLog: Removed.
+ * src/ChangeLog: Removed.
+ * src/mips/ChangeLog: Removed.
+ * src/sparc/ChangeLog: Remboved.
+ * src/x86/ChangeLog: Removed.
+
+ * ChangeLog.v1: Created.
+
+=============================================================================
+From the old ChangeLog.libffi file....
+
+2011-02-08 Andreas Tobler <andreast@fgznet.ch>
+
+ * testsuite/lib/libffi.exp: Tweak for stand-alone mode.
+
+2009-12-25 Samuli Suominen <ssuominen@gentoo.org>
+
+ * configure.ac: Undefine _AC_ARG_VAR_PRECIOUS for autoconf 2.64.
+ * configure: Rebuilt.
+ * fficonfig.h.in: Rebuilt.
+
+2009-06-16 Andrew Haley <aph@redhat.com>
+
+ * testsuite/libffi.call/cls_align_sint64.c,
+ testsuite/libffi.call/cls_align_uint64.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/cls_ulonglong.c,
+ testsuite/libffi.call/return_ll1.c,
+ testsuite/libffi.call/stret_medium2.c: Fix printf format
+ specifiers.
+ * testsuite/libffi.call/huge_struct.c: Ad x86 XFAILs.
+ * testsuite/libffi.call/float2.c: Fix dg-excess-errors.
+ * testsuite/libffi.call/ffitest.h,
+ testsuite/libffi.special/ffitestcxx.h (PRIdLL, PRIuLL): Define.
+
+2009-06-12 Andrew Haley <aph@redhat.com>
+
+ * testsuite/libffi.call/cls_align_sint64.c,
+ testsuite/libffi.call/cls_align_uint64.c,
+ testsuite/libffi.call/cls_ulonglong.c,
+ testsuite/libffi.call/return_ll1.c,
+ testsuite/libffi.call/stret_medium2.c: Fix printf format
+ specifiers.
+ testsuite/libffi.special/unwindtest.cc: include stdint.h.
+
+2009-06-11 Timothy Wall <twall@users.sf.net>
+
+ * Makefile.am,
+ configure.ac,
+ include/ffi.h.in,
+ include/ffi_common.h,
+ src/closures.c,
+ src/dlmalloc.c,
+ src/x86/ffi.c,
+ src/x86/ffitarget.h,
+ src/x86/win64.S (new),
+ README: Added win64 support (mingw or MSVC)
+ * Makefile.in,
+ include/Makefile.in,
+ man/Makefile.in,
+ testsuite/Makefile.in,
+ configure,
+ aclocal.m4: Regenerated
+ * ltcf-c.sh: properly escape cygwin/w32 path
+ * man/ffi_call.3: Clarify size requirements for return value.
+ * src/x86/ffi64.c: Fix filename in comment.
+ * src/x86/win32.S: Remove unused extern.
+
+ * testsuite/libffi.call/closure_fn0.c,
+ testsuite/libffi.call/closure_fn1.c,
+ testsuite/libffi.call/closure_fn2.c,
+ testsuite/libffi.call/closure_fn3.c,
+ testsuite/libffi.call/closure_fn4.c,
+ testsuite/libffi.call/closure_fn5.c,
+ testsuite/libffi.call/closure_fn6.c,
+ testsuite/libffi.call/closure_stdcall.c,
+ testsuite/libffi.call/cls_12byte.c,
+ testsuite/libffi.call/cls_16byte.c,
+ testsuite/libffi.call/cls_18byte.c,
+ testsuite/libffi.call/cls_19byte.c,
+ testsuite/libffi.call/cls_1_1byte.c,
+ testsuite/libffi.call/cls_20byte.c,
+ testsuite/libffi.call/cls_20byte1.c,
+ testsuite/libffi.call/cls_24byte.c,
+ testsuite/libffi.call/cls_2byte.c,
+ testsuite/libffi.call/cls_3_1byte.c,
+ testsuite/libffi.call/cls_3byte1.c,
+ testsuite/libffi.call/cls_3byte2.c,
+ testsuite/libffi.call/cls_4_1byte.c,
+ testsuite/libffi.call/cls_4byte.c,
+ testsuite/libffi.call/cls_5_1_byte.c,
+ testsuite/libffi.call/cls_5byte.c,
+ testsuite/libffi.call/cls_64byte.c,
+ testsuite/libffi.call/cls_6_1_byte.c,
+ testsuite/libffi.call/cls_6byte.c,
+ testsuite/libffi.call/cls_7_1_byte.c,
+ testsuite/libffi.call/cls_7byte.c,
+ testsuite/libffi.call/cls_8byte.c,
+ testsuite/libffi.call/cls_9byte1.c,
+ testsuite/libffi.call/cls_9byte2.c,
+ testsuite/libffi.call/cls_align_double.c,
+ testsuite/libffi.call/cls_align_float.c,
+ testsuite/libffi.call/cls_align_longdouble.c,
+ testsuite/libffi.call/cls_align_longdouble_split.c,
+ testsuite/libffi.call/cls_align_longdouble_split2.c,
+ testsuite/libffi.call/cls_align_pointer.c,
+ testsuite/libffi.call/cls_align_sint16.c,
+ testsuite/libffi.call/cls_align_sint32.c,
+ testsuite/libffi.call/cls_align_sint64.c,
+ testsuite/libffi.call/cls_align_uint16.c,
+ testsuite/libffi.call/cls_align_uint32.c,
+ testsuite/libffi.call/cls_align_uint64.c,
+ testsuite/libffi.call/cls_dbls_struct.c,
+ testsuite/libffi.call/cls_double.c,
+ testsuite/libffi.call/cls_double_va.c,
+ testsuite/libffi.call/cls_float.c,
+ testsuite/libffi.call/cls_longdouble.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/cls_multi_schar.c,
+ testsuite/libffi.call/cls_multi_sshort.c,
+ testsuite/libffi.call/cls_multi_sshortchar.c,
+ testsuite/libffi.call/cls_multi_uchar.c,
+ testsuite/libffi.call/cls_multi_ushort.c,
+ testsuite/libffi.call/cls_multi_ushortchar.c,
+ testsuite/libffi.call/cls_pointer.c,
+ testsuite/libffi.call/cls_pointer_stack.c,
+ testsuite/libffi.call/cls_schar.c,
+ testsuite/libffi.call/cls_sint.c,
+ testsuite/libffi.call/cls_sshort.c,
+ testsuite/libffi.call/cls_uchar.c,
+ testsuite/libffi.call/cls_uint.c,
+ testsuite/libffi.call/cls_ulonglong.c,
+ testsuite/libffi.call/cls_ushort.c,
+ testsuite/libffi.call/err_bad_abi.c,
+ testsuite/libffi.call/err_bad_typedef.c,
+ testsuite/libffi.call/float2.c,
+ testsuite/libffi.call/huge_struct.c,
+ testsuite/libffi.call/nested_struct.c,
+ testsuite/libffi.call/nested_struct1.c,
+ testsuite/libffi.call/nested_struct10.c,
+ testsuite/libffi.call/nested_struct2.c,
+ testsuite/libffi.call/nested_struct3.c,
+ testsuite/libffi.call/nested_struct4.c,
+ testsuite/libffi.call/nested_struct5.c,
+ testsuite/libffi.call/nested_struct6.c,
+ testsuite/libffi.call/nested_struct7.c,
+ testsuite/libffi.call/nested_struct8.c,
+ testsuite/libffi.call/nested_struct9.c,
+ testsuite/libffi.call/problem1.c,
+ testsuite/libffi.call/return_ldl.c,
+ testsuite/libffi.call/return_ll1.c,
+ testsuite/libffi.call/stret_large.c,
+ testsuite/libffi.call/stret_large2.c,
+ testsuite/libffi.call/stret_medium.c,
+ testsuite/libffi.call/stret_medium2.c,
+ testsuite/libffi.special/unwindtest.cc: use ffi_closure_alloc instead
+ of checking for MMAP. Use intptr_t instead of long casts.
+
+2009-06-04 Andrew Haley <aph@redhat.com>
+
+ * src/powerpc/ffitarget.h: Fix misapplied merge from gcc.
+
+2009-06-04 Andrew Haley <aph@redhat.com>
+
+ * src/mips/o32.S,
+ src/mips/n32.S: Fix licence formatting.
+
+2009-06-04 Andrew Haley <aph@redhat.com>
+
+ * src/x86/darwin.S: Fix licence formatting.
+ src/x86/win32.S: Likewise.
+ src/sh64/sysv.S: Likewise.
+ src/sh/sysv.S: Likewise.
+
+2009-06-04 Andrew Haley <aph@redhat.com>
+
+ * src/sh64/ffi.c: Remove lint directives. Was missing from merge
+ of Andreas Tobler's patch from 2006-04-22.
+
+2009-06-04 Andrew Haley <aph@redhat.com>
+
+ * src/sh/ffi.c: Apply missing hunk from Alexandre Oliva's patch of
+ 2007-03-07.
+
+2008-12-26 Timothy Wall <twall@users.sf.net>
+
+ * testsuite/libffi.call/cls_longdouble.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/cls_align_longdouble.c,
+ testsuite/libffi.call/cls_align_longdouble_split.c,
+ testsuite/libffi.call/cls_align_longdouble_split2.c: mark expected
+ failures on x86_64 cygwin/mingw.
+
+2008-12-22 Timothy Wall <twall@users.sf.net>
+
+ * testsuite/libffi.call/closure_fn0.c,
+ testsuite/libffi.call/closure_fn1.c,
+ testsuite/libffi.call/closure_fn2.c,
+ testsuite/libffi.call/closure_fn3.c,
+ testsuite/libffi.call/closure_fn4.c,
+ testsuite/libffi.call/closure_fn5.c,
+ testsuite/libffi.call/closure_fn6.c,
+ testsuite/libffi.call/closure_loc_fn0.c,
+ testsuite/libffi.call/closure_stdcall.c,
+ testsuite/libffi.call/cls_align_pointer.c,
+ testsuite/libffi.call/cls_pointer.c,
+ testsuite/libffi.call/cls_pointer_stack.c: use portable cast from
+ pointer to integer (intptr_t).
+ * testsuite/libffi.call/cls_longdouble.c: disable for win64.
+
+2008-12-19 Anthony Green <green@redhat.com>
+
+ * configure.ac: Bump version to 3.0.8.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+ * libtool-version: Increment revision.
+ * README: Update for new release.
+
+2008-11-11 Anthony Green <green@redhat.com>
+
+ * configure.ac: Bump version to 3.0.7.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+ * libtool-version: Increment revision.
+ * README: Update for new release.
+
+2008-08-25 Andreas Tobler <a.tobler@schweiz.org>
+
+ * src/powerpc/ffitarget.h (ffi_abi): Add FFI_LINUX and
+ FFI_LINUX_SOFT_FLOAT to the POWERPC_FREEBSD enum.
+ Add note about flag bits used for FFI_SYSV_TYPE_SMALL_STRUCT.
+ Adjust copyright notice.
+ * src/powerpc/ffi.c: Add two new flags to indicate if we have one
+ register or two register to use for FFI_SYSV structs.
+ (ffi_prep_cif_machdep): Pass the right register flag introduced above.
+ (ffi_closure_helper_SYSV): Fix the return type for
+ FFI_SYSV_TYPE_SMALL_STRUCT. Comment.
+ Adjust copyright notice.
+
+2008-07-24 Anthony Green <green@redhat.com>
+
+ * testsuite/libffi.call/cls_dbls_struct.c,
+ testsuite/libffi.call/cls_double_va.c,
+ testsuite/libffi.call/cls_longdouble.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/cls_pointer.c,
+ testsuite/libffi.call/cls_pointer_stack.c,
+ testsuite/libffi.call/err_bad_abi.c: Clean up failures from
+ compiler warnings.
+
+2008-07-17 Anthony Green <green@redhat.com>
+
+ * configure.ac: Bump version to 3.0.6.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+ * libtool-version: Increment revision. Add documentation.
+ * README: Update for new release.
+
+2008-07-16 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/ffi.c (ffi_prep_closure_loc): Turn INSN into an unsigned
+ int.
+
+2008-07-16 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * src/sh/sysv.S: Add .note.GNU-stack on Linux.
+ * src/sh64/sysv.S: Likewise.
+
+2008-04-03 Anthony Green <green@redhat.com>
+
+ * libffi.pc.in (Libs): Add -L${libdir}.
+ * configure.ac: Bump version to 3.0.5.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+ * libtool-version: Increment revision.
+ * README: Update for new release.
+
+2008-04-03 Anthony Green <green@redhat.com>
+ Xerces Ranby <xerxes@zafena.se>
+
+ * include/ffi.h.in: Wrap definition of target architecture to
+ protect from double definitions.
+
+2008-03-22 Moriyoshi Koizumi <moriyoshi@gmail.com>
+
+ * src/x86/ffi.c (ffi_prep_closure_loc): Fix for bug revealed in
+ closure_loc_fn0.c.
+ * testsuite/libffi.call/closure_loc_fn0.c (closure_loc_test_fn0):
+ New test.
+
+2008-03-04 Anthony Green <green@redhat.com>
+ Blake Chaffin
+ hos@tamanegi.org
+
+ * testsuite/libffi.call/cls_align_longdouble_split2.c
+ testsuite/libffi.call/cls_align_longdouble_split.c
+ testsuite/libffi.call/cls_dbls_struct.c
+ testsuite/libffi.call/cls_double_va.c
+ testsuite/libffi.call/cls_longdouble.c
+ testsuite/libffi.call/cls_longdouble_va.c
+ testsuite/libffi.call/cls_pointer.c
+ testsuite/libffi.call/cls_pointer_stack.c
+ testsuite/libffi.call/err_bad_abi.c
+ testsuite/libffi.call/err_bad_typedef.c
+ testsuite/libffi.call/huge_struct.c
+ testsuite/libffi.call/stret_large2.c
+ testsuite/libffi.call/stret_large.c
+ testsuite/libffi.call/stret_medium2.c
+ testsuite/libffi.call/stret_medium.c: New tests from Apple.
+
+2008-02-26 Jakub Jelinek <jakub@redhat.com>
+ Anthony Green <green@redhat.com>
+
+ * src/alpha/osf.S: Add .note.GNU-stack on Linux.
+ * src/s390/sysv.S: Likewise.
+ * src/powerpc/linux64.S: Likewise.
+ * src/powerpc/linux64_closure.S: Likewise.
+ * src/powerpc/ppc_closure.S: Likewise.
+ * src/powerpc/sysv.S: Likewise.
+ * src/x86/unix64.S: Likewise.
+ * src/x86/sysv.S: Likewise.
+ * src/sparc/v8.S: Likewise.
+ * src/sparc/v9.S: Likewise.
+ * src/m68k/sysv.S: Likewise.
+ * src/ia64/unix.S: Likewise.
+ * src/arm/sysv.S: Likewise.
+
+2008-02-26 Anthony Green <green@redhat.com>
+ Thomas Heller <theller@ctypes.org>
+
+ * src/x86/ffi.c (ffi_closure_SYSV_inner): Change C++ comment to C
+ comment.
+
+2008-02-26 Anthony Green <green@redhat.org>
+ Thomas Heller <theller@ctypes.org>
+
+ * include/ffi.h.in: Change void (*)() to void (*)(void).
+
+2008-02-26 Anthony Green <green@redhat.org>
+ Thomas Heller <theller@ctypes.org>
+
+ * src/alpha/ffi.c: Change void (*)() to void (*)(void).
+ src/alpha/osf.S, src/arm/ffi.c, src/frv/ffi.c, src/ia64/ffi.c,
+ src/ia64/unix.S, src/java_raw_api.c, src/m32r/ffi.c,
+ src/mips/ffi.c, src/pa/ffi.c, src/pa/hpux32.S, src/pa/linux.S,
+ src/powerpc/ffi.c, src/powerpc/ffi_darwin.c, src/raw_api.c,
+ src/s390/ffi.c, src/sh/ffi.c, src/sh64/ffi.c, src/sparc/ffi.c,
+ src/x86/ffi.c, src/x86/unix64.S, src/x86/darwin64.S,
+ src/x86/ffi64.c: Ditto.
+
+2008-02-24 Anthony Green <green@redhat.org>
+
+ * configure.ac: Accept openbsd*, not just openbsd.
+ Bump version to 3.0.4.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+ * libtool-version: Increment revision.
+ * README: Update for new release.
+
+2008-02-22 Anthony Green <green@redhat.com>
+
+ * README: Clean up list of tested platforms.
+
+2008-02-22 Anthony Green <green@redhat.com>
+
+ * configure.ac: Bump version to 3.0.3.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+ * libtool-version: Increment revision.
+ * README: Update for new release. Clean up test docs.
+
+2008-02-22 Bjoern Koenig <bkoenig@alpha-tierchen.de>
+ Andreas Tobler <a.tobler@schweiz.org>
+
+ * configure.ac: Add amd64-*-freebsd* target.
+ * configure: Regenerate.
+
+2008-02-22 Thomas Heller <theller@ctypes.org>
+
+ * configure.ac: Add x86 OpenBSD support.
+ * configure: Rebuilt.
+
+2008-02-21 Thomas Heller <theller@ctypes.org>
+
+ * README: Change "make test" to "make check".
+
+2008-02-21 Anthony Green <green@redhat.com>
+
+ * configure.ac: Bump version to 3.0.2.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+ * libtool-version: Increment revision.
+ * README: Update for new release.
+
+2008-02-21 Björn König <bkoenig@alpha-tierchen.de>
+
+ * src/x86/freebsd.S: New file.
+ * configure.ac: Add x86 FreeBSD support.
+ * Makefile.am: Ditto.
+
+2008-02-15 Anthony Green <green@redhat.com>
+
+ * configure.ac: Bump version to 3.0.1.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+ * libtool-version: Increment revision.
+ * README: Update for new release.
+
+2008-02-15 David Daney <ddaney@avtrex.com>
+
+ * src/mips/ffi.c: Remove extra '>' from include directive.
+ (ffi_prep_closure_loc): Use clear_location instead of tramp.
+
+2008-02-15 Anthony Green <green@redhat.com>
+
+ * configure.ac: Bump version to 3.0.0.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+
+2008-02-15 David Daney <ddaney@avtrex.com>
+
+ * src/mips/ffi.c (USE__BUILTIN___CLEAR_CACHE):
+ Define (conditionally), and use it to include cachectl.h.
+ (ffi_prep_closure_loc): Fix cache flushing.
+ * src/mips/ffitarget.h (_ABIN32, _ABI64, _ABIO32): Define.
+
+2008-02-15 Anthony Green <green@redhat.com>
+
+ * man/ffi_call.3, man/ffi_prep_cif.3, man/ffi.3:
+ Update dates and remove all references to ffi_prep_closure.
+ * configure.ac: Bump version to 2.99.9.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+
+2008-02-15 Anthony Green <green@redhat.com>
+
+ * man/ffi_prep_closure.3: Delete.
+ * man/Makefile.am (EXTRA_DIST): Remove ffi_prep_closure.3.
+ (man_MANS): Ditto.
+ * man/Makefile.in: Rebuilt.
+ * configure.ac: Bump version to 2.99.8.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * configure.ac: Bump version to 2.99.7.
+ * configure, doc/stamp-vti, doc/version.texi: Rebuilt.
+ * include/ffi.h.in LICENSE src/debug.c src/closures.c
+ src/ffitest.c src/s390/sysv.S src/s390/ffitarget.h
+ src/types.c src/m68k/ffitarget.h src/raw_api.c src/frv/ffi.c
+ src/frv/ffitarget.h src/sh/ffi.c src/sh/sysv.S
+ src/sh/ffitarget.h src/powerpc/ffitarget.h src/pa/ffi.c
+ src/pa/ffitarget.h src/pa/linux.S src/java_raw_api.c
+ src/cris/ffitarget.h src/x86/ffi.c src/x86/sysv.S
+ src/x86/unix64.S src/x86/win32.S src/x86/ffitarget.h
+ src/x86/ffi64.c src/x86/darwin.S src/ia64/ffi.c
+ src/ia64/ffitarget.h src/ia64/ia64_flags.h src/ia64/unix.S
+ src/sparc/ffi.c src/sparc/v9.S src/sparc/ffitarget.h
+ src/sparc/v8.S src/alpha/ffi.c src/alpha/ffitarget.h
+ src/alpha/osf.S src/sh64/ffi.c src/sh64/sysv.S
+ src/sh64/ffitarget.h src/mips/ffi.c src/mips/ffitarget.h
+ src/mips/n32.S src/mips/o32.S src/arm/ffi.c src/arm/sysv.S
+ src/arm/ffitarget.h src/prep_cif.c: Update license text.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * README: Update tested platforms.
+ * configure.ac: Bump version to 2.99.6.
+ * configure: Rebuilt.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * configure.ac: Bump version to 2.99.5.
+ * configure: Rebuilt.
+ * Makefile.am (EXTRA_DIST): Add darwin64.S
+ * Makefile.in: Rebuilt.
+ * testsuite/lib/libffi-dg.exp: Remove libstdc++ bits from GCC tree.
+ * LICENSE: Update WARRANTY.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * libffi.pc.in (libdir): Fix libdir definition.
+ * configure.ac: Bump version to 2.99.4.
+ * configure: Rebuilt.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * README: Update.
+ * libffi.info: New file.
+ * doc/stamp-vti: New file.
+ * configure.ac: Bump version to 2.99.3.
+ * configure: Rebuilt.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * Makefile.am (SUBDIRS): Add man dir.
+ * Makefile.in: Rebuilt.
+ * configure.ac: Create Makefile.
+ * configure: Rebuilt.
+ * man/ffi_call.3 man/ffi_prep_cif.3 man/ffi_prep_closure.3
+ man/Makefile.am man/Makefile.in: New files.
+
+2008-02-14 Tom Tromey <tromey@redhat.com>
+
+ * aclocal.m4, Makefile.in, configure, fficonfig.h.in: Rebuilt.
+ * mdate-sh, texinfo.tex: New files.
+ * Makefile.am (info_TEXINFOS): New variable.
+ * doc/libffi.texi: New file.
+ * doc/version.texi: Likewise.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * Makefile.am (AM_CFLAGS): Don't compile with -D$(TARGET).
+ (lib_LTLIBRARIES): Define.
+ (toolexeclib_LIBRARIES): Undefine.
+ * Makefile.in: Rebuilt.
+ * configure.ac: Reset version to 2.99.1.
+ * configure.in: Rebuilt.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * libffi.pc.in: Use @PACKAGE_NAME@ and @PACKAGE_VERSION@.
+ * configure.ac: Reset version to 2.99.1.
+ * configure.in: Rebuilt.
+ * Makefile.am (EXTRA_DIST): Add ChangeLog.libffi.
+ * Makefile.in: Rebuilt.
+ * LICENSE: Update copyright notice.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * include/Makefile.am (nodist_includes_HEADERS): Define. Don't
+ distribute ffitarget.h or ffi.h from the build include dir.
+ * Makefile.in: Rebuilt.
+
+2008-02-14 Anthony Green <green@redhat.com>
+
+ * include/Makefile.am (includesdir): Install headers under libdir.
+ (pkgconfigdir): Define. Install libffi.pc.
+ * include/Makefile.in: Rebuilt.
+ * libffi.pc.in: Create.
+ * libtool-version: Increment CURRENT
+ * configure.ac: Add libffi.pc.in
+ * configure: Rebuilt.
+
+2008-02-03 Anthony Green <green@redhat.com>
+
+ * include/Makefile.am (includesdir): Fix header install with
+ DESTDIR.
+ * include/Makefile.in: Rebuilt.
+
+2008-02-03 Timothy Wall <twall@users.sf.net>
+
+ * src/x86/ffi.c (FFI_INIT_TRAMPOLINE_STDCALL): Calculate jump return
+ offset based on code pointer, not data pointer.
+
+2008-02-01 Anthony Green <green@redhat.com>
+
+ * include/Makefile.am: Fix header installs.
+ * Makefile.am: Ditto.
+ * include/Makefile.in: Rebuilt.
+ * Makefile.in: Ditto.
+
+2008-02-01 Anthony Green <green@redhat.com>
+
+ * src/x86/ffi.c (FFI_INIT_TRAMPOLINE_STDCALL,
+ FFI_INIT_TRAMPOLINE): Revert my broken changes to twall's last
+ patch.
+
+2008-01-31 Anthony Green <green@redhat.com>
+
+ * Makefile.am (EXTRA_DIST): Add missing files.
+ * testsuite/Makefile.am: Ditto.
+ * Makefile.in, testsuite/Makefile.in: Rebuilt.
+
+2008-01-31 Timothy Wall <twall@users.sf.net>
+
+ * testsuite/libffi.call/closure_stdcall.c: Add test for stdcall
+ closures.
+ * src/x86/ffitarget.h: Increase size of trampoline for stdcall
+ closures.
+ * src/x86/win32.S: Add assembly for stdcall closure.
+ * src/x86/ffi.c: Initialize stdcall closure trampoline.
+
+2008-01-30 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR libffi/34612
+ * src/x86/sysv.S (ffi_closure_SYSV): Pop 4 byte from stack when
+ returning struct.
+
+ * testsuite/libffi.call/call.exp: Add "-O2 -fomit-frame-pointer"
+ tests.
+
+2008-01-30 Anthony Green <green@redhat.com>
+
+ * Makefile.am, include/Makefile.am: Move headers to
+ libffi_la_SOURCES for new automake.
+ * Makefile.in, include/Makefile.in: Rebuilt.
+
+ * testsuite/lib/wrapper.exp: Copied from gcc tree to allow for
+ execution outside of gcc tree.
+ * testsuite/lib/target-libpath.exp: Ditto.
+
+ * testsuite/lib/libffi-dg.exp: Many changes to allow for execution
+ outside of gcc tree.
+
+
+=============================================================================
+From the old ChangeLog.libgcj file....
+
+2004-01-14 Kelley Cook <kcook@gcc.gnu.org>
+
+ * configure.in: Add in AC_PREREQ(2.13)
+
+2003-02-20 Alexandre Oliva <aoliva@redhat.com>
+
+ * configure.in: Propagate ORIGINAL_LD_FOR_MULTILIBS to
+ config.status.
+ * configure: Rebuilt.
+
+2002-01-27 Alexandre Oliva <aoliva@redhat.com>
+
+ * configure.in (toolexecdir, toolexeclibdir): Set and AC_SUBST.
+ Remove USE_LIBDIR conditional.
+ * Makefile.am (toolexecdir, toolexeclibdir): Don't override.
+ * Makefile.in, configure: Rebuilt.
+
+Mon Aug 9 18:33:38 1999 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * include/Makefile.in: Rebuilt.
+ * Makefile.in: Rebuilt
+ * Makefile.am (toolexeclibdir): Add $(MULTISUBDIR) even for native
+ builds.
+ Use USE_LIBDIR.
+
+ * configure: Rebuilt.
+ * configure.in (USE_LIBDIR): Define for native builds.
+ Use lowercase in configure --help explanations.
+
+1999-08-08 Anthony Green <green@cygnus.com>
+
+ * include/ffi.h.in (FFI_FN): Remove `...'.
+
+1999-08-08 Anthony Green <green@cygnus.com>
+
+ * Makefile.in: Rebuilt.
+ * Makefile.am (AM_CFLAGS): Compile with -fexceptions.
+
+ * src/x86/sysv.S: Add exception handling metadata.
+
+
+=============================================================================
+
+The libffi version 1 ChangeLog archive.
+
+Version 1 of libffi had per-directory ChangeLogs. Current and future
+versions have a single ChangeLog file in the root directory. The
+version 1 ChangeLogs have all been concatenated into this file for
+future reference only.
+
+--- libffi ----------------------------------------------------------------
+
+Mon Oct 5 02:17:50 1998 Anthony Green <green@cygnus.com>
+
+ * configure.in: Boosted rev.
+ * configure, Makefile.in, aclocal.m4: Rebuilt.
+ * README: Boosted rev and updated release notes.
+
+Mon Oct 5 01:03:03 1998 Anthony Green <green@cygnus.com>
+
+ * configure.in: Boosted rev.
+ * configure, Makefile.in, aclocal.m4: Rebuilt.
+ * README: Boosted rev and updated release notes.
+
+1998-07-25 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * m68k/ffi.c (ffi_prep_cif_machdep): Use bitmask for cif->flags.
+ Correctly handle small structures.
+ (ffi_prep_args): Also handle small structures.
+ (ffi_call): Pass size of return type to ffi_call_SYSV.
+ * m68k/sysv.S: Adjust for above changes. Correctly align small
+ structures in the return value.
+
+ * types.c (uint64, sint64) [M68K]: Change alignment to 4.
+
+Fri Apr 17 17:26:58 1998 Anthony Green <green@hoser.cygnus.com>
+
+ * configure.in: Boosted rev.
+ * configure,Makefile.in,aclocal.m4: Rebuilt.
+ * README: Boosted rev and added release notes.
+
+Sun Feb 22 00:50:41 1998 Geoff Keating <geoffk@ozemail.com.au>
+
+ * configure.in: Add PowerPC config bits.
+
+1998-02-14 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * configure.in: Add m68k config bits. Change AC_CANONICAL_SYSTEM
+ to AC_CANONICAL_HOST, this is not a compiler. Use $host instead
+ of $target. Remove AC_CHECK_SIZEOF(char), we already know the
+ result. Fix argument of AC_ARG_ENABLE.
+ * configure, fficonfig.h.in: Rebuilt.
+
+Tue Feb 10 20:53:40 1998 Richard Henderson <rth@cygnus.com>
+
+ * configure.in: Add Alpha config bits.
+
+Tue May 13 13:39:20 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * README: Updated dates and reworded Irix comments.
+
+ * configure.in: Removed AC_PROG_RANLIB.
+
+ * Makefile.in, aclocal.m4, config.guess, config.sub, configure,
+ ltmain.sh, */Makefile.in: libtoolized again and rebuilt with
+ automake and autoconf.
+
+Sat May 10 18:44:50 1997 Tom Tromey <tromey@cygnus.com>
+
+ * configure, aclocal.m4: Rebuilt.
+ * configure.in: Don't compute EXTRADIST; now handled in
+ src/Makefile.in. Removed macros implied by AM_INIT_AUTOMAKE.
+ Don't run AM_MAINTAINER_MODE.
+
+Thu May 8 14:34:05 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * missing, ltmain.sh, ltconfig.sh: Created. These are new files
+ required by automake and libtool.
+
+ * README: Boosted rev to 1.14. Added notes.
+
+ * acconfig.h: Moved PACKAGE and VERSION for new automake.
+
+ * configure.in: Changes for libtool.
+
+ * Makefile.am (check): make test now make check. Uses libtool now.
+
+ * Makefile.in, configure.in, aclocal.h, fficonfig.h.in: Rebuilt.
+
+Thu May 1 16:27:07 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * missing: Added file required by new automake.
+
+Tue Nov 26 14:10:42 1996 Anthony Green <green@csk3.cygnus.com>
+
+ * acconfig.h: Added USING_PURIFY flag. This is defined when
+ --enable-purify-safety was used at configure time.
+
+ * configure.in (allsources): Added --enable-purify-safety switch.
+ (VERSION): Boosted rev to 1.13.
+ * configure: Rebuilt.
+
+Fri Nov 22 06:46:12 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * configure.in (VERSION): Boosted rev to 1.12.
+ Removed special CFLAGS hack for gcc.
+ * configure: Rebuilt.
+
+ * README: Boosted rev to 1.12. Added notes.
+
+ * Many files: Cygnus Support changed to Cygnus Solutions.
+
+Wed Oct 30 11:15:25 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * configure.in (VERSION): Boosted rev to 1.11.
+ * configure: Rebuilt.
+
+ * README: Boosted rev to 1.11. Added notes about GNU make.
+
+Tue Oct 29 12:25:12 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * configure.in: Fixed -Wall trick.
+ (VERSION): Boosted rev.
+ * configure: Rebuilt
+
+ * acconfig.h: Needed for --enable-debug configure switch.
+
+ * README: Boosted rev to 1.09. Added more notes on building
+ libffi, and LCLint.
+
+ * configure.in: Added --enable-debug switch. Boosted rev to
+ 1.09.
+ * configure: Rebuilt
+
+Tue Oct 15 13:11:28 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * configure.in (VERSION): Boosted rev to 1.08
+ * configure: Rebuilt.
+
+ * README: Added n32 bug fix notes.
+
+ * Makefile.am: Added "make lint" production.
+ * Makefile.in: Rebuilt.
+
+Mon Oct 14 10:54:46 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * README: Added web page reference.
+
+ * configure.in, README: Boosted rev to 1.05
+ * configure: Rebuilt.
+
+ * README: Fixed n32 sample code.
+
+Fri Oct 11 17:09:28 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * README: Added sparc notes.
+
+ * configure.in, README: Boosted rev to 1.04.
+ * configure: Rebuilt.
+
+Thu Oct 10 10:31:03 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * configure.in, README: Boosted rev to 1.03.
+ * configure: Rebuilt.
+
+ * README: Added struct notes.
+
+ * Makefile.am (EXTRA_DIST): Added LICENSE to distribution.
+ * Makefile.in: Rebuilt.
+
+ * README: Removed Linux section. No special notes now
+ because aggregates arg/return types work.
+
+Wed Oct 9 16:16:42 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * README, configure.in (VERSION): Boosted rev to 1.02
+ * configure: Rebuilt.
+
+Tue Oct 8 11:56:33 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * README (NOTE): Added n32 notes.
+
+ * Makefile.am: Added test production.
+ * Makefile: Rebuilt
+
+ * README: spell checked!
+
+ * configure.in (VERSION): Boosted rev to 1.01
+ * configure: Rebuilt.
+
+Mon Oct 7 15:50:22 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * configure.in: Added nasty bit to support SGI tools.
+ * configure: Rebuilt.
+
+ * README: Added SGI notes. Added note about automake bug.
+
+Mon Oct 7 11:00:28 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * README: Rewrote intro, and fixed examples.
+
+Fri Oct 4 10:19:55 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * configure.in: -D$TARGET is no longer used as a compiler switch.
+ It is now inserted into ffi.h at configure time.
+ * configure: Rebuilt.
+
+ * FFI_ABI and FFI_STATUS are now ffi_abi and ffi_status.
+
+Thu Oct 3 13:47:34 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * README, LICENSE: Created. Wrote some docs.
+
+ * configure.in: Don't barf on i586-unknown-linuxaout.
+ Added EXTRADIST code for "make dist".
+ * configure: Rebuilt.
+
+ * */Makefile.in: Rebuilt with patched automake.
+
+Tue Oct 1 17:12:25 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * Makefile.am, aclocal.m4, config.guess, config.sub,
+ configure.in, fficonfig.h.in, install-sh, mkinstalldirs,
+ stamp-h.in: Created
+ * Makefile.in, configure: Generated
+
+--- libffi/include --------------------------------------------------------
+
+Tue Feb 24 13:09:36 1998 Anthony Green <green@gerbil.cygnus.com>
+
+ * ffi_mips.h: Updated FFI_TYPE_STRUCT_* values based on
+ ffi.h.in changes. This is a work-around for SGI's "simple"
+ assembler.
+
+Sun Feb 22 00:51:55 1998 Geoff Keating <geoffk@ozemail.com.au>
+
+ * ffi.h.in: PowerPC support.
+
+1998-02-14 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * ffi.h.in: Add m68k support.
+ (FFI_TYPE_LONGDOUBLE): Make it a separate value.
+
+Tue Feb 10 20:55:16 1998 Richard Henderson <rth@cygnus.com>
+
+ * ffi.h.in (SIZEOF_ARG): Use a pointer type by default.
+
+ * ffi.h.in: Alpha support.
+
+Fri Nov 22 06:48:45 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.h.in, ffi_common.h: Cygnus Support -> Cygnus Solutions.
+
+Wed Nov 20 22:31:01 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.h.in: Added ffi_type_void definition.
+
+Tue Oct 29 12:22:40 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * Makefile.am (hack_DATA): Always install ffi_mips.h.
+
+ * ffi.h.in: Removed FFI_DEBUG. It's now in the correct
+ place (acconfig.h).
+ Added #include <stddef.h> for size_t definition.
+
+Tue Oct 15 17:23:35 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.h.in, ffi_common.h, ffi_mips.h: More clean up.
+ Commented out #define of FFI_DEBUG.
+
+Tue Oct 15 13:01:06 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi_common.h: Added bool definition.
+
+ * ffi.h.in, ffi_common.h: Clean up based on LCLint output.
+ Added funny /*@...@*/ comments to annotate source.
+
+Mon Oct 14 12:29:23 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.h.in: Interface changes based on feedback from Jim
+ Blandy.
+
+Fri Oct 11 16:49:35 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.h.in: Small change for sparc support.
+
+Thu Oct 10 14:53:37 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi_mips.h: Added FFI_TYPE_STRUCT_* definitions for
+ special structure return types.
+
+Wed Oct 9 13:55:57 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.h.in: Added SIZEOF_ARG definition for X86
+
+Tue Oct 8 11:40:36 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.h.in (FFI_FN): Added macro for eliminating compiler warnings.
+ Use it to case your function pointers to the proper type.
+
+ * ffi_mips.h (SIZEOF_ARG): Added magic to fix type promotion bug.
+
+ * Makefile.am (EXTRA_DIST): Added ffi_mips.h to EXTRA_DIST.
+ * Makefile: Rebuilt.
+
+ * ffi_mips.h: Created. Moved all common mips definitions here.
+
+Mon Oct 7 10:58:12 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.h.in: The SGI assember is very picky about parens. Redefined
+ some macros to avoid problems.
+
+ * ffi.h.in: Added FFI_DEFAULT_ABI definitions. Also added
+ externs for pointer, and 64bit integral ffi_types.
+
+Fri Oct 4 09:51:37 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.h.in: Added FFI_ABI member to ffi_cif and changed
+ function prototypes accordingly.
+ Added #define @TARGET@. Now programs including ffi.h don't
+ have to specify this themselves.
+
+Thu Oct 3 15:36:44 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.h.in: Changed ffi_prep_cif's values from void* to void**
+
+ * Makefile.am (EXTRA_DIST): Added EXTRA_DIST for "make dist"
+ to work.
+ * Makefile.in: Regenerated.
+
+Wed Oct 2 10:16:59 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * Makefile.am: Created
+ * Makefile.in: Generated
+
+ * ffi_common.h: Added rcsid comment
+
+Tue Oct 1 17:13:51 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.h.in, ffi_common.h: Created
+
+--- libffi/src ------------------------------------------------------------
+
+Mon Oct 5 02:17:50 1998 Anthony Green <green@cygnus.com>
+
+ * arm/ffi.c, arm/sysv.S: Created.
+
+ * Makefile.am: Added arm files.
+ * Makefile.in: Rebuilt.
+
+Mon Oct 5 01:41:38 1998 Anthony Green <green@rtl.cygnus.com>
+
+ * Makefile.am (libffi_la_LDFLAGS): Incremented revision.
+
+Sun Oct 4 16:27:17 1998 Anthony Green <green@cygnus.com>
+
+ * alpha/osf.S (ffi_call_osf): Patch for DU assembler.
+
+ * ffitest.c (main): long long and long double return values work
+ for x86.
+
+Fri Apr 17 11:50:58 1998 Anthony Green <green@hoser.cygnus.com>
+
+ * Makefile.in: Rebuilt.
+
+ * ffitest.c (main): Floating point tests not executed for systems
+ with broken lond double (SunOS 4 w/ GCC).
+
+ * types.c: Fixed x86 alignment info for long long types.
+
+Thu Apr 16 07:15:28 1998 Anthony Green <green@ada.cygnus.com>
+
+ * ffitest.c: Added more notes about GCC bugs under Irix 6.
+
+Wed Apr 15 08:42:22 1998 Anthony Green <green@hoser.cygnus.com>
+
+ * ffitest.c (struct5): New test function.
+ (main): New test with struct5.
+
+Thu Mar 5 10:48:11 1998 Anthony Green <green@tootie.to.cygnus.com>
+
+ * prep_cif.c (initialize_aggregate): Fix assertion for
+ nested structures.
+
+Tue Feb 24 16:33:41 1998 Anthony Green <green@hoser.cygnus.com>
+
+ * prep_cif.c (ffi_prep_cif): Added long double support for sparc.
+
+Sun Feb 22 00:52:18 1998 Geoff Keating <geoffk@ozemail.com.au>
+
+ * powerpc/asm.h: New file.
+ * powerpc/ffi.c: New file.
+ * powerpc/sysv.S: New file.
+ * Makefile.am: PowerPC port.
+ * ffitest.c (main): Allow all tests to run even in presence of gcc
+ bug on PowerPC.
+
+1998-02-17 Anthony Green <green@hoser.cygnus.com>
+
+ * mips/ffi.c: Fixed comment typo.
+
+ * x86/ffi.c (ffi_prep_cif_machdep), x86/sysv.S (retfloat):
+ Fixed x86 long double return handling.
+
+ * types.c: Fixed x86 long double alignment info.
+
+1998-02-14 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * types.c: Add m68k support.
+
+ * ffitest.c (floating): Add long double parameter.
+ (return_ll, ldblit): New functions to test long long and long
+ double return value.
+ (main): Fix type error in assignment of ts[1-4]_type.elements.
+ Add tests for long long and long double arguments and return
+ values.
+
+ * prep_cif.c (ffi_prep_cif) [M68K]: Don't allocate argument for
+ struct value pointer.
+
+ * m68k/ffi.c, m68k/sysv.S: New files.
+ * Makefile.am: Add bits for m68k port. Add kludge to work around
+ automake deficiency.
+ (test): Don't require "." in $PATH.
+ * Makefile.in: Rebuilt.
+
+Wed Feb 11 07:36:50 1998 Anthony Green <green@hoser.cygnus.com>
+
+ * Makefile.in: Rebuilt.
+
+Tue Feb 10 20:56:00 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha/ffi.c, alpha/osf.S: New files.
+ * Makefile.am: Alpha port.
+
+Tue Nov 18 14:12:07 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * mips/ffi.c (ffi_prep_cif_machdep): Initialize rstruct_flag
+ for n32.
+
+Tue Jun 3 17:18:20 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * ffitest.c (main): Added hack to get structure tests working
+ correctly.
+
+Sat May 10 19:06:42 1997 Tom Tromey <tromey@cygnus.com>
+
+ * Makefile.in: Rebuilt.
+ * Makefile.am (EXTRA_DIST): Explicitly list all distributable
+ files in subdirs.
+ (VERSION, CC): Removed.
+
+Thu May 8 17:19:01 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * Makefile.am: Many changes for new automake and libtool.
+ * Makefile.in: Rebuilt.
+
+Fri Nov 22 06:57:56 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffitest.c (main): Fixed test case for non mips machines.
+
+Wed Nov 20 22:31:59 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * types.c: Added ffi_type_void declaration.
+
+Tue Oct 29 13:07:19 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffitest.c (main): Fixed character constants.
+ (main): Emit warning for structure test 3 failure on Sun.
+
+ * Makefile.am (VPATH): Fixed VPATH def'n so automake won't
+ strip it out.
+ Moved distdir hack from libffi to automake.
+ (ffitest): Added missing -c for $(COMPILE) (change in automake).
+ * Makefile.in: Rebuilt.
+
+Tue Oct 15 13:08:20 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * Makefile.am: Added "make lint" production.
+ * Makefile.in: Rebuilt.
+
+ * prep_cif.c (STACK_ARG_SIZE): Improved STACK_ARG_SIZE macro.
+ Clean up based on LCLint output. Added funny /*@...@*/ comments to
+ annotate source.
+
+ * ffitest.c, debug.c: Cleaned up code.
+
+Mon Oct 14 12:26:56 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffitest.c: Changes based on interface changes.
+
+ * prep_cif.c (ffi_prep_cif): Cleaned up interface based on
+ feedback from Jim Blandy.
+
+Fri Oct 11 15:53:18 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffitest.c: Reordered tests while porting to sparc.
+ Made changes to handle lame structure passing for sparc.
+ Removed calls to fflush().
+
+ * prep_cif.c (ffi_prep_cif): Added special case for sparc
+ aggregate type arguments.
+
+Thu Oct 10 09:56:51 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffitest.c (main): Added structure passing/returning tests.
+
+ * prep_cif.c (ffi_prep_cif): Perform proper initialization
+ of structure return types if needed.
+ (initialize_aggregate): Bug fix
+
+Wed Oct 9 16:04:20 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * types.c: Added special definitions for x86 (double doesn't
+ need double word alignment).
+
+ * ffitest.c: Added many tests
+
+Tue Oct 8 09:19:22 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * prep_cif.c (ffi_prep_cif): Fixed assertion.
+
+ * debug.c (ffi_assert): Must return a non void now.
+
+ * Makefile.am: Added test production.
+ * Makefile: Rebuilt.
+
+ * ffitest.c (main): Created.
+
+ * types.c: Created. Stripped common code out of */ffi.c.
+
+ * prep_cif.c: Added missing stdlib.h include.
+
+ * debug.c (ffi_type_test): Used "a" to eliminate compiler
+ warnings in non-debug builds. Included ffi_common.h.
+
+Mon Oct 7 15:36:42 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * Makefile.am: Added a rule for .s -> .o
+ This is required by the SGI compiler.
+ * Makefile: Rebuilt.
+
+Fri Oct 4 09:51:08 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * prep_cif.c (initialize_aggregate): Moved abi specification
+ to ffi_prep_cif().
+
+Thu Oct 3 15:37:37 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * prep_cif.c (ffi_prep_cif): Changed values from void* to void**.
+ (initialize_aggregate): Fixed aggregate type initialization.
+
+ * Makefile.am (EXTRA_DIST): Added support code for "make dist".
+ * Makefile.in: Regenerated.
+
+Wed Oct 2 11:41:57 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * debug.c, prep_cif: Created.
+
+ * Makefile.am: Added debug.o and prep_cif.o to OBJ.
+ * Makefile.in: Regenerated.
+
+ * Makefile.am (INCLUDES): Added missing -I../include
+ * Makefile.in: Regenerated.
+
+Tue Oct 1 17:11:51 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * error.c, Makefile.am: Created.
+ * Makefile.in: Generated.
+
+--- libffi/src/x86 --------------------------------------------------------
+
+Sun Oct 4 16:27:17 1998 Anthony Green <green@cygnus.com>
+
+ * sysv.S (retlongdouble): Fixed long long return value support.
+ * ffi.c (ffi_prep_cif_machdep): Ditto.
+
+Wed May 13 04:30:33 1998 Anthony Green <green@raft.ppp.tsoft.net>
+
+ * ffi.c (ffi_prep_cif_machdep): Fixed long double return value
+ support.
+
+Wed Apr 15 08:43:20 1998 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.c (ffi_prep_args): small struct support was missing.
+
+Thu May 8 16:53:58 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * objects.mak: Removed.
+
+Mon Dec 2 15:12:58 1996 Tom Tromey <tromey@cygnus.com>
+
+ * sysv.S: Use .balign, for a.out Linux boxes.
+
+Tue Oct 15 13:06:50 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.c: Clean up based on LCLint output.
+ Added funny /*@...@*/ comments to annotate source.
+
+Fri Oct 11 16:43:38 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.c (ffi_call): Added assertion for bad ABIs.
+
+Wed Oct 9 13:57:27 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * sysv.S (retdouble): Fixed double return problems.
+
+ * ffi.c (ffi_call): Corrected fn arg definition.
+ (ffi_prep_cif_machdep): Fixed double return problems
+
+Tue Oct 8 12:12:49 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.c: Moved ffi_type definitions to types.c.
+ (ffi_prep_args): Fixed type promotion bug.
+
+Mon Oct 7 15:53:06 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.c (FFI_*_TYPEDEF): Removed redundant ';'
+
+Fri Oct 4 09:54:53 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.c (ffi_call): Removed FFI_ABI arg, and swapped
+ remaining args.
+
+Wed Oct 2 10:07:05 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.c, sysv.S, objects.mak: Created.
+ (ffi_prep_cif): cif->rvalue no longer initialized to NULL.
+ (ffi_prep_cif_machdep): Moved machine independent cif processing
+ to src/prep_cif.c. Introduced ffi_prep_cif_machdep().
+
+--- libffi/src/mips -------------------------------------------------------
+
+Tue Feb 17 17:18:07 1998 Anthony Green <green@hoser.cygnus.com>
+
+ * o32.S: Fixed typo in comment.
+
+ * ffi.c (ffi_prep_cif_machdep): Fixed argument processing.
+
+Thu May 8 16:53:58 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * o32.s, n32.s: Wrappers for SGI tool support.
+
+ * objects.mak: Removed.
+
+Tue Oct 29 14:37:45 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.c (ffi_prep_args): Changed int z to size_t z.
+
+Tue Oct 15 13:17:25 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * n32.S: Fixed bad stack munging.
+
+ * ffi.c: Moved prototypes for ffi_call_?32() to here from
+ ffi_mips.h because extended_cif is not defined in ffi_mips.h.
+
+Mon Oct 14 12:42:02 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.c: Interface changes based on feedback from Jim Blandy.
+
+Thu Oct 10 11:22:16 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * n32.S, ffi.c: Lots of changes to support passing and
+ returning structures with the n32 calling convention.
+
+ * n32.S: Fixed fn pointer bug.
+
+ * ffi.c (ffi_prep_cif_machdep): Fix for o32 structure
+ return values.
+ (ffi_prep_args): Fixed n32 structure passing when structures
+ partially fit in registers.
+
+Wed Oct 9 13:49:25 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * objects.mak: Added n32.o.
+
+ * n32.S: Created.
+
+ * ffi.c (ffi_prep_args): Added magic to support proper
+ n32 processing.
+
+Tue Oct 8 10:37:35 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.c: Moved ffi_type definitions to types.c.
+ (ffi_prep_args): Fixed type promotion bug.
+
+ * o32.S: This code is only built for o32 compiles.
+ A lot of the #define cruft has moved to ffi_mips.h.
+
+ * ffi.c (ffi_prep_cif_machdep): Fixed arg flags. Second arg
+ is only processed if the first is either a float or double.
+
+Mon Oct 7 15:33:59 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * o32.S: Modified to compile under each of o32, n32 and n64.
+
+ * ffi.c (FFI_*_TYPEDEF): Removed redundant ';'
+
+Fri Oct 4 09:53:25 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.c (ffi_call): Removed FFI_ABI arg, and swapped
+ remaining args.
+
+Wed Oct 2 17:41:22 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * o32.S: Removed crufty definitions.
+
+Wed Oct 2 12:53:42 1996 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.c (ffi_prep_cif): cif->rvalue no longer initialized to NULL.
+ (ffi_prep_cif_machdep): Moved all machine independent cif processing
+ to src/prep_cif.c. Introduced ffi_prep_cif_machdep. Return types
+ of FFI_TYPE_STRUCT are no different than FFI_TYPE_INT.
+
+Tue Oct 1 17:11:02 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.c, o32.S, object.mak: Created
+
+--- libffi/src/sparc ------------------------------------------------------
+
+Tue Feb 24 16:33:18 1998 Anthony Green <green@hoser.cygnus.com>
+
+ * ffi.c (ffi_prep_args): Added long double support.
+
+Thu May 8 16:53:58 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * objects.mak: Removed.
+
+Thu May 1 16:07:56 1997 Anthony Green <green@hoser.cygnus.com>
+
+ * v8.S: Fixed minor portability problem reported by
+ Russ McManus <mcmanr@eq.gs.com>.
+
+Tue Nov 26 14:12:43 1996 Anthony Green <green@csk3.cygnus.com>
+
+ * v8.S: Used STACKFRAME define elsewhere.
+
+ * ffi.c (ffi_prep_args): Zero out space when USING_PURIFY
+ is set.
+ (ffi_prep_cif_machdep): Allocate the correct stack frame
+ space for functions with < 6 args.
+
+Tue Oct 29 15:08:55 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.c (ffi_prep_args): int z is now size_t z.
+
+Mon Oct 14 13:31:24 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * v8.S (ffi_call_V8): Gordon rewrites this again. It looks
+ great now.
+
+ * ffi.c (ffi_call): The comment about hijacked registers
+ is no longer valid after gordoni hacked v8.S.
+
+ * v8.S (ffi_call_V8): Rewrote with gordoni. Much simpler.
+
+ * v8.S, ffi.c: ffi_call() had changed to accept more than
+ two args, so v8.S had to change (because it hijacks incoming
+ arg registers).
+
+ * ffi.c: Interface changes based on feedback from Jim Blandy.
+
+Thu Oct 10 17:48:16 1996 Anthony Green <green@rtl.cygnus.com>
+
+ * ffi.c, v8.S, objects.mak: Created.
+
+
diff --git a/LICENSE b/LICENSE
index a66fab4f..acb2f7a0 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-libffi - Copyright (c) 1996-2014 Anthony Green, Red Hat, Inc and others.
+libffi - Copyright (c) 1996-2019 Anthony Green, Red Hat, Inc and others.
See source files for details.
Permission is hereby granted, free of charge, to any person obtaining
diff --git a/LICENSE-BUILDTOOLS b/LICENSE-BUILDTOOLS
new file mode 100644
index 00000000..d1d626e0
--- /dev/null
+++ b/LICENSE-BUILDTOOLS
@@ -0,0 +1,353 @@
+The libffi source distribution contains certain code that is not part
+of libffi, and is only used as tooling to assist with the building and
+testing of libffi. This includes the msvcc.sh script used to wrap the
+Microsoft compiler with GNU compatible command-line options,
+make_sunver.pl, and the libffi test code distributed in the
+testsuite/libffi.bhaible directory. This code is distributed with
+libffi for the purpose of convenience only, and libffi is in no way
+derived from this code.
+
+msvcc.sh an testsuite/libffi.bhaible are both distributed under the
+terms of the GNU GPL version 2, as below.
+
+
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/METADATA b/METADATA
new file mode 100644
index 00000000..cfd64f99
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+name: "libffi"
+description: "A portable foreign-function interface library."
+third_party {
+ url {
+ type: GIT
+ value: "https://github.com/libffi/libffi.git"
+ }
+ version: "v3.3"
+ # would be NOTICE save for:
+ # .travis/
+ # testsuite/lib*/
+ # libtool-ldflags
+ # LICENSE-BUILDTOOLS
+ license_type: RESTRICTED
+ last_upgrade_date {
+ year: 2020
+ month: 3
+ day: 26
+ }
+}
diff --git a/Makefile.am b/Makefile.am
index 0e404510..4fd6193d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,239 +5,112 @@ AUTOMAKE_OPTIONS = foreign subdir-objects
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = include testsuite man
+if BUILD_DOCS
+## This hack is needed because it doesn't seem possible to make a
+## conditional info_TEXINFOS in Automake. At least Automake 1.14
+## either gives errors -- if this attempted in the most
+## straightforward way -- or simply unconditionally tries to build the
+## info file.
+SUBDIRS += doc
+endif
-EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \
- src/aarch64/ffi.c src/aarch64/ffitarget.h src/aarch64/sysv.S \
- src/alpha/ffi.c src/alpha/osf.S \
- src/alpha/ffitarget.h src/arc/ffi.c src/arc/arcompact.S \
- src/arc/ffitarget.h src/arm/ffi.c src/arm/sysv.S \
- src/arm/ffitarget.h src/avr32/ffi.c src/avr32/sysv.S \
- src/avr32/ffitarget.h src/cris/ffi.c src/cris/sysv.S \
- src/cris/ffitarget.h src/ia64/ffi.c src/ia64/ffitarget.h \
- src/ia64/ia64_flags.h src/ia64/unix.S src/mips/ffi.c \
- src/mips/n32.S src/mips/o32.S src/metag/ffi.c \
- src/metag/ffitarget.h src/metag/sysv.S src/moxie/ffi.c \
- src/moxie/ffitarget.h src/moxie/eabi.S src/mips/ffitarget.h \
- src/m32r/ffi.c src/m32r/sysv.S src/m32r/ffitarget.h \
- src/m68k/ffi.c src/m68k/sysv.S src/m68k/ffitarget.h \
- src/m88k/ffi.c src/m88k/obsd.S src/m88k/ffitarget.h \
- src/microblaze/ffi.c src/microblaze/sysv.S \
- src/microblaze/ffitarget.h \
- src/nios2/ffi.c src/nios2/ffitarget.h src/nios2/sysv.S \
- src/or1k/ffi.c src/or1k/ffitarget.h src/or1k/sysv.S \
- src/powerpc/ffi.c src/powerpc/ffi_powerpc.h \
- src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c \
- src/powerpc/sysv.S src/powerpc/linux64.S \
- src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S \
- src/powerpc/asm.h src/powerpc/aix.S src/powerpc/darwin.S \
- src/powerpc/aix_closure.S src/powerpc/darwin_closure.S \
- src/powerpc/ffi_darwin.c src/powerpc/ffitarget.h \
- src/s390/ffi.c src/s390/sysv.S src/s390/ffitarget.h \
- src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h src/sh64/ffi.c \
- src/sh64/sysv.S src/sh64/ffitarget.h src/sparc/v8.S \
- src/sparc/v9.S src/sparc/ffitarget.h src/sparc/ffi.c \
- src/x86/darwin64.S src/x86/ffi.c src/x86/sysv.S \
- src/x86/win32.S src/x86/darwin.S src/x86/win64.S \
- src/x86/freebsd.S src/x86/ffi64.c src/x86/unix64.S \
- src/x86/ffitarget.h src/pa/ffitarget.h src/pa/ffi.c \
- src/pa/linux.S src/pa/hpux32.S src/frv/ffi.c src/bfin/ffi.c \
- src/bfin/ffitarget.h src/bfin/sysv.S src/frv/eabi.S \
- src/frv/ffitarget.h src/dlmalloc.c src/tile/ffi.c \
- src/tile/ffitarget.h src/tile/tile.S libtool-version \
- src/vax/ffi.c src/vax/ffitarget.h src/vax/elfbsd.S \
- src/xtensa/ffitarget.h src/xtensa/ffi.c src/xtensa/sysv.S \
- ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4 \
+EXTRA_DIST = LICENSE ChangeLog.old \
+ m4/libtool.m4 m4/lt~obsolete.m4 \
m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \
- m4/ltversion.m4 src/arm/gentramp.sh src/debug.c msvcc.sh \
- generate-darwin-source-and-headers.py \
- libffi.xcodeproj/project.pbxproj src/arm/trampoline.S \
- libtool-ldflags ChangeLog.libffi-3.1
-
-info_TEXINFOS = doc/libffi.texi
-
-## ################################################################
-
-##
-## This section is for make and multilib madness.
-##
+ m4/ltversion.m4 src/debug.c msvcc.sh \
+ generate-darwin-source-and-headers.py \
+ libffi.xcodeproj/project.pbxproj \
+ libtool-ldflags libtool-version configure.host README.md \
+ libffi.map.in LICENSE-BUILDTOOLS msvc_build make_sunver.pl
-# Work around what appears to be a GNU make bug handling MAKEFLAGS
-# values defined in terms of make variables, as is the case for CC and
-# friends when we are called from the top level Makefile.
-AM_MAKEFLAGS = \
- 'AR_FLAGS=$(AR_FLAGS)' \
- 'CC_FOR_BUILD=$(CC_FOR_BUILD)' \
- 'CFLAGS=$(CFLAGS)' \
- 'CXXFLAGS=$(CXXFLAGS)' \
- 'CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)' \
- 'CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)' \
- 'INSTALL=$(INSTALL)' \
- 'INSTALL_DATA=$(INSTALL_DATA)' \
- 'INSTALL_PROGRAM=$(INSTALL_PROGRAM)' \
- 'INSTALL_SCRIPT=$(INSTALL_SCRIPT)' \
- 'JC1FLAGS=$(JC1FLAGS)' \
- 'LDFLAGS=$(LDFLAGS)' \
- 'LIBCFLAGS=$(LIBCFLAGS)' \
- 'LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)' \
- 'MAKE=$(MAKE)' \
- 'MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)' \
- 'PICFLAG=$(PICFLAG)' \
- 'PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)' \
- 'RUNTESTFLAGS=$(RUNTESTFLAGS)' \
- 'SHELL=$(SHELL)' \
- 'exec_prefix=$(exec_prefix)' \
- 'infodir=$(infodir)' \
- 'libdir=$(libdir)' \
- 'mandir=$(mandir)' \
- 'prefix=$(prefix)' \
- 'AR=$(AR)' \
- 'AS=$(AS)' \
- 'CC=$(CC)' \
- 'CXX=$(CXX)' \
- 'LD=$(LD)' \
- 'NM=$(NM)' \
- 'RANLIB=$(RANLIB)' \
- 'DESTDIR=$(DESTDIR)'
+# local.exp is generated by configure
+DISTCLEANFILES = local.exp
# Subdir rules rely on $(FLAGS_TO_PASS)
FLAGS_TO_PASS = $(AM_MAKEFLAGS)
MAKEOVERRIDES=
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libffi.pc
+
toolexeclib_LTLIBRARIES = libffi.la
noinst_LTLIBRARIES = libffi_convenience.la
libffi_la_SOURCES = src/prep_cif.c src/types.c \
src/raw_api.c src/java_raw_api.c src/closures.c
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libffi.pc
-
-nodist_libffi_la_SOURCES =
-
if FFI_DEBUG
-nodist_libffi_la_SOURCES += src/debug.c
-endif
-
-if MIPS
-nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S
-endif
-if BFIN
-nodist_libffi_la_SOURCES += src/bfin/ffi.c src/bfin/sysv.S
-endif
-if X86
-nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S src/x86/win32.S
-endif
-if X86_FREEBSD
-nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/freebsd.S src/x86/win32.S
-endif
-if X86_WIN32
-nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/win32.S
-endif
-if X86_WIN64
-nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/win64.S
-endif
-if X86_DARWIN
-nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S
-if X86_DARWIN32
-nodist_libffi_la_SOURCES += src/x86/win32.S
-endif
-endif
-if SPARC
-nodist_libffi_la_SOURCES += src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S
-endif
-if ALPHA
-nodist_libffi_la_SOURCES += src/alpha/ffi.c src/alpha/osf.S
-endif
-if IA64
-nodist_libffi_la_SOURCES += src/ia64/ffi.c src/ia64/unix.S
-endif
-if M32R
-nodist_libffi_la_SOURCES += src/m32r/sysv.S src/m32r/ffi.c
-endif
-if M68K
-nodist_libffi_la_SOURCES += src/m68k/ffi.c src/m68k/sysv.S
-endif
-if M88K
-nodist_libffi_la_SOURCES += src/m88k/ffi.c src/m88k/obsd.S
-endif
-if MOXIE
-nodist_libffi_la_SOURCES += src/moxie/ffi.c src/moxie/eabi.S
-endif
-if MICROBLAZE
-nodist_libffi_la_SOURCES += src/microblaze/ffi.c src/microblaze/sysv.S
-endif
-if NIOS2
-nodist_libffi_la_SOURCES += src/nios2/sysv.S src/nios2/ffi.c
-endif
-if OR1K
-nodist_libffi_la_SOURCES += src/or1k/sysv.S src/or1k/ffi.c
-endif
-if POWERPC
-nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
-endif
-if POWERPC_AIX
-nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S
-endif
-if POWERPC_DARWIN
-nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
-endif
-if POWERPC_FREEBSD
-nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/sysv.S src/powerpc/ppc_closure.S
-endif
-if AARCH64
-nodist_libffi_la_SOURCES += src/aarch64/sysv.S src/aarch64/ffi.c
-endif
-if ARC
-nodist_libffi_la_SOURCES += src/arc/arcompact.S src/arc/ffi.c
-endif
-if ARM
-nodist_libffi_la_SOURCES += src/arm/sysv.S src/arm/ffi.c
-if FFI_EXEC_TRAMPOLINE_TABLE
-nodist_libffi_la_SOURCES += src/arm/trampoline.S
-endif
-endif
-if AVR32
-nodist_libffi_la_SOURCES += src/avr32/sysv.S src/avr32/ffi.c
-endif
-if LIBFFI_CRIS
-nodist_libffi_la_SOURCES += src/cris/sysv.S src/cris/ffi.c
-endif
-if FRV
-nodist_libffi_la_SOURCES += src/frv/eabi.S src/frv/ffi.c
-endif
-if S390
-nodist_libffi_la_SOURCES += src/s390/sysv.S src/s390/ffi.c
-endif
-if X86_64
-nodist_libffi_la_SOURCES += src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S
-endif
-if SH
-nodist_libffi_la_SOURCES += src/sh/sysv.S src/sh/ffi.c
-endif
-if SH64
-nodist_libffi_la_SOURCES += src/sh64/sysv.S src/sh64/ffi.c
-endif
-if PA_LINUX
-nodist_libffi_la_SOURCES += src/pa/linux.S src/pa/ffi.c
-endif
-if PA_HPUX
-nodist_libffi_la_SOURCES += src/pa/hpux32.S src/pa/ffi.c
-endif
-if TILE
-nodist_libffi_la_SOURCES += src/tile/tile.S src/tile/ffi.c
-endif
-if XTENSA
-nodist_libffi_la_SOURCES += src/xtensa/sysv.S src/xtensa/ffi.c
-endif
-if METAG
-nodist_libffi_la_SOURCES += src/metag/sysv.S src/metag/ffi.c
-endif
-if VAX
-nodist_libffi_la_SOURCES += src/vax/elfbsd.S src/vax/ffi.c
-endif
+libffi_la_SOURCES += src/debug.c
+endif
+
+noinst_HEADERS = \
+ src/aarch64/ffitarget.h src/aarch64/internal.h \
+ src/alpha/ffitarget.h src/alpha/internal.h \
+ src/arc/ffitarget.h \
+ src/arm/ffitarget.h src/arm/internal.h \
+ src/avr32/ffitarget.h \
+ src/bfin/ffitarget.h \
+ src/cris/ffitarget.h \
+ src/frv/ffitarget.h \
+ src/ia64/ffitarget.h src/ia64/ia64_flags.h \
+ src/m32r/ffitarget.h \
+ src/m68k/ffitarget.h \
+ src/m88k/ffitarget.h \
+ src/metag/ffitarget.h \
+ src/microblaze/ffitarget.h \
+ src/mips/ffitarget.h \
+ src/moxie/ffitarget.h \
+ src/nios2/ffitarget.h \
+ src/or1k/ffitarget.h \
+ src/pa/ffitarget.h \
+ src/powerpc/ffitarget.h src/powerpc/asm.h src/powerpc/ffi_powerpc.h \
+ src/riscv/ffitarget.h \
+ src/s390/ffitarget.h src/s390/internal.h \
+ src/sh/ffitarget.h \
+ src/sh64/ffitarget.h \
+ src/sparc/ffitarget.h src/sparc/internal.h \
+ src/tile/ffitarget.h \
+ src/vax/ffitarget.h \
+ src/x86/ffitarget.h src/x86/internal.h src/x86/internal64.h src/x86/asmnames.h \
+ src/xtensa/ffitarget.h \
+ src/dlmalloc.c
+
+EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S \
+ src/aarch64/win64_armasm.S src/alpha/ffi.c src/alpha/osf.S \
+ src/arc/ffi.c src/arc/arcompact.S src/arm/ffi.c \
+ src/arm/sysv.S src/arm/ffi.c src/arm/sysv_msvc_arm32.S \
+ src/avr32/ffi.c src/avr32/sysv.S src/bfin/ffi.c \
+ src/bfin/sysv.S src/cris/ffi.c src/cris/sysv.S src/frv/ffi.c \
+ src/frv/eabi.S src/ia64/ffi.c src/ia64/unix.S src/m32r/ffi.c \
+ src/m32r/sysv.S src/m68k/ffi.c src/m68k/sysv.S src/m88k/ffi.c \
+ src/m88k/obsd.S src/metag/ffi.c src/metag/sysv.S \
+ src/microblaze/ffi.c src/microblaze/sysv.S src/mips/ffi.c \
+ src/mips/o32.S src/mips/n32.S src/moxie/ffi.c \
+ src/moxie/eabi.S src/nios2/ffi.c src/nios2/sysv.S \
+ src/or1k/ffi.c src/or1k/sysv.S src/pa/ffi.c src/pa/linux.S \
+ src/pa/hpux32.S src/powerpc/ffi.c src/powerpc/ffi_sysv.c \
+ src/powerpc/ffi_linux64.c src/powerpc/sysv.S \
+ src/powerpc/linux64.S src/powerpc/linux64_closure.S \
+ src/powerpc/ppc_closure.S src/powerpc/aix.S \
+ src/powerpc/darwin.S src/powerpc/aix_closure.S \
+ src/powerpc/darwin_closure.S src/powerpc/ffi_darwin.c \
+ src/riscv/ffi.c src/riscv/sysv.S src/s390/ffi.c \
+ src/s390/sysv.S src/sh/ffi.c src/sh/sysv.S src/sh64/ffi.c \
+ src/sh64/sysv.S src/sparc/ffi.c src/sparc/ffi64.c \
+ src/sparc/v8.S src/sparc/v9.S src/tile/ffi.c src/tile/tile.S \
+ src/vax/ffi.c src/vax/elfbsd.S src/x86/ffi.c src/x86/sysv.S \
+ src/x86/ffiw64.c src/x86/win64.S src/x86/ffi64.c \
+ src/x86/unix64.S src/x86/sysv_intel.S src/x86/win64_intel.S \
+ src/xtensa/ffi.c src/xtensa/sysv.S
+
+TARGET_OBJ = @TARGET_OBJ@
+libffi_la_LIBADD = $(TARGET_OBJ)
libffi_convenience_la_SOURCES = $(libffi_la_SOURCES)
+EXTRA_libffi_convenience_la_SOURCES = $(EXTRA_libffi_la_SOURCES)
+libffi_convenience_la_LIBADD = $(libffi_la_LIBADD)
+libffi_convenience_la_DEPENDENCIES = $(libffi_la_DEPENDENCIES)
nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES)
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/libtool-ldflags $(LDFLAGS))
@@ -249,10 +122,38 @@ if FFI_DEBUG
AM_CFLAGS += -DFFI_DEBUG
endif
-libffi_la_LDFLAGS = -no-undefined -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LTLDFLAGS) $(AM_LTLDFLAGS)
+if LIBFFI_BUILD_VERSIONED_SHLIB
+if LIBFFI_BUILD_VERSIONED_SHLIB_GNU
+libffi_version_script = -Wl,--version-script,libffi.map
+libffi_version_dep = libffi.map
+endif
+if LIBFFI_BUILD_VERSIONED_SHLIB_SUN
+libffi_version_script = -Wl,-M,libffi.map-sun
+libffi_version_dep = libffi.map-sun
+libffi.map-sun : libffi.map $(top_srcdir)/make_sunver.pl \
+ $(libffi_la_OBJECTS) $(libffi_la_LIBADD)
+ perl $(top_srcdir)/make_sunver.pl libffi.map \
+ `echo $(libffi_la_OBJECTS) $(libffi_la_LIBADD) | \
+ sed 's,\([^/ ]*\)\.l\([ao]\),.libs/\1.\2,g'` \
+ > $@ || (rm -f $@ ; exit 1)
+endif
+else
+libffi_version_script =
+libffi_version_dep =
+endif
+libffi_version_info = -version-info `grep -v '^\#' $(srcdir)/libtool-version`
+
+libffi.map: $(top_srcdir)/libffi.map.in
+ $(COMPILE) -D$(TARGET) -E -x assembler-with-cpp -o $@ $<
+
+libffi_la_LDFLAGS = -no-undefined $(libffi_version_info) $(libffi_version_script) $(LTLDFLAGS) $(AM_LTLDFLAGS)
+libffi_la_DEPENDENCIES = $(libffi_la_LIBADD) $(libffi_version_dep)
AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src
AM_CCASFLAGS = $(AM_CPPFLAGS)
dist-hook:
+ d=`(cd $(distdir); pwd)`; (cd doc; make pdf; cp *.pdf $$d/doc)
if [ -d $(top_srcdir)/.git ] ; then (cd $(top_srcdir); git log --no-decorate) ; else echo 'See git log for history.' ; fi > $(distdir)/ChangeLog
+ s=`awk '/was released on/{ print NR; exit}' $(top_srcdir)/README.md`; tail -n +$$(($$s-1)) $(top_srcdir)/README.md > $(distdir)/README.md
+
diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index a66fab4f..00000000
--- a/NOTICE
+++ /dev/null
@@ -1,21 +0,0 @@
-libffi - Copyright (c) 1996-2014 Anthony Green, Red Hat, Inc and others.
-See source files for details.
-
-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 AUTHORS OR COPYRIGHT HOLDERS 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.
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..3d6ce443
--- /dev/null
+++ b/README.md
@@ -0,0 +1,477 @@
+Status
+======
+
+[![Build Status](https://travis-ci.org/libffi/libffi.svg?branch=master)](https://travis-ci.org/libffi/libffi)
+[![Build status](https://ci.appveyor.com/api/projects/status/8lko9vagbx4w2kxq?svg=true)](https://ci.appveyor.com/project/atgreen/libffi)
+
+libffi-3.3 was released on November 23, 2019. Check the libffi web
+page for updates: <URL:http://sourceware.org/libffi/>.
+
+
+What is libffi?
+===============
+
+Compilers for high level languages generate code that follow certain
+conventions. These conventions are necessary, in part, for separate
+compilation to work. One such convention is the "calling
+convention". The "calling convention" is essentially a set of
+assumptions made by the compiler about where function arguments will
+be found on entry to a function. A "calling convention" also specifies
+where the return value for a function is found.
+
+Some programs may not know at the time of compilation what arguments
+are to be passed to a function. For instance, an interpreter may be
+told at run-time about the number and types of arguments used to call
+a given function. Libffi can be used in such programs to provide a
+bridge from the interpreter program to compiled code.
+
+The libffi library provides a portable, high level programming
+interface to various calling conventions. This allows a programmer to
+call any function specified by a call interface description at run
+time.
+
+FFI stands for Foreign Function Interface. A foreign function
+interface is the popular name for the interface that allows code
+written in one language to call code written in another language. The
+libffi library really only provides the lowest, machine dependent
+layer of a fully featured foreign function interface. A layer must
+exist above libffi that handles type conversions for values passed
+between the two languages.
+
+
+Supported Platforms
+===================
+
+Libffi has been ported to many different platforms.
+
+At the time of release, the following basic configurations have been
+tested:
+
+| Architecture | Operating System | Compiler |
+| --------------- | ---------------- | ----------------------- |
+| AArch64 (ARM64) | iOS | Clang |
+| AArch64 | Linux | GCC |
+| AArch64 | Windows | MSVC |
+| Alpha | Linux | GCC |
+| Alpha | Tru64 | GCC |
+| ARC | Linux | GCC |
+| ARM | Linux | GCC |
+| ARM | iOS | GCC |
+| ARM | Windows | MSVC |
+| AVR32 | Linux | GCC |
+| Blackfin | uClinux | GCC |
+| HPPA | HPUX | GCC |
+| IA-64 | Linux | GCC |
+| M68K | FreeMiNT | GCC |
+| M68K | Linux | GCC |
+| M68K | RTEMS | GCC |
+| M88K | OpenBSD/mvme88k | GCC |
+| Meta | Linux | GCC |
+| MicroBlaze | Linux | GCC |
+| MIPS | IRIX | GCC |
+| MIPS | Linux | GCC |
+| MIPS | RTEMS | GCC |
+| MIPS64 | Linux | GCC |
+| Moxie | Bare metal | GCC |
+| Nios II | Linux | GCC |
+| OpenRISC | Linux | GCC |
+| PowerPC 32-bit | AIX | IBM XL C |
+| PowerPC 64-bit | AIX | IBM XL C |
+| PowerPC | AMIGA | GCC |
+| PowerPC | Linux | GCC |
+| PowerPC | Mac OSX | GCC |
+| PowerPC | FreeBSD | GCC |
+| PowerPC 64-bit | FreeBSD | GCC |
+| PowerPC 64-bit | Linux ELFv1 | GCC |
+| PowerPC 64-bit | Linux ELFv2 | GCC |
+| RISC-V 32-bit | Linux | GCC |
+| RISC-V 64-bit | Linux | GCC |
+| S390 | Linux | GCC |
+| S390X | Linux | GCC |
+| SPARC | Linux | GCC |
+| SPARC | Solaris | GCC |
+| SPARC | Solaris | Oracle Solaris Studio C |
+| SPARC64 | Linux | GCC |
+| SPARC64 | FreeBSD | GCC |
+| SPARC64 | Solaris | Oracle Solaris Studio C |
+| TILE-Gx/TILEPro | Linux | GCC |
+| VAX | OpenBSD/vax | GCC |
+| X86 | FreeBSD | GCC |
+| X86 | GNU HURD | GCC |
+| X86 | Interix | GCC |
+| X86 | kFreeBSD | GCC |
+| X86 | Linux | GCC |
+| X86 | Mac OSX | GCC |
+| X86 | OpenBSD | GCC |
+| X86 | OS/2 | GCC |
+| X86 | Solaris | GCC |
+| X86 | Solaris | Oracle Solaris Studio C |
+| X86 | Windows/Cygwin | GCC |
+| X86 | Windows/MingW | GCC |
+| X86-64 | FreeBSD | GCC |
+| X86-64 | Linux | GCC |
+| X86-64 | Linux/x32 | GCC |
+| X86-64 | OpenBSD | GCC |
+| X86-64 | Solaris | Oracle Solaris Studio C |
+| X86-64 | Windows/Cygwin | GCC |
+| X86-64 | Windows/MingW | GCC |
+| X86-64 | Mac OSX | GCC |
+| Xtensa | Linux | GCC |
+
+Please send additional platform test results to
+libffi-discuss@sourceware.org.
+
+Installing libffi
+=================
+
+First you must configure the distribution for your particular
+system. Go to the directory you wish to build libffi in and run the
+"configure" program found in the root directory of the libffi source
+distribution. Note that building libffi requires a C99 compatible
+compiler.
+
+If you're building libffi directly from git hosted sources, configure
+won't exist yet; run ./autogen.sh first. This will require that you
+install autoconf, automake and libtool.
+
+You may want to tell configure where to install the libffi library and
+header files. To do that, use the ``--prefix`` configure switch. Libffi
+will install under /usr/local by default.
+
+If you want to enable extra run-time debugging checks use the the
+``--enable-debug`` configure switch. This is useful when your program dies
+mysteriously while using libffi.
+
+Another useful configure switch is ``--enable-purify-safety``. Using this
+will add some extra code which will suppress certain warnings when you
+are using Purify with libffi. Only use this switch when using
+Purify, as it will slow down the library.
+
+If you don't want to build documentation, use the ``--disable-docs``
+configure switch.
+
+It's also possible to build libffi on Windows platforms with
+Microsoft's Visual C++ compiler. In this case, use the msvcc.sh
+wrapper script during configuration like so:
+
+ path/to/configure CC=path/to/msvcc.sh CXX=path/to/msvcc.sh LD=link CPP="cl -nologo -EP" CPPFLAGS="-DFFI_BUILDING_DLL"
+
+For 64-bit Windows builds, use ``CC="path/to/msvcc.sh -m64"`` and
+``CXX="path/to/msvcc.sh -m64"``. You may also need to specify
+``--build`` appropriately.
+
+It is also possible to build libffi on Windows platforms with the LLVM
+project's clang-cl compiler, like below:
+
+ path/to/configure CC="path/to/msvcc.sh -clang-cl" CXX="path/to/msvcc.sh -clang-cl" LD=link CPP="clang-cl -EP"
+
+When building with MSVC under a MingW environment, you may need to
+remove the line in configure that sets 'fix_srcfile_path' to a 'cygpath'
+command. ('cygpath' is not present in MingW, and is not required when
+using MingW-style paths.)
+
+To build static library for ARM64 with MSVC using visual studio solution, msvc_build folder have
+ aarch64/Ffi_staticLib.sln
+ required header files in aarch64/aarch64_include/
+
+
+SPARC Solaris builds require the use of the GNU assembler and linker.
+Point ``AS`` and ``LD`` environment variables at those tool prior to
+configuration.
+
+For iOS builds, the ``libffi.xcodeproj`` Xcode project is available.
+
+Configure has many other options. Use ``configure --help`` to see them all.
+
+Once configure has finished, type "make". Note that you must be using
+GNU make. You can ftp GNU make from ftp.gnu.org:/pub/gnu/make .
+
+To ensure that libffi is working as advertised, type "make check".
+This will require that you have DejaGNU installed.
+
+To install the library and header files, type ``make install``.
+
+
+History
+=======
+
+See the git log for details at http://github.com/libffi/libffi.
+
+ 3.3 Nov-23-19
+ Add RISC-V support.
+ New API in support of GO closures.
+ Add IEEE754 binary128 long double support for 64-bit Power
+ Default to Microsoft's 64 bit long double ABI with Visual C++.
+ GNU compiler uses 80 bits (128 in memory) FFI_GNUW64 ABI.
+ Add Windows on ARM64 (WOA) support.
+ Add Windows 32-bit ARM support.
+ Raw java (gcj) API deprecated.
+ Add pre-built PDF documentation to source distribution.
+ Many new tests cases and bug fixes.
+
+ 3.2.1 Nov-12-14
+ Build fix for non-iOS AArch64 targets.
+
+ 3.2 Nov-11-14
+ Add C99 Complex Type support (currently only supported on
+ s390).
+ Add support for PASCAL and REGISTER calling conventions on x86
+ Windows/Linux.
+ Add OpenRISC and Cygwin-64 support.
+ Bug fixes.
+
+ 3.1 May-19-14
+ Add AArch64 (ARM64) iOS support.
+ Add Nios II support.
+ Add m88k and DEC VAX support.
+ Add support for stdcall, thiscall, and fastcall on non-Windows
+ 32-bit x86 targets such as Linux.
+ Various Android, MIPS N32, x86, FreeBSD and UltraSPARC IIi
+ fixes.
+ Make the testsuite more robust: eliminate several spurious
+ failures, and respect the $CC and $CXX environment variables.
+ Archive off the manually maintained ChangeLog in favor of git
+ log.
+
+ 3.0.13 Mar-17-13
+ Add Meta support.
+ Add missing Moxie bits.
+ Fix stack alignment bug on 32-bit x86.
+ Build fix for m68000 targets.
+ Build fix for soft-float Power targets.
+ Fix the install dir location for some platforms when building
+ with GCC (OS X, Solaris).
+ Fix Cygwin regression.
+
+ 3.0.12 Feb-11-13
+ Add Moxie support.
+ Add AArch64 support.
+ Add Blackfin support.
+ Add TILE-Gx/TILEPro support.
+ Add MicroBlaze support.
+ Add Xtensa support.
+ Add support for PaX enabled kernels with MPROTECT.
+ Add support for native vendor compilers on
+ Solaris and AIX.
+ Work around LLVM/GCC interoperability issue on x86_64.
+
+ 3.0.11 Apr-11-12
+ Lots of build fixes.
+ Add support for variadic functions (ffi_prep_cif_var).
+ Add Linux/x32 support.
+ Add thiscall, fastcall and MSVC cdecl support on Windows.
+ Add Amiga and newer MacOS support.
+ Add m68k FreeMiNT support.
+ Integration with iOS' xcode build tools.
+ Fix Octeon and MC68881 support.
+ Fix code pessimizations.
+
+ 3.0.10 Aug-23-11
+ Add support for Apple's iOS.
+ Add support for ARM VFP ABI.
+ Add RTEMS support for MIPS and M68K.
+ Fix instruction cache clearing problems on
+ ARM and SPARC.
+ Fix the N64 build on mips-sgi-irix6.5.
+ Enable builds with Microsoft's compiler.
+ Enable x86 builds with Oracle's Solaris compiler.
+ Fix support for calling code compiled with Oracle's Sparc
+ Solaris compiler.
+ Testsuite fixes for Tru64 Unix.
+ Additional platform support.
+
+ 3.0.9 Dec-31-09
+ Add AVR32 and win64 ports. Add ARM softfp support.
+ Many fixes for AIX, Solaris, HP-UX, *BSD.
+ Several PowerPC and x86-64 bug fixes.
+ Build DLL for windows.
+
+ 3.0.8 Dec-19-08
+ Add *BSD, BeOS, and PA-Linux support.
+
+ 3.0.7 Nov-11-08
+ Fix for ppc FreeBSD.
+ (thanks to Andreas Tobler)
+
+ 3.0.6 Jul-17-08
+ Fix for closures on sh.
+ Mark the sh/sh64 stack as non-executable.
+ (both thanks to Kaz Kojima)
+
+ 3.0.5 Apr-3-08
+ Fix libffi.pc file.
+ Fix #define ARM for IcedTea users.
+ Fix x86 closure bug.
+
+ 3.0.4 Feb-24-08
+ Fix x86 OpenBSD configury.
+
+ 3.0.3 Feb-22-08
+ Enable x86 OpenBSD thanks to Thomas Heller, and
+ x86-64 FreeBSD thanks to Björn König and Andreas Tobler.
+ Clean up test instruction in README.
+
+ 3.0.2 Feb-21-08
+ Improved x86 FreeBSD support.
+ Thanks to Björn König.
+
+ 3.0.1 Feb-15-08
+ Fix instruction cache flushing bug on MIPS.
+ Thanks to David Daney.
+
+ 3.0.0 Feb-15-08
+ Many changes, mostly thanks to the GCC project.
+ Cygnus Solutions is now Red Hat.
+
+ [10 years go by...]
+
+ 1.20 Oct-5-98
+ Raffaele Sena produces ARM port.
+
+ 1.19 Oct-5-98
+ Fixed x86 long double and long long return support.
+ m68k bug fixes from Andreas Schwab.
+ Patch for DU assembler compatibility for the Alpha from Richard
+ Henderson.
+
+ 1.18 Apr-17-98
+ Bug fixes and MIPS configuration changes.
+
+ 1.17 Feb-24-98
+ Bug fixes and m68k port from Andreas Schwab. PowerPC port from
+ Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes.
+
+ 1.16 Feb-11-98
+ Richard Henderson produces Alpha port.
+
+ 1.15 Dec-4-97
+ Fixed an n32 ABI bug. New libtool, auto* support.
+
+ 1.14 May-13-97
+ libtool is now used to generate shared and static libraries.
+ Fixed a minor portability problem reported by Russ McManus
+ <mcmanr@eq.gs.com>.
+
+ 1.13 Dec-2-96
+ Added --enable-purify-safety to keep Purify from complaining
+ about certain low level code.
+ Sparc fix for calling functions with < 6 args.
+ Linux x86 a.out fix.
+
+ 1.12 Nov-22-96
+ Added missing ffi_type_void, needed for supporting void return
+ types. Fixed test case for non MIPS machines. Cygnus Support
+ is now Cygnus Solutions.
+
+ 1.11 Oct-30-96
+ Added notes about GNU make.
+
+ 1.10 Oct-29-96
+ Added configuration fix for non GNU compilers.
+
+ 1.09 Oct-29-96
+ Added --enable-debug configure switch. Clean-ups based on LCLint
+ feedback. ffi_mips.h is always installed. Many configuration
+ fixes. Fixed ffitest.c for sparc builds.
+
+ 1.08 Oct-15-96
+ Fixed n32 problem. Many clean-ups.
+
+ 1.07 Oct-14-96
+ Gordon Irlam rewrites v8.S again. Bug fixes.
+
+ 1.06 Oct-14-96
+ Gordon Irlam improved the sparc port.
+
+ 1.05 Oct-14-96
+ Interface changes based on feedback.
+
+ 1.04 Oct-11-96
+ Sparc port complete (modulo struct passing bug).
+
+ 1.03 Oct-10-96
+ Passing struct args, and returning struct values works for
+ all architectures/calling conventions. Expanded tests.
+
+ 1.02 Oct-9-96
+ Added SGI n32 support. Fixed bugs in both o32 and Linux support.
+ Added "make test".
+
+ 1.01 Oct-8-96
+ Fixed float passing bug in mips version. Restructured some
+ of the code. Builds cleanly with SGI tools.
+
+ 1.00 Oct-7-96
+ First release. No public announcement.
+
+Authors & Credits
+=================
+
+libffi was originally written by Anthony Green <green@moxielogic.com>.
+
+The developers of the GNU Compiler Collection project have made
+innumerable valuable contributions. See the ChangeLog file for
+details.
+
+Some of the ideas behind libffi were inspired by Gianni Mariani's free
+gencall library for Silicon Graphics machines.
+
+The closure mechanism was designed and implemented by Kresten Krab
+Thorup.
+
+Major processor architecture ports were contributed by the following
+developers:
+
+ aarch64 Marcus Shawcroft, James Greenhalgh
+ alpha Richard Henderson
+ arc Hackers at Synopsis
+ arm Raffaele Sena
+ avr32 Bradley Smith
+ blackfin Alexandre Keunecke I. de Mendonca
+ cris Simon Posnjak, Hans-Peter Nilsson
+ frv Anthony Green
+ ia64 Hans Boehm
+ m32r Kazuhiro Inaoka
+ m68k Andreas Schwab
+ m88k Miod Vallat
+ metag Hackers at Imagination Technologies
+ microblaze Nathan Rossi
+ mips Anthony Green, Casey Marshall
+ mips64 David Daney
+ moxie Anthony Green
+ nios ii Sandra Loosemore
+ openrisc Sebastian Macke
+ pa Randolph Chung, Dave Anglin, Andreas Tobler
+ powerpc Geoffrey Keating, Andreas Tobler,
+ David Edelsohn, John Hornkvist
+ powerpc64 Jakub Jelinek
+ riscv Michael Knyszek, Andrew Waterman, Stef O'Rear
+ s390 Gerhard Tonn, Ulrich Weigand
+ sh Kaz Kojima
+ sh64 Kaz Kojima
+ sparc Anthony Green, Gordon Irlam
+ tile-gx/tilepro Walter Lee
+ vax Miod Vallat
+ x86 Anthony Green, Jon Beniston
+ x86-64 Bo Thorsen
+ xtensa Chris Zankel
+
+Jesper Skov and Andrew Haley both did more than their fair share of
+stepping through the code and tracking down bugs.
+
+Thanks also to Tom Tromey for bug fixes, documentation and
+configuration help.
+
+Thanks to Jim Blandy, who provided some useful feedback on the libffi
+interface.
+
+Andreas Tobler has done a tremendous amount of work on the testsuite.
+
+Alex Oliva solved the executable page problem for SElinux.
+
+The list above is almost certainly incomplete and inaccurate. I'm
+happy to make corrections or additions upon request.
+
+If you have a problem, or have found a bug, please send a note to the
+author at green@moxielogic.com, or the project mailing list at
+libffi-discuss@sourceware.org.
diff --git a/acinclude.m4 b/acinclude.m4
index 3e8f8ba5..1a70efb0 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -90,3 +90,390 @@ if test $ac_cv_func_mmap_anon = yes; then
[Define if mmap with MAP_ANON(YMOUS) works.])
fi
])
+
+dnl ----------------------------------------------------------------------
+dnl This whole bit snagged from libstdc++-v3, via libatomic.
+
+dnl
+dnl LIBFFI_ENABLE
+dnl (FEATURE, DEFAULT, HELP-ARG, HELP-STRING)
+dnl (FEATURE, DEFAULT, HELP-ARG, HELP-STRING, permit a|b|c)
+dnl (FEATURE, DEFAULT, HELP-ARG, HELP-STRING, SHELL-CODE-HANDLER)
+dnl
+dnl See docs/html/17_intro/configury.html#enable for documentation.
+dnl
+m4_define([LIBFFI_ENABLE],[dnl
+m4_define([_g_switch],[--enable-$1])dnl
+m4_define([_g_help],[AC_HELP_STRING(_g_switch$3,[$4 @<:@default=$2@:>@])])dnl
+ AC_ARG_ENABLE($1,_g_help,
+ m4_bmatch([$5],
+ [^permit ],
+ [[
+ case "$enableval" in
+ m4_bpatsubst([$5],[permit ])) ;;
+ *) AC_MSG_ERROR(Unknown argument to enable/disable $1) ;;
+ dnl Idea for future: generate a URL pointing to
+ dnl "onlinedocs/configopts.html#whatever"
+ esac
+ ]],
+ [^$],
+ [[
+ case "$enableval" in
+ yes|no) ;;
+ *) AC_MSG_ERROR(Argument to enable/disable $1 must be yes or no) ;;
+ esac
+ ]],
+ [[$5]]),
+ [enable_]m4_bpatsubst([$1],-,_)[=][$2])
+m4_undefine([_g_switch])dnl
+m4_undefine([_g_help])dnl
+])
+
+dnl
+dnl If GNU ld is in use, check to see if tricky linker opts can be used. If
+dnl the native linker is in use, all variables will be defined to something
+dnl safe (like an empty string).
+dnl
+dnl Defines:
+dnl SECTION_LDFLAGS='-Wl,--gc-sections' if possible
+dnl OPT_LDFLAGS='-Wl,-O1' if possible
+dnl LD (as a side effect of testing)
+dnl Sets:
+dnl with_gnu_ld
+dnl libat_ld_is_gold (possibly)
+dnl libat_gnu_ld_version (possibly)
+dnl
+dnl The last will be a single integer, e.g., version 1.23.45.0.67.89 will
+dnl set libat_gnu_ld_version to 12345. Zeros cause problems.
+dnl
+AC_DEFUN([LIBFFI_CHECK_LINKER_FEATURES], [
+ # If we're not using GNU ld, then there's no point in even trying these
+ # tests. Check for that first. We should have already tested for gld
+ # by now (in libtool), but require it now just to be safe...
+ test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS=''
+ test -z "$OPT_LDFLAGS" && OPT_LDFLAGS=''
+ AC_REQUIRE([AC_PROG_LD])
+ AC_REQUIRE([AC_PROG_AWK])
+
+ # The name set by libtool depends on the version of libtool. Shame on us
+ # for depending on an impl detail, but c'est la vie. Older versions used
+ # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on
+ # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually
+ # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't
+ # set (hence we're using an older libtool), then set it.
+ if test x${with_gnu_ld+set} != xset; then
+ if test x${ac_cv_prog_gnu_ld+set} != xset; then
+ # We got through "ac_require(ac_prog_ld)" and still not set? Huh?
+ with_gnu_ld=no
+ else
+ with_gnu_ld=$ac_cv_prog_gnu_ld
+ fi
+ fi
+
+ # Start by getting the version number. I think the libtool test already
+ # does some of this, but throws away the result.
+ libat_ld_is_gold=no
+ if $LD --version 2>/dev/null | grep 'GNU gold'> /dev/null 2>&1; then
+ libat_ld_is_gold=yes
+ fi
+ changequote(,)
+ ldver=`$LD --version 2>/dev/null |
+ sed -e 's/GNU gold /GNU ld /;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'`
+ changequote([,])
+ libat_gnu_ld_version=`echo $ldver | \
+ $AWK -F. '{ if (NF<3) [$]3=0; print ([$]1*100+[$]2)*100+[$]3 }'`
+
+ # Set --gc-sections.
+ if test "$with_gnu_ld" = "notbroken"; then
+ # GNU ld it is! Joy and bunny rabbits!
+
+ # All these tests are for C++; save the language and the compiler flags.
+ # Need to do this so that g++ won't try to link in libstdc++
+ ac_test_CFLAGS="${CFLAGS+set}"
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS='-x c++ -Wl,--gc-sections'
+
+ # Check for -Wl,--gc-sections
+ # XXX This test is broken at the moment, as symbols required for linking
+ # are now in libsupc++ (not built yet). In addition, this test has
+ # cored on solaris in the past. In addition, --gc-sections doesn't
+ # really work at the moment (keeps on discarding used sections, first
+ # .eh_frame and now some of the glibc sections for iconv).
+ # Bzzzzt. Thanks for playing, maybe next time.
+ AC_MSG_CHECKING([for ld that supports -Wl,--gc-sections])
+ AC_TRY_RUN([
+ int main(void)
+ {
+ try { throw 1; }
+ catch (...) { };
+ return 0;
+ }
+ ], [ac_sectionLDflags=yes],[ac_sectionLDflags=no], [ac_sectionLDflags=yes])
+ if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+ else
+ # this is the suspicious part
+ CFLAGS=''
+ fi
+ if test "$ac_sectionLDflags" = "yes"; then
+ SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS"
+ fi
+ AC_MSG_RESULT($ac_sectionLDflags)
+ fi
+
+ # Set linker optimization flags.
+ if test x"$with_gnu_ld" = x"yes"; then
+ OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS"
+ fi
+
+ AC_SUBST(SECTION_LDFLAGS)
+ AC_SUBST(OPT_LDFLAGS)
+])
+
+
+dnl
+dnl If GNU ld is in use, check to see if tricky linker opts can be used. If
+dnl the native linker is in use, all variables will be defined to something
+dnl safe (like an empty string).
+dnl
+dnl Defines:
+dnl SECTION_LDFLAGS='-Wl,--gc-sections' if possible
+dnl OPT_LDFLAGS='-Wl,-O1' if possible
+dnl LD (as a side effect of testing)
+dnl Sets:
+dnl with_gnu_ld
+dnl libat_ld_is_gold (possibly)
+dnl libat_gnu_ld_version (possibly)
+dnl
+dnl The last will be a single integer, e.g., version 1.23.45.0.67.89 will
+dnl set libat_gnu_ld_version to 12345. Zeros cause problems.
+dnl
+AC_DEFUN([LIBFFI_CHECK_LINKER_FEATURES], [
+ # If we're not using GNU ld, then there's no point in even trying these
+ # tests. Check for that first. We should have already tested for gld
+ # by now (in libtool), but require it now just to be safe...
+ test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS=''
+ test -z "$OPT_LDFLAGS" && OPT_LDFLAGS=''
+ AC_REQUIRE([AC_PROG_LD])
+ AC_REQUIRE([AC_PROG_AWK])
+
+ # The name set by libtool depends on the version of libtool. Shame on us
+ # for depending on an impl detail, but c'est la vie. Older versions used
+ # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on
+ # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually
+ # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't
+ # set (hence we're using an older libtool), then set it.
+ if test x${with_gnu_ld+set} != xset; then
+ if test x${ac_cv_prog_gnu_ld+set} != xset; then
+ # We got through "ac_require(ac_prog_ld)" and still not set? Huh?
+ with_gnu_ld=no
+ else
+ with_gnu_ld=$ac_cv_prog_gnu_ld
+ fi
+ fi
+
+ # Start by getting the version number. I think the libtool test already
+ # does some of this, but throws away the result.
+ libat_ld_is_gold=no
+ if $LD --version 2>/dev/null | grep 'GNU gold'> /dev/null 2>&1; then
+ libat_ld_is_gold=yes
+ fi
+ libat_ld_is_lld=no
+ if $LD --version 2>/dev/null | grep 'LLD '> /dev/null 2>&1; then
+ libat_ld_is_lld=yes
+ fi
+ changequote(,)
+ ldver=`$LD --version 2>/dev/null |
+ sed -e 's/GNU gold /GNU ld /;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'`
+ changequote([,])
+ libat_gnu_ld_version=`echo $ldver | \
+ $AWK -F. '{ if (NF<3) [$]3=0; print ([$]1*100+[$]2)*100+[$]3 }'`
+
+ # Set --gc-sections.
+ if test "$with_gnu_ld" = "notbroken"; then
+ # GNU ld it is! Joy and bunny rabbits!
+
+ # All these tests are for C++; save the language and the compiler flags.
+ # Need to do this so that g++ won't try to link in libstdc++
+ ac_test_CFLAGS="${CFLAGS+set}"
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS='-x c++ -Wl,--gc-sections'
+
+ # Check for -Wl,--gc-sections
+ # XXX This test is broken at the moment, as symbols required for linking
+ # are now in libsupc++ (not built yet). In addition, this test has
+ # cored on solaris in the past. In addition, --gc-sections doesn't
+ # really work at the moment (keeps on discarding used sections, first
+ # .eh_frame and now some of the glibc sections for iconv).
+ # Bzzzzt. Thanks for playing, maybe next time.
+ AC_MSG_CHECKING([for ld that supports -Wl,--gc-sections])
+ AC_TRY_RUN([
+ int main(void)
+ {
+ try { throw 1; }
+ catch (...) { };
+ return 0;
+ }
+ ], [ac_sectionLDflags=yes],[ac_sectionLDflags=no], [ac_sectionLDflags=yes])
+ if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+ else
+ # this is the suspicious part
+ CFLAGS=''
+ fi
+ if test "$ac_sectionLDflags" = "yes"; then
+ SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS"
+ fi
+ AC_MSG_RESULT($ac_sectionLDflags)
+ fi
+
+ # Set linker optimization flags.
+ if test x"$with_gnu_ld" = x"yes"; then
+ OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS"
+ fi
+
+ AC_SUBST(SECTION_LDFLAGS)
+ AC_SUBST(OPT_LDFLAGS)
+])
+
+
+dnl
+dnl Add version tags to symbols in shared library (or not), additionally
+dnl marking other symbols as private/local (or not).
+dnl
+dnl --enable-symvers=style adds a version script to the linker call when
+dnl creating the shared library. The choice of version script is
+dnl controlled by 'style'.
+dnl --disable-symvers does not.
+dnl + Usage: LIBFFI_ENABLE_SYMVERS[(DEFAULT)]
+dnl Where DEFAULT is either 'yes' or 'no'. Passing `yes' tries to
+dnl choose a default style based on linker characteristics. Passing
+dnl 'no' disables versioning.
+dnl
+AC_DEFUN([LIBFFI_ENABLE_SYMVERS], [
+
+LIBFFI_ENABLE(symvers,yes,[=STYLE],
+ [enables symbol versioning of the shared library],
+ [permit yes|no|gnu*|sun])
+
+# If we never went through the LIBFFI_CHECK_LINKER_FEATURES macro, then we
+# don't know enough about $LD to do tricks...
+AC_REQUIRE([LIBFFI_CHECK_LINKER_FEATURES])
+
+# Turn a 'yes' into a suitable default.
+if test x$enable_symvers = xyes ; then
+ # FIXME The following test is too strict, in theory.
+ if test $enable_shared = no || test "x$LD" = x; then
+ enable_symvers=no
+ else
+ if test $with_gnu_ld = yes ; then
+ enable_symvers=gnu
+ else
+ case ${target_os} in
+ # Sun symbol versioning exists since Solaris 2.5.
+ solaris2.[[5-9]]* | solaris2.1[[0-9]]*)
+ enable_symvers=sun ;;
+ *)
+ enable_symvers=no ;;
+ esac
+ fi
+ fi
+fi
+
+# Check if 'sun' was requested on non-Solaris 2 platforms.
+if test x$enable_symvers = xsun ; then
+ case ${target_os} in
+ solaris2*)
+ # All fine.
+ ;;
+ *)
+ # Unlikely to work.
+ AC_MSG_WARN([=== You have requested Sun symbol versioning, but])
+ AC_MSG_WARN([=== you are not targetting Solaris 2.])
+ AC_MSG_WARN([=== Symbol versioning will be disabled.])
+ enable_symvers=no
+ ;;
+ esac
+fi
+
+# Check to see if libgcc_s exists, indicating that shared libgcc is possible.
+if test $enable_symvers != no; then
+ AC_MSG_CHECKING([for shared libgcc])
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS=' -lgcc_s'
+ AC_TRY_LINK(, [return 0;], libat_shared_libgcc=yes, libat_shared_libgcc=no)
+ CFLAGS="$ac_save_CFLAGS"
+ if test $libat_shared_libgcc = no; then
+ cat > conftest.c <<EOF
+int main (void) { return 0; }
+EOF
+changequote(,)dnl
+ libat_libgcc_s_suffix=`${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
+ -shared -shared-libgcc -o conftest.so \
+ conftest.c -v 2>&1 >/dev/null \
+ | sed -n 's/^.* -lgcc_s\([^ ]*\) .*$/\1/p'`
+changequote([,])dnl
+ rm -f conftest.c conftest.so
+ if test x${libat_libgcc_s_suffix+set} = xset; then
+ CFLAGS=" -lgcc_s$libat_libgcc_s_suffix"
+ AC_TRY_LINK(, [return 0;], libat_shared_libgcc=yes)
+ CFLAGS="$ac_save_CFLAGS"
+ fi
+ fi
+ AC_MSG_RESULT($libat_shared_libgcc)
+fi
+
+# For GNU ld, we need at least this version. The format is described in
+# LIBFFI_CHECK_LINKER_FEATURES above.
+libat_min_gnu_ld_version=21400
+# XXXXXXXXXXX libat_gnu_ld_version=21390
+
+# Check to see if unspecified "yes" value can win, given results above.
+# Change "yes" into either "no" or a style name.
+if test $enable_symvers != no && test $libat_shared_libgcc = yes; then
+ if test $with_gnu_ld = yes; then
+ if test $libat_gnu_ld_version -ge $libat_min_gnu_ld_version ; then
+ enable_symvers=gnu
+ elif test $libat_ld_is_gold = yes ; then
+ enable_symvers=gnu
+ elif test $libat_ld_is_lld = yes ; then
+ enable_symvers=gnu
+ else
+ # The right tools, the right setup, but too old. Fallbacks?
+ AC_MSG_WARN(=== Linker version $libat_gnu_ld_version is too old for)
+ AC_MSG_WARN(=== full symbol versioning support in this release of GCC.)
+ AC_MSG_WARN(=== You would need to upgrade your binutils to version)
+ AC_MSG_WARN(=== $libat_min_gnu_ld_version or later and rebuild GCC.)
+ if test $libat_gnu_ld_version -ge 21200 ; then
+ # Globbing fix is present, proper block support is not.
+ dnl AC_MSG_WARN([=== Dude, you are soooo close. Maybe we can fake it.])
+ dnl enable_symvers=???
+ AC_MSG_WARN([=== Symbol versioning will be disabled.])
+ enable_symvers=no
+ else
+ # 2.11 or older.
+ AC_MSG_WARN([=== Symbol versioning will be disabled.])
+ enable_symvers=no
+ fi
+ fi
+ elif test $enable_symvers = sun; then
+ : All interesting versions of Sun ld support sun style symbol versioning.
+ else
+ # just fail for now
+ AC_MSG_WARN([=== You have requested some kind of symbol versioning, but])
+ AC_MSG_WARN([=== either you are not using a supported linker, or you are])
+ AC_MSG_WARN([=== not building a shared libgcc_s (which is required).])
+ AC_MSG_WARN([=== Symbol versioning will be disabled.])
+ enable_symvers=no
+ fi
+fi
+if test $enable_symvers = gnu; then
+ AC_DEFINE(LIBFFI_GNU_SYMBOL_VERSIONING, 1,
+ [Define to 1 if GNU symbol versioning is used for libatomic.])
+fi
+
+AM_CONDITIONAL(LIBFFI_BUILD_VERSIONED_SHLIB, test $enable_symvers != no)
+AM_CONDITIONAL(LIBFFI_BUILD_VERSIONED_SHLIB_GNU, test $enable_symvers = gnu)
+AM_CONDITIONAL(LIBFFI_BUILD_VERSIONED_SHLIB_SUN, test $enable_symvers = sun)
+AC_MSG_NOTICE(versioning on shared library symbols is $enable_symvers)
+])
diff --git a/autogen.sh b/autogen.sh
index d270b984..fb014a33 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-exec autoreconf -v -f -i
+exec autoreconf -v -i
diff --git a/config.guess b/config.guess
new file mode 100644
index 00000000..faa63aa9
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1466 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2017 Free Software Foundation, Inc.
+
+timestamp='2017-05-11'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2017 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ LIBC=gnu
+
+ eval $set_cc_for_build
+ cat <<-EOF > $dummy.c
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #else
+ LIBC=gnu
+ #endif
+ EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ /sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || \
+ echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ earmv*)
+ arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine=${arch}${endian}-unknown
+ ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently (or will in the future) and ABI.
+ case "${UNAME_MACHINE_ARCH}" in
+ earm*)
+ os=netbsdelf
+ ;;
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # Determine ABI tags.
+ case "${UNAME_MACHINE_ARCH}" in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}${abi}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:LibertyBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:Sortix:*:*)
+ echo ${UNAME_MACHINE}-unknown-sortix
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE=alpha ;;
+ "EV5 (21164)")
+ UNAME_MACHINE=alphaev5 ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE=alphaev56 ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE=alphapca56 ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE=alphapca57 ;;
+ "EV6 (21264)")
+ UNAME_MACHINE=alphaev6 ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE=alphaev67 ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE=alphaev69 ;;
+ "EV7 (21364)")
+ UNAME_MACHINE=alphaev7 ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE=alphaev79 ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH=i386
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH=x86_64
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/lslpp ] ; then
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH=hppa2.0n ;;
+ 64) HP_ARCH=hppa2.0w ;;
+ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = hppa2.0w ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH=hppa2.0w
+ else
+ HP_ARCH=hppa64
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
+ amd64)
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
+ esac
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo ${UNAME_MACHINE}-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ *:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ cris:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ crisv32:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ e2k:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ frv:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:Linux:*:*)
+ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ k1om:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ ;;
+ mips64el:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ openrisc*:Linux:*:*)
+ echo or1k-unknown-linux-${LIBC}
+ exit ;;
+ or32:Linux:*:* | or1k*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-${LIBC}
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+ *) echo hppa-unknown-linux-${LIBC} ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-${LIBC}
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-${LIBC}
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-${LIBC}
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-${LIBC}
+ exit ;;
+ riscv32:Linux:*:* | riscv64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ exit ;;
+ x86_64:Linux:*:*)
+ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configure will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-ACE:SUPER-UX:*:*)
+ echo sxace-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ eval $set_cc_for_build
+ if test "$UNAME_PROCESSOR" = unknown ; then
+ UNAME_PROCESSOR=powerpc
+ fi
+ if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # Avoid executing cc on OS X 10.9, as it ships with a stub
+ # that puts up a graphical alert prompting to install
+ # developer tools. Any system running Mac OS X 10.7 or
+ # later (Darwin 11 and later) is required to have a 64-bit
+ # processor. This is not true of the ARM version of Darwin
+ # that Apple uses in portable devices.
+ UNAME_PROCESSOR=x86_64
+ fi
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = x86; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-*:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-*:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSX-*:NONSTOP_KERNEL:*:*)
+ echo nsx-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = 386; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
+ amd64:Isilon\ OneFS:*:*)
+ echo x86_64-unknown-onefs
+ exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite
+config.guess and config.sub with the latest versions from:
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.sub b/config.sub
new file mode 100644
index 00000000..40ea5dfe
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1836 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2017 Free Software Foundation, Inc.
+
+timestamp='2017-04-02'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2017 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+ kopensolaris*-gnu* | cloudabi*-eabi* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze*)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arceb \
+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+ | avr | avr32 \
+ | ba \
+ | be32 | be64 \
+ | bfin \
+ | c4x | c8051 | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | e2k | epiphany \
+ | fido | fr30 | frv | ft32 \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia16 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 | nios2eb | nios2el \
+ | ns16k | ns32k \
+ | open8 | or1k | or1knd | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pru \
+ | pyramid \
+ | riscv32 | riscv64 \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | visium \
+ | wasm32 \
+ | we32k \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ leon|leon[3-9])
+ basic_machine=sparc-$basic_machine
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | ba-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | c8051-* | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | e2k-* | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | k1om-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | microblaze-* | microblazeel-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa32r6-* | mipsisa32r6el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64r6-* | mipsisa64r6el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipsr5900-* | mipsr5900el-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | or1k*-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pru-* \
+ | pyramid-* \
+ | riscv32-* | riscv64-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | visium-* \
+ | wasm32-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ asmjs)
+ basic_machine=asmjs-unknown
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ e500v[12])
+ basic_machine=powerpc-unknown
+ os=$os"spe"
+ ;;
+ e500v[12]-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=$os"spe"
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ leon-*|leon[3-9]-*)
+ basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ os=-moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i686-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ nsx-tandem)
+ basic_machine=nsx-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=-rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ wasm32)
+ basic_machine=wasm32-unknown
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* | -plan9* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* | -cloudabi* | -sortix* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -ios)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ c8051-*)
+ os=-elf
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ pru-*)
+ os=-elf
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure.ac b/configure.ac
index a7bf5eef..b764368d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ dnl Process this with autoconf to create configure
AC_PREREQ(2.68)
-AC_INIT([libffi], [3.2.1], [http://github.com/atgreen/libffi/issues])
+AC_INIT([libffi], [3.3], [http://github.com/libffi/libffi/issues])
AC_CONFIG_HEADERS([fficonfig.h])
AC_CANONICAL_SYSTEM
@@ -72,271 +72,15 @@ AM_CONDITIONAL(TESTSUBDIR, test -d $srcdir/testsuite)
TARGETDIR="unknown"
HAVE_LONG_DOUBLE_VARIANT=0
-case "$host" in
- aarch64*-*-*)
- TARGET=AARCH64; TARGETDIR=aarch64
- ;;
-
- alpha*-*-*)
- TARGET=ALPHA; TARGETDIR=alpha;
- # Support 128-bit long double, changeable via command-line switch.
- HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)'
- ;;
-
- arc*-*-*)
- TARGET=ARC; TARGETDIR=arc
- ;;
-
- arm*-*-*)
- TARGET=ARM; TARGETDIR=arm
- ;;
-
- amd64-*-freebsd* | amd64-*-openbsd*)
- TARGET=X86_64; TARGETDIR=x86
- ;;
-
- amd64-*-freebsd*)
- TARGET=X86_64; TARGETDIR=x86
- ;;
-
- amd64-*-freebsd*)
- TARGET=X86_64; TARGETDIR=x86
- ;;
-
- avr32*-*-*)
- TARGET=AVR32; TARGETDIR=avr32
- ;;
-
- bfin*)
- TARGET=BFIN; TARGETDIR=bfin
- ;;
-
- cris-*-*)
- TARGET=LIBFFI_CRIS; TARGETDIR=cris
- ;;
-
- frv-*-*)
- TARGET=FRV; TARGETDIR=frv
- ;;
-
- hppa*-*-linux* | parisc*-*-linux* | hppa*-*-openbsd*)
- TARGET=PA_LINUX; TARGETDIR=pa
- ;;
- hppa*64-*-hpux*)
- TARGET=PA64_HPUX; TARGETDIR=pa
- ;;
- hppa*-*-hpux*)
- TARGET=PA_HPUX; TARGETDIR=pa
- ;;
-
- i?86-*-freebsd* | i?86-*-openbsd*)
- TARGET=X86_FREEBSD; TARGETDIR=x86
- ;;
- i?86-win32* | i?86-*-cygwin* | i?86-*-mingw* | i?86-*-os2* | i?86-*-interix*)
- TARGET=X86_WIN32; TARGETDIR=x86
- # All mingw/cygwin/win32 builds require -no-undefined for sharedlib.
- # We must also check with_cross_host to decide if this is a native
- # or cross-build and select where to install dlls appropriately.
- if test -n "$with_cross_host" &&
- test x"$with_cross_host" != x"no"; then
- AM_LTLDFLAGS='-no-undefined -bindir "$(toolexeclibdir)"';
- else
- AM_LTLDFLAGS='-no-undefined -bindir "$(bindir)"';
- fi
- ;;
- i?86-*-darwin*)
- TARGET=X86_DARWIN; TARGETDIR=x86
- ;;
- i?86-*-solaris2.1[[0-9]]*)
- TARGETDIR=x86
- if test $ac_cv_sizeof_size_t = 4; then
- TARGET=X86;
- else
- TARGET=X86_64;
- fi
- ;;
-
- x86_64-*-darwin*)
- TARGET=X86_DARWIN; TARGETDIR=x86
- ;;
-
- x86_64-*-cygwin* | x86_64-*-mingw*)
- TARGET=X86_WIN64; TARGETDIR=x86
- # All mingw/cygwin/win32 builds require -no-undefined for sharedlib.
- # We must also check with_cross_host to decide if this is a native
- # or cross-build and select where to install dlls appropriately.
- if test -n "$with_cross_host" &&
- test x"$with_cross_host" != x"no"; then
- AM_LTLDFLAGS='-no-undefined -bindir "$(toolexeclibdir)"';
- else
- AM_LTLDFLAGS='-no-undefined -bindir "$(bindir)"';
- fi
- ;;
-
- i?86-*-* | x86_64-*-*)
- TARGETDIR=x86
- if test $ac_cv_sizeof_size_t = 4; then
- case "$host" in
- *-gnux32)
- TARGET=X86_64
- ;;
- *)
- TARGET=X86
- ;;
- esac
- else
- TARGET=X86_64;
- fi
- ;;
-
- ia64*-*-*)
- TARGET=IA64; TARGETDIR=ia64
- ;;
-
- m32r*-*-*)
- TARGET=M32R; TARGETDIR=m32r
- ;;
-
- m68k-*-*)
- TARGET=M68K; TARGETDIR=m68k
- ;;
-
- m88k-*-*)
- TARGET=M88K; TARGETDIR=m88k
- ;;
-
- microblaze*-*-*)
- TARGET=MICROBLAZE; TARGETDIR=microblaze
- ;;
-
- moxie-*-*)
- TARGET=MOXIE; TARGETDIR=moxie
- ;;
-
- metag-*-*)
- TARGET=METAG; TARGETDIR=metag
- ;;
-
- mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*)
- TARGET=MIPS; TARGETDIR=mips
- ;;
- mips*-*linux* | mips*-*-openbsd*)
- # Support 128-bit long double for NewABI.
- HAVE_LONG_DOUBLE='defined(__mips64)'
- TARGET=MIPS; TARGETDIR=mips
- ;;
-
- nios2*-linux*)
- TARGET=NIOS2; TARGETDIR=nios2
- ;;
-
- or1k*-linux*)
- TARGET=OR1K; TARGETDIR=or1k
- ;;
-
- powerpc*-*-linux* | powerpc-*-sysv*)
- TARGET=POWERPC; TARGETDIR=powerpc
- HAVE_LONG_DOUBLE_VARIANT=1
- ;;
- powerpc-*-amigaos*)
- TARGET=POWERPC; TARGETDIR=powerpc
- ;;
- powerpc-*-beos*)
- TARGET=POWERPC; TARGETDIR=powerpc
- ;;
- powerpc-*-darwin* | powerpc64-*-darwin*)
- TARGET=POWERPC_DARWIN; TARGETDIR=powerpc
- ;;
- powerpc-*-aix* | rs6000-*-aix*)
- TARGET=POWERPC_AIX; TARGETDIR=powerpc
- ;;
- powerpc-*-freebsd* | powerpc-*-openbsd*)
- TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
- HAVE_LONG_DOUBLE_VARIANT=1
- ;;
- powerpc64-*-freebsd*)
- TARGET=POWERPC; TARGETDIR=powerpc
- ;;
- powerpc*-*-rtems*)
- TARGET=POWERPC; TARGETDIR=powerpc
- ;;
-
- s390-*-* | s390x-*-*)
- TARGET=S390; TARGETDIR=s390
- ;;
-
- sh-*-* | sh[[34]]*-*-*)
- TARGET=SH; TARGETDIR=sh
- ;;
- sh64-*-* | sh5*-*-*)
- TARGET=SH64; TARGETDIR=sh64
- ;;
-
- sparc*-*-*)
- TARGET=SPARC; TARGETDIR=sparc
- ;;
-
- tile*-*)
- TARGET=TILE; TARGETDIR=tile
- ;;
-
- vax-*-*)
- TARGET=VAX; TARGETDIR=vax
- ;;
-
- xtensa*-*)
- TARGET=XTENSA; TARGETDIR=xtensa
- ;;
-
-esac
-AC_SUBST(AM_RUNTESTFLAGS)
-AC_SUBST(AM_LTLDFLAGS)
+. ${srcdir}/configure.host
-if test $TARGETDIR = unknown; then
+if test -n "${UNSUPPORTED}"; then
AC_MSG_ERROR(["libffi has not been ported to $host."])
fi
-AM_CONDITIONAL(MIPS, test x$TARGET = xMIPS)
-AM_CONDITIONAL(BFIN, test x$TARGET = xBFIN)
-AM_CONDITIONAL(SPARC, test x$TARGET = xSPARC)
-AM_CONDITIONAL(X86, test x$TARGET = xX86)
-AM_CONDITIONAL(X86_FREEBSD, test x$TARGET = xX86_FREEBSD)
-AM_CONDITIONAL(X86_WIN32, test x$TARGET = xX86_WIN32)
-AM_CONDITIONAL(X86_WIN64, test x$TARGET = xX86_WIN64)
-AM_CONDITIONAL(X86_DARWIN, test x$TARGET = xX86_DARWIN)
-AM_CONDITIONAL(X86_DARWIN32, test x$TARGET = xX86_DARWIN && test $ac_cv_sizeof_size_t = 4)
-AM_CONDITIONAL(X86_DARWIN64, test x$TARGET = xX86_DARWIN && test $ac_cv_sizeof_size_t = 8)
-AM_CONDITIONAL(ALPHA, test x$TARGET = xALPHA)
-AM_CONDITIONAL(IA64, test x$TARGET = xIA64)
-AM_CONDITIONAL(M32R, test x$TARGET = xM32R)
-AM_CONDITIONAL(M68K, test x$TARGET = xM68K)
-AM_CONDITIONAL(M88K, test x$TARGET = xM88K)
-AM_CONDITIONAL(MICROBLAZE, test x$TARGET = xMICROBLAZE)
-AM_CONDITIONAL(METAG, test x$TARGET = xMETAG)
-AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE)
-AM_CONDITIONAL(NIOS2, test x$TARGET = xNIOS2)
-AM_CONDITIONAL(OR1K, test x$TARGET = xOR1K)
-AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
-AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
-AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN)
-AM_CONDITIONAL(POWERPC_FREEBSD, test x$TARGET = xPOWERPC_FREEBSD)
-AM_CONDITIONAL(AARCH64, test x$TARGET = xAARCH64)
-AM_CONDITIONAL(ARC, test x$TARGET = xARC)
-AM_CONDITIONAL(ARM, test x$TARGET = xARM)
-AM_CONDITIONAL(AVR32, test x$TARGET = xAVR32)
-AM_CONDITIONAL(LIBFFI_CRIS, test x$TARGET = xLIBFFI_CRIS)
-AM_CONDITIONAL(FRV, test x$TARGET = xFRV)
-AM_CONDITIONAL(S390, test x$TARGET = xS390)
-AM_CONDITIONAL(X86_64, test x$TARGET = xX86_64)
-AM_CONDITIONAL(SH, test x$TARGET = xSH)
-AM_CONDITIONAL(SH64, test x$TARGET = xSH64)
-AM_CONDITIONAL(PA_LINUX, test x$TARGET = xPA_LINUX)
-AM_CONDITIONAL(PA_HPUX, test x$TARGET = xPA_HPUX)
-AM_CONDITIONAL(PA64_HPUX, test x$TARGET = xPA64_HPUX)
-AM_CONDITIONAL(TILE, test x$TARGET = xTILE)
-AM_CONDITIONAL(VAX, test x$TARGET = xVAX)
-AM_CONDITIONAL(XTENSA, test x$TARGET = xXTENSA)
+AC_SUBST(AM_RUNTESTFLAGS)
+AC_SUBST(AM_LTLDFLAGS)
AC_HEADER_STDC
AC_CHECK_FUNCS(memcpy)
@@ -367,7 +111,8 @@ AC_C_BIGENDIAN
GCC_AS_CFI_PSEUDO_OP
-if test x$TARGET = xSPARC; then
+case "$TARGET" in
+ SPARC)
AC_CACHE_CHECK([assembler and linker support unaligned pc related relocs],
libffi_cv_as_sparc_ua_pcrel, [
save_CFLAGS="$CFLAGS"
@@ -396,9 +141,9 @@ if test x$TARGET = xSPARC; then
AC_DEFINE(HAVE_AS_REGISTER_PSEUDO_OP, 1,
[Define if your assembler supports .register.])
fi
-fi
+ ;;
-if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64; then
+ X86*)
AC_CACHE_CHECK([assembler supports pc related relocs],
libffi_cv_as_x86_pcrel, [
libffi_cv_as_x86_pcrel=no
@@ -411,33 +156,25 @@ if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64
AC_DEFINE(HAVE_AS_X86_PCREL, 1,
[Define if your assembler supports PC relative relocs.])
fi
+ ;;
- AC_CACHE_CHECK([assembler .ascii pseudo-op support],
- libffi_cv_as_ascii_pseudo_op, [
- libffi_cv_as_ascii_pseudo_op=unknown
- # Check if we have .ascii
- AC_TRY_COMPILE(,[asm (".ascii \\"string\\"");],
- [libffi_cv_as_ascii_pseudo_op=yes],
- [libffi_cv_as_ascii_pseudo_op=no])
- ])
- if test "x$libffi_cv_as_ascii_pseudo_op" = xyes; then
- AC_DEFINE(HAVE_AS_ASCII_PSEUDO_OP, 1,
- [Define if your assembler supports .ascii.])
- fi
-
- AC_CACHE_CHECK([assembler .string pseudo-op support],
- libffi_cv_as_string_pseudo_op, [
- libffi_cv_as_string_pseudo_op=unknown
- # Check if we have .string
- AC_TRY_COMPILE(,[asm (".string \\"string\\"");],
- [libffi_cv_as_string_pseudo_op=yes],
- [libffi_cv_as_string_pseudo_op=no])
- ])
- if test "x$libffi_cv_as_string_pseudo_op" = xyes; then
- AC_DEFINE(HAVE_AS_STRING_PSEUDO_OP, 1,
- [Define if your assembler supports .string.])
+ S390)
+ AC_CACHE_CHECK([compiler uses zarch features],
+ libffi_cv_as_s390_zarch, [
+ libffi_cv_as_s390_zarch=no
+ echo 'void foo(void) { bar(); bar(); }' > conftest.c
+ if $CC $CFLAGS -S conftest.c > /dev/null 2>&1; then
+ if grep -q brasl conftest.s; then
+ libffi_cv_as_s390_zarch=yes
+ fi
+ fi
+ ])
+ if test "x$libffi_cv_as_s390_zarch" = xyes; then
+ AC_DEFINE(HAVE_AS_S390_ZARCH, 1,
+ [Define if the compiler uses zarch features.])
fi
-fi
+ ;;
+esac
# On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC.
AC_ARG_ENABLE(pax_emutramp,
@@ -454,13 +191,13 @@ fi
FFI_EXEC_TRAMPOLINE_TABLE=0
case "$target" in
- *arm*-apple-darwin*)
+ *arm*-apple-* | aarch64-apple-*)
FFI_EXEC_TRAMPOLINE_TABLE=1
AC_DEFINE(FFI_EXEC_TRAMPOLINE_TABLE, 1,
[Cannot use PROT_EXEC on this target, so, we revert to
alternative means])
;;
- *-apple-darwin1* | *-*-freebsd* | *-*-kfreebsd* | *-*-openbsd* | *-pc-solaris*)
+ *-apple-* | *-*-freebsd* | *-*-kfreebsd* | *-*-openbsd* | *-pc-solaris* | *-linux-android*)
AC_DEFINE(FFI_MMAP_EXEC_WRIT, 1,
[Cannot use malloc on this target, so, we revert to
alternative means])
@@ -508,11 +245,13 @@ if test "x$GCC" = "xyes"; then
if $CC $CFLAGS -c -fpic -fexceptions -o conftest.o conftest.c > /dev/null 2>&1; then
objdump -h conftest.o > conftest.dump 2>&1
libffi_eh_frame_line=`grep -n eh_frame conftest.dump | cut -d: -f 1`
- libffi_test_line=`expr $libffi_eh_frame_line + 1`p
- sed -n $libffi_test_line conftest.dump > conftest.line
- if grep READONLY conftest.line > /dev/null; then
- libffi_cv_ro_eh_frame=yes
- fi
+ if test "x$libffi_eh_frame_line" != "x"; then
+ libffi_test_line=`expr $libffi_eh_frame_line + 1`p
+ sed -n $libffi_test_line conftest.dump > conftest.line
+ if grep READONLY conftest.line > /dev/null; then
+ libffi_cv_ro_eh_frame=yes
+ fi
+ fi
fi
rm -f conftest.*
])
@@ -531,7 +270,7 @@ if test "x$GCC" = "xyes"; then
echo 'int __attribute__ ((visibility ("hidden"))) foo (void) { return 1 ; }' > conftest.c
libffi_cv_hidden_visibility_attribute=no
if AC_TRY_COMMAND(${CC-cc} -Werror -S conftest.c -o conftest.s 1>&AS_MESSAGE_LOG_FD); then
- if grep '\.hidden.*foo' conftest.s >/dev/null; then
+ if egrep '(\.hidden|\.private_extern).*foo' conftest.s >/dev/null; then
libffi_cv_hidden_visibility_attribute=yes
fi
fi
@@ -543,10 +282,21 @@ if test "x$GCC" = "xyes"; then
fi
fi
+AC_ARG_ENABLE(docs,
+ AC_HELP_STRING([--disable-docs],
+ [Disable building of docs (default: no)]),
+ [enable_docs=no],
+ [enable_docs=yes])
+AM_CONDITIONAL(BUILD_DOCS, [test x$enable_docs = xyes])
+
AH_BOTTOM([
#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
#ifdef LIBFFI_ASM
+#ifdef __APPLE__
+#define FFI_HIDDEN(name) .private_extern name
+#else
#define FFI_HIDDEN(name) .hidden name
+#endif
#else
#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
#endif
@@ -562,6 +312,14 @@ AH_BOTTOM([
AC_SUBST(TARGET)
AC_SUBST(TARGETDIR)
+changequote(<,>)
+TARGET_OBJ=
+for i in $SOURCES; do
+ TARGET_OBJ="${TARGET_OBJ} src/${TARGETDIR}/"`echo $i | sed 's/[cS]$/lo/'`
+done
+changequote([,])
+AC_SUBST(TARGET_OBJ)
+
AC_SUBST(SHELL)
AC_ARG_ENABLE(debug,
@@ -590,36 +348,47 @@ AC_ARG_ENABLE(purify-safety,
AC_DEFINE(USING_PURIFY, 1, [Define this if you are using Purify and want to suppress spurious messages.])
fi)
+AC_ARG_ENABLE(multi-os-directory,
+[ --disable-multi-os-directory
+ disable use of gcc --print-multi-os-directory to change the library installation directory])
+
# These variables are only ever used when we cross-build to X86_WIN32.
# And we only support this with GCC, so...
if test "x$GCC" = "xyes"; then
if test -n "$with_cross_host" &&
test x"$with_cross_host" != x"no"; then
- toolexecdir="${exec_prefix}"/'$(target_alias)'
- toolexeclibdir="${toolexecdir}"/lib
+ toolexecdir='${exec_prefix}'/'$(target_alias)'
+ toolexeclibdir='${toolexecdir}'/lib
else
- toolexecdir="${libdir}"/gcc-lib/'$(target_alias)'
- toolexeclibdir="${libdir}"
+ toolexecdir='${libdir}'/gcc-lib/'$(target_alias)'
+ toolexeclibdir='${libdir}'
+ fi
+ if test x"$enable_multi_os_directory" != x"no"; then
+ multi_os_directory=`$CC $CFLAGS -print-multi-os-directory`
+ case $multi_os_directory in
+ .) ;; # Avoid trailing /.
+ ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;;
+ esac
fi
- multi_os_directory=`$CC $CFLAGS -print-multi-os-directory`
- case $multi_os_directory in
- .) ;; # Avoid trailing /.
- ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;;
- esac
AC_SUBST(toolexecdir)
else
- toolexeclibdir="${libdir}"
+ toolexeclibdir='${libdir}'
fi
AC_SUBST(toolexeclibdir)
+# Check linker support.
+LIBFFI_ENABLE_SYMVERS
+
AC_CONFIG_COMMANDS(include, [test -d include || mkdir include])
AC_CONFIG_COMMANDS(src, [
test -d src || mkdir src
test -d src/$TARGETDIR || mkdir src/$TARGETDIR
], [TARGETDIR="$TARGETDIR"])
-AC_CONFIG_LINKS(include/ffitarget.h:src/$TARGETDIR/ffitarget.h)
-
-AC_CONFIG_FILES(include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile libffi.pc)
+AC_CONFIG_FILES(include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile doc/Makefile libffi.pc)
AC_OUTPUT
+
+# Copy this file instead of using AC_CONFIG_LINK in order to support
+# compiling with MSVC, which won't understand cygwin style symlinks.
+cp ${srcdir}/src/$TARGETDIR/ffitarget.h include/ffitarget.h
diff --git a/configure.host b/configure.host
new file mode 100644
index 00000000..9a72cda8
--- /dev/null
+++ b/configure.host
@@ -0,0 +1,303 @@
+# configure.host
+#
+# This shell script handles all host based configuration for libffi.
+#
+
+# THIS TABLE IS SORTED. KEEP IT THAT WAY.
+# Most of the time we can define all the variables all at once...
+case "${host}" in
+ aarch64*-*-cygwin* | aarch64*-*-mingw* | aarch64*-*-win* )
+ TARGET=ARM_WIN64; TARGETDIR=aarch64
+ MSVC=1
+ ;;
+
+ aarch64*-*-*)
+ TARGET=AARCH64; TARGETDIR=aarch64
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ alpha*-*-*)
+ TARGET=ALPHA; TARGETDIR=alpha;
+ # Support 128-bit long double, changeable via command-line switch.
+ HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)'
+ SOURCES="ffi.c osf.S"
+ ;;
+
+ arc*-*-*)
+ TARGET=ARC; TARGETDIR=arc
+ SOURCES="ffi.c arcompact.S"
+ ;;
+
+ arm*-*-cygwin* | arm*-*-mingw* | arm*-*-win* )
+ TARGET=ARM_WIN32; TARGETDIR=arm
+ MSVC=1
+ ;;
+
+ arm*-*-*)
+ TARGET=ARM; TARGETDIR=arm
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ avr32*-*-*)
+ TARGET=AVR32; TARGETDIR=avr32
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ bfin*)
+ TARGET=BFIN; TARGETDIR=bfin
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ cris-*-*)
+ TARGET=LIBFFI_CRIS; TARGETDIR=cris
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ frv-*-*)
+ TARGET=FRV; TARGETDIR=frv
+ SOURCES="ffi.c eabi.S"
+ ;;
+
+ hppa*-*-linux* | parisc*-*-linux* | hppa*-*-openbsd*)
+ TARGET=PA_LINUX; TARGETDIR=pa
+ SOURCES="ffi.c linux.S"
+ ;;
+ hppa*64-*-hpux*)
+ TARGET=PA64_HPUX; TARGETDIR=pa
+ ;;
+ hppa*-*-hpux*)
+ TARGET=PA_HPUX; TARGETDIR=pa
+ SOURCES="ffi.c hpux32.S"
+ ;;
+
+ i?86-*-freebsd* | i?86-*-openbsd*)
+ TARGET=X86_FREEBSD; TARGETDIR=x86
+ ;;
+
+ i?86-*-cygwin* | i?86-*-mingw* | i?86-*-win* | i?86-*-os2* | i?86-*-interix* \
+ | x86_64-*-cygwin* | x86_64-*-mingw* | x86_64-*-win* )
+ TARGETDIR=x86
+ if test $ac_cv_sizeof_size_t = 4; then
+ TARGET=X86_WIN32
+ else
+ TARGET=X86_WIN64
+ fi
+ if test "${ax_cv_c_compiler_vendor}" = "microsoft"; then
+ MSVC=1
+ fi
+ # All mingw/cygwin/win32 builds require -no-undefined for sharedlib.
+ # We must also check with_cross_host to decide if this is a native
+ # or cross-build and select where to install dlls appropriately.
+ if test -n "$with_cross_host" &&
+ test x"$with_cross_host" != x"no"; then
+ AM_LTLDFLAGS='-no-undefined -bindir "$(toolexeclibdir)"';
+ else
+ AM_LTLDFLAGS='-no-undefined -bindir "$(bindir)"';
+ fi
+ ;;
+
+ i?86-*-darwin* | x86_64-*-darwin* | i?86-*-ios | x86_64-*-ios)
+ TARGETDIR=x86
+ if test $ac_cv_sizeof_size_t = 4; then
+ TARGET=X86_DARWIN
+ else
+ TARGET=X86_64
+ fi
+ ;;
+
+ i?86-*-* | x86_64-*-* | amd64-*)
+ TARGETDIR=x86
+ if test $ac_cv_sizeof_size_t = 4; then
+ case "$host" in
+ x86_64-*x32|x86_64-x32-*)
+ TARGET_X32=yes
+ TARGET=X86_64
+ ;;
+ *)
+ echo 'int foo (void) { return __x86_64__; }' > conftest.c
+ if $CC $CFLAGS -Werror -S conftest.c -o conftest.s > /dev/null 2>&1; then
+ TARGET_X32=yes
+ TARGET=X86_64
+ else
+ TARGET=X86;
+ fi
+ rm -f conftest.*
+ ;;
+ esac
+ else
+ TARGET=X86_64;
+ fi
+ ;;
+
+ ia64*-*-*)
+ TARGET=IA64; TARGETDIR=ia64
+ SOURCES="ffi.c unix.S"
+ ;;
+
+ m32r*-*-*)
+ TARGET=M32R; TARGETDIR=m32r
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ m68k-*-*)
+ TARGET=M68K; TARGETDIR=m68k
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ m88k-*-*)
+ TARGET=M88K; TARGETDIR=m88k
+ SOURCES="ffi.c obsd.S"
+ ;;
+
+ microblaze*-*-*)
+ TARGET=MICROBLAZE; TARGETDIR=microblaze
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ moxie-*-*)
+ TARGET=MOXIE; TARGETDIR=moxie
+ SOURCES="ffi.c eabi.S"
+ ;;
+
+ metag-*-*)
+ TARGET=METAG; TARGETDIR=metag
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*)
+ TARGET=MIPS; TARGETDIR=mips
+ ;;
+ mips*-*linux* | mips*-*-openbsd*)
+ # Support 128-bit long double for NewABI.
+ HAVE_LONG_DOUBLE='defined(__mips64)'
+ TARGET=MIPS; TARGETDIR=mips
+ ;;
+
+ nios2*-linux*)
+ TARGET=NIOS2; TARGETDIR=nios2
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ or1k*-*-*)
+ TARGET=OR1K; TARGETDIR=or1k
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ powerpc*-*-linux* | powerpc-*-sysv*)
+ TARGET=POWERPC; TARGETDIR=powerpc
+ HAVE_LONG_DOUBLE_VARIANT=1
+ ;;
+ powerpc-*-amigaos*)
+ TARGET=POWERPC; TARGETDIR=powerpc
+ ;;
+ powerpc-*-beos*)
+ TARGET=POWERPC; TARGETDIR=powerpc
+ ;;
+ powerpc-*-darwin* | powerpc64-*-darwin*)
+ TARGET=POWERPC_DARWIN; TARGETDIR=powerpc
+ ;;
+ powerpc-*-aix* | rs6000-*-aix*)
+ TARGET=POWERPC_AIX; TARGETDIR=powerpc
+ ;;
+ powerpc-*-freebsd* | powerpc-*-openbsd* | powerpc-*-netbsd*)
+ TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
+ HAVE_LONG_DOUBLE_VARIANT=1
+ ;;
+ powerpc64-*-freebsd*)
+ TARGET=POWERPC; TARGETDIR=powerpc
+ ;;
+ powerpc*-*-rtems*)
+ TARGET=POWERPC; TARGETDIR=powerpc
+ ;;
+
+ riscv*-*)
+ TARGET=RISCV; TARGETDIR=riscv
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ s390-*-* | s390x-*-*)
+ TARGET=S390; TARGETDIR=s390
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ sh-*-* | sh[34]*-*-*)
+ TARGET=SH; TARGETDIR=sh
+ SOURCES="ffi.c sysv.S"
+ ;;
+ sh64-*-* | sh5*-*-*)
+ TARGET=SH64; TARGETDIR=sh64
+ SOURCES="ffi.c sysv.S"
+ ;;
+
+ sparc*-*-*)
+ TARGET=SPARC; TARGETDIR=sparc
+ SOURCES="ffi.c ffi64.c v8.S v9.S"
+ ;;
+
+ tile*-*)
+ TARGET=TILE; TARGETDIR=tile
+ SOURCES="ffi.c tile.S"
+ ;;
+
+ vax-*-*)
+ TARGET=VAX; TARGETDIR=vax
+ SOURCES="ffi.c elfbsd.S"
+ ;;
+
+ xtensa*-*)
+ TARGET=XTENSA; TARGETDIR=xtensa
+ SOURCES="ffi.c sysv.S"
+ ;;
+esac
+
+# ... but some of the cases above share configury.
+case "${TARGET}" in
+ ARM_WIN32)
+ SOURCES="ffi.c sysv_msvc_arm32.S"
+ ;;
+ ARM_WIN64)
+ SOURCES="ffi.c win64_armasm.S"
+ ;;
+ MIPS)
+ SOURCES="ffi.c o32.S n32.S"
+ ;;
+ POWERPC)
+ SOURCES="ffi.c ffi_sysv.c ffi_linux64.c sysv.S ppc_closure.S"
+ SOURCES="${SOURCES} linux64.S linux64_closure.S"
+ ;;
+ POWERPC_AIX)
+ SOURCES="ffi_darwin.c aix.S aix_closure.S"
+ ;;
+ POWERPC_DARWIN)
+ SOURCES="ffi_darwin.c darwin.S darwin_closure.S"
+ ;;
+ POWERPC_FREEBSD)
+ SOURCES="ffi.c ffi_sysv.c sysv.S ppc_closure.S"
+ ;;
+ X86 | X86_DARWIN | X86_FREEBSD | X86_WIN32)
+ if test "$MSVC" = 1; then
+ SOURCES="ffi.c sysv_intel.S"
+ else
+ SOURCES="ffi.c sysv.S"
+ fi
+ ;;
+ X86_64)
+ if test x"$TARGET_X32" = xyes; then
+ SOURCES="ffi64.c unix64.S"
+ else
+ SOURCES="ffi64.c unix64.S ffiw64.c win64.S"
+ fi
+ ;;
+ X86_WIN64)
+ if test "$MSVC" = 1; then
+ SOURCES="ffiw64.c win64_intel.S"
+ else
+ SOURCES="ffiw64.c win64.S"
+ fi
+ ;;
+esac
+
+# If we failed to configure SOURCES, we can't do anything.
+if test -z "${SOURCES}"; then
+ UNSUPPORTED=1
+fi
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 00000000..43b650ae
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,3 @@
+## Process this with automake to create Makefile.in
+
+info_TEXINFOS = libffi.texi
diff --git a/doc/libffi.texi b/doc/libffi.texi
index b1c9bc36..bd305936 100644
--- a/doc/libffi.texi
+++ b/doc/libffi.texi
@@ -1,7 +1,8 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename libffi.info
-@settitle libffi
+@include version.texi
+@settitle libffi: the portable foreign function interface library
@setchapternewpage off
@c %**end of header
@@ -12,32 +13,43 @@
@syncodeindex pg cp
@syncodeindex tp cp
-@include version.texi
-
@copying
-This manual is for Libffi, a portable foreign-function interface
+This manual is for libffi, a portable foreign function interface
library.
-Copyright @copyright{} 2008, 2010, 2011 Red Hat, Inc.
+Copyright @copyright{} 2008--2019 Anthony Green and Red Hat, Inc.
+
+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.
-@quotation
-Permission is granted to copy, distribute and/or modify this document
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version. A copy of the license is included in the
-section entitled ``GNU General Public License''.
+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 AUTHORS OR COPYRIGHT HOLDERS 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.
-@end quotation
@end copying
@dircategory Development
@direntry
-* libffi: (libffi). Portable foreign-function interface library.
+* libffi: (libffi). Portable foreign function interface library.
@end direntry
@titlepage
-@title Libffi
+@title libffi: a foreign function interface library
+@subtitle For Version @value{VERSION} of libffi
+@author Anthony Green
@page
@vskip 0pt plus 1filll
@insertcopying
@@ -107,6 +119,7 @@ values passed between the two languages.
* Multiple ABIs:: Different passing styles on one platform.
* The Closure API:: Writing a generic function.
* Closure Example:: A closure example.
+* Thread Safety:: Thread safety.
@end menu
@@ -152,16 +165,16 @@ If the function being called is variadic (varargs) then
@code{ffi_prep_cif_var} must be used instead of @code{ffi_prep_cif}.
@findex ffi_prep_cif_var
-@defun ffi_status ffi_prep_cif_var (ffi_cif *@var{cif}, ffi_abi var{abi}, unsigned int @var{nfixedargs}, unsigned int var{ntotalargs}, ffi_type *@var{rtype}, ffi_type **@var{argtypes})
+@defun ffi_status ffi_prep_cif_var (ffi_cif *@var{cif}, ffi_abi @var{abi}, unsigned int @var{nfixedargs}, unsigned int @var{ntotalargs}, ffi_type *@var{rtype}, ffi_type **@var{argtypes})
This initializes @var{cif} according to the given parameters for
-a call to a variadic function. In general it's operation is the
+a call to a variadic function. In general its operation is the
same as for @code{ffi_prep_cif} except that:
@var{nfixedargs} is the number of fixed arguments, prior to any
variadic arguments. It must be greater than zero.
@var{ntotalargs} the total number of arguments, including variadic
-and fixed arguments.
+and fixed arguments. @var{argtypes} must have this many elements.
Note that, different cif's must be prepped for calls to the same
function when different numbers of arguments are passed.
@@ -172,6 +185,10 @@ Also note that a call to @code{ffi_prep_cif_var} with
@end defun
+Note that the resulting @code{ffi_cif} holds pointers to all the
+@code{ffi_type} objects that were used during initialization. You
+must ensure that these type objects have a lifetime at least as long
+as that of the @code{ffi_cif}.
To call a function using an initialized @code{ffi_cif}, use the
@code{ffi_call} function:
@@ -190,12 +207,29 @@ to ensure this. If @var{cif} declares that the function returns
@code{void} (using @code{ffi_type_void}), then @var{rvalue} is
ignored.
+In most situations, @samp{libffi} will handle promotion according to
+the ABI. However, for historical reasons, there is a special case
+with return values that must be handled by your code. In particular,
+for integral (not @code{struct}) types that are narrower than the
+system register size, the return value will be widened by
+@samp{libffi}. @samp{libffi} provides a type, @code{ffi_arg}, that
+can be used as the return type. For example, if the CIF was defined
+with a return type of @code{char}, @samp{libffi} will try to store a
+full @code{ffi_arg} into the return value.
+
@var{avalues} is a vector of @code{void *} pointers that point to the
memory locations holding the argument values for a call. If @var{cif}
declares that the function has no arguments (i.e., @var{nargs} was 0),
then @var{avalues} is ignored. Note that argument values may be
modified by the callee (for instance, structs passed by value); the
burden of copying pass-by-value arguments is placed on the caller.
+
+Note that while the return value must be register-sized, arguments
+should exactly match their declared type. For example, if an argument
+is a @code{short}, then the entry in @var{avalues} should point to an
+object declared as @code{short}; but if the return type is
+@code{short}, then @var{rvalue} should point to an object declared as
+a larger type -- usually @code{ffi_arg}.
@end defun
@@ -246,6 +280,8 @@ int main()
@menu
* Primitive Types:: Built-in types.
* Structures:: Structure types.
+* Size and Alignment:: Size and alignment of types.
+* Arrays Unions Enums:: Arrays, unions, and enumerations.
* Type Example:: Structure type example.
* Complex:: Complex types.
* Complex Type Example:: Complex type example.
@@ -370,8 +406,7 @@ when passing to @code{ffi_prep_cif}.
@node Structures
@subsection Structures
-Although @samp{libffi} has no special support for unions or
-bit-fields, it is perfectly happy passing structures back and forth.
+@samp{libffi} is perfectly happy passing structures back and forth.
You must first describe the structure to @samp{libffi} by creating a
new @code{ffi_type} object for it.
@@ -391,9 +426,166 @@ For a structure, this should be set to @code{FFI_TYPE_STRUCT}.
@item ffi_type **elements
This is a @samp{NULL}-terminated array of pointers to @code{ffi_type}
objects. There is one element per field of the struct.
+
+Note that @samp{libffi} has no special support for bit-fields. You
+must manage these manually.
@end table
@end deftp
+The @code{size} and @code{alignment} fields will be filled in by
+@code{ffi_prep_cif} or @code{ffi_prep_cif_var}, as needed.
+
+@node Size and Alignment
+@subsection Size and Alignment
+
+@code{libffi} will set the @code{size} and @code{alignment} fields of
+an @code{ffi_type} object for you. It does so using its knowledge of
+the ABI.
+
+You might expect that you can simply read these fields for a type that
+has been laid out by @code{libffi}. However, there are some caveats.
+
+@itemize @bullet
+@item
+The size or alignment of some of the built-in types may vary depending
+on the chosen ABI.
+
+@item
+The size and alignment of a new structure type will not be set by
+@code{libffi} until it has been passed to @code{ffi_prep_cif} or
+@code{ffi_get_struct_offsets}.
+
+@item
+A structure type cannot be shared across ABIs. Instead each ABI needs
+its own copy of the structure type.
+@end itemize
+
+So, before examining these fields, it is safest to pass the
+@code{ffi_type} object to @code{ffi_prep_cif} or
+@code{ffi_get_struct_offsets} first. This function will do all the
+needed setup.
+
+@example
+ffi_type *desired_type;
+ffi_abi desired_abi;
+@dots{}
+ffi_cif cif;
+if (ffi_prep_cif (&cif, desired_abi, 0, desired_type, NULL) == FFI_OK)
+ @{
+ size_t size = desired_type->size;
+ unsigned short alignment = desired_type->alignment;
+ @}
+@end example
+
+@code{libffi} also provides a way to get the offsets of the members of
+a structure.
+
+@findex ffi_get_struct_offsets
+@defun ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets)
+Compute the offset of each element of the given structure type.
+@var{abi} is the ABI to use; this is needed because in some cases the
+layout depends on the ABI.
+
+@var{offsets} is an out parameter. The caller is responsible for
+providing enough space for all the results to be written -- one
+element per element type in @var{struct_type}. If @var{offsets} is
+@code{NULL}, then the type will be laid out but not otherwise
+modified. This can be useful for accessing the type's size or layout,
+as mentioned above.
+
+This function returns @code{FFI_OK} on success; @code{FFI_BAD_ABI} if
+@var{abi} is invalid; or @code{FFI_BAD_TYPEDEF} if @var{struct_type}
+is invalid in some way. Note that only @code{FFI_STRUCT} types are
+valid here.
+@end defun
+
+@node Arrays Unions Enums
+@subsection Arrays, Unions, and Enumerations
+
+@subsubsection Arrays
+
+@samp{libffi} does not have direct support for arrays or unions.
+However, they can be emulated using structures.
+
+To emulate an array, simply create an @code{ffi_type} using
+@code{FFI_TYPE_STRUCT} with as many members as there are elements in
+the array.
+
+@example
+ffi_type array_type;
+ffi_type **elements
+int i;
+
+elements = malloc ((n + 1) * sizeof (ffi_type *));
+for (i = 0; i < n; ++i)
+ elements[i] = array_element_type;
+elements[n] = NULL;
+
+array_type.size = array_type.alignment = 0;
+array_type.type = FFI_TYPE_STRUCT;
+array_type.elements = elements;
+@end example
+
+Note that arrays cannot be passed or returned by value in C --
+structure types created like this should only be used to refer to
+members of real @code{FFI_TYPE_STRUCT} objects.
+
+However, a phony array type like this will not cause any errors from
+@samp{libffi} if you use it as an argument or return type. This may
+be confusing.
+
+@subsubsection Unions
+
+A union can also be emulated using @code{FFI_TYPE_STRUCT}. In this
+case, however, you must make sure that the size and alignment match
+the real requirements of the union.
+
+One simple way to do this is to ensue that each element type is laid
+out. Then, give the new structure type a single element; the size of
+the largest element; and the largest alignment seen as well.
+
+This example uses the @code{ffi_prep_cif} trick to ensure that each
+element type is laid out.
+
+@example
+ffi_abi desired_abi;
+ffi_type union_type;
+ffi_type **union_elements;
+
+int i;
+ffi_type element_types[2];
+
+element_types[1] = NULL;
+
+union_type.size = union_type.alignment = 0;
+union_type.type = FFI_TYPE_STRUCT;
+union_type.elements = element_types;
+
+for (i = 0; union_elements[i]; ++i)
+ @{
+ ffi_cif cif;
+ if (ffi_prep_cif (&cif, desired_abi, 0, union_elements[i], NULL) == FFI_OK)
+ @{
+ if (union_elements[i]->size > union_type.size)
+ @{
+ union_type.size = union_elements[i];
+ size = union_elements[i]->size;
+ @}
+ if (union_elements[i]->alignment > union_type.alignment)
+ union_type.alignment = union_elements[i]->alignment;
+ @}
+ @}
+@end example
+
+@subsubsection Enumerations
+
+@code{libffi} does not have any special support for C @code{enum}s.
+Although any given @code{enum} is implemented using a specific
+underlying integral type, exactly which type will be used cannot be
+determined by @code{libffi} -- it may depend on the values in the
+enumeration or on compiler flags such as @option{-fshort-enums}.
+@xref{Structures unions enumerations and bit-fields implementation, , , gcc},
+for more information about how GCC handles enumerations.
@node Type Example
@subsection Type Example
@@ -630,30 +822,47 @@ the closure function:
@findex ffi_prep_closure_loc
@defun ffi_status ffi_prep_closure_loc (ffi_closure *@var{closure}, ffi_cif *@var{cif}, void (*@var{fun}) (ffi_cif *@var{cif}, void *@var{ret}, void **@var{args}, void *@var{user_data}), void *@var{user_data}, void *@var{codeloc})
-Prepare a closure function.
+Prepare a closure function. The arguments to
+@code{ffi_prep_closure_loc} are:
-@var{closure} is the address of a @code{ffi_closure} object; this is
-the writable address returned by @code{ffi_closure_alloc}.
+@table @var
+@item closure
+The address of a @code{ffi_closure} object; this is the writable
+address returned by @code{ffi_closure_alloc}.
+
+@item cif
+The @code{ffi_cif} describing the function parameters. Note that this
+object, and the types to which it refers, must be kept alive until the
+closure itself is freed.
-@var{cif} is the @code{ffi_cif} describing the function parameters.
+@item user_data
+An arbitrary datum that is passed, uninterpreted, to your closure
+function.
-@var{user_data} is an arbitrary datum that is passed, uninterpreted,
-to your closure function.
+@item codeloc
+The executable address returned by @code{ffi_closure_alloc}.
-@var{codeloc} is the executable address returned by
-@code{ffi_closure_alloc}.
+@item fun
+The function which will be called when the closure is invoked. It is
+called with the arguments:
-@var{fun} is the function which will be called when the closure is
-invoked. It is called with the arguments:
@table @var
@item cif
The @code{ffi_cif} passed to @code{ffi_prep_closure_loc}.
@item ret
A pointer to the memory used for the function's return value.
-@var{fun} must fill this, unless the function is declared as returning
-@code{void}.
-@c FIXME: is this NULL for void-returning functions?
+
+If the function is declared as returning @code{void}, then this value
+is garbage and should not be used.
+
+Otherwise, @var{fun} must fill the object to which this points,
+following the same special promotion behavior as @code{ffi_call}.
+That is, in most cases, @var{ret} points to an object of exactly the
+size of the type specified when @var{cif} was constructed. However,
+integral types narrower than the system register size are widened. In
+these cases your program may assume that @var{ret} points to an
+@code{ffi_arg} object.
@item args
A vector of pointers to memory holding the arguments to the function.
@@ -662,10 +871,10 @@ A vector of pointers to memory holding the arguments to the function.
The same @var{user_data} that was passed to
@code{ffi_prep_closure_loc}.
@end table
+@end table
@code{ffi_prep_closure_loc} will return @code{FFI_OK} if everything
-went ok, and something else on error.
-@c FIXME: what?
+went ok, and one of the other @code{ffi_status} values on error.
After calling @code{ffi_prep_closure_loc}, you can cast @var{codeloc}
to the appropriate pointer-to-function type.
@@ -733,6 +942,28 @@ int main()
@end example
+@node Thread Safety
+@section Thread Safety
+
+@code{libffi} is not completely thread-safe. However, many parts are,
+and if you follow some simple rules, you can use it safely in a
+multi-threaded program.
+
+@itemize @bullet
+@item
+@code{ffi_prep_cif} may modify the @code{ffi_type} objects passed to
+it. It is best to ensure that only a single thread prepares a given
+@code{ffi_cif} at a time.
+
+@item
+On some platforms, @code{ffi_prep_cif} may modify the size and
+alignment of some types, depending on the chosen ABI. On these
+platforms, if you switch between ABIs, you must ensure that there is
+only one call to @code{ffi_prep_cif} at a time.
+
+Currently the only affected platform is PowerPC and the only affected
+type is @code{long double}.
+@end itemize
@node Missing Features
@chapter Missing Features
@@ -748,15 +979,11 @@ Variadic closures.
There is no support for bit fields in structures.
@item
-The closure API is
-
-@c FIXME: ...
-
-@item
The ``raw'' API is undocumented.
-@c argument promotion?
-@c unions?
@c anything else?
+
+@item
+The Go API is undocumented.
@end itemize
Note that variadic support is very new and tested on a relatively
diff --git a/doc/version.texi b/doc/version.texi
index ccef70f4..d9d50949 100644
--- a/doc/version.texi
+++ b/doc/version.texi
@@ -1,4 +1,4 @@
-@set UPDATED 8 November 2014
-@set UPDATED-MONTH November 2014
-@set EDITION 3.2.1
-@set VERSION 3.2.1
+@set UPDATED 22 November 2019
+@set UPDATED-MONTH November 2019
+@set EDITION 3.3
+@set VERSION 3.3
diff --git a/generate-darwin-source-and-headers.py b/generate-darwin-source-and-headers.py
index 964e861d..f7fc414b 100644
--- a/generate-darwin-source-and-headers.py
+++ b/generate-darwin-source-and-headers.py
@@ -14,12 +14,12 @@ class simulator_platform(Platform):
sdk = 'iphonesimulator'
arch = 'i386'
triple = 'i386-apple-darwin11'
- version_min = '-miphoneos-version-min=5.1.1'
+ version_min = '-miphoneos-version-min=7.0'
prefix = "#ifdef __i386__\n\n"
suffix = "\n\n#endif"
src_dir = 'x86'
- src_files = ['darwin.S', 'win32.S', 'ffi.c']
+ src_files = ['sysv.S', 'ffi.c', 'internal.h']
class simulator64_platform(Platform):
@@ -32,7 +32,7 @@ class simulator64_platform(Platform):
prefix = "#ifdef __x86_64__\n\n"
suffix = "\n\n#endif"
src_dir = 'x86'
- src_files = ['darwin64.S', 'ffi64.c']
+ src_files = ['unix64.S', 'ffi64.c', 'ffiw64.c', 'win64.S', 'internal64.h', 'asmnames.h']
class device_platform(Platform):
@@ -40,12 +40,12 @@ class device_platform(Platform):
sdk = 'iphoneos'
arch = 'armv7'
triple = 'arm-apple-darwin11'
- version_min = '-miphoneos-version-min=5.1.1'
+ version_min = '-miphoneos-version-min=7.0'
prefix = "#ifdef __arm__\n\n"
suffix = "\n\n#endif"
src_dir = 'arm'
- src_files = ['sysv.S', 'trampoline.S', 'ffi.c']
+ src_files = ['sysv.S', 'ffi.c', 'internal.h']
class device64_platform(Platform):
@@ -58,7 +58,7 @@ class device64_platform(Platform):
prefix = "#ifdef __arm64__\n\n"
suffix = "\n\n#endif"
src_dir = 'aarch64'
- src_files = ['sysv.S', 'ffi.c']
+ src_files = ['sysv.S', 'ffi.c', 'internal.h']
class desktop32_platform(Platform):
@@ -68,7 +68,7 @@ class desktop32_platform(Platform):
triple = 'i386-apple-darwin10'
version_min = '-mmacosx-version-min=10.6'
src_dir = 'x86'
- src_files = ['darwin.S', 'win32.S', 'ffi.c']
+ src_files = ['sysv.S', 'ffi.c', 'internal.h']
prefix = "#ifdef __i386__\n\n"
suffix = "\n\n#endif"
@@ -84,16 +84,14 @@ class desktop64_platform(Platform):
prefix = "#ifdef __x86_64__\n\n"
suffix = "\n\n#endif"
src_dir = 'x86'
- src_files = ['darwin64.S', 'ffi64.c']
+ src_files = ['unix64.S', 'ffi64.c', 'ffiw64.c', 'win64.S', 'internal64.h', 'asmnames.h']
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
- if exc.errno == errno.EEXIST:
- pass
- else:
+ if exc.errno != errno.EEXIST:
raise
@@ -102,8 +100,11 @@ def move_file(src_dir, dst_dir, filename, file_suffix=None, prefix='', suffix=''
out_filename = filename
if file_suffix:
- split_name = os.path.splitext(filename)
- out_filename = "%s_%s%s" % (split_name[0], file_suffix, split_name[1])
+ if filename in ['internal64.h', 'asmnames.h', 'internal.h']:
+ out_filename = filename
+ else:
+ split_name = os.path.splitext(filename)
+ out_filename = "%s_%s%s" % (split_name[0], file_suffix, split_name[1])
with open(os.path.join(src_dir, filename)) as in_file:
with open(os.path.join(dst_dir, out_filename), 'w') as out_file:
@@ -162,18 +163,11 @@ def build_target(platform, platform_headers):
platform_headers[filename].add((platform.prefix, platform.arch, platform.suffix))
-def make_tramp():
- with open('src/arm/trampoline.S', 'w') as tramp_out:
- p = subprocess.Popen(['bash', 'src/arm/gentramp.sh'], stdout=tramp_out)
- p.wait()
-
-
def generate_source_and_headers(generate_osx=True, generate_ios=True):
copy_files('src', 'darwin_common/src', pattern='*.c')
copy_files('include', 'darwin_common/include', pattern='*.h')
if generate_ios:
- make_tramp()
copy_src_platform_files(simulator_platform)
copy_src_platform_files(simulator64_platform)
copy_src_platform_files(device_platform)
diff --git a/include/Makefile.am b/include/Makefile.am
index fd280249..c59df9fb 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -3,7 +3,7 @@
AUTOMAKE_OPTIONS=foreign
DISTCLEANFILES=ffitarget.h
-EXTRA_DIST=ffi.h.in ffi_common.h
+noinst_HEADERS=ffi_common.h ffi_cfi.h
+EXTRA_DIST=ffi.h.in
-includesdir = $(libdir)/@PACKAGE_NAME@-@PACKAGE_VERSION@/include
-nodist_includes_HEADERS = ffi.h ffitarget.h
+nodist_include_HEADERS = ffi.h ffitarget.h
diff --git a/include/ffi.h.in b/include/ffi.h.in
index f403ae06..71cc05c9 100644
--- a/include/ffi.h.in
+++ b/include/ffi.h.in
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------*-C-*-
- libffi @VERSION@ - Copyright (c) 2011, 2014 Anthony Green
+ libffi @VERSION@ - Copyright (c) 2011, 2014, 2019 Anthony Green
- Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person
@@ -25,23 +25,14 @@
----------------------------------------------------------------------- */
/* -------------------------------------------------------------------
- The basic API is described in the README file.
+ Most of the API is documented in doc/libffi.texi.
- The raw API is designed to bypass some of the argument packing
- and unpacking on architectures for which it can be avoided.
+ The raw API is designed to bypass some of the argument packing and
+ unpacking on architectures for which it can be avoided. Routines
+ are provided to emulate the raw API if the underlying platform
+ doesn't allow faster implementation.
- The closure API allows interpreted functions to be packaged up
- inside a C function pointer, so that they can be called as C functions,
- with no understanding on the client side that they are interpreted.
- It can also be used in other cases in which it is necessary to package
- up a user specified parameter and a function pointer as a single
- function pointer.
-
- The closure API must be implemented in order to get its functionality,
- e.g. for use by gij. Routines are provided to emulate the raw API
- if the underlying platform doesn't allow faster implementation.
-
- More details on the raw and cloure API can be found in:
+ More details on the raw API can be found in:
http://gcc.gnu.org/ml/java/1999-q3/msg00138.html
@@ -106,8 +97,8 @@ extern "C" {
# endif
#endif
-/* The closure code assumes that this works on pointers, i.e. a size_t */
-/* can hold a pointer. */
+/* The closure code assumes that this works on pointers, i.e. a size_t
+ can hold a pointer. */
typedef struct _ffi_type
{
@@ -117,6 +108,32 @@ typedef struct _ffi_type
struct _ffi_type **elements;
} ffi_type;
+/* Need minimal decorations for DLLs to work on Windows. GCC has
+ autoimport and autoexport. Always mark externally visible symbols
+ as dllimport for MSVC clients, even if it means an extra indirection
+ when using the static version of the library.
+ Besides, as a workaround, they can define FFI_BUILDING if they
+ *know* they are going to link with the static library. */
+#if defined _MSC_VER
+# if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */
+# define FFI_API __declspec(dllexport)
+# elif !defined FFI_BUILDING /* Importing libffi.DLL */
+# define FFI_API __declspec(dllimport)
+# else /* Building/linking static library */
+# define FFI_API
+# endif
+#else
+# define FFI_API
+#endif
+
+/* The externally visible type declarations also need the MSVC DLL
+ decorations, or they will not be exported from the object file. */
+#if defined LIBFFI_HIDE_BASIC_TYPES
+# define FFI_EXTERN FFI_API
+#else
+# define FFI_EXTERN extern FFI_API
+#endif
+
#ifndef LIBFFI_HIDE_BASIC_TYPES
#if SCHAR_MAX == 127
# define ffi_type_uchar ffi_type_uint8
@@ -166,21 +183,7 @@ typedef struct _ffi_type
#error "long size not supported"
#endif
-/* Need minimal decorations for DLLs to works on Windows. */
-/* GCC has autoimport and autoexport. Rely on Libtool to */
-/* help MSVC export from a DLL, but always declare data */
-/* to be imported for MSVC clients. This costs an extra */
-/* indirection for MSVC clients using the static version */
-/* of the library, but don't worry about that. Besides, */
-/* as a workaround, they can define FFI_BUILDING if they */
-/* *know* they are going to link with the static library. */
-#if defined _MSC_VER && !defined FFI_BUILDING
-#define FFI_EXTERN extern __declspec(dllimport)
-#else
-#define FFI_EXTERN extern
-#endif
-
-/* These are defined in types.c */
+/* These are defined in types.c. */
FFI_EXTERN ffi_type ffi_type_void;
FFI_EXTERN ffi_type ffi_type_uint8;
FFI_EXTERN ffi_type ffi_type_sint8;
@@ -217,8 +220,6 @@ typedef enum {
FFI_BAD_ABI
} ffi_status;
-typedef unsigned FFI_TYPE;
-
typedef struct {
ffi_abi abi;
unsigned nargs;
@@ -231,20 +232,6 @@ typedef struct {
#endif
} ffi_cif;
-#if @HAVE_LONG_DOUBLE_VARIANT@
-/* Used to adjust size/alignment of ffi types. */
-void ffi_prep_types (ffi_abi abi);
-#endif
-
-/* Used internally, but overridden by some architectures */
-ffi_status ffi_prep_cif_core(ffi_cif *cif,
- ffi_abi abi,
- unsigned int isvariadic,
- unsigned int nfixedargs,
- unsigned int ntotalargs,
- ffi_type *rtype,
- ffi_type **atypes);
-
/* ---- Definitions for the raw API -------------------------------------- */
#ifndef FFI_SIZEOF_ARG
@@ -282,27 +269,34 @@ typedef ffi_raw ffi_java_raw;
#endif
+FFI_API
void ffi_raw_call (ffi_cif *cif,
void (*fn)(void),
void *rvalue,
ffi_raw *avalue);
-void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
-void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
-size_t ffi_raw_size (ffi_cif *cif);
+FFI_API void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
+FFI_API void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
+FFI_API size_t ffi_raw_size (ffi_cif *cif);
-/* This is analogous to the raw API, except it uses Java parameter */
-/* packing, even on 64-bit machines. I.e. on 64-bit machines */
-/* longs and doubles are followed by an empty 64-bit word. */
+/* This is analogous to the raw API, except it uses Java parameter
+ packing, even on 64-bit machines. I.e. on 64-bit machines longs
+ and doubles are followed by an empty 64-bit word. */
+#if !FFI_NATIVE_RAW_API
+FFI_API
void ffi_java_raw_call (ffi_cif *cif,
void (*fn)(void),
void *rvalue,
- ffi_java_raw *avalue);
+ ffi_java_raw *avalue) __attribute__((deprecated));
+#endif
-void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw);
-void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args);
-size_t ffi_java_raw_size (ffi_cif *cif);
+FFI_API
+void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw) __attribute__((deprecated));
+FFI_API
+void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) __attribute__((deprecated));
+FFI_API
+size_t ffi_java_raw_size (ffi_cif *cif) __attribute__((deprecated));
/* ---- Definitions for closures ----------------------------------------- */
@@ -321,25 +315,34 @@ typedef struct {
ffi_cif *cif;
void (*fun)(ffi_cif*,void*,void**,void*);
void *user_data;
+} ffi_closure
#ifdef __GNUC__
-} ffi_closure __attribute__((aligned (8)));
-#else
-} ffi_closure;
+ __attribute__((aligned (8)))
+#endif
+ ;
+
+#ifndef __GNUC__
# ifdef __sgi
# pragma pack 0
# endif
#endif
-void *ffi_closure_alloc (size_t size, void **code);
-void ffi_closure_free (void *);
+FFI_API void *ffi_closure_alloc (size_t size, void **code);
+FFI_API void ffi_closure_free (void *);
-ffi_status
+FFI_API ffi_status
ffi_prep_closure (ffi_closure*,
ffi_cif *,
void (*fun)(ffi_cif*,void*,void**,void*),
- void *user_data);
+ void *user_data)
+#if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 405)
+ __attribute__((deprecated ("use ffi_prep_closure_loc instead")))
+#elif defined(__GNUC__) && __GNUC__ >= 3
+ __attribute__((deprecated))
+#endif
+ ;
-ffi_status
+FFI_API ffi_status
ffi_prep_closure_loc (ffi_closure*,
ffi_cif *,
void (*fun)(ffi_cif*,void*,void**,void*),
@@ -360,9 +363,9 @@ typedef struct {
#if !FFI_NATIVE_RAW_API
- /* if this is enabled, then a raw closure has the same layout
+ /* If this is enabled, then a raw closure has the same layout
as a regular closure. We use this to install an intermediate
- handler to do the transaltion, void** -> ffi_raw*. */
+ handler to do the transaltion, void** -> ffi_raw*. */
void (*translate_args)(ffi_cif*,void*,void**,void*);
void *this_closure;
@@ -386,9 +389,9 @@ typedef struct {
#if !FFI_NATIVE_RAW_API
- /* if this is enabled, then a raw closure has the same layout
+ /* If this is enabled, then a raw closure has the same layout
as a regular closure. We use this to install an intermediate
- handler to do the transaltion, void** -> ffi_raw*. */
+ handler to do the translation, void** -> ffi_raw*. */
void (*translate_args)(ffi_cif*,void*,void**,void*);
void *this_closure;
@@ -400,42 +403,62 @@ typedef struct {
} ffi_java_raw_closure;
-ffi_status
+FFI_API ffi_status
ffi_prep_raw_closure (ffi_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data);
-ffi_status
+FFI_API ffi_status
ffi_prep_raw_closure_loc (ffi_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc);
-ffi_status
+#if !FFI_NATIVE_RAW_API
+FFI_API ffi_status
ffi_prep_java_raw_closure (ffi_java_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
- void *user_data);
+ void *user_data) __attribute__((deprecated));
-ffi_status
+FFI_API ffi_status
ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
void *user_data,
- void *codeloc);
+ void *codeloc) __attribute__((deprecated));
+#endif
#endif /* FFI_CLOSURES */
+#if FFI_GO_CLOSURES
+
+typedef struct {
+ void *tramp;
+ ffi_cif *cif;
+ void (*fun)(ffi_cif*,void*,void**,void*);
+} ffi_go_closure;
+
+FFI_API ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
+ void (*fun)(ffi_cif*,void*,void**,void*));
+
+FFI_API void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure);
+
+#endif /* FFI_GO_CLOSURES */
+
/* ---- Public interface definition -------------------------------------- */
+FFI_API
ffi_status ffi_prep_cif(ffi_cif *cif,
ffi_abi abi,
unsigned int nargs,
ffi_type *rtype,
ffi_type **atypes);
+FFI_API
ffi_status ffi_prep_cif_var(ffi_cif *cif,
ffi_abi abi,
unsigned int nfixedargs,
@@ -443,12 +466,17 @@ ffi_status ffi_prep_cif_var(ffi_cif *cif,
ffi_type *rtype,
ffi_type **atypes);
+FFI_API
void ffi_call(ffi_cif *cif,
void (*fn)(void),
void *rvalue,
void **avalue);
-/* Useful for eliminating compiler warnings */
+FFI_API
+ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
+ size_t *offsets);
+
+/* Useful for eliminating compiler warnings. */
#define FFI_FN(f) ((void (*)(void))f)
/* ---- Definitions shared with assembly code ---------------------------- */
@@ -477,7 +505,7 @@ void ffi_call(ffi_cif *cif,
#define FFI_TYPE_POINTER 14
#define FFI_TYPE_COMPLEX 15
-/* This should always refer to the last type code (for sanity checks) */
+/* This should always refer to the last type code (for sanity checks). */
#define FFI_TYPE_LAST FFI_TYPE_COMPLEX
#ifdef __cplusplus
diff --git a/include/ffi_cfi.h b/include/ffi_cfi.h
new file mode 100644
index 00000000..244ce572
--- /dev/null
+++ b/include/ffi_cfi.h
@@ -0,0 +1,55 @@
+/* -----------------------------------------------------------------------
+ ffi_cfi.h - Copyright (c) 2014 Red Hat, Inc.
+
+ Conditionally assemble cfi directives. Only necessary for building libffi.
+ ----------------------------------------------------------------------- */
+
+#ifndef FFI_CFI_H
+#define FFI_CFI_H
+
+#ifdef HAVE_AS_CFI_PSEUDO_OP
+
+# define cfi_startproc .cfi_startproc
+# define cfi_endproc .cfi_endproc
+# define cfi_def_cfa(reg, off) .cfi_def_cfa reg, off
+# define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
+# define cfi_def_cfa_offset(off) .cfi_def_cfa_offset off
+# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
+# define cfi_offset(reg, off) .cfi_offset reg, off
+# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
+# define cfi_register(r1, r2) .cfi_register r1, r2
+# define cfi_return_column(reg) .cfi_return_column reg
+# define cfi_restore(reg) .cfi_restore reg
+# define cfi_same_value(reg) .cfi_same_value reg
+# define cfi_undefined(reg) .cfi_undefined reg
+# define cfi_remember_state .cfi_remember_state
+# define cfi_restore_state .cfi_restore_state
+# define cfi_window_save .cfi_window_save
+# define cfi_personality(enc, exp) .cfi_personality enc, exp
+# define cfi_lsda(enc, exp) .cfi_lsda enc, exp
+# define cfi_escape(...) .cfi_escape __VA_ARGS__
+
+#else
+
+# define cfi_startproc
+# define cfi_endproc
+# define cfi_def_cfa(reg, off)
+# define cfi_def_cfa_register(reg)
+# define cfi_def_cfa_offset(off)
+# define cfi_adjust_cfa_offset(off)
+# define cfi_offset(reg, off)
+# define cfi_rel_offset(reg, off)
+# define cfi_register(r1, r2)
+# define cfi_return_column(reg)
+# define cfi_restore(reg)
+# define cfi_same_value(reg)
+# define cfi_undefined(reg)
+# define cfi_remember_state
+# define cfi_restore_state
+# define cfi_window_save
+# define cfi_personality(enc, exp)
+# define cfi_lsda(enc, exp)
+# define cfi_escape(...)
+
+#endif /* HAVE_AS_CFI_PSEUDO_OP */
+#endif /* FFI_CFI_H */
diff --git a/include/ffi_common.h b/include/ffi_common.h
index 37f5a9e9..76b9dd6f 100644
--- a/include/ffi_common.h
+++ b/include/ffi_common.h
@@ -74,14 +74,35 @@ void ffi_type_test(ffi_type *a, char *file, int line);
#define FFI_ASSERT_VALID_TYPE(x)
#endif
-#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
-#define ALIGN_DOWN(v, a) (((size_t) (v)) & -a)
+/* v cast to size_t and aligned up to a multiple of a */
+#define FFI_ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
+/* v cast to size_t and aligned down to a multiple of a */
+#define FFI_ALIGN_DOWN(v, a) (((size_t) (v)) & -a)
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
unsigned int nfixedargs, unsigned int ntotalargs);
+
+#if HAVE_LONG_DOUBLE_VARIANT
+/* Used to adjust size/alignment of ffi types. */
+void ffi_prep_types (ffi_abi abi);
+#endif
+
+/* Used internally, but overridden by some architectures */
+ffi_status ffi_prep_cif_core(ffi_cif *cif,
+ ffi_abi abi,
+ unsigned int isvariadic,
+ unsigned int nfixedargs,
+ unsigned int ntotalargs,
+ ffi_type *rtype,
+ ffi_type **atypes);
+
+/* Translate a data pointer to a code pointer. Needed for closures on
+ some targets. */
+void *ffi_data_to_code_pointer (void *data) FFI_HIDDEN;
+
/* Extended cif, used in callback from assembly routine */
typedef struct
{
diff --git a/libffi.map.in b/libffi.map.in
new file mode 100644
index 00000000..5553ab02
--- /dev/null
+++ b/libffi.map.in
@@ -0,0 +1,80 @@
+#define LIBFFI_ASM
+#define LIBFFI_H
+#include <fficonfig.h>
+#include <ffitarget.h>
+
+/* These version numbers correspond to the libtool-version abi numbers,
+ not to the libffi release numbers. */
+
+LIBFFI_BASE_7.0 {
+ global:
+ /* Exported data variables. */
+ ffi_type_void;
+ ffi_type_uint8;
+ ffi_type_sint8;
+ ffi_type_uint16;
+ ffi_type_sint16;
+ ffi_type_uint32;
+ ffi_type_sint32;
+ ffi_type_uint64;
+ ffi_type_sint64;
+ ffi_type_float;
+ ffi_type_double;
+ ffi_type_longdouble;
+ ffi_type_pointer;
+
+ /* Exported functions. */
+ ffi_call;
+ ffi_prep_cif;
+ ffi_prep_cif_var;
+
+ ffi_raw_call;
+ ffi_ptrarray_to_raw;
+ ffi_raw_to_ptrarray;
+ ffi_raw_size;
+
+ ffi_java_raw_call;
+ ffi_java_ptrarray_to_raw;
+ ffi_java_raw_to_ptrarray;
+ ffi_java_raw_size;
+
+ local:
+ *;
+};
+
+LIBFFI_BASE_7.1 {
+ global:
+ ffi_get_struct_offsets;
+} LIBFFI_BASE_7.0;
+
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+LIBFFI_COMPLEX_7.0 {
+ global:
+ /* Exported data variables. */
+ ffi_type_complex_float;
+ ffi_type_complex_double;
+ ffi_type_complex_longdouble;
+} LIBFFI_BASE_7.0;
+#endif
+
+#if FFI_CLOSURES
+LIBFFI_CLOSURE_7.0 {
+ global:
+ ffi_closure_alloc;
+ ffi_closure_free;
+ ffi_prep_closure;
+ ffi_prep_closure_loc;
+ ffi_prep_raw_closure;
+ ffi_prep_raw_closure_loc;
+ ffi_prep_java_raw_closure;
+ ffi_prep_java_raw_closure_loc;
+} LIBFFI_BASE_7.0;
+#endif
+
+#if FFI_GO_CLOSURES
+LIBFFI_GO_CLOSURE_7.0 {
+ global:
+ ffi_call_go;
+ ffi_prep_go_closure;
+} LIBFFI_CLOSURE_7.0;
+#endif
diff --git a/libffi.pc.in b/libffi.pc.in
index edf6fde5..6fad83b4 100644
--- a/libffi.pc.in
+++ b/libffi.pc.in
@@ -2,7 +2,7 @@ prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
toolexeclibdir=@toolexeclibdir@
-includedir=${libdir}/@PACKAGE_NAME@-@PACKAGE_VERSION@/include
+includedir=@includedir@
Name: @PACKAGE_NAME@
Description: Library supporting Foreign Function Interfaces
diff --git a/libffi.xcodeproj/project.pbxproj b/libffi.xcodeproj/project.pbxproj
index 1cf396ff..9a107b49 100644
--- a/libffi.xcodeproj/project.pbxproj
+++ b/libffi.xcodeproj/project.pbxproj
@@ -7,6 +7,10 @@
objects = {
/* Begin PBXBuildFile section */
+ 43B5D3F81D35473200D1E1FD /* ffiw64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = 43B5D3F71D35473200D1E1FD /* ffiw64_x86_64.c */; };
+ 43B5D3FA1D3547CE00D1E1FD /* win64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 43B5D3F91D3547CE00D1E1FD /* win64_x86_64.S */; };
+ 43E9A5C71D352C1500926A8F /* sysv_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 43E9A5C51D352C1500926A8F /* sysv_i386.S */; };
+ 43E9A5C81D352C1500926A8F /* unix64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 43E9A5C61D352C1500926A8F /* unix64_x86_64.S */; };
DBFA714A187F1D8600A76262 /* ffi.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA713E187F1D8600A76262 /* ffi.h */; };
DBFA714B187F1D8600A76262 /* ffi_common.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA713F187F1D8600A76262 /* ffi_common.h */; };
DBFA714C187F1D8600A76262 /* fficonfig.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7140187F1D8600A76262 /* fficonfig.h */; };
@@ -23,9 +27,6 @@
DBFA7178187F1D9B00A76262 /* sysv_arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716D187F1D9B00A76262 /* sysv_arm64.S */; };
DBFA7179187F1D9B00A76262 /* ffi_armv7.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716F187F1D9B00A76262 /* ffi_armv7.c */; };
DBFA717A187F1D9B00A76262 /* sysv_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7170187F1D9B00A76262 /* sysv_armv7.S */; };
- DBFA717B187F1D9B00A76262 /* trampoline_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */; };
- DBFA717C187F1D9B00A76262 /* darwin64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */; };
- DBFA717D187F1D9B00A76262 /* darwin_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7174187F1D9B00A76262 /* darwin_i386.S */; };
DBFA717E187F1D9B00A76262 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */; };
DBFA717F187F1D9B00A76262 /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7176187F1D9B00A76262 /* ffi_i386.c */; };
DBFA718E187F1DA100A76262 /* ffi_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7182187F1DA100A76262 /* ffi_i386.h */; };
@@ -34,25 +35,117 @@
DBFA7191187F1DA100A76262 /* fficonfig_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */; };
DBFA7192187F1DA100A76262 /* ffitarget_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7186187F1DA100A76262 /* ffitarget_i386.h */; };
DBFA7193187F1DA100A76262 /* ffitarget_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */; };
- DBFA7194187F1DA100A76262 /* darwin64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */; };
- DBFA7195187F1DA100A76262 /* darwin_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718B187F1DA100A76262 /* darwin_i386.S */; };
+ DBFA7194187F1DA100A76262 /* unix64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718A187F1DA100A76262 /* unix64_x86_64.S */; };
+ DBFA7195187F1DA100A76262 /* sysv_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718B187F1DA100A76262 /* sysv_i386.S */; };
DBFA7196187F1DA100A76262 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */; };
DBFA7197187F1DA100A76262 /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718D187F1DA100A76262 /* ffi_i386.c */; };
+ FDB52FB31F6144FA00AA92E6 /* unix64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 43E9A5C61D352C1500926A8F /* unix64_x86_64.S */; };
+ FDB52FB41F6144FA00AA92E6 /* sysv_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 43E9A5C51D352C1500926A8F /* sysv_i386.S */; };
+ FDB52FB51F6144FA00AA92E6 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */; };
+ FDB52FB61F6144FA00AA92E6 /* ffi_armv7.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716F187F1D9B00A76262 /* ffi_armv7.c */; };
+ FDB52FB71F6144FA00AA92E6 /* closures.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7143187F1D8600A76262 /* closures.c */; };
+ FDB52FB81F6144FA00AA92E6 /* sysv_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7170187F1D9B00A76262 /* sysv_armv7.S */; };
+ FDB52FB91F6144FA00AA92E6 /* ffiw64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = 43B5D3F71D35473200D1E1FD /* ffiw64_x86_64.c */; };
+ FDB52FBA1F6144FA00AA92E6 /* prep_cif.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7147187F1D8600A76262 /* prep_cif.c */; };
+ FDB52FBB1F6144FA00AA92E6 /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7176187F1D9B00A76262 /* ffi_i386.c */; };
+ FDB52FBC1F6144FA00AA92E6 /* raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7148187F1D8600A76262 /* raw_api.c */; };
+ FDB52FBD1F6144FA00AA92E6 /* sysv_arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716D187F1D9B00A76262 /* sysv_arm64.S */; };
+ FDB52FBE1F6144FA00AA92E6 /* types.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7149187F1D8600A76262 /* types.c */; };
+ FDB52FBF1F6144FA00AA92E6 /* ffi_arm64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716C187F1D9B00A76262 /* ffi_arm64.c */; };
+ FDB52FC01F6144FA00AA92E6 /* win64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 43B5D3F91D3547CE00D1E1FD /* win64_x86_64.S */; };
+ FDB52FD01F614A8B00AA92E6 /* ffi.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA713E187F1D8600A76262 /* ffi.h */; };
+ FDB52FD11F614AA700AA92E6 /* ffi_arm64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA715E187F1D9B00A76262 /* ffi_arm64.h */; };
+ FDB52FD21F614AAB00AA92E6 /* ffi_armv7.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA715F187F1D9B00A76262 /* ffi_armv7.h */; };
+ FDB52FD31F614AB000AA92E6 /* ffi_i386.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7160187F1D9B00A76262 /* ffi_i386.h */; };
+ FDB52FD41F614AB500AA92E6 /* ffi_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7161187F1D9B00A76262 /* ffi_x86_64.h */; };
+ FDB52FD51F614AE200AA92E6 /* ffi.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA713E187F1D8600A76262 /* ffi.h */; };
+ FDB52FD61F614AEA00AA92E6 /* ffi_arm64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA715E187F1D9B00A76262 /* ffi_arm64.h */; };
+ FDB52FD71F614AED00AA92E6 /* ffi_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7161187F1D9B00A76262 /* ffi_x86_64.h */; };
+ FDB52FD81F614B8700AA92E6 /* ffitarget.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7141187F1D8600A76262 /* ffitarget.h */; };
+ FDB52FD91F614B8E00AA92E6 /* ffitarget_arm64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7166187F1D9B00A76262 /* ffitarget_arm64.h */; };
+ FDB52FDA1F614B9300AA92E6 /* ffitarget_armv7.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7167187F1D9B00A76262 /* ffitarget_armv7.h */; };
+ FDB52FDB1F614B9700AA92E6 /* ffitarget_i386.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7168187F1D9B00A76262 /* ffitarget_i386.h */; };
+ FDB52FDD1F614BA900AA92E6 /* ffitarget_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7169187F1D9B00A76262 /* ffitarget_x86_64.h */; };
+ FDB52FDE1F6155E300AA92E6 /* ffitarget.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7141187F1D8600A76262 /* ffitarget.h */; };
+ FDB52FDF1F6155EA00AA92E6 /* ffitarget_arm64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7166187F1D9B00A76262 /* ffitarget_arm64.h */; };
+ FDB52FE01F6155EF00AA92E6 /* ffitarget_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7169187F1D9B00A76262 /* ffitarget_x86_64.h */; };
+ FDB52FE21F6156FA00AA92E6 /* ffi.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA713E187F1D8600A76262 /* ffi.h */; };
+ FDB52FE31F61571A00AA92E6 /* ffi_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7183187F1DA100A76262 /* ffi_x86_64.h */; };
+ FDB52FE41F61571D00AA92E6 /* ffitarget.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7141187F1D8600A76262 /* ffitarget.h */; };
+ FDB52FE61F61573100AA92E6 /* ffitarget_x86_64.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */; };
+ FDDB2F411F5D66E200EF414E /* ffiw64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB2F3F1F5D666900EF414E /* ffiw64_x86_64.c */; };
+ FDDB2F461F5D691E00EF414E /* win64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = FDDB2F441F5D68C900EF414E /* win64_x86_64.S */; };
+ FDDB2F4A1F5D846400EF414E /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */; };
+ FDDB2F4B1F5D846400EF414E /* sysv_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718B187F1DA100A76262 /* sysv_i386.S */; };
+ FDDB2F4C1F5D846400EF414E /* prep_cif.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7147187F1D8600A76262 /* prep_cif.c */; };
+ FDDB2F4D1F5D846400EF414E /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718D187F1DA100A76262 /* ffi_i386.c */; };
+ FDDB2F4E1F5D846400EF414E /* ffiw64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB2F3F1F5D666900EF414E /* ffiw64_x86_64.c */; };
+ FDDB2F4F1F5D846400EF414E /* types.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7149187F1D8600A76262 /* types.c */; };
+ FDDB2F501F5D846400EF414E /* raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7148187F1D8600A76262 /* raw_api.c */; };
+ FDDB2F511F5D846400EF414E /* closures.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7143187F1D8600A76262 /* closures.c */; };
+ FDDB2F521F5D846400EF414E /* unix64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718A187F1DA100A76262 /* unix64_x86_64.S */; };
+ FDDB2F531F5D846400EF414E /* win64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = FDDB2F441F5D68C900EF414E /* win64_x86_64.S */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
DB13B1641849DF1E0010F42D /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
+ buildActionMask = 12;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
+ FDB52FD01F614A8B00AA92E6 /* ffi.h in CopyFiles */,
+ FDB52FD11F614AA700AA92E6 /* ffi_arm64.h in CopyFiles */,
+ FDB52FD21F614AAB00AA92E6 /* ffi_armv7.h in CopyFiles */,
+ FDB52FD31F614AB000AA92E6 /* ffi_i386.h in CopyFiles */,
+ FDB52FD41F614AB500AA92E6 /* ffi_x86_64.h in CopyFiles */,
+ FDB52FD81F614B8700AA92E6 /* ffitarget.h in CopyFiles */,
+ FDB52FD91F614B8E00AA92E6 /* ffitarget_arm64.h in CopyFiles */,
+ FDB52FDA1F614B9300AA92E6 /* ffitarget_armv7.h in CopyFiles */,
+ FDB52FDB1F614B9700AA92E6 /* ffitarget_i386.h in CopyFiles */,
+ FDB52FDD1F614BA900AA92E6 /* ffitarget_x86_64.h in CopyFiles */,
);
- runOnlyForDeploymentPostprocessing = 1;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDB52FC11F6144FA00AA92E6 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 12;
+ dstPath = "include/$(PRODUCT_NAME)";
+ dstSubfolderSpec = 16;
+ files = (
+ FDB52FD51F614AE200AA92E6 /* ffi.h in CopyFiles */,
+ FDB52FD61F614AEA00AA92E6 /* ffi_arm64.h in CopyFiles */,
+ FDB52FD71F614AED00AA92E6 /* ffi_x86_64.h in CopyFiles */,
+ FDB52FDE1F6155E300AA92E6 /* ffitarget.h in CopyFiles */,
+ FDB52FDF1F6155EA00AA92E6 /* ffitarget_arm64.h in CopyFiles */,
+ FDB52FE01F6155EF00AA92E6 /* ffitarget_x86_64.h in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDB52FE11F6156E000AA92E6 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "include/$(PRODUCT_NAME)";
+ dstSubfolderSpec = 16;
+ files = (
+ FDB52FE21F6156FA00AA92E6 /* ffi.h in CopyFiles */,
+ FDB52FE31F61571A00AA92E6 /* ffi_x86_64.h in CopyFiles */,
+ FDB52FE41F61571D00AA92E6 /* ffitarget.h in CopyFiles */,
+ FDB52FE61F61573100AA92E6 /* ffitarget_x86_64.h in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 43B5D3F71D35473200D1E1FD /* ffiw64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffiw64_x86_64.c; sourceTree = "<group>"; };
+ 43B5D3F91D3547CE00D1E1FD /* win64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = win64_x86_64.S; sourceTree = "<group>"; };
+ 43E9A5C51D352C1500926A8F /* sysv_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_i386.S; sourceTree = "<group>"; };
+ 43E9A5C61D352C1500926A8F /* unix64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = unix64_x86_64.S; sourceTree = "<group>"; };
+ 43E9A5DA1D35373600926A8F /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
+ 43E9A5DB1D35374400926A8F /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
+ 43E9A5DC1D35375400926A8F /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
+ 43E9A5DD1D35375400926A8F /* internal64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal64.h; sourceTree = "<group>"; };
DB13B1661849DF1E0010F42D /* libffi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; };
DB13B1911849DF510010F42D /* ffi.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = ffi.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
DBFA713E187F1D8600A76262 /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = "<group>"; };
@@ -76,13 +169,10 @@
DBFA7167187F1D9B00A76262 /* ffitarget_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_armv7.h; sourceTree = "<group>"; };
DBFA7168187F1D9B00A76262 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = "<group>"; };
DBFA7169187F1D9B00A76262 /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = "<group>"; };
- DBFA716C187F1D9B00A76262 /* ffi_arm64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_arm64.c; sourceTree = "<group>"; };
+ DBFA716C187F1D9B00A76262 /* ffi_arm64.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = ffi_arm64.c; sourceTree = "<group>"; };
DBFA716D187F1D9B00A76262 /* sysv_arm64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_arm64.S; sourceTree = "<group>"; };
- DBFA716F187F1D9B00A76262 /* ffi_armv7.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_armv7.c; sourceTree = "<group>"; };
+ DBFA716F187F1D9B00A76262 /* ffi_armv7.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = ffi_armv7.c; sourceTree = "<group>"; };
DBFA7170187F1D9B00A76262 /* sysv_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_armv7.S; sourceTree = "<group>"; };
- DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = trampoline_armv7.S; sourceTree = "<group>"; };
- DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64_x86_64.S; sourceTree = "<group>"; };
- DBFA7174187F1D9B00A76262 /* darwin_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin_i386.S; sourceTree = "<group>"; };
DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = "<group>"; };
DBFA7176187F1D9B00A76262 /* ffi_i386.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_i386.c; sourceTree = "<group>"; };
DBFA7182187F1DA100A76262 /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = "<group>"; };
@@ -91,10 +181,17 @@
DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_x86_64.h; sourceTree = "<group>"; };
DBFA7186187F1DA100A76262 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = "<group>"; };
DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = "<group>"; };
- DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64_x86_64.S; sourceTree = "<group>"; };
- DBFA718B187F1DA100A76262 /* darwin_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin_i386.S; sourceTree = "<group>"; };
- DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = "<group>"; };
+ DBFA718A187F1DA100A76262 /* unix64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = unix64_x86_64.S; sourceTree = "<group>"; };
+ DBFA718B187F1DA100A76262 /* sysv_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_i386.S; sourceTree = "<group>"; };
+ DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = "<group>"; };
DBFA718D187F1DA100A76262 /* ffi_i386.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_i386.c; sourceTree = "<group>"; };
+ FDB52FC51F6144FA00AA92E6 /* libffi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDDB2F3E1F5D61BC00EF414E /* asmnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asmnames.h; sourceTree = "<group>"; };
+ FDDB2F3F1F5D666900EF414E /* ffiw64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffiw64_x86_64.c; sourceTree = "<group>"; };
+ FDDB2F421F5D68C900EF414E /* internal64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal64.h; sourceTree = "<group>"; };
+ FDDB2F431F5D68C900EF414E /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
+ FDDB2F441F5D68C900EF414E /* win64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = win64_x86_64.S; sourceTree = "<group>"; };
+ FDDB2F621F5D846400EF414E /* libffi.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
@@ -113,6 +210,8 @@
children = (
DB13B1661849DF1E0010F42D /* libffi.a */,
DB13B1911849DF510010F42D /* ffi.dylib */,
+ FDDB2F621F5D846400EF414E /* libffi.a */,
+ FDB52FC51F6144FA00AA92E6 /* libffi.a */,
);
name = Products;
sourceTree = "<group>";
@@ -123,7 +222,7 @@
DBFA713D187F1D8600A76262 /* include */,
DBFA7142187F1D8600A76262 /* src */,
);
- path = "darwin_common";
+ path = darwin_common;
sourceTree = "<group>";
};
DBFA713D187F1D8600A76262 /* include */ = {
@@ -155,7 +254,7 @@
DBFA715D187F1D9B00A76262 /* include */,
DBFA716A187F1D9B00A76262 /* src */,
);
- path = "darwin_ios";
+ path = darwin_ios;
sourceTree = "<group>";
};
DBFA715D187F1D9B00A76262 /* include */ = {
@@ -190,6 +289,7 @@
DBFA716B187F1D9B00A76262 /* aarch64 */ = {
isa = PBXGroup;
children = (
+ 43E9A5DA1D35373600926A8F /* internal.h */,
DBFA716C187F1D9B00A76262 /* ffi_arm64.c */,
DBFA716D187F1D9B00A76262 /* sysv_arm64.S */,
);
@@ -199,9 +299,9 @@
DBFA716E187F1D9B00A76262 /* arm */ = {
isa = PBXGroup;
children = (
+ 43E9A5DB1D35374400926A8F /* internal.h */,
DBFA716F187F1D9B00A76262 /* ffi_armv7.c */,
DBFA7170187F1D9B00A76262 /* sysv_armv7.S */,
- DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */,
);
path = arm;
sourceTree = "<group>";
@@ -209,10 +309,14 @@
DBFA7172187F1D9B00A76262 /* x86 */ = {
isa = PBXGroup;
children = (
- DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */,
- DBFA7174187F1D9B00A76262 /* darwin_i386.S */,
+ 43E9A5DC1D35375400926A8F /* internal.h */,
+ 43E9A5DD1D35375400926A8F /* internal64.h */,
DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */,
+ 43B5D3F71D35473200D1E1FD /* ffiw64_x86_64.c */,
DBFA7176187F1D9B00A76262 /* ffi_i386.c */,
+ 43E9A5C51D352C1500926A8F /* sysv_i386.S */,
+ 43E9A5C61D352C1500926A8F /* unix64_x86_64.S */,
+ 43B5D3F91D3547CE00D1E1FD /* win64_x86_64.S */,
);
path = x86;
sourceTree = "<group>";
@@ -223,7 +327,7 @@
DBFA7181187F1DA100A76262 /* include */,
DBFA7188187F1DA100A76262 /* src */,
);
- path = "darwin_osx";
+ path = darwin_osx;
sourceTree = "<group>";
};
DBFA7181187F1DA100A76262 /* include */ = {
@@ -250,10 +354,15 @@
DBFA7189187F1DA100A76262 /* x86 */ = {
isa = PBXGroup;
children = (
- DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */,
- DBFA718B187F1DA100A76262 /* darwin_i386.S */,
+ FDDB2F431F5D68C900EF414E /* internal.h */,
+ FDDB2F421F5D68C900EF414E /* internal64.h */,
+ FDDB2F3E1F5D61BC00EF414E /* asmnames.h */,
DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */,
+ FDDB2F3F1F5D666900EF414E /* ffiw64_x86_64.c */,
DBFA718D187F1DA100A76262 /* ffi_i386.c */,
+ DBFA718B187F1DA100A76262 /* sysv_i386.S */,
+ DBFA718A187F1DA100A76262 /* unix64_x86_64.S */,
+ FDDB2F441F5D68C900EF414E /* win64_x86_64.S */,
);
path = x86;
sourceTree = "<group>";
@@ -285,7 +394,7 @@
isa = PBXNativeTarget;
buildConfigurationList = DB13B18B1849DF1E0010F42D /* Build configuration list for PBXNativeTarget "libffi-iOS" */;
buildPhases = (
- DB13B3051849E01C0010F42D /* ShellScript */,
+ 43B5D3FB1D35480D00D1E1FD /* Run Script */,
DB13B1621849DF1E0010F42D /* Sources */,
DB13B1641849DF1E0010F42D /* CopyFiles */,
);
@@ -315,13 +424,47 @@
productReference = DB13B1911849DF510010F42D /* ffi.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
+ FDB52FB01F6144FA00AA92E6 /* libffi-tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDB52FC21F6144FA00AA92E6 /* Build configuration list for PBXNativeTarget "libffi-tvOS" */;
+ buildPhases = (
+ FDB52FB11F6144FA00AA92E6 /* Run Script */,
+ FDB52FB21F6144FA00AA92E6 /* Sources */,
+ FDB52FC11F6144FA00AA92E6 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "libffi-tvOS";
+ productName = ffi;
+ productReference = FDB52FC51F6144FA00AA92E6 /* libffi.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ FDDB2F471F5D846400EF414E /* libffi-static-Mac */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDDB2F5F1F5D846400EF414E /* Build configuration list for PBXNativeTarget "libffi-static-Mac" */;
+ buildPhases = (
+ FDDB2F481F5D846400EF414E /* ShellScript */,
+ FDDB2F491F5D846400EF414E /* Sources */,
+ FDB52FE11F6156E000AA92E6 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "libffi-static-Mac";
+ productName = ffi;
+ productReference = FDDB2F621F5D846400EF414E /* libffi.a */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
DB13B15C1849DEB70010F42D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0510;
+ LastUpgradeCheck = 0830;
};
buildConfigurationList = DB13B15F1849DEB70010F42D /* Build configuration list for PBXProject "libffi" */;
compatibilityVersion = "Xcode 3.2";
@@ -336,24 +479,27 @@
projectRoot = "";
targets = (
DB13B1651849DF1E0010F42D /* libffi-iOS */,
+ FDB52FB01F6144FA00AA92E6 /* libffi-tvOS */,
DB13B1901849DF510010F42D /* libffi-Mac */,
+ FDDB2F471F5D846400EF414E /* libffi-static-Mac */,
);
};
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
- DB13B3051849E01C0010F42D /* ShellScript */ = {
+ 43B5D3FB1D35480D00D1E1FD /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
+ name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "/usr/bin/python generate-darwin-source-and-headers.py --only-ios";
+ shellScript = "if [ ! -f \"./compile\" ]\nthen\nautoreconf -i -f -v\nif [ -f \"../ltmain.sh\" ]\nthen\necho \"fixing ltmain.sh for some reason\"\nmv ../ltmain.sh ./\nautoreconf -i -f -v\nfi\n/usr/bin/python generate-darwin-source-and-headers.py --only-ios\nfi";
};
DB13B3061849E0490010F42D /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
@@ -366,7 +512,34 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "/usr/bin/python generate-darwin-source-and-headers.py --only-osx";
+ shellScript = "if [ ! -f \"./compile\" ]\nthen\nautoreconf -i -f -v\nif [ -f \"../ltmain.sh\" ]\nthen\necho \"fixing ltmain.sh for some reason\"\nmv ../ltmain.sh ./\nautoreconf -i -f -v\nfi\n/usr/bin/python generate-darwin-source-and-headers.py --only-osx\nfi";
+ };
+ FDB52FB11F6144FA00AA92E6 /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ ! -f \"./compile\" ]\nthen\nautoreconf -i -f -v\nif [ -f \"../ltmain.sh\" ]\nthen\necho \"fixing ltmain.sh for some reason\"\nmv ../ltmain.sh ./\nautoreconf -i -f -v\nfi\n/usr/bin/python generate-darwin-source-and-headers.py --only-ios\nfi";
+ };
+ FDDB2F481F5D846400EF414E /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ ! -f \"./compile\" ]\nthen\nautoreconf -i -f -v\nif [ -f \"../ltmain.sh\" ]\nthen\necho \"fixing ltmain.sh for some reason\"\nmv ../ltmain.sh ./\nautoreconf -i -f -v\nfi\n/usr/bin/python generate-darwin-source-and-headers.py --only-osx\nfi";
};
/* End PBXShellScriptBuildPhase section */
@@ -375,19 +548,20 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 43E9A5C81D352C1500926A8F /* unix64_x86_64.S in Sources */,
+ 43E9A5C71D352C1500926A8F /* sysv_i386.S in Sources */,
DBFA717E187F1D9B00A76262 /* ffi64_x86_64.c in Sources */,
DBFA7179187F1D9B00A76262 /* ffi_armv7.c in Sources */,
- DBFA717B187F1D9B00A76262 /* trampoline_armv7.S in Sources */,
DBFA714E187F1D8600A76262 /* closures.c in Sources */,
DBFA717A187F1D9B00A76262 /* sysv_armv7.S in Sources */,
- DBFA717D187F1D9B00A76262 /* darwin_i386.S in Sources */,
+ 43B5D3F81D35473200D1E1FD /* ffiw64_x86_64.c in Sources */,
DBFA7156187F1D8600A76262 /* prep_cif.c in Sources */,
DBFA717F187F1D9B00A76262 /* ffi_i386.c in Sources */,
DBFA7158187F1D8600A76262 /* raw_api.c in Sources */,
DBFA7178187F1D9B00A76262 /* sysv_arm64.S in Sources */,
- DBFA717C187F1D9B00A76262 /* darwin64_x86_64.S in Sources */,
DBFA715A187F1D8600A76262 /* types.c in Sources */,
DBFA7177187F1D9B00A76262 /* ffi_arm64.c in Sources */,
+ 43B5D3FA1D3547CE00D1E1FD /* win64_x86_64.S in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -396,13 +570,53 @@
buildActionMask = 2147483647;
files = (
DBFA7196187F1DA100A76262 /* ffi64_x86_64.c in Sources */,
- DBFA7195187F1DA100A76262 /* darwin_i386.S in Sources */,
+ DBFA7195187F1DA100A76262 /* sysv_i386.S in Sources */,
DBFA7157187F1D8600A76262 /* prep_cif.c in Sources */,
DBFA7197187F1DA100A76262 /* ffi_i386.c in Sources */,
+ FDDB2F411F5D66E200EF414E /* ffiw64_x86_64.c in Sources */,
DBFA715B187F1D8600A76262 /* types.c in Sources */,
DBFA7159187F1D8600A76262 /* raw_api.c in Sources */,
DBFA714F187F1D8600A76262 /* closures.c in Sources */,
- DBFA7194187F1DA100A76262 /* darwin64_x86_64.S in Sources */,
+ DBFA7194187F1DA100A76262 /* unix64_x86_64.S in Sources */,
+ FDDB2F461F5D691E00EF414E /* win64_x86_64.S in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDB52FB21F6144FA00AA92E6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDB52FB31F6144FA00AA92E6 /* unix64_x86_64.S in Sources */,
+ FDB52FB41F6144FA00AA92E6 /* sysv_i386.S in Sources */,
+ FDB52FB51F6144FA00AA92E6 /* ffi64_x86_64.c in Sources */,
+ FDB52FB61F6144FA00AA92E6 /* ffi_armv7.c in Sources */,
+ FDB52FB71F6144FA00AA92E6 /* closures.c in Sources */,
+ FDB52FB81F6144FA00AA92E6 /* sysv_armv7.S in Sources */,
+ FDB52FB91F6144FA00AA92E6 /* ffiw64_x86_64.c in Sources */,
+ FDB52FBA1F6144FA00AA92E6 /* prep_cif.c in Sources */,
+ FDB52FBB1F6144FA00AA92E6 /* ffi_i386.c in Sources */,
+ FDB52FBC1F6144FA00AA92E6 /* raw_api.c in Sources */,
+ FDB52FBD1F6144FA00AA92E6 /* sysv_arm64.S in Sources */,
+ FDB52FBE1F6144FA00AA92E6 /* types.c in Sources */,
+ FDB52FBF1F6144FA00AA92E6 /* ffi_arm64.c in Sources */,
+ FDB52FC01F6144FA00AA92E6 /* win64_x86_64.S in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDDB2F491F5D846400EF414E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDDB2F4A1F5D846400EF414E /* ffi64_x86_64.c in Sources */,
+ FDDB2F4B1F5D846400EF414E /* sysv_i386.S in Sources */,
+ FDDB2F4C1F5D846400EF414E /* prep_cif.c in Sources */,
+ FDDB2F4D1F5D846400EF414E /* ffi_i386.c in Sources */,
+ FDDB2F4E1F5D846400EF414E /* ffiw64_x86_64.c in Sources */,
+ FDDB2F4F1F5D846400EF414E /* types.c in Sources */,
+ FDDB2F501F5D846400EF414E /* raw_api.c in Sources */,
+ FDDB2F511F5D846400EF414E /* closures.c in Sources */,
+ FDDB2F521F5D846400EF414E /* unix64_x86_64.S in Sources */,
+ FDDB2F531F5D846400EF414E /* win64_x86_64.S in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -412,9 +626,27 @@
DB13B1601849DEB70010F42D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
- "darwin_common/include",
+ darwin_common/include,
);
ONLY_ACTIVE_ARCH = YES;
};
@@ -423,9 +655,26 @@
DB13B1611849DEB70010F42D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
- "darwin_common/include",
+ darwin_common/include,
);
};
name = Release;
@@ -434,11 +683,6 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
@@ -449,14 +693,11 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DSTROOT = /tmp/ffi.dst;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -465,14 +706,13 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
- "darwin_ios/include",
+ darwin_ios/include,
);
- IPHONEOS_DEPLOYMENT_TARGET = 5.0;
- "IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0;
- OTHER_LDFLAGS = "-ObjC";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
PRODUCT_NAME = ffi;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
+ VALID_ARCHS = "arm64 armv7 armv7s i386 x86_64";
};
name = Debug;
};
@@ -480,11 +720,6 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
@@ -496,7 +731,6 @@
COPY_PHASE_STRIP = YES;
DSTROOT = /tmp/ffi.dst;
ENABLE_NS_ASSERTIONS = NO;
- GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -505,15 +739,14 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
- "darwin_ios/include",
+ darwin_ios/include,
);
- IPHONEOS_DEPLOYMENT_TARGET = 5.0;
- "IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0;
- OTHER_LDFLAGS = "-ObjC";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
PRODUCT_NAME = ffi;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
VALIDATE_PRODUCT = YES;
+ VALID_ARCHS = "arm64 armv7 armv7s i386 x86_64";
};
name = Release;
};
@@ -532,6 +765,7 @@
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -552,7 +786,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
- "darwin_osx/include",
+ darwin_osx/include,
);
MACOSX_DEPLOYMENT_TARGET = 10.6;
ONLY_ACTIVE_ARCH = YES;
@@ -577,6 +811,7 @@
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -592,7 +827,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
- "darwin_osx/include",
+ darwin_osx/include,
);
MACOSX_DEPLOYMENT_TARGET = 10.6;
OTHER_LDFLAGS = "-Wl,-no_compact_unwind";
@@ -601,6 +836,159 @@
};
name = Release;
};
+ FDB52FC31F6144FA00AA92E6 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ darwin_ios/include,
+ );
+ PRODUCT_NAME = ffi;
+ SDKROOT = appletvos;
+ SKIP_INSTALL = YES;
+ TVOS_DEPLOYMENT_TARGET = 9.0;
+ };
+ name = Debug;
+ };
+ FDB52FC41F6144FA00AA92E6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ darwin_ios/include,
+ );
+ PRODUCT_NAME = ffi;
+ SDKROOT = appletvos;
+ SKIP_INSTALL = YES;
+ TVOS_DEPLOYMENT_TARGET = 9.0;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ FDDB2F601F5D846400EF414E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = NO;
+ EXECUTABLE_EXTENSION = a;
+ EXECUTABLE_PREFIX = lib;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ darwin_osx/include,
+ );
+ MACH_O_TYPE = staticlib;
+ MACOSX_DEPLOYMENT_TARGET = 10.6;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = ffi;
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ FDDB2F611F5D846400EF414E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ EXECUTABLE_EXTENSION = a;
+ EXECUTABLE_PREFIX = lib;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ darwin_osx/include,
+ );
+ MACH_O_TYPE = staticlib;
+ MACOSX_DEPLOYMENT_TARGET = 10.6;
+ PRODUCT_NAME = ffi;
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -631,6 +1019,24 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ FDB52FC21F6144FA00AA92E6 /* Build configuration list for PBXNativeTarget "libffi-tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDB52FC31F6144FA00AA92E6 /* Debug */,
+ FDB52FC41F6144FA00AA92E6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDDB2F5F1F5D846400EF414E /* Build configuration list for PBXNativeTarget "libffi-static-Mac" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDDB2F601F5D846400EF414E /* Debug */,
+ FDDB2F611F5D846400EF414E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = DB13B15C1849DEB70010F42D /* Project object */;
diff --git a/libtool-version b/libtool-version
index 149a51a2..e4f5aa20 100644
--- a/libtool-version
+++ b/libtool-version
@@ -26,4 +26,4 @@
# release, then set age to 0.
#
# CURRENT:REVISION:AGE
-6:4:0
+8:0:1
diff --git a/linux-arm/fficonfig.h b/linux-arm/fficonfig.h
index 1055e03f..4bc40c82 100644
--- a/linux-arm/fficonfig.h
+++ b/linux-arm/fficonfig.h
@@ -41,7 +41,7 @@
#define HAVE_DLFCN_H 1
/* Define if __attribute__((visibility("hidden"))) is supported. */
-#undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+#define HAVE_HIDDEN_VISIBILITY_ATTRIBUTE 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
@@ -146,7 +146,11 @@
#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
#ifdef LIBFFI_ASM
+#ifdef __APPLE__
+#define FFI_HIDDEN(name) .private_extern name
+#else
#define FFI_HIDDEN(name) .hidden name
+#endif
#else
#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
#endif
diff --git a/linux-arm64/fficonfig.h b/linux-arm64/fficonfig.h
index 1055e03f..4bc40c82 100644
--- a/linux-arm64/fficonfig.h
+++ b/linux-arm64/fficonfig.h
@@ -41,7 +41,7 @@
#define HAVE_DLFCN_H 1
/* Define if __attribute__((visibility("hidden"))) is supported. */
-#undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+#define HAVE_HIDDEN_VISIBILITY_ATTRIBUTE 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
@@ -146,7 +146,11 @@
#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
#ifdef LIBFFI_ASM
+#ifdef __APPLE__
+#define FFI_HIDDEN(name) .private_extern name
+#else
#define FFI_HIDDEN(name) .hidden name
+#endif
#else
#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
#endif
diff --git a/linux-x86/ffi.h b/linux-x86/ffi.h
index 5717a82f..f11ee39e 100644
--- a/linux-x86/ffi.h
+++ b/linux-x86/ffi.h
@@ -15,7 +15,7 @@
*/
#ifndef LIBFFI_H
-#define X86 1
+#define X86_64 1
#define CONF_HAVE_LONG_DOUBLE 1
#define LIBFFI_H
diff --git a/linux-x86/fficonfig.h b/linux-x86/fficonfig.h
index 939ef310..5b3aa8b3 100644
--- a/linux-x86/fficonfig.h
+++ b/linux-x86/fficonfig.h
@@ -9,7 +9,7 @@
#undef C_ALLOCA
/* Define to the flags needed for the .section .eh_frame directive. */
-#define EH_FRAME_FLAGS "aw"
+#define EH_FRAME_FLAGS "a"
/* Define this if you want extra debugging. */
#undef FFI_DEBUG
@@ -41,7 +41,7 @@
#define HAVE_DLFCN_H 1
/* Define if __attribute__((visibility("hidden"))) is supported. */
-#undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+#define HAVE_HIDDEN_VISIBILITY_ATTRIBUTE 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
@@ -68,7 +68,7 @@
#define HAVE_MMAP_FILE 1
/* Define if .eh_frame sections should be read-only. */
-#undef HAVE_RO_EH_FRAME
+#define HAVE_RO_EH_FRAME 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
@@ -146,7 +146,11 @@
#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
#ifdef LIBFFI_ASM
+#ifdef __APPLE__
+#define FFI_HIDDEN(name) .private_extern name
+#else
#define FFI_HIDDEN(name) .hidden name
+#endif
#else
#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
#endif
diff --git a/m4/asmcfi.m4 b/m4/asmcfi.m4
index dbf73a0b..3e286022 100644
--- a/m4/asmcfi.m4
+++ b/m4/asmcfi.m4
@@ -2,7 +2,7 @@ AC_DEFUN([GCC_AS_CFI_PSEUDO_OP],
[AC_CACHE_CHECK([assembler .cfi pseudo-op support],
gcc_cv_as_cfi_pseudo_op, [
gcc_cv_as_cfi_pseudo_op=unknown
- AC_TRY_COMPILE([asm (".cfi_startproc\n\t.cfi_endproc");],,
+ AC_TRY_COMPILE([asm (".cfi_sections\n\t.cfi_startproc\n\t.cfi_endproc");],,
[gcc_cv_as_cfi_pseudo_op=yes],
[gcc_cv_as_cfi_pseudo_op=no])
])
diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4
index 1d38b76f..dd6d8b61 100644
--- a/m4/ax_append_flag.m4
+++ b/m4/ax_append_flag.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html
+# https://www.gnu.org/software/autoconf-archive/ax_append_flag.html
# ===========================================================================
#
# SYNOPSIS
@@ -23,47 +23,28 @@
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
-#serial 2
+#serial 8
AC_DEFUN([AX_APPEND_FLAG],
-[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
-AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl
-AS_VAR_SET_IF(FLAGS,
- [case " AS_VAR_GET(FLAGS) " in
- *" $1 "*)
- AC_RUN_LOG([: FLAGS already contains $1])
- ;;
- *)
- AC_RUN_LOG([: FLAGS="$FLAGS $1"])
- AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"])
- ;;
- esac],
- [AS_VAR_SET(FLAGS,["$1"])])
+[dnl
+AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
+AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
+AS_VAR_SET_IF(FLAGS,[
+ AS_CASE([" AS_VAR_GET(FLAGS) "],
+ [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
+ [
+ AS_VAR_APPEND(FLAGS,[" $1"])
+ AC_RUN_LOG([: FLAGS="$FLAGS"])
+ ])
+ ],
+ [
+ AS_VAR_SET(FLAGS,[$1])
+ AC_RUN_LOG([: FLAGS="$FLAGS"])
+ ])
AS_VAR_POPDEF([FLAGS])dnl
])dnl AX_APPEND_FLAG
diff --git a/m4/ax_cc_maxopt.m4 b/m4/ax_cc_maxopt.m4
index 62e3b533..9e7f1ee4 100644
--- a/m4/ax_cc_maxopt.m4
+++ b/m4/ax_cc_maxopt.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_cc_maxopt.html
+# https://www.gnu.org/software/autoconf-archive/ax_cc_maxopt.html
# ===========================================================================
#
# SYNOPSIS
@@ -40,7 +40,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
+# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -55,7 +55,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 13
+#serial 17
AC_DEFUN([AX_CC_MAXOPT],
[
@@ -115,11 +115,19 @@ if test "$ac_test_CFLAGS" != "set"; then
AX_GCC_X86_CPUID(0)
AX_GCC_X86_CPUID(1)
case $ax_cv_gcc_x86_cpuid_0 in # see AX_GCC_ARCHFLAG
- *:756e6547:*:*) # Intel
+ *:756e6547:6c65746e:49656e69) # Intel
case $ax_cv_gcc_x86_cpuid_1 in
- *6a?:*[[234]]:*:*|*6[[789b]]?:*:*:*) icc_flags="-xK";;
- *f3[[347]]:*:*:*|*f4[1347]:*:*:*) icc_flags="-xP -xN -xW -xK";;
- *f??:*:*:*) icc_flags="-xN -xW -xK";;
+ *0?6[[78ab]]?:*:*:*|?6[[78ab]]?:*:*:*|6[[78ab]]?:*:*:*) icc_flags="-xK" ;;
+ *0?6[[9d]]?:*:*:*|?6[[9d]]?:*:*:*|6[[9d]]?:*:*:*|*1?65?:*:*:*) icc_flags="-xSSE2 -xB -xK" ;;
+ *0?6e?:*:*:*|?6e?:*:*:*|6e?:*:*:*) icc_flags="-xSSE3 -xP -xO -xB -xK" ;;
+ *0?6f?:*:*:*|?6f?:*:*:*|6f?:*:*:*|*1?66?:*:*:*) icc_flags="-xSSSE3 -xT -xB -xK" ;;
+ *1?6[[7d]]?:*:*:*) icc_flags="-xSSE4.1 -xS -xT -xB -xK" ;;
+ *1?6[[aef]]?:*:*:*|*2?6[[5cef]]?:*:*:*) icc_flags="-xSSE4.2 -xS -xT -xB -xK" ;;
+ *2?6[[ad]]?:*:*:*) icc_flags="-xAVX -SSE4.2 -xS -xT -xB -xK" ;;
+ *3?6[[ae]]?:*:*:*) icc_flags="-xCORE-AVX-I -xAVX -SSE4.2 -xS -xT -xB -xK" ;;
+ *3?6[[cf]]?:*:*:*|*4?6[[56]]?:*:*:*) icc_flags="-xCORE-AVX2 -xCORE-AVX-I -xAVX -SSE4.2 -xS -xT -xB -xK" ;;
+ *000?f[[346]]?:*:*:*|?f[[346]]?:*:*:*|f[[346]]?:*:*:*) icc_flags="-xSSE3 -xP -xO -xN -xW -xK" ;;
+ *00??f??:*:*:*|??f??:*:*:*|?f??:*:*:*|f??:*:*:*) icc_flags="-xSSE2 -xN -xW -xK" ;;
esac ;;
esac ;;
esac
@@ -141,7 +149,7 @@ if test "$ac_test_CFLAGS" != "set"; then
CFLAGS="-O3 -fomit-frame-pointer"
# -malign-double for x86 systems
- # LIBFFI -- DON'T DO THIS - CHANGES ABI
+ # libffi local change -- don't align double, as it changes the ABI
# AX_CHECK_COMPILE_FLAG(-malign-double, CFLAGS="$CFLAGS -malign-double")
# -fstrict-aliasing for gcc-2.95+
@@ -153,6 +161,11 @@ if test "$ac_test_CFLAGS" != "set"; then
AX_GCC_ARCHFLAG($acx_maxopt_portable)
;;
+
+ microsoft)
+ # default optimization flags for MSVC opt builds
+ CFLAGS="-O2"
+ ;;
esac
if test -z "$CFLAGS"; then
diff --git a/m4/ax_cflags_warn_all.m4 b/m4/ax_cflags_warn_all.m4
index 0fa3e186..094577e4 100644
--- a/m4/ax_cflags_warn_all.m4
+++ b/m4/ax_cflags_warn_all.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html
+# https://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html
# ===========================================================================
#
# SYNOPSIS
@@ -43,7 +43,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
+# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -58,7 +58,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 14
+#serial 16
AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl
AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl
@@ -84,7 +84,7 @@ done
FLAGS="$ac_save_[]FLAGS"
])
AS_VAR_POPDEF([FLAGS])dnl
-AC_REQUIRE([AX_APPEND_FLAG])
+AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
case ".$VAR" in
.ok|.ok,*) m4_ifvaln($3,$3) ;;
.|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;;
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
index c3a8d695..bd753b34 100644
--- a/m4/ax_check_compile_flag.m4
+++ b/m4/ax_check_compile_flag.m4
@@ -1,10 +1,10 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
+# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
-# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS])
+# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
@@ -19,6 +19,8 @@
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
+# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
@@ -27,45 +29,24 @@
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
-#serial 2
+#serial 6
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
-[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+ AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
-AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
+AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
diff --git a/m4/ax_compiler_vendor.m4 b/m4/ax_compiler_vendor.m4
index 73e32ea9..73efdb00 100644
--- a/m4/ax_compiler_vendor.m4
+++ b/m4/ax_compiler_vendor.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html
+# https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html
# ===========================================================================
#
# SYNOPSIS
@@ -29,7 +29,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
+# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -44,22 +44,25 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 11
+#serial 17
AC_DEFUN([AX_COMPILER_VENDOR],
[AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
+ dnl Please add if possible support to ax_compiler_version.m4
[# note: don't check for gcc first since some other compilers define __GNUC__
vendors="intel: __ICC,__ECC,__INTEL_COMPILER
ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__
pathscale: __PATHCC__,__PATHSCALE__
clang: __clang__
+ cray: _CRAYC
+ fujitsu: __FUJITSU
+ sdcc: SDCC, __SDCC
gnu: __GNUC__
sun: __SUNPRO_C,__SUNPRO_CC
hp: __HP_cc,__HP_aCC
dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER
- borland: __BORLANDC__,__TURBOC__
+ borland: __BORLANDC__,__CODEGEARC__,__TURBOC__
comeau: __COMO__
- cray: _CRAYC
kai: __KCC
lcc: __LCC__
sgi: __sgi,sgi
@@ -67,6 +70,7 @@ AC_DEFUN([AX_COMPILER_VENDOR],
metrowerks: __MWERKS__
watcom: __WATCOMC__
portland: __PGI
+ tcc: __TINYC__
unknown: UNKNOWN"
for ventest in $vendors; do
case $ventest in
diff --git a/m4/ax_configure_args.m4 b/m4/ax_configure_args.m4
index 0726b1bc..9237efea 100644
--- a/m4/ax_configure_args.m4
+++ b/m4/ax_configure_args.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_configure_args.html
+# https://www.gnu.org/software/autoconf-archive/ax_configure_args.html
# ===========================================================================
#
# SYNOPSIS
@@ -15,7 +15,7 @@
# to rely on eval'ing $ac_configure_args however some old autoconf
# versions do not provide that. To ensure maximum portability of autoconf
# extension macros this helper can be AC_REQUIRE'd so that
-# $ac_configure_args will alsways be present.
+# $ac_configure_args will always be present.
#
# Sadly, the traditional "exec $SHELL" of the enable_builddir macros is
# spoiled now and must be replaced by "eval + exit $?".
@@ -31,36 +31,15 @@
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
-#serial 9
+#serial 14
AC_DEFUN([AX_CONFIGURE_ARGS],[
- # [$]@ is unsable in 2.60+ but earlier autoconf had no ac_configure_args
+ # [$]@ is unusable in 2.60+ but earlier autoconf had no ac_configure_args
if test "${ac_configure_args+set}" != "set" ; then
ac_configure_args=
for ac_arg in ${1+"[$]@"}; do
diff --git a/m4/ax_enable_builddir.m4 b/m4/ax_enable_builddir.m4
index 3cb20937..710384da 100644
--- a/m4/ax_enable_builddir.m4
+++ b/m4/ax_enable_builddir.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_enable_builddir.html
+# https://www.gnu.org/software/autoconf-archive/ax_enable_builddir.html
# ===========================================================================
#
# SYNOPSIS
@@ -24,7 +24,7 @@
# toplevel builddir Makefile. It just copies the variables and
# rule-targets, each extended with a default rule-execution that recurses
# into the build directory of the current "HOST". You can override the
-# auto-dection through `config.guess` and build-time of course, as in
+# auto-detection through `config.guess` and build-time of course, as in
#
# make HOST=i386-mingw-cross
#
@@ -42,7 +42,7 @@
# into. Usually, the last one is the only one used. However, almost all
# targets have an additional "*-all" rule which makes the script to
# recurse into _all_ variants of the current HOST (!!) setting. The "-all"
-# suffix can be overriden for the macro as well.
+# suffix can be overridden for the macro as well.
#
# a special rule is only given for things like "dist" that will copy the
# tarball from the builddir to the sourcedir (or $(PUB)) for reason of
@@ -64,7 +64,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
+# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -79,10 +79,11 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 23
+#serial 30
AC_DEFUN([AX_ENABLE_BUILDDIR],[
AC_REQUIRE([AC_CANONICAL_HOST])[]dnl
+AC_REQUIRE([AC_CANONICAL_TARGET])[]dnl
AC_REQUIRE([AX_CONFIGURE_ARGS])[]dnl
AC_REQUIRE([AM_AUX_DIR_EXPAND])[]dnl
AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl
@@ -121,7 +122,7 @@ if test ".$srcdir" = ".." ; then
test -f $srcdir/$cache_file && mv $srcdir/$cache_file .
AC_MSG_RESULT(....exec $SHELL $srcdir/[$]0 "--srcdir=$srcdir" "--enable-builddir=$SUB" ${1+"[$]@"})
case "[$]0" in # restart
- [[\\/]]* | ?:[[\\/]]*) # Asbolute name
+ [[\\/]]* | ?:[[\\/]]*) # Absolute name
eval $SHELL "'[$]0'" "'--srcdir=$srcdir'" "'--enable-builddir=$SUB'" $ac_configure_args ;;
*) eval $SHELL "'$srcdir/[$]0'" "'--srcdir=$srcdir'" "'--enable-builddir=$SUB'" $ac_configure_args ;;
esac ; exit $?
diff --git a/m4/ax_gcc_archflag.m4 b/m4/ax_gcc_archflag.m4
index aab2661c..c52b9b29 100644
--- a/m4/ax_gcc_archflag.m4
+++ b/m4/ax_gcc_archflag.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_gcc_archflag.html
+# https://www.gnu.org/software/autoconf-archive/ax_gcc_archflag.html
# ===========================================================================
#
# SYNOPSIS
@@ -36,7 +36,8 @@
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2008 Matteo Frigo
-# Copyright (c) 2012 Tsukasa Oi
+# Copyright (c) 2014 Tsukasa Oi
+# Copyright (c) 2017-2018 Alexey Kopytov
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
@@ -49,7 +50,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
+# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -64,11 +65,13 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 11
+#serial 22
AC_DEFUN([AX_GCC_ARCHFLAG],
[AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_SED])
+AC_REQUIRE([AX_COMPILER_VENDOR])
AC_ARG_WITH(gcc-arch, [AS_HELP_STRING([--with-gcc-arch=<arch>], [use architecture <arch> for gcc -march/-mtune, instead of guessing])],
ax_gcc_arch=$withval, ax_gcc_arch=yes)
@@ -85,63 +88,70 @@ if test "x$ax_gcc_arch" = xyes; then
ax_gcc_arch=""
if test "$cross_compiling" = no; then
case $host_cpu in
- i[[3456]]86*|x86_64*) # use cpuid codes
+ i[[3456]]86*|x86_64*|amd64*) # use cpuid codes
AX_GCC_X86_CPUID(0)
AX_GCC_X86_CPUID(1)
case $ax_cv_gcc_x86_cpuid_0 in
- *:756e6547:*:*) # Intel
+ *:756e6547:6c65746e:49656e69) # Intel
case $ax_cv_gcc_x86_cpuid_1 in
- *5[[48]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;;
- *5??:*:*:*) ax_gcc_arch=pentium ;;
- *0?6[[3456]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;;
- *0?6a?:*[[01]]:*:*) ax_gcc_arch="pentium2 pentiumpro" ;;
- *0?6a?:*[[234]]:*:*) ax_gcc_arch="pentium3 pentiumpro" ;;
- *0?6[[9de]]?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;;
- *0?6[[78b]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;;
- *0?6f?:*:*:*|*1?66?:*:*:*) ax_gcc_arch="core2 pentium-m pentium3 pentiumpro" ;;
+ *5[[4578]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;;
+ *5[[123]]?:*:*:*) ax_gcc_arch=pentium ;;
+ *0?61?:*:*:*|?61?:*:*:*|61?:*:*:*) ax_gcc_arch=pentiumpro ;;
+ *0?6[[356]]?:*:*:*|?6[[356]]?:*:*:*|6[[356]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;;
+ *0?6[[78ab]]?:*:*:*|?6[[78ab]]?:*:*:*|6[[78ab]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;;
+ *0?6[[9d]]?:*:*:*|?6[[9d]]?:*:*:*|6[[9d]]?:*:*:*|*1?65?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;;
+ *0?6e?:*:*:*|?6e?:*:*:*|6e?:*:*:*) ax_gcc_arch="yonah pentium-m pentium3 pentiumpro" ;;
+ *0?6f?:*:*:*|?6f?:*:*:*|6f?:*:*:*|*1?66?:*:*:*) ax_gcc_arch="core2 pentium-m pentium3 pentiumpro" ;;
*1?6[[7d]]?:*:*:*) ax_gcc_arch="penryn core2 pentium-m pentium3 pentiumpro" ;;
- *1?6[[aef]]?:*:*:*|*2?6[[5cef]]?:*:*:*) ax_gcc_arch="corei7 core2 pentium-m pentium3 pentiumpro" ;;
- *1?6c?:*:*:*|*[[23]]?66?:*:*:*) ax_gcc_arch="atom core2 pentium-m pentium3 pentiumpro" ;;
- *2?6[[ad]]?:*:*:*) ax_gcc_arch="corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;;
- *0?6??:*:*:*) ax_gcc_arch=pentiumpro ;;
- *6??:*:*:*) ax_gcc_arch="core2 pentiumpro" ;;
- ?000?f3[[347]]:*:*:*|?000?f4[1347]:*:*:*|?000?f6?:*:*:*)
- case $host_cpu in
- x86_64*) ax_gcc_arch="nocona pentium4 pentiumpro" ;;
- *) ax_gcc_arch="prescott pentium4 pentiumpro" ;;
- esac ;;
- ?000?f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro";;
+ *1?6[[aef]]?:*:*:*|*2?6e?:*:*:*) ax_gcc_arch="nehalem corei7 core2 pentium-m pentium3 pentiumpro" ;;
+ *2?6[[5cf]]?:*:*:*) ax_gcc_arch="westmere corei7 core2 pentium-m pentium3 pentiumpro" ;;
+ *2?6[[ad]]?:*:*:*) ax_gcc_arch="sandybridge corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;;
+ *3?6[[ae]]?:*:*:*) ax_gcc_arch="ivybridge core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;;
+ *3?6[[cf]]?:*:*:*|*4?6[[56]]?:*:*:*) ax_gcc_arch="haswell core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;;
+ *3?6d?:*:*:*|*4?6[[7f]]?:*:*:*|*5?66?:*:*:*) ax_gcc_arch="broadwell core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;;
+ *1?6c?:*:*:*|*2?6[[67]]?:*:*:*|*3?6[[56]]?:*:*:*) ax_gcc_arch="bonnell atom core2 pentium-m pentium3 pentiumpro" ;;
+ *3?67?:*:*:*|*[[45]]?6[[ad]]?:*:*:*) ax_gcc_arch="silvermont atom core2 pentium-m pentium3 pentiumpro" ;;
+ *000?f[[012]]?:*:*:*|?f[[012]]?:*:*:*|f[[012]]?:*:*:*) ax_gcc_arch="pentium4 pentiumpro" ;;
+ *000?f[[346]]?:*:*:*|?f[[346]]?:*:*:*|f[[346]]?:*:*:*) ax_gcc_arch="nocona prescott pentium4 pentiumpro" ;;
+ # fallback
+ *5??:*:*:*) ax_gcc_arch=pentium ;;
+ *??6??:*:*:*) ax_gcc_arch="core2 pentiumpro" ;;
+ *6??:*:*:*) ax_gcc_arch=pentiumpro ;;
+ *00??f??:*:*:*|??f??:*:*:*|?f??:*:*:*|f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro" ;;
esac ;;
- *:68747541:*:*) # AMD
+ *:68747541:444d4163:69746e65) # AMD
case $ax_cv_gcc_x86_cpuid_1 in
*5[[67]]?:*:*:*) ax_gcc_arch=k6 ;;
- *5[[8d]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;;
- *5[[9]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;;
- *60?:*:*:*) ax_gcc_arch=k7 ;;
+ *5[[8]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;;
+ *5[[9d]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;;
*6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;;
*6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;;
- *67?:*:*:*) ax_gcc_arch="athlon-4 athlon k7" ;;
- *6[[68a]]?:*:*:*)
- AX_GCC_X86_CPUID(0x80000006) # L2 cache size
- case $ax_cv_gcc_x86_cpuid_0x80000006 in
- *:*:*[[1-9a-f]]??????:*) # (L2 = ecx >> 16) >= 256
- ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;;
- *) ax_gcc_arch="athlon-4 athlon k7" ;;
- esac ;;
- ?00??f[[4cef8b]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;;
- ?00??f5?:*:*:*) ax_gcc_arch="opteron k8" ;;
- ?00??f7?:*:*:*) ax_gcc_arch="athlon-fx opteron k8" ;;
- ?00??f??:*:*:*) ax_gcc_arch="k8" ;;
- ?05??f??:*:*:*) ax_gcc_arch="btver1 amdfam10 k8" ;;
- ?06??f??:*:*:*) ax_gcc_arch="bdver1 amdfam10 k8" ;;
- *f??:*:*:*) ax_gcc_arch="amdfam10 k8" ;;
+ *6[[678a]]?:*:*:*) ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;;
+ *000?f[[4578bcef]]?:*:*:*|?f[[4578bcef]]?:*:*:*|f[[4578bcef]]?:*:*:*|*001?f[[4578bcf]]?:*:*:*|1?f[[4578bcf]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;;
+ *002?f[[13457bcf]]?:*:*:*|2?f[[13457bcf]]?:*:*:*|*004?f[[138bcf]]?:*:*:*|4?f[[138bcf]]?:*:*:*|*005?f[[df]]?:*:*:*|5?f[[df]]?:*:*:*|*006?f[[8bcf]]?:*:*:*|6?f[[8bcf]]?:*:*:*|*007?f[[cf]]?:*:*:*|7?f[[cf]]?:*:*:*|*00c?f1?:*:*:*|c?f1?:*:*:*|*020?f3?:*:*:*|20?f3?:*:*:*) ax_gcc_arch="athlon64-sse3 k8-sse3 athlon64 k8" ;;
+ *010?f[[245689a]]?:*:*:*|10?f[[245689a]]?:*:*:*|*030?f1?:*:*:*|30?f1?:*:*:*) ax_gcc_arch="barcelona amdfam10 k8" ;;
+ *050?f[[12]]?:*:*:*|50?f[[12]]?:*:*:*) ax_gcc_arch="btver1 amdfam10 k8" ;;
+ *060?f1?:*:*:*|60?f1?:*:*:*) ax_gcc_arch="bdver1 amdfam10 k8" ;;
+ *060?f2?:*:*:*|60?f2?:*:*:*|*061?f[[03]]?:*:*:*|61?f[[03]]?:*:*:*) ax_gcc_arch="bdver2 bdver1 amdfam10 k8" ;;
+ *063?f0?:*:*:*|63?f0?:*:*:*) ax_gcc_arch="bdver3 bdver2 bdver1 amdfam10 k8" ;;
+ *07[[03]]?f0?:*:*:*|7[[03]]?f0?:*:*:*) ax_gcc_arch="btver2 btver1 amdfam10 k8" ;;
+ # fallback
+ *0[[13]]??f??:*:*:*|[[13]]??f??:*:*:*) ax_gcc_arch="barcelona amdfam10 k8" ;;
+ *020?f??:*:*:*|20?f??:*:*:*) ax_gcc_arch="athlon64-sse3 k8-sse3 athlon64 k8" ;;
+ *05??f??:*:*:*|5??f??:*:*:*) ax_gcc_arch="btver1 amdfam10 k8" ;;
+ *060?f??:*:*:*|60?f??:*:*:*) ax_gcc_arch="bdver1 amdfam10 k8" ;;
+ *061?f??:*:*:*|61?f??:*:*:*) ax_gcc_arch="bdver2 bdver1 amdfam10 k8" ;;
+ *06??f??:*:*:*|6??f??:*:*:*) ax_gcc_arch="bdver3 bdver2 bdver1 amdfam10 k8" ;;
+ *070?f??:*:*:*|70?f??:*:*:*) ax_gcc_arch="btver2 btver1 amdfam10 k8" ;;
+ *???f??:*:*:*) ax_gcc_arch="amdfam10 k8" ;;
esac ;;
- *:746e6543:*:*) # IDT
+ *:746e6543:736c7561:48727561) # IDT / VIA (Centaur)
case $ax_cv_gcc_x86_cpuid_1 in
*54?:*:*:*) ax_gcc_arch=winchip-c6 ;;
- *58?:*:*:*) ax_gcc_arch=winchip2 ;;
+ *5[[89]]?:*:*:*) ax_gcc_arch=winchip2 ;;
+ *66?:*:*:*) ax_gcc_arch=winchip2 ;;
*6[[78]]?:*:*:*) ax_gcc_arch=c3 ;;
- *69?:*:*:*) ax_gcc_arch="c3-2 c3" ;;
+ *6[[9adf]]?:*:*:*) ax_gcc_arch="c3-2 c3" ;;
esac ;;
esac
if test x"$ax_gcc_arch" = x; then # fallback
@@ -155,7 +165,7 @@ case $host_cpu in
sparc*)
AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/])
cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null`
- cputype=`echo "$cputype" | tr -d ' -' | sed 's/SPARCIIi/SPARCII/' | tr $as_cr_LETTERS $as_cr_letters`
+ cputype=`echo "$cputype" | tr -d ' -' | $SED 's/SPARCIIi/SPARCII/' |tr $as_cr_LETTERS $as_cr_letters`
case $cputype in
*ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;;
*ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;;
@@ -177,8 +187,8 @@ case $host_cpu in
alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;;
powerpc*)
- cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | sed 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null`
- cputype=`echo $cputype | sed -e 's/ppc//g;s/ *//g'`
+ cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | $SED 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null`
+ cputype=`echo $cputype | $SED -e 's/ppc//g;s/ *//g'`
case $cputype in
*750*) ax_gcc_arch="750 G3" ;;
*740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;;
@@ -188,26 +198,58 @@ case $host_cpu in
*POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";;
*POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";;
603ev|8240) ax_gcc_arch="$cputype 603e 603";;
+ *POWER7*) ax_gcc_arch="power7";;
+ *POWER8*) ax_gcc_arch="power8";;
+ *POWER9*) ax_gcc_arch="power9";;
+ *POWER10*) ax_gcc_arch="power10";;
*) ax_gcc_arch=$cputype ;;
esac
ax_gcc_arch="$ax_gcc_arch powerpc"
;;
+ aarch64)
+ cpuimpl=`grep 'CPU implementer' /proc/cpuinfo 2> /dev/null | cut -d: -f2 | tr -d " " | head -n 1`
+ cpuarch=`grep 'CPU architecture' /proc/cpuinfo 2> /dev/null | cut -d: -f2 | tr -d " " | head -n 1`
+ cpuvar=`grep 'CPU variant' /proc/cpuinfo 2> /dev/null | cut -d: -f2 | tr -d " " | head -n 1`
+ case $cpuimpl in
+ 0x42) case $cpuarch in
+ 8) case $cpuvar in
+ 0x0) ax_gcc_arch="thunderx2t99 vulcan armv8.1-a armv8-a+lse armv8-a native" ;;
+ esac
+ ;;
+ esac
+ ;;
+ 0x43) case $cpuarch in
+ 8) case $cpuvar in
+ 0x0) ax_gcc_arch="thunderx armv8-a native" ;;
+ 0x1) ax_gcc_arch="thunderx+lse armv8.1-a armv8-a+lse armv8-a native" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ ;;
esac
fi # not cross-compiling
fi # guess arch
if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then
-for arch in $ax_gcc_arch; do
- if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code
- flags="-mtune=$arch"
- # -mcpu=$arch and m$arch generate nonportable code on every arch except
- # x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr.
- case $host_cpu in i*86|x86_64*) flags="$flags -mcpu=$arch -m$arch";; esac
- else
- flags="-march=$arch -mcpu=$arch -m$arch"
- fi
- for flag in $flags; do
- AX_CHECK_COMPILE_FLAG($flag, [ax_cv_gcc_archflag=$flag; break])
+if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code
+ flag_prefixes="-mtune="
+ if test "x$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor" = xclang; then flag_prefixes="-march="; fi
+ # -mcpu=$arch and m$arch generate nonportable code on every arch except
+ # x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr.
+ case $host_cpu in i*86|x86_64*|amd64*) flag_prefixes="$flag_prefixes -mcpu= -m";; esac
+else
+ flag_prefixes="-march= -mcpu= -m"
+fi
+for flag_prefix in $flag_prefixes; do
+ for arch in $ax_gcc_arch; do
+ flag="$flag_prefix$arch"
+ AX_CHECK_COMPILE_FLAG($flag, [if test "x$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor" = xclang; then
+ if test "x[]m4_default([$1],yes)" = xyes; then
+ if test "x$flag" = "x-march=$arch"; then flag=-mtune=$arch; fi
+ fi
+ fi; ax_cv_gcc_archflag=$flag; break])
done
test "x$ax_cv_gcc_archflag" = xunknown || break
done
diff --git a/m4/ax_gcc_x86_cpuid.m4 b/m4/ax_gcc_x86_cpuid.m4
index 7d46fee0..df954658 100644
--- a/m4/ax_gcc_x86_cpuid.m4
+++ b/m4/ax_gcc_x86_cpuid.m4
@@ -1,17 +1,19 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_gcc_x86_cpuid.html
+# https://www.gnu.org/software/autoconf-archive/ax_gcc_x86_cpuid.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_GCC_X86_CPUID(OP)
+# AX_GCC_X86_CPUID_COUNT(OP, COUNT)
#
# DESCRIPTION
#
# On Pentium and later x86 processors, with gcc or a compiler that has a
# compatible syntax for inline assembly instructions, run a small program
# that executes the cpuid instruction with input OP. This can be used to
-# detect the CPU type.
+# detect the CPU type. AX_GCC_X86_CPUID_COUNT takes an additional COUNT
+# parameter that gets passed into register ECX before calling cpuid.
#
# On output, the values of the eax, ebx, ecx, and edx registers are stored
# as hexadecimal strings as "eax:ebx:ecx:edx" in the cache variable
@@ -28,6 +30,7 @@
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2008 Matteo Frigo
+# Copyright (c) 2015 Michael Petch <mpetch@capp-sysware.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
@@ -40,7 +43,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
+# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -55,18 +58,25 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 7
+#serial 10
AC_DEFUN([AX_GCC_X86_CPUID],
+[AX_GCC_X86_CPUID_COUNT($1, 0)
+])
+
+AC_DEFUN([AX_GCC_X86_CPUID_COUNT],
[AC_REQUIRE([AC_PROG_CC])
AC_LANG_PUSH([C])
AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1,
[AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <stdio.h>], [
- int op = $1, eax, ebx, ecx, edx;
+ int op = $1, level = $2, eax, ebx, ecx, edx;
FILE *f;
- __asm__("cpuid"
- : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
- : "a" (op));
+ __asm__ __volatile__ ("xchg %%ebx, %1\n"
+ "cpuid\n"
+ "xchg %%ebx, %1\n"
+ : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op), "2" (level));
+
f = fopen("conftest_cpuid", "w"); if (!f) return 1;
fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
fclose(f);
diff --git a/m4/ax_require_defined.m4 b/m4/ax_require_defined.m4
new file mode 100644
index 00000000..17c3eab7
--- /dev/null
+++ b/m4/ax_require_defined.m4
@@ -0,0 +1,37 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_REQUIRE_DEFINED(MACRO)
+#
+# DESCRIPTION
+#
+# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
+# been defined and thus are available for use. This avoids random issues
+# where a macro isn't expanded. Instead the configure script emits a
+# non-fatal:
+#
+# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
+#
+# It's like AC_REQUIRE except it doesn't expand the required macro.
+#
+# Here's an example:
+#
+# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
+#
+# LICENSE
+#
+# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 2
+
+AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
+ m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
+])dnl AX_REQUIRE_DEFINED
diff --git a/make_sunver.pl b/make_sunver.pl
new file mode 100644
index 00000000..8a90b1fe
--- /dev/null
+++ b/make_sunver.pl
@@ -0,0 +1,333 @@
+#!/usr/bin/perl -w
+
+# make_sunver.pl
+#
+# This script takes at least two arguments, a GNU style version script and
+# a list of object and archive files, and generates a corresponding Sun
+# style version script as follows:
+#
+# Each glob pattern, C++ mangled pattern or literal in the input script is
+# matched against all global symbols in the input objects, emitting those
+# that matched (or nothing if no match was found).
+# A comment with the original pattern and its type is left in the output
+# file to make it easy to understand the matches.
+#
+# It uses elfdump when present (native), GNU readelf otherwise.
+# It depends on the GNU version of c++filt, since it must understand the
+# GNU mangling style.
+
+use FileHandle;
+use IPC::Open2;
+
+# Enforce C locale.
+$ENV{'LC_ALL'} = "C";
+$ENV{'LANG'} = "C";
+
+# Input version script, GNU style.
+my $symvers = shift;
+
+##########
+# Get all the symbols from the library, match them, and add them to a hash.
+
+my %sym_hash = ();
+
+# List of objects and archives to process.
+my @OBJECTS = ();
+
+# List of shared objects to omit from processing.
+my @SHAREDOBJS = ();
+
+# Filter out those input archives that have corresponding shared objects to
+# avoid adding all symbols matched in the archive to the output map.
+foreach $file (@ARGV) {
+ if (($so = $file) =~ s/\.a$/.so/ && -e $so) {
+ printf STDERR "omitted $file -> $so\n";
+ push (@SHAREDOBJS, $so);
+ } else {
+ push (@OBJECTS, $file);
+ }
+}
+
+# We need to detect and ignore hidden symbols. Solaris nm can only detect
+# this in the harder to parse default output format, and GNU nm not at all,
+# so use elfdump -s in the native case and GNU readelf -s otherwise.
+# GNU objdump -t cannot be used since it produces a variable number of
+# columns.
+
+# The path to elfdump.
+my $elfdump = "/usr/ccs/bin/elfdump";
+
+if (-f $elfdump) {
+ open ELFDUMP,$elfdump.' -s '.(join ' ',@OBJECTS).'|' or die $!;
+ my $skip_arsym = 0;
+
+ while (<ELFDUMP>) {
+ chomp;
+
+ # Ignore empty lines.
+ if (/^$/) {
+ # End of archive symbol table, stop skipping.
+ $skip_arsym = 0 if $skip_arsym;
+ next;
+ }
+
+ # Keep skipping until end of archive symbol table.
+ next if ($skip_arsym);
+
+ # Ignore object name header for individual objects and archives.
+ next if (/:$/);
+
+ # Ignore table header lines.
+ next if (/^Symbol Table Section:/);
+ next if (/index.*value.*size/);
+
+ # Start of archive symbol table: start skipping.
+ if (/^Symbol Table: \(archive/) {
+ $skip_arsym = 1;
+ next;
+ }
+
+ # Split table.
+ (undef, undef, undef, undef, $bind, $oth, undef, $shndx, $name) = split;
+
+ # Error out for unknown input.
+ die "unknown input line:\n$_" unless defined($bind);
+
+ # Ignore local symbols.
+ next if ($bind eq "LOCL");
+ # Ignore hidden symbols.
+ next if ($oth eq "H");
+ # Ignore undefined symbols.
+ next if ($shndx eq "UNDEF");
+ # Error out for unhandled cases.
+ if ($bind !~ /^(GLOB|WEAK)/ or $oth ne "D") {
+ die "unhandled symbol:\n$_";
+ }
+
+ # Remember symbol.
+ $sym_hash{$name}++;
+ }
+ close ELFDUMP or die "$elfdump error";
+} else {
+ open READELF, 'readelf -s -W '.(join ' ',@OBJECTS).'|' or die $!;
+ # Process each symbol.
+ while (<READELF>) {
+ chomp;
+
+ # Ignore empty lines.
+ next if (/^$/);
+
+ # Ignore object name header.
+ next if (/^File: .*$/);
+
+ # Ignore table header lines.
+ next if (/^Symbol table.*contains.*:/);
+ next if (/Num:.*Value.*Size/);
+
+ # Split table.
+ (undef, undef, undef, undef, $bind, $vis, $ndx, $name) = split;
+
+ # Error out for unknown input.
+ die "unknown input line:\n$_" unless defined($bind);
+
+ # Ignore local symbols.
+ next if ($bind eq "LOCAL");
+ # Ignore hidden symbols.
+ next if ($vis eq "HIDDEN");
+ # Ignore undefined symbols.
+ next if ($ndx eq "UND");
+ # Error out for unhandled cases.
+ if ($bind !~ /^(GLOBAL|WEAK)/ or $vis ne "DEFAULT") {
+ die "unhandled symbol:\n$_";
+ }
+
+ # Remember symbol.
+ $sym_hash{$name}++;
+ }
+ close READELF or die "readelf error";
+}
+
+##########
+# The various types of glob patterns.
+#
+# A glob pattern that is to be applied to the demangled name: 'cxx'.
+# A glob patterns that applies directly to the name in the .o files: 'glob'.
+# This pattern is ignored; used for local variables (usually just '*'): 'ign'.
+
+# The type of the current pattern.
+my $glob = 'glob';
+
+# We're currently inside `extern "C++"', which Sun ld doesn't understand.
+my $in_extern = 0;
+
+# The c++filt command to use. This *must* be GNU c++filt; the Sun Studio
+# c++filt doesn't handle the GNU mangling style.
+my $cxxfilt = $ENV{'CXXFILT'} || "c++filt";
+
+# The current version name.
+my $current_version = "";
+
+# Was there any attempt to match a symbol to this version?
+my $matches_attempted;
+
+# The number of versions which matched this symbol.
+my $matched_symbols;
+
+open F,$symvers or die $!;
+
+# Print information about generating this file
+print "# This file was generated by make_sunver.pl. DO NOT EDIT!\n";
+print "# It was generated by:\n";
+printf "# %s %s %s\n", $0, $symvers, (join ' ',@ARGV);
+printf "# Omitted archives with corresponding shared libraries: %s\n",
+ (join ' ', @SHAREDOBJS) if $#SHAREDOBJS >= 0;
+print "#\n\n";
+
+while (<F>) {
+ # Lines of the form '};'
+ if (/^([ \t]*)(\}[ \t]*;[ \t]*)$/) {
+ $glob = 'glob';
+ if ($in_extern) {
+ $in_extern--;
+ print "$1##$2\n";
+ } else {
+ print;
+ }
+ next;
+ }
+
+ # Lines of the form '} SOME_VERSION_NAME_1.0;'
+ if (/^[ \t]*\}[ \tA-Z0-9_.a-z]+;[ \t]*$/) {
+ $glob = 'glob';
+ # We tried to match symbols agains this version, but none matched.
+ # Emit dummy hidden symbol to avoid marking this version WEAK.
+ if ($matches_attempted && $matched_symbols == 0) {
+ print " hidden:\n";
+ print " .force_WEAK_off_$current_version = DATA S0x0 V0x0;\n";
+ }
+ print; next;
+ }
+
+ # Comment and blank lines
+ if (/^[ \t]*\#/) { print; next; }
+ if (/^[ \t]*$/) { print; next; }
+
+ # Lines of the form '{'
+ if (/^([ \t]*){$/) {
+ if ($in_extern) {
+ print "$1##{\n";
+ } else {
+ print;
+ }
+ next;
+ }
+
+ # Lines of the form 'SOME_VERSION_NAME_1.1 {'
+ if (/^([A-Z0-9_.]+)[ \t]+{$/) {
+ # Record version name.
+ $current_version = $1;
+ # Reset match attempts, #matched symbols for this version.
+ $matches_attempted = 0;
+ $matched_symbols = 0;
+ print;
+ next;
+ }
+
+ # Ignore 'global:'
+ if (/^[ \t]*global:$/) { print; next; }
+
+ # After 'local:', globs should be ignored, they won't be exported.
+ if (/^[ \t]*local:$/) {
+ $glob = 'ign';
+ print;
+ next;
+ }
+
+ # After 'extern "C++"', globs are C++ patterns
+ if (/^([ \t]*)(extern \"C\+\+\"[ \t]*)$/) {
+ $in_extern++;
+ $glob = 'cxx';
+ # Need to comment, Sun ld cannot handle this.
+ print "$1##$2\n"; next;
+ }
+
+ # Chomp newline now we're done with passing through the input file.
+ chomp;
+
+ # Catch globs. Note that '{}' is not allowed in globs by this script,
+ # so only '*' and '[]' are available.
+ if (/^([ \t]*)([^ \t;{}#]+);?[ \t]*$/) {
+ my $ws = $1;
+ my $ptn = $2;
+ # Turn the glob into a regex by replacing '*' with '.*', '?' with '.'.
+ # Keep $ptn so we can still print the original form.
+ ($pattern = $ptn) =~ s/\*/\.\*/g;
+ $pattern =~ s/\?/\./g;
+
+ if ($glob eq 'ign') {
+ # We're in a local: * section; just continue.
+ print "$_\n";
+ next;
+ }
+
+ # Print the glob commented for human readers.
+ print "$ws##$ptn ($glob)\n";
+ # We tried to match a symbol to this version.
+ $matches_attempted++;
+
+ if ($glob eq 'glob') {
+ my %ptn_syms = ();
+
+ # Match ptn against symbols in %sym_hash.
+ foreach my $sym (keys %sym_hash) {
+ # Maybe it matches one of the patterns based on the symbol in
+ # the .o file.
+ $ptn_syms{$sym}++ if ($sym =~ /^$pattern$/);
+ }
+
+ foreach my $sym (sort keys(%ptn_syms)) {
+ $matched_symbols++;
+ print "$ws$sym;\n";
+ }
+ } elsif ($glob eq 'cxx') {
+ my %dem_syms = ();
+
+ # Verify that we're actually using GNU c++filt. Other versions
+ # most likely cannot handle GNU style symbol mangling.
+ my $cxxout = `$cxxfilt --version 2>&1`;
+ $cxxout =~ m/GNU/ or die "$0 requires GNU c++filt to function";
+
+ # Talk to c++filt through a pair of file descriptors.
+ # Need to start a fresh instance per pattern, otherwise the
+ # process grows to 500+ MB.
+ my $pid = open2(*FILTIN, *FILTOUT, $cxxfilt) or die $!;
+
+ # Match ptn against symbols in %sym_hash.
+ foreach my $sym (keys %sym_hash) {
+ # No? Well, maybe its demangled form matches one of those
+ # patterns.
+ printf FILTOUT "%s\n",$sym;
+ my $dem = <FILTIN>;
+ chomp $dem;
+ $dem_syms{$sym}++ if ($dem =~ /^$pattern$/);
+ }
+
+ close FILTOUT or die "c++filt error";
+ close FILTIN or die "c++filt error";
+ # Need to wait for the c++filt process to avoid lots of zombies.
+ waitpid $pid, 0;
+
+ foreach my $sym (sort keys(%dem_syms)) {
+ $matched_symbols++;
+ print "$ws$sym;\n";
+ }
+ } else {
+ # No? Well, then ignore it.
+ }
+ next;
+ }
+ # Important sanity check. This script can't handle lots of formats
+ # that GNU ld can, so be sure to error out if one is seen!
+ die "strange line `$_'";
+}
+close F;
diff --git a/msvc_build/aarch64/Ffi_staticLib.sln b/msvc_build/aarch64/Ffi_staticLib.sln
new file mode 100644
index 00000000..d9119dfa
--- /dev/null
+++ b/msvc_build/aarch64/Ffi_staticLib.sln
@@ -0,0 +1,33 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28302.56
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ffi_staticLib_arm64", "Ffi_staticLib.vcxproj", "{115502C0-BE05-4767-BF19-5C87D805FAD6}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {115502C0-BE05-4767-BF19-5C87D805FAD6}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {115502C0-BE05-4767-BF19-5C87D805FAD6}.Debug|ARM64.Build.0 = Debug|ARM64
+ {115502C0-BE05-4767-BF19-5C87D805FAD6}.Debug|x64.ActiveCfg = Debug|ARM64
+ {115502C0-BE05-4767-BF19-5C87D805FAD6}.Debug|x86.ActiveCfg = Debug|ARM64
+ {115502C0-BE05-4767-BF19-5C87D805FAD6}.Release|ARM64.ActiveCfg = Release|ARM64
+ {115502C0-BE05-4767-BF19-5C87D805FAD6}.Release|ARM64.Build.0 = Release|ARM64
+ {115502C0-BE05-4767-BF19-5C87D805FAD6}.Release|x64.ActiveCfg = Release|ARM64
+ {115502C0-BE05-4767-BF19-5C87D805FAD6}.Release|x86.ActiveCfg = Release|ARM64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {241C54C7-20DD-4897-9376-E6B6D1B43BD5}
+ EndGlobalSection
+EndGlobal
diff --git a/msvc_build/aarch64/Ffi_staticLib.vcxproj b/msvc_build/aarch64/Ffi_staticLib.vcxproj
new file mode 100644
index 00000000..3187699c
--- /dev/null
+++ b/msvc_build/aarch64/Ffi_staticLib.vcxproj
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{115502C0-BE05-4767-BF19-5C87D805FAD6}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>FfistaticLib</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+ <ProjectName>Ffi_staticLib_arm64</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>FFI_BUILDING_DLL;_DEBUG;_LIB;USE_DL_PREFIX;ARM64;_M_ARM64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>..\..\include;.\aarch64_include;..\..\src\aarch64;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
+ <BrowseInformation>true</BrowseInformation>
+ <OmitFramePointers>
+ </OmitFramePointers>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>FFI_BUILDING_DLL;USE_DL_PREFIX;ARM64;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>..\..\include;.\aarch64_include;..\..\src\aarch64;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <OmitFramePointers>true</OmitFramePointers>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <AdditionalUsingDirectories>..\..\src;..\..\src\aarch64;%(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ <ProjectReference>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ </ProjectReference>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include=".\aarch64_include\ffi.h" />
+ <ClInclude Include=".\aarch64_include\fficonfig.h" />
+ <ClInclude Include="..\..\src\aarch64\ffitarget.h" />
+ <ClInclude Include="..\include\ffi_cfi.h" />
+ <ClInclude Include="..\include\ffi_common.h" />
+ <ClInclude Include="..\..\src\aarch64\internal.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\closures.c" />
+ <ClCompile Include="..\..\src\dlmalloc.c" />
+ <ClCompile Include="..\..\src\aarch64\ffi.c" />
+ <ClCompile Include="..\..\src\prep_cif.c" />
+ <ClCompile Include="..\..\src\types.c" />
+ </ItemGroup>
+ <!--ItemGroup>
+ <Object Include="..\..\..\..\Downloads\libffi-master-win64\src\aarch64\win64_armasm.obj" />
+ </ItemGroup-->
+ <ItemGroup>
+ <CustomBuild Include="..\..\src\aarch64\win64_armasm.S">
+ <!--ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild -->
+ <Command>
+ cl /FA /EP /nologo /I"..\..\include" /I".\aarch64_include" /I"..\..\src\aarch64" "%(FullPath)" &gt; $(IntDir)win64_armasm.i
+ armasm64 $(IntDir)win64_armasm.i /I"src\" /I"..\..\include" /I"..\..\src\aarch64" -o "$(IntDir)win64_armasm.obj"
+ </Command>
+ <Outputs>win64_armasm.obj;%(Outputs)</Outputs>
+ </CustomBuild>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/msvc_build/aarch64/Ffi_staticLib.vcxproj.filters b/msvc_build/aarch64/Ffi_staticLib.vcxproj.filters
new file mode 100644
index 00000000..1f8c6e13
--- /dev/null
+++ b/msvc_build/aarch64/Ffi_staticLib.vcxproj.filters
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\ffi.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\ffi_cfi.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\ffi_common.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\fficonfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\ffitarget.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\internal.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\closures.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\dlmalloc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\ffi.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\prep_cif.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\types.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="src\win64_armasm.S" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/msvc_build/aarch64/Ffi_staticLib.vcxproj.user b/msvc_build/aarch64/Ffi_staticLib.vcxproj.user
new file mode 100644
index 00000000..be250787
--- /dev/null
+++ b/msvc_build/aarch64/Ffi_staticLib.vcxproj.user
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup />
+</Project> \ No newline at end of file
diff --git a/msvc_build/aarch64/aarch64_include/ffi.h b/msvc_build/aarch64/aarch64_include/ffi.h
new file mode 100644
index 00000000..02f26a2f
--- /dev/null
+++ b/msvc_build/aarch64/aarch64_include/ffi.h
@@ -0,0 +1,511 @@
+/* -----------------------------------------------------------------*-C-*-
+ libffi 3.3-rc0 - Copyright (c) 2011, 2014 Anthony Green
+ - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.
+
+ 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 AUTHORS OR COPYRIGHT
+ HOLDERS 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.
+
+ ----------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------
+ Most of the API is documented in doc/libffi.texi.
+
+ The raw API is designed to bypass some of the argument packing and
+ unpacking on architectures for which it can be avoided. Routines
+ are provided to emulate the raw API if the underlying platform
+ doesn't allow faster implementation.
+
+ More details on the raw API can be found in:
+
+ http://gcc.gnu.org/ml/java/1999-q3/msg00138.html
+
+ and
+
+ http://gcc.gnu.org/ml/java/1999-q3/msg00174.html
+ -------------------------------------------------------------------- */
+
+#ifndef LIBFFI_H
+#define LIBFFI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Specify which architecture libffi is configured for. */
+#ifndef AARCH64
+#define AARCH64
+#endif
+
+/* ---- System configuration information --------------------------------- */
+
+#include <ffitarget.h>
+
+#ifndef LIBFFI_ASM
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define __attribute__(X)
+#endif
+
+#include <stddef.h>
+#include <limits.h>
+
+/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example).
+ But we can find it either under the correct ANSI name, or under GNU
+ C's internal name. */
+
+#define FFI_64_BIT_MAX 9223372036854775807
+
+#ifdef LONG_LONG_MAX
+# define FFI_LONG_LONG_MAX LONG_LONG_MAX
+#else
+# ifdef LLONG_MAX
+# define FFI_LONG_LONG_MAX LLONG_MAX
+# ifdef _AIX52 /* or newer has C99 LLONG_MAX */
+# undef FFI_64_BIT_MAX
+# define FFI_64_BIT_MAX 9223372036854775807LL
+# endif /* _AIX52 or newer */
+# else
+# ifdef __GNUC__
+# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__
+# endif
+# ifdef _AIX /* AIX 5.1 and earlier have LONGLONG_MAX */
+# ifndef __PPC64__
+# if defined (__IBMC__) || defined (__IBMCPP__)
+# define FFI_LONG_LONG_MAX LONGLONG_MAX
+# endif
+# endif /* __PPC64__ */
+# undef FFI_64_BIT_MAX
+# define FFI_64_BIT_MAX 9223372036854775807LL
+# endif
+# endif
+#endif
+
+/* The closure code assumes that this works on pointers, i.e. a size_t
+ can hold a pointer. */
+
+typedef struct _ffi_type
+{
+ size_t size;
+ unsigned short alignment;
+ unsigned short type;
+ struct _ffi_type **elements;
+} ffi_type;
+
+/* Need minimal decorations for DLLs to work on Windows. GCC has
+ autoimport and autoexport. Always mark externally visible symbols
+ as dllimport for MSVC clients, even if it means an extra indirection
+ when using the static version of the library.
+ Besides, as a workaround, they can define FFI_BUILDING if they
+ *know* they are going to link with the static library. */
+#if defined _MSC_VER
+# if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */
+# define FFI_API __declspec(dllexport)
+# elif !defined FFI_BUILDING /* Importing libffi.DLL */
+# define FFI_API __declspec(dllimport)
+# else /* Building/linking static library */
+# define FFI_API
+# endif
+#else
+# define FFI_API
+#endif
+
+/* The externally visible type declarations also need the MSVC DLL
+ decorations, or they will not be exported from the object file. */
+#if defined LIBFFI_HIDE_BASIC_TYPES
+# define FFI_EXTERN FFI_API
+#else
+# define FFI_EXTERN extern FFI_API
+#endif
+
+#ifndef LIBFFI_HIDE_BASIC_TYPES
+#if SCHAR_MAX == 127
+# define ffi_type_uchar ffi_type_uint8
+# define ffi_type_schar ffi_type_sint8
+#else
+ #error "char size not supported"
+#endif
+
+#if SHRT_MAX == 32767
+# define ffi_type_ushort ffi_type_uint16
+# define ffi_type_sshort ffi_type_sint16
+#elif SHRT_MAX == 2147483647
+# define ffi_type_ushort ffi_type_uint32
+# define ffi_type_sshort ffi_type_sint32
+#else
+ #error "short size not supported"
+#endif
+
+#if INT_MAX == 32767
+# define ffi_type_uint ffi_type_uint16
+# define ffi_type_sint ffi_type_sint16
+#elif INT_MAX == 2147483647
+# define ffi_type_uint ffi_type_uint32
+# define ffi_type_sint ffi_type_sint32
+#elif INT_MAX == 9223372036854775807
+# define ffi_type_uint ffi_type_uint64
+# define ffi_type_sint ffi_type_sint64
+#else
+ #error "int size not supported"
+#endif
+
+#if LONG_MAX == 2147483647
+# if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX
+ #error "no 64-bit data type supported"
+# endif
+#elif LONG_MAX != FFI_64_BIT_MAX
+ #error "long size not supported"
+#endif
+
+#if LONG_MAX == 2147483647
+# define ffi_type_ulong ffi_type_uint32
+# define ffi_type_slong ffi_type_sint32
+#elif LONG_MAX == FFI_64_BIT_MAX
+# define ffi_type_ulong ffi_type_uint64
+# define ffi_type_slong ffi_type_sint64
+#else
+ #error "long size not supported"
+#endif
+
+/* These are defined in types.c. */
+FFI_EXTERN ffi_type ffi_type_void;
+FFI_EXTERN ffi_type ffi_type_uint8;
+FFI_EXTERN ffi_type ffi_type_sint8;
+FFI_EXTERN ffi_type ffi_type_uint16;
+FFI_EXTERN ffi_type ffi_type_sint16;
+FFI_EXTERN ffi_type ffi_type_uint32;
+FFI_EXTERN ffi_type ffi_type_sint32;
+FFI_EXTERN ffi_type ffi_type_uint64;
+FFI_EXTERN ffi_type ffi_type_sint64;
+FFI_EXTERN ffi_type ffi_type_float;
+FFI_EXTERN ffi_type ffi_type_double;
+FFI_EXTERN ffi_type ffi_type_pointer;
+
+#ifndef _M_ARM64
+FFI_EXTERN ffi_type ffi_type_longdouble;
+#else
+#define ffi_type_longdouble ffi_type_double
+#endif
+
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+FFI_EXTERN ffi_type ffi_type_complex_float;
+FFI_EXTERN ffi_type ffi_type_complex_double;
+#if 1
+FFI_EXTERN ffi_type ffi_type_complex_longdouble;
+#else
+#define ffi_type_complex_longdouble ffi_type_complex_double
+#endif
+#endif
+#endif /* LIBFFI_HIDE_BASIC_TYPES */
+
+typedef enum {
+ FFI_OK = 0,
+ FFI_BAD_TYPEDEF,
+ FFI_BAD_ABI
+} ffi_status;
+
+typedef struct {
+ ffi_abi abi;
+ unsigned nargs;
+ ffi_type **arg_types;
+ ffi_type *rtype;
+ unsigned bytes;
+ unsigned flags;
+#ifdef FFI_EXTRA_CIF_FIELDS
+ FFI_EXTRA_CIF_FIELDS;
+#endif
+} ffi_cif;
+
+/* ---- Definitions for the raw API -------------------------------------- */
+
+#ifndef FFI_SIZEOF_ARG
+# if LONG_MAX == 2147483647
+# define FFI_SIZEOF_ARG 4
+# elif LONG_MAX == FFI_64_BIT_MAX
+# define FFI_SIZEOF_ARG 8
+# endif
+#endif
+
+#ifndef FFI_SIZEOF_JAVA_RAW
+# define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG
+#endif
+
+typedef union {
+ ffi_sarg sint;
+ ffi_arg uint;
+ float flt;
+ char data[FFI_SIZEOF_ARG];
+ void* ptr;
+} ffi_raw;
+
+#if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8
+/* This is a special case for mips64/n32 ABI (and perhaps others) where
+ sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */
+typedef union {
+ signed int sint;
+ unsigned int uint;
+ float flt;
+ char data[FFI_SIZEOF_JAVA_RAW];
+ void* ptr;
+} ffi_java_raw;
+#else
+typedef ffi_raw ffi_java_raw;
+#endif
+
+
+FFI_API
+void ffi_raw_call (ffi_cif *cif,
+ void (*fn)(void),
+ void *rvalue,
+ ffi_raw *avalue);
+
+FFI_API void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
+FFI_API void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
+FFI_API size_t ffi_raw_size (ffi_cif *cif);
+
+/* This is analogous to the raw API, except it uses Java parameter
+ packing, even on 64-bit machines. I.e. on 64-bit machines longs
+ and doubles are followed by an empty 64-bit word. */
+
+FFI_API
+void ffi_java_raw_call (ffi_cif *cif,
+ void (*fn)(void),
+ void *rvalue,
+ ffi_java_raw *avalue);
+
+FFI_API
+void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw);
+FFI_API
+void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args);
+FFI_API
+size_t ffi_java_raw_size (ffi_cif *cif);
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#if FFI_CLOSURES
+
+#ifdef _MSC_VER
+__declspec(align(8))
+#endif
+typedef struct {
+#if 0
+ void *trampoline_table;
+ void *trampoline_table_entry;
+#else
+ char tramp[FFI_TRAMPOLINE_SIZE];
+#endif
+ ffi_cif *cif;
+ void (*fun)(ffi_cif*,void*,void**,void*);
+ void *user_data;
+} ffi_closure
+#ifdef __GNUC__
+ __attribute__((aligned (8)))
+#endif
+ ;
+
+#ifndef __GNUC__
+# ifdef __sgi
+# pragma pack 0
+# endif
+#endif
+
+FFI_API void *ffi_closure_alloc (size_t size, void **code);
+FFI_API void ffi_closure_free (void *);
+
+FFI_API ffi_status
+ffi_prep_closure (ffi_closure*,
+ ffi_cif *,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data)
+#if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 405)
+ __attribute__((deprecated ("use ffi_prep_closure_loc instead")))
+#elif defined(__GNUC__) && __GNUC__ >= 3
+ __attribute__((deprecated))
+#endif
+ ;
+
+FFI_API ffi_status
+ffi_prep_closure_loc (ffi_closure*,
+ ffi_cif *,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data,
+ void*codeloc);
+
+#ifdef __sgi
+# pragma pack 8
+#endif
+typedef struct {
+#if 0
+ void *trampoline_table;
+ void *trampoline_table_entry;
+#else
+ char tramp[FFI_TRAMPOLINE_SIZE];
+#endif
+ ffi_cif *cif;
+
+#if !FFI_NATIVE_RAW_API
+
+ /* If this is enabled, then a raw closure has the same layout
+ as a regular closure. We use this to install an intermediate
+ handler to do the transaltion, void** -> ffi_raw*. */
+
+ void (*translate_args)(ffi_cif*,void*,void**,void*);
+ void *this_closure;
+
+#endif
+
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*);
+ void *user_data;
+
+} ffi_raw_closure;
+
+typedef struct {
+#if 0
+ void *trampoline_table;
+ void *trampoline_table_entry;
+#else
+ char tramp[FFI_TRAMPOLINE_SIZE];
+#endif
+
+ ffi_cif *cif;
+
+#if !FFI_NATIVE_RAW_API
+
+ /* If this is enabled, then a raw closure has the same layout
+ as a regular closure. We use this to install an intermediate
+ handler to do the translation, void** -> ffi_raw*. */
+
+ void (*translate_args)(ffi_cif*,void*,void**,void*);
+ void *this_closure;
+
+#endif
+
+ void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*);
+ void *user_data;
+
+} ffi_java_raw_closure;
+
+FFI_API ffi_status
+ffi_prep_raw_closure (ffi_raw_closure*,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+ void *user_data);
+
+FFI_API ffi_status
+ffi_prep_raw_closure_loc (ffi_raw_closure*,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+ void *user_data,
+ void *codeloc);
+
+FFI_API ffi_status
+ffi_prep_java_raw_closure (ffi_java_raw_closure*,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
+ void *user_data);
+
+FFI_API ffi_status
+ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
+ void *user_data,
+ void *codeloc);
+
+#endif /* FFI_CLOSURES */
+
+#if FFI_GO_CLOSURES
+
+typedef struct {
+ void *tramp;
+ ffi_cif *cif;
+ void (*fun)(ffi_cif*,void*,void**,void*);
+} ffi_go_closure;
+
+FFI_API ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
+ void (*fun)(ffi_cif*,void*,void**,void*));
+
+FFI_API void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure);
+
+#endif /* FFI_GO_CLOSURES */
+
+/* ---- Public interface definition -------------------------------------- */
+
+FFI_API
+ffi_status ffi_prep_cif(ffi_cif *cif,
+ ffi_abi abi,
+ unsigned int nargs,
+ ffi_type *rtype,
+ ffi_type **atypes);
+
+FFI_API
+ffi_status ffi_prep_cif_var(ffi_cif *cif,
+ ffi_abi abi,
+ unsigned int nfixedargs,
+ unsigned int ntotalargs,
+ ffi_type *rtype,
+ ffi_type **atypes);
+
+FFI_API
+void ffi_call(ffi_cif *cif,
+ void (*fn)(void),
+ void *rvalue,
+ void **avalue);
+
+FFI_API
+ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
+ size_t *offsets);
+
+/* Useful for eliminating compiler warnings. */
+#define FFI_FN(f) ((void (*)(void))f)
+
+/* ---- Definitions shared with assembly code ---------------------------- */
+
+#endif
+
+/* If these change, update src/mips/ffitarget.h. */
+#define FFI_TYPE_VOID 0
+#define FFI_TYPE_INT 1
+#define FFI_TYPE_FLOAT 2
+#define FFI_TYPE_DOUBLE 3
+#ifndef _M_ARM64
+#define FFI_TYPE_LONGDOUBLE 4
+#else
+#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE
+#endif
+#define FFI_TYPE_UINT8 5
+#define FFI_TYPE_SINT8 6
+#define FFI_TYPE_UINT16 7
+#define FFI_TYPE_SINT16 8
+#define FFI_TYPE_UINT32 9
+#define FFI_TYPE_SINT32 10
+#define FFI_TYPE_UINT64 11
+#define FFI_TYPE_SINT64 12
+#define FFI_TYPE_STRUCT 13
+#define FFI_TYPE_POINTER 14
+#define FFI_TYPE_COMPLEX 15
+/* This should always refer to the last type code (for sanity checks). */
+#define FFI_TYPE_LAST FFI_TYPE_COMPLEX
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/msvc_build/aarch64/aarch64_include/fficonfig.h b/msvc_build/aarch64/aarch64_include/fficonfig.h
new file mode 100644
index 00000000..b3d89b03
--- /dev/null
+++ b/msvc_build/aarch64/aarch64_include/fficonfig.h
@@ -0,0 +1,219 @@
+/* fficonfig.h. Generated from fficonfig.h.in by configure. */
+/* fficonfig.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define to 1 if using `alloca.c'. */
+/* #undef C_ALLOCA */
+
+/* Define to the flags needed for the .section .eh_frame directive. */
+#define EH_FRAME_FLAGS "a"
+
+/* Define this if you want extra debugging. */
+/* #undef FFI_DEBUG */
+
+/* Cannot use PROT_EXEC on this target, so, we revert to alternative means */
+/* #undef FFI_EXEC_TRAMPOLINE_TABLE */
+
+/* Define this if you want to enable pax emulated trampolines */
+/* #undef FFI_MMAP_EXEC_EMUTRAMP_PAX */
+
+/* Cannot use malloc on this target, so, we revert to alternative means */
+/* #undef FFI_MMAP_EXEC_WRIT */
+
+/* Define this if you do not want support for the raw API. */
+/* #undef FFI_NO_RAW_API */
+
+/* Define this if you do not want support for aggregate types. */
+/* #undef FFI_NO_STRUCTS */
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+ */
+/*#define HAVE_ALLOCA_H 1 */
+
+/* Define if your assembler supports .cfi_* directives. */
+#define HAVE_AS_CFI_PSEUDO_OP 1
+
+/* Define if your assembler supports .register. */
+/* #undef HAVE_AS_REGISTER_PSEUDO_OP */
+
+/* Define if the compiler uses zarch features. */
+/* #undef HAVE_AS_S390_ZARCH */
+
+/* Define if your assembler and linker support unaligned PC relative relocs.
+ */
+/* #undef HAVE_AS_SPARC_UA_PCREL */
+
+/* Define if your assembler supports unwind section type. */
+/* #undef HAVE_AS_X86_64_UNWIND_SECTION_TYPE */
+
+/* Define if your assembler supports PC relative relocs. */
+/* #undef HAVE_AS_X86_PCREL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if __attribute__((visibility("hidden"))) is supported. */
+#define HAVE_HIDDEN_VISIBILITY_ATTRIBUTE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define if you have the long double type and it is bigger than a double */
+#define HAVE_LONG_DOUBLE 1
+
+/* Define if you support more than one size of the long double type */
+/* #undef HAVE_LONG_DOUBLE_VARIANT */
+
+/* Define to 1 if you have the `memcpy' function. */
+#define HAVE_MEMCPY 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+#define HAVE_MKOSTEMP 1
+
+/* Define to 1 if you have the `mmap' function. */
+#define HAVE_MMAP 1
+
+/* Define if mmap with MAP_ANON(YMOUS) works. */
+#define HAVE_MMAP_ANON 1
+
+/* Define if mmap of /dev/zero works. */
+#define HAVE_MMAP_DEV_ZERO 1
+
+/* Define if read-only mmap of a plain file works. */
+#define HAVE_MMAP_FILE 1
+
+/* Define if .eh_frame sections should be read-only. */
+#define HAVE_RO_EH_FRAME 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+//#define HAVE_STDLIB_H 0
+#define LACKS_STDLIB_H 1
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if GNU symbol versioning is used for libatomic. */
+#define LIBFFI_GNU_SYMBOL_VERSIONING 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "libffi"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "http://github.com/libffi/libffi/issues"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libffi"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libffi 3.3-rc0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libffi"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "3.3-rc0"
+
+/* The size of `double', as computed by sizeof. */
+#define SIZEOF_DOUBLE 8
+
+/* The size of `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 8
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at runtime.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+/* #undef STACK_DIRECTION */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if symbols are underscored. */
+/* #undef SYMBOL_UNDERSCORE */
+
+/* Define this if you are using Purify and want to suppress spurious messages.
+ */
+/* #undef USING_PURIFY */
+
+/* Version number of package */
+#define VERSION "3.3-rc0"
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* # undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+
+#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+#ifdef LIBFFI_ASM
+#ifdef __APPLE__
+#define FFI_HIDDEN(name) .private_extern name
+#else
+#define FFI_HIDDEN(name) .hidden name
+#endif
+#else
+#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
+#endif
+#else
+#ifdef LIBFFI_ASM
+#define FFI_HIDDEN(name)
+#else
+#define FFI_HIDDEN
+#endif
+#endif
+
diff --git a/msvcc.sh b/msvcc.sh
index 65fbfef7..97facd69 100755
--- a/msvcc.sh
+++ b/msvcc.sh
@@ -44,17 +44,29 @@
args_orig=$@
args="-nologo -W3"
+linkargs=
static_crt=
debug_crt=
cl="cl"
ml="ml"
safeseh="-safeseh"
output=
+libpaths=
+libversion=7
+verbose=
while [ $# -gt 0 ]
do
case $1
in
+ --verbose)
+ verbose=1
+ shift 1
+ ;;
+ --version)
+ args="-help"
+ shift 1
+ ;;
-fexceptions)
# Don't enable exceptions for now.
#args="$args -EHac"
@@ -68,9 +80,18 @@ do
safeseh=
shift 1
;;
+ -marm)
+ ml='armasm'
+ safeseh=
+ shift 1
+ ;;
+ -marm64)
+ ml='armasm64'
+ safeseh=
+ shift 1
+ ;;
-clang-cl)
cl="clang-cl"
- safeseh=
shift 1
;;
-O0)
@@ -144,13 +165,44 @@ do
shift 1
;;
-I)
- args="$args -I$2"
- includes="$includes -I$2"
+ p=$(cygpath -m $2)
+ args="$args -I$p"
+ includes="$includes -I$p"
shift 2
;;
-I*)
- args="$args $1"
- includes="$includes $1"
+ p=$(cygpath -m ${1#-I})
+ args="$args -I$p"
+ includes="$includes -I$p"
+ shift 1
+ ;;
+ -L)
+ p=$(cygpath -m $2)
+ linkargs="$linkargs -LIBPATH:$p"
+ shift 2
+ ;;
+ -L*)
+ p=$(cygpath -m ${1#-L})
+ linkargs="$linkargs -LIBPATH:$p"
+ shift 1
+ ;;
+ -link)
+ # add next argument verbatim to linker args
+ linkargs="$linkargs $2"
+ shift 2
+ ;;
+ -l*)
+ case $1
+ in
+ -lffi)
+ linkargs="$linkargs lib${1#-l}-${libversion}.lib"
+ ;;
+ *)
+ # ignore other libraries like -lm, hope they are
+ # covered by MSVCRT
+ # linkargs="$linkargs ${1#-l}.lib"
+ ;;
+ esac
shift 1
;;
-W|-Wextra)
@@ -166,6 +218,15 @@ do
# libffi tests -pedantic with -Wall, so drop it also.
shift 1
;;
+ -warn)
+ # ignore -warn all from libtool as well.
+ if test "$2" = "all"; then
+ shift 2
+ else
+ args="$args -warn"
+ shift 1
+ fi
+ ;;
-Werror)
args="$args -WX"
shift 1
@@ -186,6 +247,7 @@ do
else
output="-Fe$2"
fi
+ armasm_output="-o $2"
if [ -n "$assembly" ]; then
args="$args $output"
else
@@ -210,11 +272,16 @@ do
esac
done
-# If -Zi is specified, certain optimizations are implicitly disabled
-# by MSVC. Add back those optimizations if this is an optimized build.
-# NOTE: These arguments must come after all others.
-if [ -n "$opt" ]; then
- args="$args -link -OPT:REF -OPT:ICF -INCREMENTAL:NO"
+if [ -n "$linkargs" ]; then
+
+ # If -Zi is specified, certain optimizations are implicitly disabled
+ # by MSVC. Add back those optimizations if this is an optimized build.
+ # NOTE: These arguments must come after all others.
+ if [ -n "$opt" ]; then
+ linkargs="$linkargs -OPT:REF -OPT:ICF -INCREMENTAL:NO"
+ fi
+
+ args="$args -link $linkargs"
fi
if [ -n "$static_crt" ]; then
@@ -232,12 +299,33 @@ if [ -n "$assembly" ]; then
outdir="."
fi
ppsrc="$outdir/$(basename $src|sed 's/.S$/.asm/g')"
- echo "$cl -nologo -EP $includes $defines $src > $ppsrc"
+
+ if [ $ml = "armasm" ]; then
+ defines="$defines -D_M_ARM"
+ fi
+
+ if [ $ml = "armasm64" ]; then
+ defines="$defines -D_M_ARM64"
+ fi
+
+ if test -n "$verbose"; then
+ echo "$cl -nologo -EP $includes $defines $src > $ppsrc"
+ fi
+
"$cl" -nologo -EP $includes $defines $src > $ppsrc || exit $?
output="$(echo $output | sed 's%/F[dpa][^ ]*%%g')"
- args="-nologo $safeseh $single $output $ppsrc"
+ if [ $ml = "armasm" ]; then
+ args="-nologo -g -oldit $armasm_output $ppsrc -errorReport:prompt"
+ elif [ $ml = "armasm64" ]; then
+ args="-nologo -g $armasm_output $ppsrc -errorReport:prompt"
+ else
+ args="-nologo $safeseh $single $output $ppsrc"
+ fi
+
+ if test -n "$verbose"; then
+ echo "$ml $args"
+ fi
- echo "$ml $args"
eval "\"$ml\" $args"
result=$?
@@ -245,13 +333,21 @@ if [ -n "$assembly" ]; then
#mv *.obj $outdir
else
args="$md $args"
- echo "$cl $args"
+
+ if test -n "$verbose"; then
+ echo "$cl $args"
+ fi
# Return an error code of 1 if an invalid command line parameter is passed
- # instead of just ignoring it.
+ # instead of just ignoring it. Any output that is not a warning or an
+ # error is filtered so this command behaves more like gcc. cl.exe prints
+ # the name of the compiled file otherwise, which breaks the dejagnu checks
+ # for excess warnings and errors.
eval "(\"$cl\" $args 2>&1 1>&3 | \
- awk '{print \$0} /D9002/ {error=1} END{exit error}' >&2) 3>&1"
+ awk '{print \$0} /D9002/ {error=1} END{exit error}' >&2) 3>&1 | \
+ awk '/warning|error/'"
result=$?
fi
exit $result
+# vim: noai:ts=4:sw=4
diff --git a/src/aarch64/ffi.c b/src/aarch64/ffi.c
index cdb7816e..1ebf43c1 100644
--- a/src/aarch64/ffi.c
+++ b/src/aarch64/ffi.c
@@ -19,385 +19,225 @@ 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. */
+#if defined(__aarch64__) || defined(__arm64__)|| defined (_M_ARM64)
#include <stdio.h>
-
+#include <stdlib.h>
+#include <stdint.h>
+#include <fficonfig.h>
#include <ffi.h>
#include <ffi_common.h>
+#include "internal.h"
+#ifdef _M_ARM64
+#include <windows.h> /* FlushInstructionCache */
+#endif
-#include <stdlib.h>
-
-/* Stack alignment requirement in bytes */
-#if defined (__APPLE__)
-#define AARCH64_STACK_ALIGN 1
+/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
+ all further uses in this file will refer to the 128-bit type. */
+#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
+# if FFI_TYPE_LONGDOUBLE != 4
+# error FFI_TYPE_LONGDOUBLE out of date
+# endif
#else
-#define AARCH64_STACK_ALIGN 16
+# undef FFI_TYPE_LONGDOUBLE
+# define FFI_TYPE_LONGDOUBLE 4
#endif
-#define N_X_ARG_REG 8
-#define N_V_ARG_REG 8
-
-#define AARCH64_FFI_WITH_V (1 << AARCH64_FFI_WITH_V_BIT)
-
union _d
{
UINT64 d;
UINT32 s[2];
};
+struct _v
+{
+ union _d d[2] __attribute__((aligned(16)));
+};
+
struct call_context
{
- UINT64 x [AARCH64_N_XREG];
- struct
- {
- union _d d[2];
- } v [AARCH64_N_VREG];
+ struct _v v[N_V_ARG_REG];
+ UINT64 x[N_X_ARG_REG];
};
+#if FFI_EXEC_TRAMPOLINE_TABLE
+
+#ifdef __MACH__
+#include <mach/vm_param.h>
+#endif
+
+#else
+
#if defined (__clang__) && defined (__APPLE__)
-extern void
-sys_icache_invalidate (void *start, size_t len);
+extern void sys_icache_invalidate (void *start, size_t len);
#endif
static inline void
ffi_clear_cache (void *start, void *end)
{
#if defined (__clang__) && defined (__APPLE__)
- sys_icache_invalidate (start, (char *)end - (char *)start);
+ sys_icache_invalidate (start, (char *)end - (char *)start);
#elif defined (__GNUC__)
- __builtin___clear_cache (start, end);
+ __builtin___clear_cache (start, end);
+#elif defined (_M_ARM64)
+ FlushInstructionCache(GetCurrentProcess(), start, (char*)end - (char*)start);
#else
#error "Missing builtin to flush instruction cache"
#endif
}
-static void *
-get_x_addr (struct call_context *context, unsigned n)
-{
- return &context->x[n];
-}
-
-static void *
-get_s_addr (struct call_context *context, unsigned n)
-{
-#if defined __AARCH64EB__
- return &context->v[n].d[1].s[1];
-#else
- return &context->v[n].d[0].s[0];
#endif
-}
-static void *
-get_d_addr (struct call_context *context, unsigned n)
-{
-#if defined __AARCH64EB__
- return &context->v[n].d[1];
-#else
- return &context->v[n].d[0];
-#endif
-}
+/* A subroutine of is_vfp_type. Given a structure type, return the type code
+ of the first non-structure element. Recurse for structure elements.
+ Return -1 if the structure is in fact empty, i.e. no nested elements. */
-static void *
-get_v_addr (struct call_context *context, unsigned n)
+static int
+is_hfa0 (const ffi_type *ty)
{
- return &context->v[n];
-}
+ ffi_type **elements = ty->elements;
+ int i, ret = -1;
-/* Return the memory location at which a basic type would reside
- were it to have been stored in register n. */
+ if (elements != NULL)
+ for (i = 0; elements[i]; ++i)
+ {
+ ret = elements[i]->type;
+ if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX)
+ {
+ ret = is_hfa0 (elements[i]);
+ if (ret < 0)
+ continue;
+ }
+ break;
+ }
-static void *
-get_basic_type_addr (unsigned short type, struct call_context *context,
- unsigned n)
-{
- switch (type)
- {
- case FFI_TYPE_FLOAT:
- return get_s_addr (context, n);
- case FFI_TYPE_DOUBLE:
- return get_d_addr (context, n);
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
- return get_v_addr (context, n);
-#endif
- 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_INT:
- case FFI_TYPE_POINTER:
- case FFI_TYPE_UINT64:
- case FFI_TYPE_SINT64:
- return get_x_addr (context, n);
- case FFI_TYPE_VOID:
- return NULL;
- default:
- FFI_ASSERT (0);
- return NULL;
- }
+ return ret;
}
-/* Return the alignment width for each of the basic types. */
+/* A subroutine of is_vfp_type. Given a structure type, return true if all
+ of the non-structure elements are the same as CANDIDATE. */
-static size_t
-get_basic_type_alignment (unsigned short type)
+static int
+is_hfa1 (const ffi_type *ty, int candidate)
{
- switch (type)
- {
- case FFI_TYPE_FLOAT:
-#if defined (__APPLE__)
- return sizeof (UINT32);
-#endif
- case FFI_TYPE_DOUBLE:
- return sizeof (UINT64);
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
- return sizeof (long double);
-#endif
- case FFI_TYPE_UINT8:
- case FFI_TYPE_SINT8:
-#if defined (__APPLE__)
- return sizeof (UINT8);
-#endif
- case FFI_TYPE_UINT16:
- case FFI_TYPE_SINT16:
-#if defined (__APPLE__)
- return sizeof (UINT16);
-#endif
- case FFI_TYPE_UINT32:
- case FFI_TYPE_INT:
- case FFI_TYPE_SINT32:
-#if defined (__APPLE__)
- return sizeof (UINT32);
-#endif
- case FFI_TYPE_POINTER:
- case FFI_TYPE_UINT64:
- case FFI_TYPE_SINT64:
- return sizeof (UINT64);
-
- default:
- FFI_ASSERT (0);
- return 0;
- }
-}
-
-/* Return the size in bytes for each of the basic types. */
+ ffi_type **elements = ty->elements;
+ int i;
-static size_t
-get_basic_type_size (unsigned short type)
-{
- switch (type)
- {
- case FFI_TYPE_FLOAT:
- return sizeof (UINT32);
- case FFI_TYPE_DOUBLE:
- return sizeof (UINT64);
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
- return sizeof (long double);
-#endif
- case FFI_TYPE_UINT8:
- return sizeof (UINT8);
- case FFI_TYPE_SINT8:
- return sizeof (SINT8);
- case FFI_TYPE_UINT16:
- return sizeof (UINT16);
- case FFI_TYPE_SINT16:
- return sizeof (SINT16);
- case FFI_TYPE_UINT32:
- return sizeof (UINT32);
- case FFI_TYPE_INT:
- case FFI_TYPE_SINT32:
- return sizeof (SINT32);
- case FFI_TYPE_POINTER:
- case FFI_TYPE_UINT64:
- return sizeof (UINT64);
- case FFI_TYPE_SINT64:
- return sizeof (SINT64);
+ if (elements != NULL)
+ for (i = 0; elements[i]; ++i)
+ {
+ int t = elements[i]->type;
+ if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
+ {
+ if (!is_hfa1 (elements[i], candidate))
+ return 0;
+ }
+ else if (t != candidate)
+ return 0;
+ }
- default:
- FFI_ASSERT (0);
- return 0;
- }
+ return 1;
}
-extern void
-ffi_call_SYSV (unsigned (*)(struct call_context *context, unsigned char *,
- extended_cif *),
- struct call_context *context,
- extended_cif *,
- size_t,
- void (*fn)(void));
-
-extern void
-ffi_closure_SYSV (ffi_closure *);
-
-/* Test for an FFI floating point representation. */
+/* Determine if TY may be allocated to the FP registers. This is both an
+ fp scalar type as well as an homogenous floating point aggregate (HFA).
+ That is, a structure consisting of 1 to 4 members of all the same type,
+ where that type is an fp scalar.
-static unsigned
-is_floating_type (unsigned short type)
-{
- return (type == FFI_TYPE_FLOAT || type == FFI_TYPE_DOUBLE
- || type == FFI_TYPE_LONGDOUBLE);
-}
+ Returns non-zero iff TY is an HFA. The result is the AARCH64_RET_*
+ constant for the type. */
-/* Test for a homogeneous structure. */
-
-static unsigned short
-get_homogeneous_type (ffi_type *ty)
+static int
+is_vfp_type (const ffi_type *ty)
{
- if (ty->type == FFI_TYPE_STRUCT && ty->elements)
- {
- unsigned i;
- unsigned short candidate_type
- = get_homogeneous_type (ty->elements[0]);
- for (i =1; ty->elements[i]; i++)
- {
- unsigned short iteration_type = 0;
- /* If we have a nested struct, we must find its homogeneous type.
- If that fits with our candidate type, we are still
- homogeneous. */
- if (ty->elements[i]->type == FFI_TYPE_STRUCT
- && ty->elements[i]->elements)
- {
- iteration_type = get_homogeneous_type (ty->elements[i]);
- }
- else
- {
- iteration_type = ty->elements[i]->type;
- }
-
- /* If we are not homogeneous, return FFI_TYPE_STRUCT. */
- if (candidate_type != iteration_type)
- return FFI_TYPE_STRUCT;
- }
- return candidate_type;
- }
-
- /* Base case, we have no more levels of nesting, so we
- are a basic type, and so, trivially homogeneous in that type. */
- return ty->type;
-}
-
-/* Determine the number of elements within a STRUCT.
+ ffi_type **elements;
+ int candidate, i;
+ size_t size, ele_count;
- Note, we must handle nested structs.
-
- If ty is not a STRUCT this function will return 0. */
-
-static unsigned
-element_count (ffi_type *ty)
-{
- if (ty->type == FFI_TYPE_STRUCT && ty->elements)
+ /* Quickest tests first. */
+ candidate = ty->type;
+ switch (candidate)
{
- unsigned n;
- unsigned elems = 0;
- for (n = 0; ty->elements[n]; n++)
+ default:
+ return 0;
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ ele_count = 1;
+ goto done;
+ case FFI_TYPE_COMPLEX:
+ candidate = ty->elements[0]->type;
+ switch (candidate)
{
- if (ty->elements[n]->type == FFI_TYPE_STRUCT
- && ty->elements[n]->elements)
- elems += element_count (ty->elements[n]);
- else
- elems++;
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ ele_count = 2;
+ goto done;
}
- return elems;
+ return 0;
+ case FFI_TYPE_STRUCT:
+ break;
}
- return 0;
-}
-
-/* Test for a homogeneous floating point aggregate.
- A homogeneous floating point aggregate is a homogeneous aggregate of
- a half- single- or double- precision floating point type with one
- to four elements. Note that this includes nested structs of the
- basic type. */
+ /* No HFA types are smaller than 4 bytes, or larger than 64 bytes. */
+ size = ty->size;
+ if (size < 4 || size > 64)
+ return 0;
-static int
-is_hfa (ffi_type *ty)
-{
- if (ty->type == FFI_TYPE_STRUCT
- && ty->elements[0]
- && is_floating_type (get_homogeneous_type (ty)))
+ /* Find the type of the first non-structure member. */
+ elements = ty->elements;
+ candidate = elements[0]->type;
+ if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX)
{
- unsigned n = element_count (ty);
- return n >= 1 && n <= 4;
+ for (i = 0; ; ++i)
+ {
+ candidate = is_hfa0 (elements[i]);
+ if (candidate >= 0)
+ break;
+ }
}
- return 0;
-}
-
-/* Test if an ffi_type is a candidate for passing in a register.
-
- This test does not check that sufficient registers of the
- appropriate class are actually available, merely that IFF
- sufficient registers are available then the argument will be passed
- in register(s).
- Note that an ffi_type that is deemed to be a register candidate
- will always be returned in registers.
-
- Returns 1 if a register candidate else 0. */
-
-static int
-is_register_candidate (ffi_type *ty)
-{
- switch (ty->type)
+ /* If the first member is not a floating point type, it's not an HFA.
+ Also quickly re-check the size of the structure. */
+ switch (candidate)
{
- case FFI_TYPE_VOID:
case FFI_TYPE_FLOAT:
+ ele_count = size / sizeof(float);
+ if (size != ele_count * sizeof(float))
+ return 0;
+ break;
case FFI_TYPE_DOUBLE:
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
+ ele_count = size / sizeof(double);
+ if (size != ele_count * sizeof(double))
+ return 0;
+ break;
case FFI_TYPE_LONGDOUBLE:
-#endif
- case FFI_TYPE_UINT8:
- case FFI_TYPE_UINT16:
- case FFI_TYPE_UINT32:
- case FFI_TYPE_UINT64:
- case FFI_TYPE_POINTER:
- case FFI_TYPE_SINT8:
- case FFI_TYPE_SINT16:
- case FFI_TYPE_SINT32:
- case FFI_TYPE_INT:
- case FFI_TYPE_SINT64:
- return 1;
-
- case FFI_TYPE_STRUCT:
- if (is_hfa (ty))
- {
- return 1;
- }
- else if (ty->size > 16)
- {
- /* Too large. Will be replaced with a pointer to memory. The
- pointer MAY be passed in a register, but the value will
- not. This test specifically fails since the argument will
- never be passed by value in registers. */
- return 0;
- }
- else
- {
- /* Might be passed in registers depending on the number of
- registers required. */
- return (ty->size + 7) / 8 < N_X_ARG_REG;
- }
+ ele_count = size / sizeof(long double);
+ if (size != ele_count * sizeof(long double))
+ return 0;
break;
-
default:
- FFI_ASSERT (0);
- break;
+ return 0;
}
+ if (ele_count > 4)
+ return 0;
- return 0;
-}
-
-/* Test if an ffi_type argument or result is a candidate for a vector
- register. */
+ /* Finally, make sure that all scalar elements are the same type. */
+ for (i = 0; elements[i]; ++i)
+ {
+ int t = elements[i]->type;
+ if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
+ {
+ if (!is_hfa1 (elements[i], candidate))
+ return 0;
+ }
+ else if (t != candidate)
+ return 0;
+ }
-static int
-is_v_register_candidate (ffi_type *ty)
-{
- return is_floating_type (ty->type)
- || (ty->type == FFI_TYPE_STRUCT && is_hfa (ty));
+ /* All tests succeeded. Encode the result. */
+ done:
+ return candidate * 4 + (4 - (int)ele_count);
}
/* Representation of the procedure call argument marshalling
@@ -419,254 +259,362 @@ struct arg_state
/* Initialize a procedure call argument marshalling state. */
static void
-arg_init (struct arg_state *state, size_t call_frame_size)
+arg_init (struct arg_state *state)
{
state->ngrn = 0;
state->nsrn = 0;
state->nsaa = 0;
-
#if defined (__APPLE__)
state->allocating_variadic = 0;
#endif
}
-/* Return the number of available consecutive core argument
- registers. */
-
-static unsigned
-available_x (struct arg_state *state)
-{
- return N_X_ARG_REG - state->ngrn;
-}
-
-/* Return the number of available consecutive vector argument
- registers. */
-
-static unsigned
-available_v (struct arg_state *state)
-{
- return N_V_ARG_REG - state->nsrn;
-}
-
-static void *
-allocate_to_x (struct call_context *context, struct arg_state *state)
-{
- FFI_ASSERT (state->ngrn < N_X_ARG_REG);
- return get_x_addr (context, (state->ngrn)++);
-}
-
-static void *
-allocate_to_s (struct call_context *context, struct arg_state *state)
-{
- FFI_ASSERT (state->nsrn < N_V_ARG_REG);
- return get_s_addr (context, (state->nsrn)++);
-}
-
-static void *
-allocate_to_d (struct call_context *context, struct arg_state *state)
-{
- FFI_ASSERT (state->nsrn < N_V_ARG_REG);
- return get_d_addr (context, (state->nsrn)++);
-}
-
-static void *
-allocate_to_v (struct call_context *context, struct arg_state *state)
-{
- FFI_ASSERT (state->nsrn < N_V_ARG_REG);
- return get_v_addr (context, (state->nsrn)++);
-}
-
/* Allocate an aligned slot on the stack and return a pointer to it. */
static void *
-allocate_to_stack (struct arg_state *state, void *stack, size_t alignment,
- size_t size)
+allocate_to_stack (struct arg_state *state, void *stack,
+ size_t alignment, size_t size)
{
- void *allocation;
+ size_t nsaa = state->nsaa;
/* Round up the NSAA to the larger of 8 or the natural
alignment of the argument's type. */
- state->nsaa = ALIGN (state->nsaa, alignment);
- state->nsaa = ALIGN (state->nsaa, alignment);
#if defined (__APPLE__)
- if (state->allocating_variadic)
- state->nsaa = ALIGN (state->nsaa, 8);
+ if (state->allocating_variadic && alignment < 8)
+ alignment = 8;
#else
- state->nsaa = ALIGN (state->nsaa, 8);
+ if (alignment < 8)
+ alignment = 8;
#endif
+
+ nsaa = FFI_ALIGN (nsaa, alignment);
+ state->nsaa = nsaa + size;
- allocation = stack + state->nsaa;
-
- state->nsaa += size;
- return allocation;
+ return (char *)stack + nsaa;
}
-static void
-copy_basic_type (void *dest, void *source, unsigned short type)
+static ffi_arg
+extend_integer_type (void *source, int type)
{
- /* This is necessary to ensure that basic types are copied
- sign extended to 64-bits as libffi expects. */
switch (type)
{
- case FFI_TYPE_FLOAT:
- *(float *) dest = *(float *) source;
- break;
- case FFI_TYPE_DOUBLE:
- *(double *) dest = *(double *) source;
- break;
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
- *(long double *) dest = *(long double *) source;
- break;
-#endif
case FFI_TYPE_UINT8:
- *(ffi_arg *) dest = *(UINT8 *) source;
- break;
+ return *(UINT8 *) source;
case FFI_TYPE_SINT8:
- *(ffi_sarg *) dest = *(SINT8 *) source;
- break;
+ return *(SINT8 *) source;
case FFI_TYPE_UINT16:
- *(ffi_arg *) dest = *(UINT16 *) source;
- break;
+ return *(UINT16 *) source;
case FFI_TYPE_SINT16:
- *(ffi_sarg *) dest = *(SINT16 *) source;
- break;
+ return *(SINT16 *) source;
case FFI_TYPE_UINT32:
- *(ffi_arg *) dest = *(UINT32 *) source;
- break;
+ return *(UINT32 *) source;
case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
- *(ffi_sarg *) dest = *(SINT32 *) source;
- break;
- case FFI_TYPE_POINTER:
+ return *(SINT32 *) source;
case FFI_TYPE_UINT64:
- *(ffi_arg *) dest = *(UINT64 *) source;
- break;
case FFI_TYPE_SINT64:
- *(ffi_sarg *) dest = *(SINT64 *) source;
+ return *(UINT64 *) source;
break;
- case FFI_TYPE_VOID:
- break;
-
+ case FFI_TYPE_POINTER:
+ return *(uintptr_t *) source;
default:
- FFI_ASSERT (0);
+ abort();
}
}
+#if defined(_MSC_VER)
+void extend_hfa_type (void *dest, void *src, int h);
+#else
static void
-copy_hfa_to_reg_or_stack (void *memory,
- ffi_type *ty,
- struct call_context *context,
- unsigned char *stack,
- struct arg_state *state)
+extend_hfa_type (void *dest, void *src, int h)
+{
+ ssize_t f = h - AARCH64_RET_S4;
+ void *x0;
+
+ asm volatile (
+ "adr %0, 0f\n"
+" add %0, %0, %1\n"
+" br %0\n"
+"0: ldp s16, s17, [%3]\n" /* S4 */
+" ldp s18, s19, [%3, #8]\n"
+" b 4f\n"
+" ldp s16, s17, [%3]\n" /* S3 */
+" ldr s18, [%3, #8]\n"
+" b 3f\n"
+" ldp s16, s17, [%3]\n" /* S2 */
+" b 2f\n"
+" nop\n"
+" ldr s16, [%3]\n" /* S1 */
+" b 1f\n"
+" nop\n"
+" ldp d16, d17, [%3]\n" /* D4 */
+" ldp d18, d19, [%3, #16]\n"
+" b 4f\n"
+" ldp d16, d17, [%3]\n" /* D3 */
+" ldr d18, [%3, #16]\n"
+" b 3f\n"
+" ldp d16, d17, [%3]\n" /* D2 */
+" b 2f\n"
+" nop\n"
+" ldr d16, [%3]\n" /* D1 */
+" b 1f\n"
+" nop\n"
+" ldp q16, q17, [%3]\n" /* Q4 */
+" ldp q18, q19, [%3, #32]\n"
+" b 4f\n"
+" ldp q16, q17, [%3]\n" /* Q3 */
+" ldr q18, [%3, #32]\n"
+" b 3f\n"
+" ldp q16, q17, [%3]\n" /* Q2 */
+" b 2f\n"
+" nop\n"
+" ldr q16, [%3]\n" /* Q1 */
+" b 1f\n"
+"4: str q19, [%2, #48]\n"
+"3: str q18, [%2, #32]\n"
+"2: str q17, [%2, #16]\n"
+"1: str q16, [%2]"
+ : "=&r"(x0)
+ : "r"(f * 12), "r"(dest), "r"(src)
+ : "memory", "v16", "v17", "v18", "v19");
+}
+#endif
+
+#if defined(_MSC_VER)
+void* compress_hfa_type (void *dest, void *src, int h);
+#else
+static void *
+compress_hfa_type (void *dest, void *reg, int h)
{
- unsigned elems = element_count (ty);
- if (available_v (state) < elems)
- {
- /* There are insufficient V registers. Further V register allocations
- are prevented, the NSAA is adjusted (by allocate_to_stack ())
- and the argument is copied to memory at the adjusted NSAA. */
- state->nsrn = N_V_ARG_REG;
- memcpy (allocate_to_stack (state, stack, ty->alignment, ty->size),
- memory,
- ty->size);
- }
- else
+ switch (h)
{
- int i;
- unsigned short type = get_homogeneous_type (ty);
- for (i = 0; i < elems; i++)
+ case AARCH64_RET_S1:
+ if (dest == reg)
+ {
+#ifdef __AARCH64EB__
+ dest += 12;
+#endif
+ }
+ else
+ *(float *)dest = *(float *)reg;
+ break;
+ case AARCH64_RET_S2:
+ asm ("ldp q16, q17, [%1]\n\t"
+ "st2 { v16.s, v17.s }[0], [%0]"
+ : : "r"(dest), "r"(reg) : "memory", "v16", "v17");
+ break;
+ case AARCH64_RET_S3:
+ asm ("ldp q16, q17, [%1]\n\t"
+ "ldr q18, [%1, #32]\n\t"
+ "st3 { v16.s, v17.s, v18.s }[0], [%0]"
+ : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18");
+ break;
+ case AARCH64_RET_S4:
+ asm ("ldp q16, q17, [%1]\n\t"
+ "ldp q18, q19, [%1, #32]\n\t"
+ "st4 { v16.s, v17.s, v18.s, v19.s }[0], [%0]"
+ : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19");
+ break;
+
+ case AARCH64_RET_D1:
+ if (dest == reg)
{
- void *reg = allocate_to_v (context, state);
- copy_basic_type (reg, memory, type);
- memory += get_basic_type_size (type);
+#ifdef __AARCH64EB__
+ dest += 8;
+#endif
}
+ else
+ *(double *)dest = *(double *)reg;
+ break;
+ case AARCH64_RET_D2:
+ asm ("ldp q16, q17, [%1]\n\t"
+ "st2 { v16.d, v17.d }[0], [%0]"
+ : : "r"(dest), "r"(reg) : "memory", "v16", "v17");
+ break;
+ case AARCH64_RET_D3:
+ asm ("ldp q16, q17, [%1]\n\t"
+ "ldr q18, [%1, #32]\n\t"
+ "st3 { v16.d, v17.d, v18.d }[0], [%0]"
+ : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18");
+ break;
+ case AARCH64_RET_D4:
+ asm ("ldp q16, q17, [%1]\n\t"
+ "ldp q18, q19, [%1, #32]\n\t"
+ "st4 { v16.d, v17.d, v18.d, v19.d }[0], [%0]"
+ : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19");
+ break;
+
+ default:
+ if (dest != reg)
+ return memcpy (dest, reg, 16 * (4 - (h & 3)));
+ break;
}
+ return dest;
}
+#endif
/* Either allocate an appropriate register for the argument type, or if
none are available, allocate a stack slot and return a pointer
to the allocated space. */
static void *
-allocate_to_register_or_stack (struct call_context *context,
- unsigned char *stack,
- struct arg_state *state,
- unsigned short type)
+allocate_int_to_reg_or_stack (struct call_context *context,
+ struct arg_state *state,
+ void *stack, size_t size)
{
- size_t alignment = get_basic_type_alignment (type);
- size_t size = alignment;
- switch (type)
+ if (state->ngrn < N_X_ARG_REG)
+ return &context->x[state->ngrn++];
+
+ state->ngrn = N_X_ARG_REG;
+ return allocate_to_stack (state, stack, size, size);
+}
+
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep (ffi_cif *cif)
+{
+ ffi_type *rtype = cif->rtype;
+ size_t bytes = cif->bytes;
+ int flags, i, n;
+
+ switch (rtype->type)
{
- case FFI_TYPE_FLOAT:
- /* This is the only case for which the allocated stack size
- should not match the alignment of the type. */
- size = sizeof (UINT32);
- /* Fall through. */
- case FFI_TYPE_DOUBLE:
- if (state->nsrn < N_V_ARG_REG)
- return allocate_to_d (context, state);
- state->nsrn = N_V_ARG_REG;
- break;
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
- if (state->nsrn < N_V_ARG_REG)
- return allocate_to_v (context, state);
- state->nsrn = N_V_ARG_REG;
+ case FFI_TYPE_VOID:
+ flags = AARCH64_RET_VOID;
break;
-#endif
case FFI_TYPE_UINT8:
- case FFI_TYPE_SINT8:
+ flags = AARCH64_RET_UINT8;
+ break;
case FFI_TYPE_UINT16:
- case FFI_TYPE_SINT16:
+ flags = AARCH64_RET_UINT16;
+ break;
case FFI_TYPE_UINT32:
- case FFI_TYPE_SINT32:
+ flags = AARCH64_RET_UINT32;
+ break;
+ case FFI_TYPE_SINT8:
+ flags = AARCH64_RET_SINT8;
+ break;
+ case FFI_TYPE_SINT16:
+ flags = AARCH64_RET_SINT16;
+ break;
case FFI_TYPE_INT:
- case FFI_TYPE_POINTER:
- case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT32:
+ flags = AARCH64_RET_SINT32;
+ break;
case FFI_TYPE_SINT64:
- if (state->ngrn < N_X_ARG_REG)
- return allocate_to_x (context, state);
- state->ngrn = N_X_ARG_REG;
+ case FFI_TYPE_UINT64:
+ flags = AARCH64_RET_INT64;
+ break;
+ case FFI_TYPE_POINTER:
+ flags = (sizeof(void *) == 4 ? AARCH64_RET_UINT32 : AARCH64_RET_INT64);
break;
+
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_COMPLEX:
+ flags = is_vfp_type (rtype);
+ if (flags == 0)
+ {
+ size_t s = rtype->size;
+ if (s > 16)
+ {
+ flags = AARCH64_RET_VOID | AARCH64_RET_IN_MEM;
+ bytes += 8;
+ }
+ else if (s == 16)
+ flags = AARCH64_RET_INT128;
+ else if (s == 8)
+ flags = AARCH64_RET_INT64;
+ else
+ flags = AARCH64_RET_INT128 | AARCH64_RET_NEED_COPY;
+ }
+ break;
+
default:
- FFI_ASSERT (0);
+ abort();
}
- return allocate_to_stack (state, stack, alignment, size);
-}
+ for (i = 0, n = cif->nargs; i < n; i++)
+ if (is_vfp_type (cif->arg_types[i]))
+ {
+ flags |= AARCH64_FLAG_ARG_V;
+ break;
+ }
+
+ /* Round the stack up to a multiple of the stack alignment requirement. */
+ cif->bytes = (unsigned) FFI_ALIGN(bytes, 16);
+ cif->flags = flags;
+#if defined (__APPLE__)
+ cif->aarch64_nfixedargs = 0;
+#endif
-/* Copy a value to an appropriate register, or if none are
- available, to the stack. */
+ return FFI_OK;
+}
-static void
-copy_to_register_or_stack (struct call_context *context,
- unsigned char *stack,
- struct arg_state *state,
- void *value,
- unsigned short type)
+#if defined (__APPLE__)
+/* Perform Apple-specific cif processing for variadic calls */
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
+ unsigned int ntotalargs)
{
- copy_basic_type (
- allocate_to_register_or_stack (context, stack, state, type),
- value,
- type);
+ ffi_status status = ffi_prep_cif_machdep (cif);
+ cif->aarch64_nfixedargs = nfixedargs;
+ return status;
}
+#endif /* __APPLE__ */
-/* Marshall the arguments from FFI representation to procedure call
- context and stack. */
+extern void ffi_call_SYSV (struct call_context *context, void *frame,
+ void (*fn)(void), void *rvalue, int flags,
+ void *closure) FFI_HIDDEN;
-static unsigned
-aarch64_prep_args (struct call_context *context, unsigned char *stack,
- extended_cif *ecif)
+/* Call a function with the provided arguments and capture the return
+ value. */
+static void
+ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
+ void **avalue, void *closure)
{
- int i;
+ struct call_context *context;
+ void *stack, *frame, *rvalue;
struct arg_state state;
-
- arg_init (&state, ALIGN(ecif->cif->bytes, 16));
-
- for (i = 0; i < ecif->cif->nargs; i++)
+ size_t stack_bytes, rtype_size, rsize;
+ int i, nargs, flags;
+ ffi_type *rtype;
+
+ flags = cif->flags;
+ rtype = cif->rtype;
+ rtype_size = rtype->size;
+ stack_bytes = cif->bytes;
+
+ /* If the target function returns a structure via hidden pointer,
+ then we cannot allow a null rvalue. Otherwise, mash a null
+ rvalue to void return type. */
+ rsize = 0;
+ if (flags & AARCH64_RET_IN_MEM)
{
- ffi_type *ty = ecif->cif->arg_types[i];
- switch (ty->type)
+ if (orig_rvalue == NULL)
+ rsize = rtype_size;
+ }
+ else if (orig_rvalue == NULL)
+ flags &= AARCH64_FLAG_ARG_V;
+ else if (flags & AARCH64_RET_NEED_COPY)
+ rsize = 16;
+
+ /* Allocate consectutive stack for everything we'll need. */
+ context = alloca (sizeof(struct call_context) + stack_bytes + 32 + rsize);
+ stack = context + 1;
+ frame = (void*)((uintptr_t)stack + (uintptr_t)stack_bytes);
+ rvalue = (rsize ? (void*)((uintptr_t)frame + 32) : orig_rvalue);
+
+ arg_init (&state);
+ for (i = 0, nargs = cif->nargs; i < nargs; i++)
+ {
+ ffi_type *ty = cif->arg_types[i];
+ size_t s = ty->size;
+ void *a = avalue[i];
+ int h, t;
+
+ t = ty->type;
+ switch (t)
{
case FFI_TYPE_VOID:
FFI_ASSERT (0);
@@ -674,258 +622,156 @@ aarch64_prep_args (struct call_context *context, unsigned char *stack,
/* If the argument is a basic type the argument is allocated to an
appropriate register, or if none are available, to the stack. */
- case FFI_TYPE_FLOAT:
- case FFI_TYPE_DOUBLE:
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
-#endif
+ case FFI_TYPE_INT:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT32:
- case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
- case FFI_TYPE_POINTER:
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
- copy_to_register_or_stack (context, stack, &state,
- ecif->avalue[i], ty->type);
+ case FFI_TYPE_POINTER:
+ do_pointer:
+ {
+ ffi_arg ext = extend_integer_type (a, t);
+ if (state.ngrn < N_X_ARG_REG)
+ context->x[state.ngrn++] = ext;
+ else
+ {
+ void *d = allocate_to_stack (&state, stack, ty->alignment, s);
+ state.ngrn = N_X_ARG_REG;
+ /* Note that the default abi extends each argument
+ to a full 64-bit slot, while the iOS abi allocates
+ only enough space. */
+#ifdef __APPLE__
+ memcpy(d, a, s);
+#else
+ *(ffi_arg *)d = ext;
+#endif
+ }
+ }
break;
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
case FFI_TYPE_STRUCT:
- if (is_hfa (ty))
- {
- copy_hfa_to_reg_or_stack (ecif->avalue[i], ty, context,
- stack, &state);
- }
- else if (ty->size > 16)
- {
- /* If the argument is a composite type that is larger than 16
- bytes, then the argument has been copied to memory, and
- the argument is replaced by a pointer to the copy. */
-
- copy_to_register_or_stack (context, stack, &state,
- &(ecif->avalue[i]), FFI_TYPE_POINTER);
- }
- else if (available_x (&state) >= (ty->size + 7) / 8)
- {
- /* If the argument is a composite type and the size in
- double-words is not more than the number of available
- X registers, then the argument is copied into consecutive
- X registers. */
- int j;
- for (j = 0; j < (ty->size + 7) / 8; j++)
- {
- memcpy (allocate_to_x (context, &state),
- &(((UINT64 *) ecif->avalue[i])[j]),
- sizeof (UINT64));
+ case FFI_TYPE_COMPLEX:
+ {
+ void *dest;
+
+ h = is_vfp_type (ty);
+ if (h)
+ {
+ int elems = 4 - (h & 3);
+#ifdef _M_ARM64 /* for handling armasm calling convention */
+ if (cif->is_variadic)
+ {
+ if (state.ngrn + elems <= N_X_ARG_REG)
+ {
+ dest = &context->x[state.ngrn];
+ state.ngrn += elems;
+ extend_hfa_type(dest, a, h);
+ break;
+ }
+ state.nsrn = N_X_ARG_REG;
+ dest = allocate_to_stack(&state, stack, ty->alignment, s);
+ }
+ else
+ {
+#endif /* for handling armasm calling convention */
+ if (state.nsrn + elems <= N_V_ARG_REG)
+ {
+ dest = &context->v[state.nsrn];
+ state.nsrn += elems;
+ extend_hfa_type (dest, a, h);
+ break;
+ }
+ state.nsrn = N_V_ARG_REG;
+ dest = allocate_to_stack (&state, stack, ty->alignment, s);
+#ifdef _M_ARM64 /* for handling armasm calling convention */
+ }
+#endif /* for handling armasm calling convention */
+ }
+ else if (s > 16)
+ {
+ /* If the argument is a composite type that is larger than 16
+ bytes, then the argument has been copied to memory, and
+ the argument is replaced by a pointer to the copy. */
+ a = &avalue[i];
+ t = FFI_TYPE_POINTER;
+ s = sizeof (void *);
+ goto do_pointer;
+ }
+ else
+ {
+ size_t n = (s + 7) / 8;
+ if (state.ngrn + n <= N_X_ARG_REG)
+ {
+ /* If the argument is a composite type and the size in
+ double-words is not more than the number of available
+ X registers, then the argument is copied into
+ consecutive X registers. */
+ dest = &context->x[state.ngrn];
+ state.ngrn += (unsigned int)n;
+ }
+ else
+ {
+ /* Otherwise, there are insufficient X registers. Further
+ X register allocations are prevented, the NSAA is
+ adjusted and the argument is copied to memory at the
+ adjusted NSAA. */
+ state.ngrn = N_X_ARG_REG;
+ dest = allocate_to_stack (&state, stack, ty->alignment, s);
+ }
}
- }
- else
- {
- /* Otherwise, there are insufficient X registers. Further X
- register allocations are prevented, the NSAA is adjusted
- (by allocate_to_stack ()) and the argument is copied to
- memory at the adjusted NSAA. */
- state.ngrn = N_X_ARG_REG;
-
- memcpy (allocate_to_stack (&state, stack, ty->alignment,
- ty->size), ecif->avalue + i, ty->size);
+ memcpy (dest, a, s);
}
break;
default:
- FFI_ASSERT (0);
- break;
+ abort();
}
#if defined (__APPLE__)
- if (i + 1 == ecif->cif->aarch64_nfixedargs)
+ if (i + 1 == cif->aarch64_nfixedargs)
{
state.ngrn = N_X_ARG_REG;
state.nsrn = N_V_ARG_REG;
-
state.allocating_variadic = 1;
}
#endif
}
- return ecif->cif->aarch64_flags;
-}
-
-ffi_status
-ffi_prep_cif_machdep (ffi_cif *cif)
-{
- /* Round the stack up to a multiple of the stack alignment requirement. */
- cif->bytes =
- (cif->bytes + (AARCH64_STACK_ALIGN - 1)) & ~ (AARCH64_STACK_ALIGN - 1);
-
- /* Initialize our flags. We are interested if this CIF will touch a
- vector register, if so we will enable context save and load to
- those registers, otherwise not. This is intended to be friendly
- to lazy float context switching in the kernel. */
- cif->aarch64_flags = 0;
-
- if (is_v_register_candidate (cif->rtype))
- {
- cif->aarch64_flags |= AARCH64_FFI_WITH_V;
- }
- else
- {
- int i;
- for (i = 0; i < cif->nargs; i++)
- if (is_v_register_candidate (cif->arg_types[i]))
- {
- cif->aarch64_flags |= AARCH64_FFI_WITH_V;
- break;
- }
- }
-
-#if defined (__APPLE__)
- cif->aarch64_nfixedargs = 0;
-#endif
+ ffi_call_SYSV (context, frame, fn, rvalue, flags, closure);
- return FFI_OK;
+ if (flags & AARCH64_RET_NEED_COPY)
+ memcpy (orig_rvalue, rvalue, rtype_size);
}
-#if defined (__APPLE__)
-
-/* Perform Apple-specific cif processing for variadic calls */
-ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
- unsigned int nfixedargs,
- unsigned int ntotalargs)
+void
+ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
{
- ffi_status status;
-
- status = ffi_prep_cif_machdep (cif);
-
- cif->aarch64_nfixedargs = nfixedargs;
-
- return status;
+ ffi_call_int (cif, fn, rvalue, avalue, NULL);
}
-#endif
-
-/* Call a function with the provided arguments and capture the return
- value. */
+#ifdef FFI_GO_CLOSURES
void
-ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
+ void **avalue, void *closure)
{
- extended_cif ecif;
-
- ecif.cif = cif;
- ecif.avalue = avalue;
- ecif.rvalue = rvalue;
-
- switch (cif->abi)
- {
- case FFI_SYSV:
- {
- struct call_context context;
- size_t stack_bytes;
-
- /* Figure out the total amount of stack space we need, the
- above call frame space needs to be 16 bytes aligned to
- ensure correct alignment of the first object inserted in
- that space hence the ALIGN applied to cif->bytes.*/
- stack_bytes = ALIGN(cif->bytes, 16);
-
- memset (&context, 0, sizeof (context));
- if (is_register_candidate (cif->rtype))
- {
- ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn);
- switch (cif->rtype->type)
- {
- case FFI_TYPE_VOID:
- case FFI_TYPE_FLOAT:
- case FFI_TYPE_DOUBLE:
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
-#endif
- 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_POINTER:
- case FFI_TYPE_UINT64:
- case FFI_TYPE_INT:
- case FFI_TYPE_SINT64:
- {
- void *addr = get_basic_type_addr (cif->rtype->type,
- &context, 0);
- copy_basic_type (rvalue, addr, cif->rtype->type);
- break;
- }
-
- case FFI_TYPE_STRUCT:
- if (is_hfa (cif->rtype))
- {
- int j;
- unsigned short type = get_homogeneous_type (cif->rtype);
- unsigned elems = element_count (cif->rtype);
- for (j = 0; j < elems; j++)
- {
- void *reg = get_basic_type_addr (type, &context, j);
- copy_basic_type (rvalue, reg, type);
- rvalue += get_basic_type_size (type);
- }
- }
- else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
- {
- size_t size = ALIGN (cif->rtype->size, sizeof (UINT64));
- memcpy (rvalue, get_x_addr (&context, 0), size);
- }
- else
- {
- FFI_ASSERT (0);
- }
- break;
-
- default:
- FFI_ASSERT (0);
- break;
- }
- }
- else
- {
- memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64));
- ffi_call_SYSV (aarch64_prep_args, &context, &ecif,
- stack_bytes, fn);
- }
- break;
- }
-
- default:
- FFI_ASSERT (0);
- break;
- }
+ ffi_call_int (cif, fn, rvalue, avalue, closure);
}
-
-static unsigned char trampoline [] =
-{ 0x70, 0x00, 0x00, 0x58, /* ldr x16, 1f */
- 0x91, 0x00, 0x00, 0x10, /* adr x17, 2f */
- 0x00, 0x02, 0x1f, 0xd6 /* br x16 */
-};
+#endif /* FFI_GO_CLOSURES */
/* Build a trampoline. */
-#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,FLAGS) \
- ({unsigned char *__tramp = (unsigned char*)(TRAMP); \
- UINT64 __fun = (UINT64)(FUN); \
- UINT64 __ctx = (UINT64)(CTX); \
- UINT64 __flags = (UINT64)(FLAGS); \
- memcpy (__tramp, trampoline, sizeof (trampoline)); \
- memcpy (__tramp + 12, &__fun, sizeof (__fun)); \
- memcpy (__tramp + 20, &__ctx, sizeof (__ctx)); \
- memcpy (__tramp + 28, &__flags, sizeof (__flags)); \
- ffi_clear_cache(__tramp, __tramp + FFI_TRAMPOLINE_SIZE); \
- })
+extern void ffi_closure_SYSV (void) FFI_HIDDEN;
+extern void ffi_closure_SYSV_V (void) FFI_HIDDEN;
ffi_status
-ffi_prep_closure_loc (ffi_closure* closure,
+ffi_prep_closure_loc (ffi_closure *closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
@@ -934,16 +780,77 @@ ffi_prep_closure_loc (ffi_closure* closure,
if (cif->abi != FFI_SYSV)
return FFI_BAD_ABI;
- FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV, codeloc,
- cif->aarch64_flags);
+ void (*start)(void);
+
+ if (cif->flags & AARCH64_FLAG_ARG_V)
+ start = ffi_closure_SYSV_V;
+ else
+ start = ffi_closure_SYSV;
- closure->cif = cif;
+#if FFI_EXEC_TRAMPOLINE_TABLE
+#ifdef __MACH__
+ void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
+ config[0] = closure;
+ config[1] = start;
+#endif
+#else
+ static const unsigned char trampoline[16] = {
+ 0x90, 0x00, 0x00, 0x58, /* ldr x16, tramp+16 */
+ 0xf1, 0xff, 0xff, 0x10, /* adr x17, tramp+0 */
+ 0x00, 0x02, 0x1f, 0xd6 /* br x16 */
+ };
+ char *tramp = closure->tramp;
+
+ memcpy (tramp, trampoline, sizeof(trampoline));
+
+ *(UINT64 *)(tramp + 16) = (uintptr_t)start;
+
+ ffi_clear_cache(tramp, tramp + FFI_TRAMPOLINE_SIZE);
+
+ /* Also flush the cache for code mapping. */
+#ifdef _M_ARM64
+ // Not using dlmalloc.c for Windows ARM64 builds
+ // so calling ffi_data_to_code_pointer() isn't necessary
+ unsigned char *tramp_code = tramp;
+ #else
+ unsigned char *tramp_code = ffi_data_to_code_pointer (tramp);
+ #endif
+ ffi_clear_cache (tramp_code, tramp_code + FFI_TRAMPOLINE_SIZE);
+#endif
+
+ closure->cif = cif;
+ closure->fun = fun;
closure->user_data = user_data;
- closure->fun = fun;
return FFI_OK;
}
+#ifdef FFI_GO_CLOSURES
+extern void ffi_go_closure_SYSV (void) FFI_HIDDEN;
+extern void ffi_go_closure_SYSV_V (void) FFI_HIDDEN;
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*))
+{
+ void (*start)(void);
+
+ if (cif->abi != FFI_SYSV)
+ return FFI_BAD_ABI;
+
+ if (cif->flags & AARCH64_FLAG_ARG_V)
+ start = ffi_go_closure_SYSV_V;
+ else
+ start = ffi_go_closure_SYSV;
+
+ closure->tramp = start;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+#endif /* FFI_GO_CLOSURES */
+
/* Primary handler to setup and invoke a function within a closure.
A closure when invoked enters via the assembler wrapper
@@ -960,220 +867,143 @@ ffi_prep_closure_loc (ffi_closure* closure,
descriptors, invokes the wrapped function, then marshalls the return
value back into the call context. */
-void FFI_HIDDEN
-ffi_closure_SYSV_inner (ffi_closure *closure, struct call_context *context,
- void *stack)
+int FFI_HIDDEN
+ffi_closure_SYSV_inner (ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data,
+ struct call_context *context,
+ void *stack, void *rvalue, void *struct_rvalue)
{
- ffi_cif *cif = closure->cif;
void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
- void *rvalue = NULL;
- int i;
+ int i, h, nargs, flags;
struct arg_state state;
- arg_init (&state, ALIGN(cif->bytes, 16));
+ arg_init (&state);
- for (i = 0; i < cif->nargs; i++)
+ for (i = 0, nargs = cif->nargs; i < nargs; i++)
{
ffi_type *ty = cif->arg_types[i];
+ int t = ty->type;
+ size_t n, s = ty->size;
- switch (ty->type)
+ switch (t)
{
case FFI_TYPE_VOID:
FFI_ASSERT (0);
break;
+ case FFI_TYPE_INT:
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_INT:
- case FFI_TYPE_POINTER:
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
- case FFI_TYPE_FLOAT:
- case FFI_TYPE_DOUBLE:
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
- avalue[i] = allocate_to_register_or_stack (context, stack,
- &state, ty->type);
+ case FFI_TYPE_POINTER:
+ avalue[i] = allocate_int_to_reg_or_stack (context, &state, stack, s);
break;
-#endif
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
case FFI_TYPE_STRUCT:
- if (is_hfa (ty))
- {
- unsigned n = element_count (ty);
- if (available_v (&state) < n)
- {
- state.nsrn = N_V_ARG_REG;
- avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
- ty->size);
- }
- else
- {
- switch (get_homogeneous_type (ty))
- {
- case FFI_TYPE_FLOAT:
- {
- /* Eeek! We need a pointer to the structure,
- however the homogeneous float elements are
- being passed in individual S registers,
- therefore the structure is not represented as
- a contiguous sequence of bytes in our saved
- register context. We need to fake up a copy
- of the structure laid out in memory
- correctly. The fake can be tossed once the
- closure function has returned hence alloca()
- is sufficient. */
- int j;
- UINT32 *p = avalue[i] = alloca (ty->size);
- for (j = 0; j < element_count (ty); j++)
- memcpy (&p[j],
- allocate_to_s (context, &state),
- sizeof (*p));
- break;
- }
-
- case FFI_TYPE_DOUBLE:
- {
- /* Eeek! We need a pointer to the structure,
- however the homogeneous float elements are
- being passed in individual S registers,
- therefore the structure is not represented as
- a contiguous sequence of bytes in our saved
- register context. We need to fake up a copy
- of the structure laid out in memory
- correctly. The fake can be tossed once the
- closure function has returned hence alloca()
- is sufficient. */
- int j;
- UINT64 *p = avalue[i] = alloca (ty->size);
- for (j = 0; j < element_count (ty); j++)
- memcpy (&p[j],
- allocate_to_d (context, &state),
- sizeof (*p));
- break;
- }
-
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
- memcpy (&avalue[i],
- allocate_to_v (context, &state),
- sizeof (*avalue));
- break;
-#endif
-
- default:
- FFI_ASSERT (0);
- break;
- }
- }
- }
- else if (ty->size > 16)
- {
- /* Replace Composite type of size greater than 16 with a
- pointer. */
- memcpy (&avalue[i],
- allocate_to_register_or_stack (context, stack,
- &state, FFI_TYPE_POINTER),
- sizeof (avalue[i]));
- }
- else if (available_x (&state) >= (ty->size + 7) / 8)
- {
- avalue[i] = get_x_addr (context, state.ngrn);
- state.ngrn += (ty->size + 7) / 8;
- }
- else
- {
- state.ngrn = N_X_ARG_REG;
-
- avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
- ty->size);
- }
- break;
-
- default:
- FFI_ASSERT (0);
- break;
- }
- }
-
- /* Figure out where the return value will be passed, either in
- registers or in a memory block allocated by the caller and passed
- in x8. */
-
- if (is_register_candidate (cif->rtype))
- {
- /* Register candidates are *always* returned in registers. */
-
- /* Allocate a scratchpad for the return value, we will let the
- callee scrible the result into the scratch pad then move the
- contents into the appropriate return value location for the
- call convention. */
- rvalue = alloca (cif->rtype->size);
- (closure->fun) (cif, rvalue, avalue, closure->user_data);
-
- /* Copy the return value into the call context so that it is returned
- as expected to our caller. */
- switch (cif->rtype->type)
- {
- case FFI_TYPE_VOID:
- break;
-
- case FFI_TYPE_UINT8:
- case FFI_TYPE_UINT16:
- case FFI_TYPE_UINT32:
- case FFI_TYPE_POINTER:
- case FFI_TYPE_UINT64:
- case FFI_TYPE_SINT8:
- case FFI_TYPE_SINT16:
- case FFI_TYPE_INT:
- case FFI_TYPE_SINT32:
- case FFI_TYPE_SINT64:
- case FFI_TYPE_FLOAT:
- case FFI_TYPE_DOUBLE:
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
-#endif
- {
- void *addr = get_basic_type_addr (cif->rtype->type, context, 0);
- copy_basic_type (addr, rvalue, cif->rtype->type);
- break;
- }
- case FFI_TYPE_STRUCT:
- if (is_hfa (cif->rtype))
+ case FFI_TYPE_COMPLEX:
+ h = is_vfp_type (ty);
+ if (h)
{
- int j;
- unsigned short type = get_homogeneous_type (cif->rtype);
- unsigned elems = element_count (cif->rtype);
- for (j = 0; j < elems; j++)
- {
- void *reg = get_basic_type_addr (type, context, j);
- copy_basic_type (reg, rvalue, type);
- rvalue += get_basic_type_size (type);
- }
- }
- else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
+ n = 4 - (h & 3);
+#ifdef _M_ARM64 /* for handling armasm calling convention */
+ if (cif->is_variadic)
+ {
+ if (state.ngrn + n <= N_X_ARG_REG)
+ {
+ void *reg = &context->x[state.ngrn];
+ state.ngrn += (unsigned int)n;
+
+ /* Eeek! We need a pointer to the structure, however the
+ homogeneous float elements are being passed in individual
+ registers, therefore for float and double the structure
+ is not represented as a contiguous sequence of bytes in
+ our saved register context. We don't need the original
+ contents of the register storage, so we reformat the
+ structure into the same memory. */
+ avalue[i] = compress_hfa_type(reg, reg, h);
+ }
+ else
+ {
+ state.ngrn = N_X_ARG_REG;
+ state.nsrn = N_V_ARG_REG;
+ avalue[i] = allocate_to_stack(&state, stack,
+ ty->alignment, s);
+ }
+ }
+ else
+ {
+#endif /* for handling armasm calling convention */
+ if (state.nsrn + n <= N_V_ARG_REG)
+ {
+ void *reg = &context->v[state.nsrn];
+ state.nsrn += (unsigned int)n;
+ avalue[i] = compress_hfa_type(reg, reg, h);
+ }
+ else
+ {
+ state.nsrn = N_V_ARG_REG;
+ avalue[i] = allocate_to_stack(&state, stack,
+ ty->alignment, s);
+ }
+#ifdef _M_ARM64 /* for handling armasm calling convention */
+ }
+#endif /* for handling armasm calling convention */
+ }
+ else if (s > 16)
{
- size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)) ;
- memcpy (get_x_addr (context, 0), rvalue, size);
+ /* Replace Composite type of size greater than 16 with a
+ pointer. */
+ avalue[i] = *(void **)
+ allocate_int_to_reg_or_stack (context, &state, stack,
+ sizeof (void *));
}
else
{
- FFI_ASSERT (0);
+ n = (s + 7) / 8;
+ if (state.ngrn + n <= N_X_ARG_REG)
+ {
+ avalue[i] = &context->x[state.ngrn];
+ state.ngrn += (unsigned int)n;
+ }
+ else
+ {
+ state.ngrn = N_X_ARG_REG;
+ avalue[i] = allocate_to_stack(&state, stack,
+ ty->alignment, s);
+ }
}
break;
+
default:
- FFI_ASSERT (0);
- break;
- }
- }
- else
- {
- memcpy (&rvalue, get_x_addr (context, 8), sizeof (UINT64));
- (closure->fun) (cif, rvalue, avalue, closure->user_data);
+ abort();
+ }
+
+#if defined (__APPLE__)
+ if (i + 1 == cif->aarch64_nfixedargs)
+ {
+ state.ngrn = N_X_ARG_REG;
+ state.nsrn = N_V_ARG_REG;
+ state.allocating_variadic = 1;
+ }
+#endif
}
+
+ flags = cif->flags;
+ if (flags & AARCH64_RET_IN_MEM)
+ rvalue = struct_rvalue;
+
+ fun (cif, rvalue, avalue, user_data);
+
+ return flags;
}
+#endif /* (__aarch64__) || defined(__arm64__)|| defined (_M_ARM64)*/
diff --git a/src/aarch64/ffitarget.h b/src/aarch64/ffitarget.h
index 4bbced26..ecb6d2de 100644
--- a/src/aarch64/ffitarget.h
+++ b/src/aarch64/ffitarget.h
@@ -27,8 +27,19 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#endif
#ifndef LIBFFI_ASM
+#ifdef __ILP32__
+#define FFI_SIZEOF_ARG 8
+#define FFI_SIZEOF_JAVA_RAW 4
+typedef unsigned long long ffi_arg;
+typedef signed long long ffi_sarg;
+#elif defined(_M_ARM64)
+#define FFI_SIZEOF_ARG 8
+typedef unsigned long long ffi_arg;
+typedef signed long long ffi_sarg;
+#else
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
+#endif
typedef enum ffi_abi
{
@@ -42,22 +53,40 @@ typedef enum ffi_abi
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
-#define FFI_TRAMPOLINE_SIZE 36
#define FFI_NATIVE_RAW_API 0
+#if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE
+
+#ifdef __MACH__
+#define FFI_TRAMPOLINE_SIZE 16
+#define FFI_TRAMPOLINE_CLOSURE_OFFSET 16
+#else
+#error "No trampoline table implementation"
+#endif
+
+#else
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE
+#endif
+
+#ifdef _M_ARM64
+#define FFI_EXTRA_CIF_FIELDS unsigned is_variadic
+#endif
+
/* ---- Internal ---- */
#if defined (__APPLE__)
#define FFI_TARGET_SPECIFIC_VARIADIC
-#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags; unsigned aarch64_nfixedargs
-#else
-#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags
+#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs
+#elif !defined(_M_ARM64)
+/* iOS and Windows reserve x18 for the system. Disable Go closures until
+ a new static chain is chosen. */
+#define FFI_GO_CLOSURES 1
#endif
-#define AARCH64_FFI_WITH_V_BIT 0
-
-#define AARCH64_N_XREG 32
-#define AARCH64_N_VREG 32
-#define AARCH64_CALL_CONTEXT_SIZE (AARCH64_N_XREG * 8 + AARCH64_N_VREG * 16)
+#ifndef _M_ARM64
+/* No complex type on Windows */
+#define FFI_TARGET_HAS_COMPLEX_TYPE
+#endif
#endif
diff --git a/src/aarch64/internal.h b/src/aarch64/internal.h
new file mode 100644
index 00000000..9c3e0772
--- /dev/null
+++ b/src/aarch64/internal.h
@@ -0,0 +1,67 @@
+/*
+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 AUTHORS OR COPYRIGHT HOLDERS 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 AARCH64_RET_VOID 0
+#define AARCH64_RET_INT64 1
+#define AARCH64_RET_INT128 2
+
+#define AARCH64_RET_UNUSED3 3
+#define AARCH64_RET_UNUSED4 4
+#define AARCH64_RET_UNUSED5 5
+#define AARCH64_RET_UNUSED6 6
+#define AARCH64_RET_UNUSED7 7
+
+/* Note that FFI_TYPE_FLOAT == 2, _DOUBLE == 3, _LONGDOUBLE == 4,
+ so _S4 through _Q1 are layed out as (TYPE * 4) + (4 - COUNT). */
+#define AARCH64_RET_S4 8
+#define AARCH64_RET_S3 9
+#define AARCH64_RET_S2 10
+#define AARCH64_RET_S1 11
+
+#define AARCH64_RET_D4 12
+#define AARCH64_RET_D3 13
+#define AARCH64_RET_D2 14
+#define AARCH64_RET_D1 15
+
+#define AARCH64_RET_Q4 16
+#define AARCH64_RET_Q3 17
+#define AARCH64_RET_Q2 18
+#define AARCH64_RET_Q1 19
+
+/* Note that each of the sub-64-bit integers gets two entries. */
+#define AARCH64_RET_UINT8 20
+#define AARCH64_RET_UINT16 22
+#define AARCH64_RET_UINT32 24
+
+#define AARCH64_RET_SINT8 26
+#define AARCH64_RET_SINT16 28
+#define AARCH64_RET_SINT32 30
+
+#define AARCH64_RET_MASK 31
+
+#define AARCH64_RET_IN_MEM (1 << 5)
+#define AARCH64_RET_NEED_COPY (1 << 6)
+
+#define AARCH64_FLAG_ARG_V_BIT 7
+#define AARCH64_FLAG_ARG_V (1 << AARCH64_FLAG_ARG_V_BIT)
+
+#define N_X_ARG_REG 8
+#define N_V_ARG_REG 8
+#define CALL_CONTEXT_SIZE (N_V_ARG_REG * 16 + N_X_ARG_REG * 8)
diff --git a/src/aarch64/sysv.S b/src/aarch64/sysv.S
index 169eab80..6761ee1e 100644
--- a/src/aarch64/sysv.S
+++ b/src/aarch64/sysv.S
@@ -19,9 +19,12 @@ 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. */
+#if defined(__aarch64__) || defined(__arm64__)
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
+#include <ffi_cfi.h>
+#include "internal.h"
#ifdef HAVE_MACHINE_ASM_H
#include <machine/asm.h>
@@ -37,297 +40,401 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#endif
#endif
-#define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
-#define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
-#define cfi_restore(reg) .cfi_restore reg
-#define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
-
- .text
- .globl CNAME(ffi_call_SYSV)
-#ifdef __ELF__
- .type CNAME(ffi_call_SYSV), #function
-#endif
-#ifdef __APPLE__
- .align 2
+#ifdef __AARCH64EB__
+# define BE(X) X
+#else
+# define BE(X) 0
#endif
-/* ffi_call_SYSV()
-
- Create a stack frame, setup an argument context, call the callee
- and extract the result.
+#ifdef __ILP32__
+#define PTR_REG(n) w##n
+#else
+#define PTR_REG(n) x##n
+#endif
- The maximum required argument stack size is provided,
- ffi_call_SYSV() allocates that stack space then calls the
- prepare_fn to populate register context and stack. The
- argument passing registers are loaded from the register
- context and the callee called, on return the register passing
- register are saved back to the context. Our caller will
- extract the return value from the final state of the saved
- register context.
+#ifdef __ILP32__
+#define PTR_SIZE 4
+#else
+#define PTR_SIZE 8
+#endif
- Prototype:
+ .text
+ .align 4
- extern unsigned
- ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
- extended_cif *),
- struct call_context *context,
- extended_cif *,
- size_t required_stack_size,
- void (*fn)(void));
+/* ffi_call_SYSV
+ extern void ffi_call_SYSV (void *stack, void *frame,
+ void (*fn)(void), void *rvalue,
+ int flags, void *closure);
Therefore on entry we have:
- x0 prepare_fn
- x1 &context
- x2 &ecif
- x3 bytes
- x4 fn
-
- This function uses the following stack frame layout:
+ x0 stack
+ x1 frame
+ x2 fn
+ x3 rvalue
+ x4 flags
+ x5 closure
+*/
- ==
- saved x30(lr)
- x29(fp)-> saved x29(fp)
- saved x24
- saved x23
- saved x22
- sp' -> saved x21
- ...
- sp -> (constructed callee stack arguments)
- ==
-
- Voila! */
-
-#define ffi_call_SYSV_FS (8 * 4)
-
- .cfi_startproc
+ cfi_startproc
CNAME(ffi_call_SYSV):
- stp x29, x30, [sp, #-16]!
- cfi_adjust_cfa_offset (16)
- cfi_rel_offset (x29, 0)
- cfi_rel_offset (x30, 8)
-
- mov x29, sp
- cfi_def_cfa_register (x29)
- sub sp, sp, #ffi_call_SYSV_FS
-
- stp x21, x22, [sp, #0]
- cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS)
- cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS)
-
- stp x23, x24, [sp, #16]
- cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS)
- cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS)
-
- mov x21, x1
- mov x22, x2
- mov x24, x4
-
- /* Allocate the stack space for the actual arguments, many
- arguments will be passed in registers, but we assume
- worst case and allocate sufficient stack for ALL of
- the arguments. */
- sub sp, sp, x3
-
- /* unsigned (*prepare_fn) (struct call_context *context,
- unsigned char *stack, extended_cif *ecif);
- */
- mov x23, x0
- mov x0, x1
- mov x1, sp
- /* x2 already in place */
- blr x23
-
- /* Preserve the flags returned. */
- mov x23, x0
-
- /* Figure out if we should touch the vector registers. */
- tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
-
- /* Load the vector argument passing registers. */
- ldp q0, q1, [x21, #8*32 + 0]
- ldp q2, q3, [x21, #8*32 + 32]
- ldp q4, q5, [x21, #8*32 + 64]
- ldp q6, q7, [x21, #8*32 + 96]
-1:
- /* Load the core argument passing registers. */
- ldp x0, x1, [x21, #0]
- ldp x2, x3, [x21, #16]
- ldp x4, x5, [x21, #32]
- ldp x6, x7, [x21, #48]
-
- /* Don't forget x8 which may be holding the address of a return buffer.
- */
- ldr x8, [x21, #8*8]
-
- blr x24
-
- /* Save the core argument passing registers. */
- stp x0, x1, [x21, #0]
- stp x2, x3, [x21, #16]
- stp x4, x5, [x21, #32]
- stp x6, x7, [x21, #48]
-
- /* Note nothing useful ever comes back in x8! */
-
- /* Figure out if we should touch the vector registers. */
- tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
-
- /* Save the vector argument passing registers. */
- stp q0, q1, [x21, #8*32 + 0]
- stp q2, q3, [x21, #8*32 + 32]
- stp q4, q5, [x21, #8*32 + 64]
- stp q6, q7, [x21, #8*32 + 96]
+ /* Use a stack frame allocated by our caller. */
+ cfi_def_cfa(x1, 32);
+ stp x29, x30, [x1]
+ mov x29, x1
+ mov sp, x0
+ cfi_def_cfa_register(x29)
+ cfi_rel_offset (x29, 0)
+ cfi_rel_offset (x30, 8)
+
+ mov x9, x2 /* save fn */
+ mov x8, x3 /* install structure return */
+#ifdef FFI_GO_CLOSURES
+ mov x18, x5 /* install static chain */
+#endif
+ stp x3, x4, [x29, #16] /* save rvalue and flags */
+
+ /* Load the vector argument passing registers, if necessary. */
+ tbz w4, #AARCH64_FLAG_ARG_V_BIT, 1f
+ ldp q0, q1, [sp, #0]
+ ldp q2, q3, [sp, #32]
+ ldp q4, q5, [sp, #64]
+ ldp q6, q7, [sp, #96]
1:
- /* All done, unwind our stack frame. */
- ldp x21, x22, [x29, # - ffi_call_SYSV_FS]
- cfi_restore (x21)
- cfi_restore (x22)
+ /* Load the core argument passing registers, including
+ the structure return pointer. */
+ ldp x0, x1, [sp, #16*N_V_ARG_REG + 0]
+ ldp x2, x3, [sp, #16*N_V_ARG_REG + 16]
+ ldp x4, x5, [sp, #16*N_V_ARG_REG + 32]
+ ldp x6, x7, [sp, #16*N_V_ARG_REG + 48]
- ldp x23, x24, [x29, # - ffi_call_SYSV_FS + 16]
- cfi_restore (x23)
- cfi_restore (x24)
+ /* Deallocate the context, leaving the stacked arguments. */
+ add sp, sp, #CALL_CONTEXT_SIZE
- mov sp, x29
- cfi_def_cfa_register (sp)
-
- ldp x29, x30, [sp], #16
- cfi_adjust_cfa_offset (-16)
- cfi_restore (x29)
- cfi_restore (x30)
+ blr x9 /* call fn */
- ret
+ ldp x3, x4, [x29, #16] /* reload rvalue and flags */
- .cfi_endproc
+ /* Partially deconstruct the stack frame. */
+ mov sp, x29
+ cfi_def_cfa_register (sp)
+ ldp x29, x30, [x29]
+
+ /* Save the return value as directed. */
+ adr x5, 0f
+ and w4, w4, #AARCH64_RET_MASK
+ add x5, x5, x4, lsl #3
+ br x5
+
+ /* Note that each table entry is 2 insns, and thus 8 bytes.
+ For integer data, note that we're storing into ffi_arg
+ and therefore we want to extend to 64 bits; these types
+ have two consecutive entries allocated for them. */
+ .align 4
+0: ret /* VOID */
+ nop
+1: str x0, [x3] /* INT64 */
+ ret
+2: stp x0, x1, [x3] /* INT128 */
+ ret
+3: brk #1000 /* UNUSED */
+ ret
+4: brk #1000 /* UNUSED */
+ ret
+5: brk #1000 /* UNUSED */
+ ret
+6: brk #1000 /* UNUSED */
+ ret
+7: brk #1000 /* UNUSED */
+ ret
+8: st4 { v0.s, v1.s, v2.s, v3.s }[0], [x3] /* S4 */
+ ret
+9: st3 { v0.s, v1.s, v2.s }[0], [x3] /* S3 */
+ ret
+10: stp s0, s1, [x3] /* S2 */
+ ret
+11: str s0, [x3] /* S1 */
+ ret
+12: st4 { v0.d, v1.d, v2.d, v3.d }[0], [x3] /* D4 */
+ ret
+13: st3 { v0.d, v1.d, v2.d }[0], [x3] /* D3 */
+ ret
+14: stp d0, d1, [x3] /* D2 */
+ ret
+15: str d0, [x3] /* D1 */
+ ret
+16: str q3, [x3, #48] /* Q4 */
+ nop
+17: str q2, [x3, #32] /* Q3 */
+ nop
+18: stp q0, q1, [x3] /* Q2 */
+ ret
+19: str q0, [x3] /* Q1 */
+ ret
+20: uxtb w0, w0 /* UINT8 */
+ str x0, [x3]
+21: ret /* reserved */
+ nop
+22: uxth w0, w0 /* UINT16 */
+ str x0, [x3]
+23: ret /* reserved */
+ nop
+24: mov w0, w0 /* UINT32 */
+ str x0, [x3]
+25: ret /* reserved */
+ nop
+26: sxtb x0, w0 /* SINT8 */
+ str x0, [x3]
+27: ret /* reserved */
+ nop
+28: sxth x0, w0 /* SINT16 */
+ str x0, [x3]
+29: ret /* reserved */
+ nop
+30: sxtw x0, w0 /* SINT32 */
+ str x0, [x3]
+31: ret /* reserved */
+ nop
+
+ cfi_endproc
+
+ .globl CNAME(ffi_call_SYSV)
+ FFI_HIDDEN(CNAME(ffi_call_SYSV))
#ifdef __ELF__
- .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
+ .type CNAME(ffi_call_SYSV), #function
+ .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
#endif
-#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
-
/* ffi_closure_SYSV
Closure invocation glue. This is the low level code invoked directly by
the closure trampoline to setup and call a closure.
- On entry x17 points to a struct trampoline_data, x16 has been clobbered
+ On entry x17 points to a struct ffi_closure, x16 has been clobbered
all other registers are preserved.
We allocate a call context and save the argument passing registers,
then invoked the generic C ffi_closure_SYSV_inner() function to do all
the real work, on return we load the result passing registers back from
the call context.
+*/
+
+#define ffi_closure_SYSV_FS (8*2 + CALL_CONTEXT_SIZE + 64)
+
+ .align 4
+CNAME(ffi_closure_SYSV_V):
+ cfi_startproc
+ stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
+ cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
+ cfi_rel_offset (x29, 0)
+ cfi_rel_offset (x30, 8)
+
+ /* Save the argument passing vector registers. */
+ stp q0, q1, [sp, #16 + 0]
+ stp q2, q3, [sp, #16 + 32]
+ stp q4, q5, [sp, #16 + 64]
+ stp q6, q7, [sp, #16 + 96]
+ b 0f
+ cfi_endproc
+
+ .globl CNAME(ffi_closure_SYSV_V)
+ FFI_HIDDEN(CNAME(ffi_closure_SYSV_V))
+#ifdef __ELF__
+ .type CNAME(ffi_closure_SYSV_V), #function
+ .size CNAME(ffi_closure_SYSV_V), . - CNAME(ffi_closure_SYSV_V)
+#endif
- On entry
-
- extern void
- ffi_closure_SYSV (struct trampoline_data *);
-
- struct trampoline_data
- {
- UINT64 *ffi_closure;
- UINT64 flags;
- };
-
- This function uses the following stack frame layout:
-
- ==
- saved x30(lr)
- x29(fp)-> saved x29(fp)
- saved x22
- saved x21
- ...
- sp -> call_context
- ==
+ .align 4
+ cfi_startproc
+CNAME(ffi_closure_SYSV):
+ stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
+ cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
+ cfi_rel_offset (x29, 0)
+ cfi_rel_offset (x30, 8)
+0:
+ mov x29, sp
+
+ /* Save the argument passing core registers. */
+ stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
+ stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
+ stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
+ stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
+
+ /* Load ffi_closure_inner arguments. */
+ ldp PTR_REG(0), PTR_REG(1), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET] /* load cif, fn */
+ ldr PTR_REG(2), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET+PTR_SIZE*2] /* load user_data */
+.Ldo_closure:
+ add x3, sp, #16 /* load context */
+ add x4, sp, #ffi_closure_SYSV_FS /* load stack */
+ add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */
+ mov x6, x8 /* load struct_rval */
+ bl CNAME(ffi_closure_SYSV_inner)
+
+ /* Load the return value as directed. */
+ adr x1, 0f
+ and w0, w0, #AARCH64_RET_MASK
+ add x1, x1, x0, lsl #3
+ add x3, sp, #16+CALL_CONTEXT_SIZE
+ br x1
+
+ /* Note that each table entry is 2 insns, and thus 8 bytes. */
+ .align 4
+0: b 99f /* VOID */
+ nop
+1: ldr x0, [x3] /* INT64 */
+ b 99f
+2: ldp x0, x1, [x3] /* INT128 */
+ b 99f
+3: brk #1000 /* UNUSED */
+ nop
+4: brk #1000 /* UNUSED */
+ nop
+5: brk #1000 /* UNUSED */
+ nop
+6: brk #1000 /* UNUSED */
+ nop
+7: brk #1000 /* UNUSED */
+ nop
+8: ldr s3, [x3, #12] /* S4 */
+ nop
+9: ldr s2, [x3, #8] /* S3 */
+ nop
+10: ldp s0, s1, [x3] /* S2 */
+ b 99f
+11: ldr s0, [x3] /* S1 */
+ b 99f
+12: ldr d3, [x3, #24] /* D4 */
+ nop
+13: ldr d2, [x3, #16] /* D3 */
+ nop
+14: ldp d0, d1, [x3] /* D2 */
+ b 99f
+15: ldr d0, [x3] /* D1 */
+ b 99f
+16: ldr q3, [x3, #48] /* Q4 */
+ nop
+17: ldr q2, [x3, #32] /* Q3 */
+ nop
+18: ldp q0, q1, [x3] /* Q2 */
+ b 99f
+19: ldr q0, [x3] /* Q1 */
+ b 99f
+20: ldrb w0, [x3, #BE(7)] /* UINT8 */
+ b 99f
+21: brk #1000 /* reserved */
+ nop
+22: ldrh w0, [x3, #BE(6)] /* UINT16 */
+ b 99f
+23: brk #1000 /* reserved */
+ nop
+24: ldr w0, [x3, #BE(4)] /* UINT32 */
+ b 99f
+25: brk #1000 /* reserved */
+ nop
+26: ldrsb x0, [x3, #BE(7)] /* SINT8 */
+ b 99f
+27: brk #1000 /* reserved */
+ nop
+28: ldrsh x0, [x3, #BE(6)] /* SINT16 */
+ b 99f
+29: brk #1000 /* reserved */
+ nop
+30: ldrsw x0, [x3, #BE(4)] /* SINT32 */
+ nop
+31: /* reserved */
+99: ldp x29, x30, [sp], #ffi_closure_SYSV_FS
+ cfi_adjust_cfa_offset (-ffi_closure_SYSV_FS)
+ cfi_restore (x29)
+ cfi_restore (x30)
+ ret
+ cfi_endproc
+
+ .globl CNAME(ffi_closure_SYSV)
+ FFI_HIDDEN(CNAME(ffi_closure_SYSV))
+#ifdef __ELF__
+ .type CNAME(ffi_closure_SYSV), #function
+ .size CNAME(ffi_closure_SYSV), . - CNAME(ffi_closure_SYSV)
+#endif
- Voila! */
+#if FFI_EXEC_TRAMPOLINE_TABLE
+
+#ifdef __MACH__
+#include <mach/machine/vm_param.h>
+ .align PAGE_MAX_SHIFT
+CNAME(ffi_closure_trampoline_table_page):
+ .rept PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE
+ adr x16, -PAGE_MAX_SIZE
+ ldp x17, x16, [x16]
+ br x16
+ nop /* each entry in the trampoline config page is 2*sizeof(void*) so the trampoline itself cannot be smaller that 16 bytes */
+ .endr
+
+ .globl CNAME(ffi_closure_trampoline_table_page)
+ FFI_HIDDEN(CNAME(ffi_closure_trampoline_table_page))
+ #ifdef __ELF__
+ .type CNAME(ffi_closure_trampoline_table_page), #function
+ .size CNAME(ffi_closure_trampoline_table_page), . - CNAME(ffi_closure_trampoline_table_page)
+ #endif
+#endif
- .text
- .globl CNAME(ffi_closure_SYSV)
-#ifdef __APPLE__
- .align 2
+#endif /* FFI_EXEC_TRAMPOLINE_TABLE */
+
+#ifdef FFI_GO_CLOSURES
+ .align 4
+CNAME(ffi_go_closure_SYSV_V):
+ cfi_startproc
+ stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
+ cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
+ cfi_rel_offset (x29, 0)
+ cfi_rel_offset (x30, 8)
+
+ /* Save the argument passing vector registers. */
+ stp q0, q1, [sp, #16 + 0]
+ stp q2, q3, [sp, #16 + 32]
+ stp q4, q5, [sp, #16 + 64]
+ stp q6, q7, [sp, #16 + 96]
+ b 0f
+ cfi_endproc
+
+ .globl CNAME(ffi_go_closure_SYSV_V)
+ FFI_HIDDEN(CNAME(ffi_go_closure_SYSV_V))
+#ifdef __ELF__
+ .type CNAME(ffi_go_closure_SYSV_V), #function
+ .size CNAME(ffi_go_closure_SYSV_V), . - CNAME(ffi_go_closure_SYSV_V)
#endif
- .cfi_startproc
-CNAME(ffi_closure_SYSV):
- stp x29, x30, [sp, #-16]!
- cfi_adjust_cfa_offset (16)
- cfi_rel_offset (x29, 0)
- cfi_rel_offset (x30, 8)
-
- mov x29, sp
- cfi_def_cfa_register (x29)
-
- sub sp, sp, #ffi_closure_SYSV_FS
-
- stp x21, x22, [x29, #-16]
- cfi_rel_offset (x21, -16)
- cfi_rel_offset (x22, -8)
-
- /* Load x21 with &call_context. */
- mov x21, sp
- /* Preserve our struct trampoline_data * */
- mov x22, x17
-
- /* Save the rest of the argument passing registers. */
- stp x0, x1, [x21, #0]
- stp x2, x3, [x21, #16]
- stp x4, x5, [x21, #32]
- stp x6, x7, [x21, #48]
- /* Don't forget we may have been given a result scratch pad address.
- */
- str x8, [x21, #64]
-
- /* Figure out if we should touch the vector registers. */
- ldr x0, [x22, #8]
- tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
-
- /* Save the argument passing vector registers. */
- stp q0, q1, [x21, #8*32 + 0]
- stp q2, q3, [x21, #8*32 + 32]
- stp q4, q5, [x21, #8*32 + 64]
- stp q6, q7, [x21, #8*32 + 96]
-1:
- /* Load &ffi_closure.. */
- ldr x0, [x22, #0]
- mov x1, x21
- /* Compute the location of the stack at the point that the
- trampoline was called. */
- add x2, x29, #16
-
- bl CNAME(ffi_closure_SYSV_inner)
-
- /* Figure out if we should touch the vector registers. */
- ldr x0, [x22, #8]
- tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
-
- /* Load the result passing vector registers. */
- ldp q0, q1, [x21, #8*32 + 0]
- ldp q2, q3, [x21, #8*32 + 32]
- ldp q4, q5, [x21, #8*32 + 64]
- ldp q6, q7, [x21, #8*32 + 96]
-1:
- /* Load the result passing core registers. */
- ldp x0, x1, [x21, #0]
- ldp x2, x3, [x21, #16]
- ldp x4, x5, [x21, #32]
- ldp x6, x7, [x21, #48]
- /* Note nothing useful is returned in x8. */
-
- /* We are done, unwind our frame. */
- ldp x21, x22, [x29, #-16]
- cfi_restore (x21)
- cfi_restore (x22)
-
- mov sp, x29
- cfi_def_cfa_register (sp)
-
- ldp x29, x30, [sp], #16
- cfi_adjust_cfa_offset (-16)
- cfi_restore (x29)
- cfi_restore (x30)
-
- ret
- .cfi_endproc
+
+ .align 4
+ cfi_startproc
+CNAME(ffi_go_closure_SYSV):
+ stp x29, x30, [sp, #-ffi_closure_SYSV_FS]!
+ cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
+ cfi_rel_offset (x29, 0)
+ cfi_rel_offset (x30, 8)
+0:
+ mov x29, sp
+
+ /* Save the argument passing core registers. */
+ stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
+ stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
+ stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
+ stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
+
+ /* Load ffi_closure_inner arguments. */
+ ldp PTR_REG(0), PTR_REG(1), [x18, #PTR_SIZE]/* load cif, fn */
+ mov x2, x18 /* load user_data */
+ b .Ldo_closure
+ cfi_endproc
+
+ .globl CNAME(ffi_go_closure_SYSV)
+ FFI_HIDDEN(CNAME(ffi_go_closure_SYSV))
#ifdef __ELF__
- .size CNAME(ffi_closure_SYSV), .-CNAME(ffi_closure_SYSV)
+ .type CNAME(ffi_go_closure_SYSV), #function
+ .size CNAME(ffi_go_closure_SYSV), . - CNAME(ffi_go_closure_SYSV)
+#endif
+#endif /* FFI_GO_CLOSURES */
+#endif /* __arm64__ */
+
+#if defined __ELF__ && defined __linux__
+ .section .note.GNU-stack,"",%progbits
#endif
+
diff --git a/src/aarch64/win64_armasm.S b/src/aarch64/win64_armasm.S
new file mode 100644
index 00000000..a79f8a8a
--- /dev/null
+++ b/src/aarch64/win64_armasm.S
@@ -0,0 +1,506 @@
+/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
+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 AUTHORS OR COPYRIGHT HOLDERS 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 <fficonfig.h>
+#include <ffi.h>
+#include <ffi_cfi.h>
+#include "internal.h"
+
+ OPT 2 /*disable listing */
+/* For some macros to add unwind information */
+#include "ksarm64.h"
+ OPT 1 /*re-enable listing */
+
+#define BE(X) 0
+#define PTR_REG(n) x##n
+#define PTR_SIZE 8
+
+ IMPORT ffi_closure_SYSV_inner
+ EXPORT ffi_call_SYSV
+ EXPORT ffi_closure_SYSV_V
+ EXPORT ffi_closure_SYSV
+ EXPORT extend_hfa_type
+ EXPORT compress_hfa_type
+#ifdef FFI_GO_CLOSURES
+ EXPORT ffi_go_closure_SYSV_V
+ EXPORT ffi_go_closure_SYSV
+#endif
+
+ TEXTAREA, ALLIGN=8
+
+/* ffi_call_SYSV
+ extern void ffi_call_SYSV (void *stack, void *frame,
+ void (*fn)(void), void *rvalue,
+ int flags, void *closure);
+ Therefore on entry we have:
+ x0 stack
+ x1 frame
+ x2 fn
+ x3 rvalue
+ x4 flags
+ x5 closure
+*/
+
+ NESTED_ENTRY ffi_call_SYSV_fake
+
+ /* For unwind information, Windows has to store fp and lr */
+ PROLOG_SAVE_REG_PAIR x29, x30, #-32!
+
+ ALTERNATE_ENTRY ffi_call_SYSV
+ /* Use a stack frame allocated by our caller. */
+ stp x29, x30, [x1]
+ mov x29, x1
+ mov sp, x0
+
+ mov x9, x2 /* save fn */
+ mov x8, x3 /* install structure return */
+#ifdef FFI_GO_CLOSURES
+ /*mov x18, x5 install static chain */
+#endif
+ stp x3, x4, [x29, #16] /* save rvalue and flags */
+
+ /* Load the vector argument passing registers, if necessary. */
+ tbz x4, #AARCH64_FLAG_ARG_V_BIT, ffi_call_SYSV_L1
+ ldp q0, q1, [sp, #0]
+ ldp q2, q3, [sp, #32]
+ ldp q4, q5, [sp, #64]
+ ldp q6, q7, [sp, #96]
+
+ffi_call_SYSV_L1
+ /* Load the core argument passing registers, including
+ the structure return pointer. */
+ ldp x0, x1, [sp, #16*N_V_ARG_REG + 0]
+ ldp x2, x3, [sp, #16*N_V_ARG_REG + 16]
+ ldp x4, x5, [sp, #16*N_V_ARG_REG + 32]
+ ldp x6, x7, [sp, #16*N_V_ARG_REG + 48]
+
+ /* Deallocate the context, leaving the stacked arguments. */
+ add sp, sp, #CALL_CONTEXT_SIZE
+
+ blr x9 /* call fn */
+
+ ldp x3, x4, [x29, #16] /* reload rvalue and flags */
+
+ /* Partially deconstruct the stack frame. */
+ mov sp, x29
+ ldp x29, x30, [x29]
+
+ /* Save the return value as directed. */
+ adr x5, ffi_call_SYSV_return
+ and w4, w4, #AARCH64_RET_MASK
+ add x5, x5, x4, lsl #3
+ br x5
+
+ /* Note that each table entry is 2 insns, and thus 8 bytes.
+ For integer data, note that we're storing into ffi_arg
+ and therefore we want to extend to 64 bits; these types
+ have two consecutive entries allocated for them. */
+ ALIGN 4
+ffi_call_SYSV_return
+ ret /* VOID */
+ nop
+ str x0, [x3] /* INT64 */
+ ret
+ stp x0, x1, [x3] /* INT128 */
+ ret
+ brk #1000 /* UNUSED */
+ ret
+ brk #1000 /* UNUSED */
+ ret
+ brk #1000 /* UNUSED */
+ ret
+ brk #1000 /* UNUSED */
+ ret
+ brk #1000 /* UNUSED */
+ ret
+ st4 { v0.s, v1.s, v2.s, v3.s }[0], [x3] /* S4 */
+ ret
+ st3 { v0.s, v1.s, v2.s }[0], [x3] /* S3 */
+ ret
+ stp s0, s1, [x3] /* S2 */
+ ret
+ str s0, [x3] /* S1 */
+ ret
+ st4 { v0.d, v1.d, v2.d, v3.d }[0], [x3] /* D4 */
+ ret
+ st3 { v0.d, v1.d, v2.d }[0], [x3] /* D3 */
+ ret
+ stp d0, d1, [x3] /* D2 */
+ ret
+ str d0, [x3] /* D1 */
+ ret
+ str q3, [x3, #48] /* Q4 */
+ nop
+ str q2, [x3, #32] /* Q3 */
+ nop
+ stp q0, q1, [x3] /* Q2 */
+ ret
+ str q0, [x3] /* Q1 */
+ ret
+ uxtb w0, w0 /* UINT8 */
+ str x0, [x3]
+ ret /* reserved */
+ nop
+ uxth w0, w0 /* UINT16 */
+ str x0, [x3]
+ ret /* reserved */
+ nop
+ mov w0, w0 /* UINT32 */
+ str x0, [x3]
+ ret /* reserved */
+ nop
+ sxtb x0, w0 /* SINT8 */
+ str x0, [x3]
+ ret /* reserved */
+ nop
+ sxth x0, w0 /* SINT16 */
+ str x0, [x3]
+ ret /* reserved */
+ nop
+ sxtw x0, w0 /* SINT32 */
+ str x0, [x3]
+ ret /* reserved */
+ nop
+
+
+ NESTED_END ffi_call_SYSV_fake
+
+
+/* ffi_closure_SYSV
+ Closure invocation glue. This is the low level code invoked directly by
+ the closure trampoline to setup and call a closure.
+ On entry x17 points to a struct ffi_closure, x16 has been clobbered
+ all other registers are preserved.
+ We allocate a call context and save the argument passing registers,
+ then invoked the generic C ffi_closure_SYSV_inner() function to do all
+ the real work, on return we load the result passing registers back from
+ the call context.
+*/
+
+#define ffi_closure_SYSV_FS (8*2 + CALL_CONTEXT_SIZE + 64)
+
+ NESTED_ENTRY ffi_closure_SYSV_V
+ PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
+
+ /* Save the argument passing vector registers. */
+ stp q0, q1, [sp, #16 + 0]
+ stp q2, q3, [sp, #16 + 32]
+ stp q4, q5, [sp, #16 + 64]
+ stp q6, q7, [sp, #16 + 96]
+
+ b ffi_closure_SYSV_save_argument
+ NESTED_END ffi_closure_SYSV_V
+
+ NESTED_ENTRY ffi_closure_SYSV
+ PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
+
+ffi_closure_SYSV_save_argument
+ /* Save the argument passing core registers. */
+ stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
+ stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
+ stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
+ stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
+
+ /* Load ffi_closure_inner arguments. */
+ ldp PTR_REG(0), PTR_REG(1), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET] /* load cif, fn */
+ ldr PTR_REG(2), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET+PTR_SIZE*2] /* load user_data */
+
+do_closure
+ add x3, sp, #16 /* load context */
+ add x4, sp, #ffi_closure_SYSV_FS /* load stack */
+ add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */
+ mov x6, x8 /* load struct_rval */
+
+ bl ffi_closure_SYSV_inner
+
+ /* Load the return value as directed. */
+ adr x1, ffi_closure_SYSV_return_base
+ and w0, w0, #AARCH64_RET_MASK
+ add x1, x1, x0, lsl #3
+ add x3, sp, #16+CALL_CONTEXT_SIZE
+ br x1
+
+ /* Note that each table entry is 2 insns, and thus 8 bytes. */
+ ALIGN 8
+ffi_closure_SYSV_return_base
+ b ffi_closure_SYSV_epilog /* VOID */
+ nop
+ ldr x0, [x3] /* INT64 */
+ b ffi_closure_SYSV_epilog
+ ldp x0, x1, [x3] /* INT128 */
+ b ffi_closure_SYSV_epilog
+ brk #1000 /* UNUSED */
+ nop
+ brk #1000 /* UNUSED */
+ nop
+ brk #1000 /* UNUSED */
+ nop
+ brk #1000 /* UNUSED */
+ nop
+ brk #1000 /* UNUSED */
+ nop
+ ldr s3, [x3, #12] /* S4 */
+ nop
+ ldr s2, [x3, #8] /* S3 */
+ nop
+ ldp s0, s1, [x3] /* S2 */
+ b ffi_closure_SYSV_epilog
+ ldr s0, [x3] /* S1 */
+ b ffi_closure_SYSV_epilog
+ ldr d3, [x3, #24] /* D4 */
+ nop
+ ldr d2, [x3, #16] /* D3 */
+ nop
+ ldp d0, d1, [x3] /* D2 */
+ b ffi_closure_SYSV_epilog
+ ldr d0, [x3] /* D1 */
+ b ffi_closure_SYSV_epilog
+ ldr q3, [x3, #48] /* Q4 */
+ nop
+ ldr q2, [x3, #32] /* Q3 */
+ nop
+ ldp q0, q1, [x3] /* Q2 */
+ b ffi_closure_SYSV_epilog
+ ldr q0, [x3] /* Q1 */
+ b ffi_closure_SYSV_epilog
+ ldrb w0, [x3, #BE(7)] /* UINT8 */
+ b ffi_closure_SYSV_epilog
+ brk #1000 /* reserved */
+ nop
+ ldrh w0, [x3, #BE(6)] /* UINT16 */
+ b ffi_closure_SYSV_epilog
+ brk #1000 /* reserved */
+ nop
+ ldr w0, [x3, #BE(4)] /* UINT32 */
+ b ffi_closure_SYSV_epilog
+ brk #1000 /* reserved */
+ nop
+ ldrsb x0, [x3, #BE(7)] /* SINT8 */
+ b ffi_closure_SYSV_epilog
+ brk #1000 /* reserved */
+ nop
+ ldrsh x0, [x3, #BE(6)] /* SINT16 */
+ b ffi_closure_SYSV_epilog
+ brk #1000 /* reserved */
+ nop
+ ldrsw x0, [x3, #BE(4)] /* SINT32 */
+ nop
+ /* reserved */
+
+ffi_closure_SYSV_epilog
+ EPILOG_RESTORE_REG_PAIR x29, x30, #ffi_closure_SYSV_FS!
+ EPILOG_RETURN
+ NESTED_END ffi_closure_SYSV
+
+
+#ifdef FFI_GO_CLOSURES
+ NESTED_ENTRY ffi_go_closure_SYSV_V
+ PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
+
+ /* Save the argument passing vector registers. */
+ stp q0, q1, [sp, #16 + 0]
+ stp q2, q3, [sp, #16 + 32]
+ stp q4, q5, [sp, #16 + 64]
+ stp q6, q7, [sp, #16 + 96]
+ b ffi_go_closure_SYSV_save_argument
+ NESTED_END ffi_go_closure_SYSV_V
+
+ NESTED_ENTRY ffi_go_closure_SYSV
+ PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
+
+ffi_go_closure_SYSV_save_argument
+ /* Save the argument passing core registers. */
+ stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
+ stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
+ stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
+ stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
+
+ /* Load ffi_closure_inner arguments. */
+ ldp PTR_REG(0), PTR_REG(1), [x18, #PTR_SIZE]/* load cif, fn */
+ mov x2, x18 /* load user_data */
+ b do_closure
+ NESTED_END ffi_go_closure_SYSV
+
+#endif /* FFI_GO_CLOSURES */
+
+
+/* void extend_hfa_type (void *dest, void *src, int h) */
+
+ LEAF_ENTRY extend_hfa_type
+
+ adr x3, extend_hfa_type_jump_base
+ and w2, w2, #AARCH64_RET_MASK
+ sub x2, x2, #AARCH64_RET_S4
+ add x3, x3, x2, lsl #4
+ br x3
+
+ ALIGN 4
+extend_hfa_type_jump_base
+ ldp s16, s17, [x1] /* S4 */
+ ldp s18, s19, [x1, #8]
+ b extend_hfa_type_store_4
+ nop
+
+ ldp s16, s17, [x1] /* S3 */
+ ldr s18, [x1, #8]
+ b extend_hfa_type_store_3
+ nop
+
+ ldp s16, s17, [x1] /* S2 */
+ b extend_hfa_type_store_2
+ nop
+ nop
+
+ ldr s16, [x1] /* S1 */
+ b extend_hfa_type_store_1
+ nop
+ nop
+
+ ldp d16, d17, [x1] /* D4 */
+ ldp d18, d19, [x1, #16]
+ b extend_hfa_type_store_4
+ nop
+
+ ldp d16, d17, [x1] /* D3 */
+ ldr d18, [x1, #16]
+ b extend_hfa_type_store_3
+ nop
+
+ ldp d16, d17, [x1] /* D2 */
+ b extend_hfa_type_store_2
+ nop
+ nop
+
+ ldr d16, [x1] /* D1 */
+ b extend_hfa_type_store_1
+ nop
+ nop
+
+ ldp q16, q17, [x1] /* Q4 */
+ ldp q18, q19, [x1, #16]
+ b extend_hfa_type_store_4
+ nop
+
+ ldp q16, q17, [x1] /* Q3 */
+ ldr q18, [x1, #16]
+ b extend_hfa_type_store_3
+ nop
+
+ ldp q16, q17, [x1] /* Q2 */
+ b extend_hfa_type_store_2
+ nop
+ nop
+
+ ldr q16, [x1] /* Q1 */
+ b extend_hfa_type_store_1
+
+extend_hfa_type_store_4
+ str q19, [x0, #48]
+extend_hfa_type_store_3
+ str q18, [x0, #32]
+extend_hfa_type_store_2
+ str q17, [x0, #16]
+extend_hfa_type_store_1
+ str q16, [x0]
+ ret
+
+ LEAF_END extend_hfa_type
+
+
+/* void compress_hfa_type (void *dest, void *reg, int h) */
+
+ LEAF_ENTRY compress_hfa_type
+
+ adr x3, compress_hfa_type_jump_base
+ and w2, w2, #AARCH64_RET_MASK
+ sub x2, x2, #AARCH64_RET_S4
+ add x3, x3, x2, lsl #4
+ br x3
+
+ ALIGN 4
+compress_hfa_type_jump_base
+ ldp q16, q17, [x1] /* S4 */
+ ldp q18, q19, [x1, #32]
+ st4 { v16.s, v17.s, v18.s, v19.s }[0], [x0]
+ ret
+
+ ldp q16, q17, [x1] /* S3 */
+ ldr q18, [x1, #32]
+ st3 { v16.s, v17.s, v18.s }[0], [x0]
+ ret
+
+ ldp q16, q17, [x1] /* S2 */
+ st2 { v16.s, v17.s }[0], [x0]
+ ret
+ nop
+
+ ldr q16, [x1] /* S1 */
+ st1 { v16.s }[0], [x0]
+ ret
+ nop
+
+ ldp q16, q17, [x1] /* D4 */
+ ldp q18, q19, [x1, #32]
+ st4 { v16.d, v17.d, v18.d, v19.d }[0], [x0]
+ ret
+
+ ldp q16, q17, [x1] /* D3 */
+ ldr q18, [x1, #32]
+ st3 { v16.d, v17.d, v18.d }[0], [x0]
+ ret
+
+ ldp q16, q17, [x1] /* D2 */
+ st2 { v16.d, v17.d }[0], [x0]
+ ret
+ nop
+
+ ldr q16, [x1] /* D1 */
+ st1 { v16.d }[0], [x0]
+ ret
+ nop
+
+ ldp q16, q17, [x1] /* Q4 */
+ ldp q18, q19, [x1, #32]
+ b compress_hfa_type_store_q4
+ nop
+
+ ldp q16, q17, [x1] /* Q3 */
+ ldr q18, [x1, #32]
+ b compress_hfa_type_store_q3
+ nop
+
+ ldp q16, q17, [x1] /* Q2 */
+ stp q16, q17, [x0]
+ ret
+ nop
+
+ ldr q16, [x1] /* Q1 */
+ str q16, [x0]
+ ret
+
+compress_hfa_type_store_q4
+ str q19, [x0, #48]
+compress_hfa_type_store_q3
+ str q18, [x0, #32]
+ stp q16, q17, [x0]
+ ret
+
+ LEAF_END compress_hfa_type
+
+ END \ No newline at end of file
diff --git a/src/alpha/ffi.c b/src/alpha/ffi.c
index 192f691c..7a95e970 100644
--- a/src/alpha/ffi.c
+++ b/src/alpha/ffi.c
@@ -1,8 +1,8 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2012 Anthony Green
- Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
-
- Alpha Foreign Function Interface
+ Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
+
+ Alpha Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -28,6 +28,7 @@
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
+#include "internal.h"
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
all further uses in this file will refer to the 128-bit type. */
@@ -40,135 +41,286 @@
# define FFI_TYPE_LONGDOUBLE 4
#endif
-extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void))
- FFI_HIDDEN;
+extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
+ void *raddr, void (*fn)(void), void *closure)
+ FFI_HIDDEN;
extern void ffi_closure_osf(void) FFI_HIDDEN;
+extern void ffi_go_closure_osf(void) FFI_HIDDEN;
+/* Promote a float value to its in-register double representation.
+ Unlike actually casting to double, this does not trap on NaN. */
+static inline UINT64 lds(void *ptr)
+{
+ UINT64 ret;
+ asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
+ return ret;
+}
-ffi_status
+/* And the reverse. */
+static inline void sts(void *ptr, UINT64 val)
+{
+ asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
+}
+
+ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif *cif)
{
- /* Adjust cif->bytes to represent a minimum 6 words for the temporary
- register argument loading area. */
- if (cif->bytes < 6*FFI_SIZEOF_ARG)
- cif->bytes = 6*FFI_SIZEOF_ARG;
+ size_t bytes = 0;
+ int flags, i, avn;
+ ffi_type *rtype, *itype;
+
+ if (cif->abi != FFI_OSF)
+ return FFI_BAD_ABI;
+
+ /* Compute the size of the argument area. */
+ for (i = 0, avn = cif->nargs; i < avn; i++)
+ {
+ itype = cif->arg_types[i];
+ switch (itype->type)
+ {
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ /* All take one 8 byte slot. */
+ bytes += 8;
+ break;
+
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_STRUCT:
+ /* Passed by value in N slots. */
+ bytes += FFI_ALIGN(itype->size, FFI_SIZEOF_ARG);
+ break;
+
+ case FFI_TYPE_COMPLEX:
+ /* _Complex long double passed by reference; others in 2 slots. */
+ if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
+ bytes += 8;
+ else
+ bytes += 16;
+ break;
+
+ default:
+ abort();
+ }
+ }
/* Set the return type flag */
- switch (cif->rtype->type)
+ rtype = cif->rtype;
+ switch (rtype->type)
{
- case FFI_TYPE_STRUCT:
+ case FFI_TYPE_VOID:
+ flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32);
+ break;
case FFI_TYPE_FLOAT:
+ flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
+ break;
case FFI_TYPE_DOUBLE:
- cif->flags = cif->rtype->type;
+ flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE);
+ break;
+ case FFI_TYPE_UINT8:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8);
+ break;
+ case FFI_TYPE_SINT8:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8);
+ break;
+ case FFI_TYPE_UINT16:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16);
+ break;
+ case FFI_TYPE_SINT16:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16);
+ break;
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_POINTER:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
break;
-
case FFI_TYPE_LONGDOUBLE:
- /* 128-bit long double is returned in memory, like a struct. */
- cif->flags = FFI_TYPE_STRUCT;
+ case FFI_TYPE_STRUCT:
+ /* Passed in memory, with a hidden pointer. */
+ flags = ALPHA_RET_IN_MEM;
break;
-
- default:
- cif->flags = FFI_TYPE_INT;
+ case FFI_TYPE_COMPLEX:
+ itype = rtype->elements[0];
+ switch (itype->type)
+ {
+ case FFI_TYPE_FLOAT:
+ flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF);
+ break;
+ case FFI_TYPE_DOUBLE:
+ flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD);
+ break;
+ default:
+ if (rtype->size <= 8)
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
+ else
+ flags = ALPHA_RET_IN_MEM;
+ break;
+ }
break;
+ default:
+ abort();
}
-
+ cif->flags = flags;
+
+ /* Include the hidden structure pointer in args requirement. */
+ if (flags == ALPHA_RET_IN_MEM)
+ bytes += 8;
+ /* Minimum size is 6 slots, so that ffi_call_osf can pop them. */
+ if (bytes < 6*8)
+ bytes = 6*8;
+ cif->bytes = bytes;
+
return FFI_OK;
}
+static unsigned long
+extend_basic_type(void *valp, int type, int argn)
+{
+ switch (type)
+ {
+ case FFI_TYPE_SINT8:
+ return *(SINT8 *)valp;
+ case FFI_TYPE_UINT8:
+ return *(UINT8 *)valp;
+ case FFI_TYPE_SINT16:
+ return *(SINT16 *)valp;
+ case FFI_TYPE_UINT16:
+ return *(UINT16 *)valp;
+
+ case FFI_TYPE_FLOAT:
+ if (argn < 6)
+ return lds(valp);
+ /* FALLTHRU */
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ /* Note that unsigned 32-bit quantities are sign extended. */
+ return *(SINT32 *)valp;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_DOUBLE:
+ return *(UINT64 *)valp;
-void
-ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+ default:
+ abort();
+ }
+}
+
+static void
+ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
{
- unsigned long *stack, *argp;
- long i, avn;
+ unsigned long *argp;
+ long i, avn, argn, flags = cif->flags;
ffi_type **arg_types;
-
+ void *frame;
+
/* 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 && cif->flags == FFI_TYPE_STRUCT)
+ if (rvalue == NULL && flags == ALPHA_RET_IN_MEM)
rvalue = alloca(cif->rtype->size);
/* Allocate the space for the arguments, plus 4 words of temp
space for ffi_call_osf. */
- argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
+ argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
+ frame += cif->bytes;
- if (cif->flags == FFI_TYPE_STRUCT)
- *(void **) argp++ = rvalue;
+ argn = 0;
+ if (flags == ALPHA_RET_IN_MEM)
+ argp[argn++] = (unsigned long)rvalue;
- i = 0;
avn = cif->nargs;
arg_types = cif->arg_types;
- while (i < avn)
+ for (i = 0, avn = cif->nargs; i < avn; i++)
{
- size_t size = (*arg_types)->size;
+ ffi_type *ty = arg_types[i];
+ void *valp = avalue[i];
+ int type = ty->type;
+ size_t size;
- switch ((*arg_types)->type)
+ switch (type)
{
+ case FFI_TYPE_INT:
case FFI_TYPE_SINT8:
- *(SINT64 *) argp = *(SINT8 *)(* avalue);
- break;
-
case FFI_TYPE_UINT8:
- *(SINT64 *) argp = *(UINT8 *)(* avalue);
- break;
-
case FFI_TYPE_SINT16:
- *(SINT64 *) argp = *(SINT16 *)(* avalue);
- break;
-
case FFI_TYPE_UINT16:
- *(SINT64 *) argp = *(UINT16 *)(* avalue);
- break;
-
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
- /* Note that unsigned 32-bit quantities are sign extended. */
- *(SINT64 *) argp = *(SINT32 *)(* avalue);
- break;
-
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
- *(UINT64 *) argp = *(UINT64 *)(* avalue);
- break;
-
case FFI_TYPE_FLOAT:
- if (argp - stack < 6)
- {
- /* Note the conversion -- all the fp regs are loaded as
- doubles. The in-register format is the same. */
- *(double *) argp = *(float *)(* avalue);
- }
- else
- *(float *) argp = *(float *)(* avalue);
- break;
-
case FFI_TYPE_DOUBLE:
- *(double *) argp = *(double *)(* avalue);
+ argp[argn] = extend_basic_type(valp, type, argn);
+ argn++;
break;
case FFI_TYPE_LONGDOUBLE:
- /* 128-bit long double is passed by reference. */
- *(long double **) argp = (long double *)(* avalue);
- size = sizeof (long double *);
+ by_reference:
+ /* Note that 128-bit long double is passed by reference. */
+ argp[argn++] = (unsigned long)valp;
break;
+ case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
- memcpy(argp, *avalue, (*arg_types)->size);
+ size = ty->size;
+ memcpy(argp + argn, valp, size);
+ argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ break;
+
+ case FFI_TYPE_COMPLEX:
+ type = ty->elements[0]->type;
+ if (type == FFI_TYPE_LONGDOUBLE)
+ goto by_reference;
+
+ /* Most complex types passed as two separate arguments. */
+ size = ty->elements[0]->size;
+ argp[argn] = extend_basic_type(valp, type, argn);
+ argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1);
+ argn += 2;
break;
default:
- FFI_ASSERT(0);
+ abort();
}
-
- argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
- i++, arg_types++, avalue++;
}
- ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
+ flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
+ ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
+}
+
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, NULL);
}
+void
+ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, closure);
+}
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
@@ -204,39 +356,56 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*))
+{
+ if (cif->abi != FFI_OSF)
+ return FFI_BAD_ABI;
+
+ closure->tramp = (void *)ffi_go_closure_osf;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
long FFI_HIDDEN
-ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
+ffi_closure_osf_inner (ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ void *rvalue, unsigned long *argp)
{
- ffi_cif *cif;
void **avalue;
ffi_type **arg_types;
- long i, avn, argn;
+ long i, avn, argn, flags;
- cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
-
+ flags = cif->flags;
argn = 0;
/* Copy the caller's structure return address to that the closure
returns the data directly to the caller. */
- if (cif->flags == FFI_TYPE_STRUCT)
+ if (flags == ALPHA_RET_IN_MEM)
{
rvalue = (void *) argp[0];
argn = 1;
}
- i = 0;
- avn = cif->nargs;
arg_types = cif->arg_types;
-
+
/* Grab the addresses of the arguments from the stack frame. */
- while (i < avn)
+ for (i = 0, avn = cif->nargs; i < avn; i++)
{
- size_t size = arg_types[i]->size;
+ ffi_type *ty = arg_types[i];
+ int type = ty->type;
+ void *valp = &argp[argn];
+ size_t size;
- switch (arg_types[i]->type)
+ switch (type)
{
+ case FFI_TYPE_INT:
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
@@ -246,43 +415,107 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
+ argn += 1;
+ break;
+
+ case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
- avalue[i] = &argp[argn];
+ size = ty->size;
+ argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
break;
case FFI_TYPE_FLOAT:
+ /* Floats coming from registers need conversion from double
+ back to float format. */
if (argn < 6)
{
- /* Floats coming from registers need conversion from double
- back to float format. */
- *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
- avalue[i] = &argp[argn - 6];
+ valp = &argp[argn - 6];
+ sts(valp, argp[argn - 6]);
}
- else
- avalue[i] = &argp[argn];
+ argn += 1;
break;
case FFI_TYPE_DOUBLE:
- avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
+ if (argn < 6)
+ valp = &argp[argn - 6];
+ argn += 1;
break;
case FFI_TYPE_LONGDOUBLE:
+ by_reference:
/* 128-bit long double is passed by reference. */
- avalue[i] = (long double *) argp[argn];
- size = sizeof (long double *);
+ valp = (void *)argp[argn];
+ argn += 1;
+ break;
+
+ case FFI_TYPE_COMPLEX:
+ type = ty->elements[0]->type;
+ switch (type)
+ {
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ /* Passed as separate arguments, but they wind up sequential. */
+ break;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ /* Passed as separate arguments. Disjoint, but there's room
+ enough in one slot to hold the pair. */
+ size = ty->elements[0]->size;
+ memcpy(valp + size, valp + 8, size);
+ break;
+
+ case FFI_TYPE_FLOAT:
+ /* Passed as separate arguments. Disjoint, and each piece
+ may need conversion back to float. */
+ if (argn < 6)
+ {
+ valp = &argp[argn - 6];
+ sts(valp, argp[argn - 6]);
+ }
+ if (argn + 1 < 6)
+ sts(valp + 4, argp[argn + 1 - 6]);
+ else
+ *(UINT32 *)(valp + 4) = argp[argn + 1];
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ /* Passed as separate arguments. Only disjoint if one part
+ is in fp regs and the other is on the stack. */
+ if (argn < 5)
+ valp = &argp[argn - 6];
+ else if (argn == 5)
+ {
+ valp = alloca(16);
+ ((UINT64 *)valp)[0] = argp[5 - 6];
+ ((UINT64 *)valp)[1] = argp[6];
+ }
+ break;
+
+ case FFI_TYPE_LONGDOUBLE:
+ goto by_reference;
+
+ default:
+ abort();
+ }
+ argn += 2;
break;
default:
abort ();
}
- argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
- i++;
+ avalue[i] = valp;
}
/* Invoke the closure. */
- closure->fun (cif, rvalue, avalue, closure->user_data);
+ fun (cif, rvalue, avalue, user_data);
/* Tell ffi_closure_osf how to perform return type promotions. */
- return cif->rtype->type;
+ return (flags >> ALPHA_LD_SHIFT) & 0xff;
}
diff --git a/src/alpha/ffitarget.h b/src/alpha/ffitarget.h
index af145bce..a02dbd04 100644
--- a/src/alpha/ffitarget.h
+++ b/src/alpha/ffitarget.h
@@ -44,9 +44,13 @@ typedef enum ffi_abi {
} ffi_abi;
#endif
+#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
+#define FFI_TARGET_HAS_COMPLEX_TYPE
+
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
+#define FFI_GO_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 24
#define FFI_NATIVE_RAW_API 0
diff --git a/src/alpha/internal.h b/src/alpha/internal.h
new file mode 100644
index 00000000..44da1922
--- /dev/null
+++ b/src/alpha/internal.h
@@ -0,0 +1,23 @@
+#define ALPHA_ST_VOID 0
+#define ALPHA_ST_INT 1
+#define ALPHA_ST_FLOAT 2
+#define ALPHA_ST_DOUBLE 3
+#define ALPHA_ST_CPLXF 4
+#define ALPHA_ST_CPLXD 5
+
+#define ALPHA_LD_VOID 0
+#define ALPHA_LD_INT64 1
+#define ALPHA_LD_INT32 2
+#define ALPHA_LD_UINT16 3
+#define ALPHA_LD_SINT16 4
+#define ALPHA_LD_UINT8 5
+#define ALPHA_LD_SINT8 6
+#define ALPHA_LD_FLOAT 7
+#define ALPHA_LD_DOUBLE 8
+#define ALPHA_LD_CPLXF 9
+#define ALPHA_LD_CPLXD 10
+
+#define ALPHA_ST_SHIFT 0
+#define ALPHA_LD_SHIFT 8
+#define ALPHA_RET_IN_MEM 0x10000
+#define ALPHA_FLAGS(S, L) (((L) << ALPHA_LD_SHIFT) | (S))
diff --git a/src/alpha/osf.S b/src/alpha/osf.S
index 6b9f4dfa..b0318282 100644
--- a/src/alpha/osf.S
+++ b/src/alpha/osf.S
@@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
- osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011 Red Hat
-
- Alpha/OSF Foreign Function Interface
+ osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011, 2014 Red Hat
+
+ Alpha/OSF Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -24,40 +24,49 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
-#define LIBFFI_ASM
+#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
+#include <ffi_cfi.h>
+#include "internal.h"
.arch ev6
.text
-/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
- void *raddr, void (*fnaddr)(void));
+/* Aid in building a direct addressed jump table, 4 insns per entry. */
+.macro E index
+ .align 4
+ .org 99b + \index * 16
+.endm
+
+/* ffi_call_osf (void *stack, void *frame, unsigned flags,
+ void *raddr, void (*fnaddr)(void), void *closure)
- Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
+ Bit o trickiness here -- FRAME is the base of the stack frame
for this function. This has been allocated by ffi_call. We also
deallocate some of the stack that has been alloca'd. */
- .align 3
+ .align 4
.globl ffi_call_osf
.ent ffi_call_osf
FFI_HIDDEN(ffi_call_osf)
ffi_call_osf:
- .frame $15, 32, $26, 0
- .mask 0x4008000, -32
-$LFB1:
- addq $16,$17,$1
+ cfi_startproc
+ cfi_def_cfa($17, 32)
mov $16, $30
- stq $26, 0($1)
- stq $15, 8($1)
- stq $18, 16($1)
- mov $1, $15
-$LCFI1:
+ stq $26, 0($17)
+ stq $15, 8($17)
+ mov $17, $15
.prologue 0
+ cfi_def_cfa_register($15)
+ cfi_rel_offset($26, 0)
+ cfi_rel_offset($15, 8)
- stq $19, 24($1)
- mov $20, $27
+ stq $18, 16($17) # save flags into frame
+ stq $19, 24($17) # save rvalue into frame
+ mov $20, $27 # fn into place for call
+ mov $21, $1 # closure into static chain
# Load up all of the (potential) argument registers.
ldq $16, 0($30)
@@ -77,311 +86,197 @@ $LCFI1:
lda $30, 48($30)
jsr $26, ($27), 0
- ldgp $29, 0($26)
-
- # If the return value pointer is NULL, assume no return value.
- ldq $19, 24($15)
- ldq $18, 16($15)
+0:
+ ldah $29, 0($26) !gpdisp!1
+ ldq $2, 24($15) # reload rvalue
+ lda $29, 0($29) !gpdisp!1
+ ldq $3, 16($15) # reload flags
+ lda $1, 99f-0b($26)
ldq $26, 0($15)
-$LCFI2:
- beq $19, $noretval
-
- # Store the return value out in the proper type.
- cmpeq $18, FFI_TYPE_INT, $1
- bne $1, $retint
- cmpeq $18, FFI_TYPE_FLOAT, $2
- bne $2, $retfloat
- cmpeq $18, FFI_TYPE_DOUBLE, $3
- bne $3, $retdouble
-
- .align 3
-$noretval:
ldq $15, 8($15)
- ret
+ cfi_restore($26)
+ cfi_restore($15)
+ cfi_def_cfa($sp, 0)
+ cmoveq $2, ALPHA_ST_VOID, $3 # mash null rvalue to void
+ addq $3, $3, $3
+ s8addq $3, $1, $1 # 99f + stcode * 16
+ jmp $31, ($1), $st_int
.align 4
-$retint:
- stq $0, 0($19)
- nop
- ldq $15, 8($15)
+99:
+E ALPHA_ST_VOID
ret
-
- .align 4
-$retfloat:
- sts $f0, 0($19)
- nop
- ldq $15, 8($15)
+E ALPHA_ST_INT
+$st_int:
+ stq $0, 0($2)
ret
-
- .align 4
-$retdouble:
- stt $f0, 0($19)
- nop
- ldq $15, 8($15)
+E ALPHA_ST_FLOAT
+ sts $f0, 0($2)
+ ret
+E ALPHA_ST_DOUBLE
+ stt $f0, 0($2)
+ ret
+E ALPHA_ST_CPLXF
+ sts $f0, 0($2)
+ sts $f1, 4($2)
+ ret
+E ALPHA_ST_CPLXD
+ stt $f0, 0($2)
+ stt $f1, 8($2)
ret
-$LFE1:
+ cfi_endproc
.end ffi_call_osf
/* ffi_closure_osf(...)
Receives the closure argument in $1. */
- .align 3
+#define CLOSURE_FS (16*8)
+
+ .align 4
+ .globl ffi_go_closure_osf
+ .ent ffi_go_closure_osf
+ FFI_HIDDEN(ffi_go_closure_osf)
+
+ffi_go_closure_osf:
+ cfi_startproc
+ ldgp $29, 0($27)
+ subq $30, CLOSURE_FS, $30
+ cfi_adjust_cfa_offset(CLOSURE_FS)
+ stq $26, 0($30)
+ .prologue 1
+ cfi_rel_offset($26, 0)
+
+ stq $16, 10*8($30)
+ stq $17, 11*8($30)
+ stq $18, 12*8($30)
+
+ ldq $16, 8($1) # load cif
+ ldq $17, 16($1) # load fun
+ mov $1, $18 # closure is user_data
+ br $do_closure
+
+ cfi_endproc
+ .end ffi_go_closure_osf
+
+ .align 4
.globl ffi_closure_osf
.ent ffi_closure_osf
FFI_HIDDEN(ffi_closure_osf)
ffi_closure_osf:
- .frame $30, 16*8, $26, 0
- .mask 0x4000000, -16*8
-$LFB2:
+ cfi_startproc
ldgp $29, 0($27)
- subq $30, 16*8, $30
-$LCFI5:
+ subq $30, CLOSURE_FS, $30
+ cfi_adjust_cfa_offset(CLOSURE_FS)
stq $26, 0($30)
-$LCFI6:
.prologue 1
+ cfi_rel_offset($26, 0)
# Store all of the potential argument registers in va_list format.
- stt $f16, 4*8($30)
- stt $f17, 5*8($30)
- stt $f18, 6*8($30)
- stt $f19, 7*8($30)
- stt $f20, 8*8($30)
- stt $f21, 9*8($30)
stq $16, 10*8($30)
stq $17, 11*8($30)
stq $18, 12*8($30)
+
+ ldq $16, 24($1) # load cif
+ ldq $17, 32($1) # load fun
+ ldq $18, 40($1) # load user_data
+
+$do_closure:
stq $19, 13*8($30)
stq $20, 14*8($30)
stq $21, 15*8($30)
+ stt $f16, 4*8($30)
+ stt $f17, 5*8($30)
+ stt $f18, 6*8($30)
+ stt $f19, 7*8($30)
+ stt $f20, 8*8($30)
+ stt $f21, 9*8($30)
# Call ffi_closure_osf_inner to do the bulk of the work.
- mov $1, $16
- lda $17, 2*8($30)
- lda $18, 10*8($30)
+ lda $19, 2*8($30)
+ lda $20, 10*8($30)
jsr $26, ffi_closure_osf_inner
- ldgp $29, 0($26)
+0:
+ ldah $29, 0($26) !gpdisp!2
+ lda $2, 99f-0b($26)
+ s4addq $0, 0, $1 # ldcode * 4
+ ldq $0, 16($30) # preload return value
+ s4addq $1, $2, $1 # 99f + ldcode * 16
+ lda $29, 0($29) !gpdisp!2
ldq $26, 0($30)
-
- # Load up the return value in the proper type.
- lda $1, $load_table
- s4addq $0, $1, $1
- ldl $1, 0($1)
- addq $1, $29, $1
+ cfi_restore($26)
jmp $31, ($1), $load_32
- .align 4
-$load_none:
- addq $30, 16*8, $30
+.macro epilogue
+ addq $30, CLOSURE_FS, $30
+ cfi_adjust_cfa_offset(-CLOSURE_FS)
ret
+ .align 4
+ cfi_adjust_cfa_offset(CLOSURE_FS)
+.endm
.align 4
-$load_float:
- lds $f0, 16($30)
- nop
- addq $30, 16*8, $30
- ret
+99:
+E ALPHA_LD_VOID
+ epilogue
- .align 4
-$load_double:
- ldt $f0, 16($30)
- nop
- addq $30, 16*8, $30
- ret
+E ALPHA_LD_INT64
+ epilogue
- .align 4
-$load_u8:
+E ALPHA_LD_INT32
+$load_32:
+ sextl $0, $0
+ epilogue
+
+E ALPHA_LD_UINT16
+ zapnot $0, 3, $0
+ epilogue
+
+E ALPHA_LD_SINT16
#ifdef __alpha_bwx__
- ldbu $0, 16($30)
- nop
+ sextw $0, $0
#else
- ldq $0, 16($30)
- and $0, 255, $0
+ sll $0, 48, $0
+ sra $0, 48, $0
#endif
- addq $30, 16*8, $30
- ret
+ epilogue
- .align 4
-$load_s8:
+E ALPHA_LD_UINT8
+ and $0, 0xff, $0
+ epilogue
+
+E ALPHA_LD_SINT8
#ifdef __alpha_bwx__
- ldbu $0, 16($30)
sextb $0, $0
#else
- ldq $0, 16($30)
sll $0, 56, $0
sra $0, 56, $0
#endif
- addq $30, 16*8, $30
- ret
+ epilogue
- .align 4
-$load_u16:
-#ifdef __alpha_bwx__
- ldwu $0, 16($30)
- nop
-#else
- ldq $0, 16($30)
- zapnot $0, 3, $0
-#endif
- addq $30, 16*8, $30
- ret
+E ALPHA_LD_FLOAT
+ lds $f0, 16($sp)
+ epilogue
- .align 4
-$load_s16:
-#ifdef __alpha_bwx__
- ldwu $0, 16($30)
- sextw $0, $0
-#else
- ldq $0, 16($30)
- sll $0, 48, $0
- sra $0, 48, $0
-#endif
- addq $30, 16*8, $30
- ret
+E ALPHA_LD_DOUBLE
+ ldt $f0, 16($sp)
+ epilogue
- .align 4
-$load_32:
- ldl $0, 16($30)
- nop
- addq $30, 16*8, $30
- ret
+E ALPHA_LD_CPLXF
+ lds $f0, 16($sp)
+ lds $f1, 20($sp)
+ epilogue
- .align 4
-$load_64:
- ldq $0, 16($30)
- nop
- addq $30, 16*8, $30
- ret
-$LFE2:
+E ALPHA_LD_CPLXD
+ ldt $f0, 16($sp)
+ ldt $f1, 24($sp)
+ epilogue
+ cfi_endproc
.end ffi_closure_osf
-#ifdef __ELF__
-.section .rodata
-#else
-.rdata
-#endif
-$load_table:
- .gprel32 $load_none # FFI_TYPE_VOID
- .gprel32 $load_32 # FFI_TYPE_INT
- .gprel32 $load_float # FFI_TYPE_FLOAT
- .gprel32 $load_double # FFI_TYPE_DOUBLE
- .gprel32 $load_none # FFI_TYPE_LONGDOUBLE
- .gprel32 $load_u8 # FFI_TYPE_UINT8
- .gprel32 $load_s8 # FFI_TYPE_SINT8
- .gprel32 $load_u16 # FFI_TYPE_UINT16
- .gprel32 $load_s16 # FFI_TYPE_SINT16
- .gprel32 $load_32 # FFI_TYPE_UINT32
- .gprel32 $load_32 # FFI_TYPE_SINT32
- .gprel32 $load_64 # FFI_TYPE_UINT64
- .gprel32 $load_64 # FFI_TYPE_SINT64
- .gprel32 $load_none # FFI_TYPE_STRUCT
- .gprel32 $load_64 # FFI_TYPE_POINTER
-
-/* Assert that the table above is in sync with ffi.h. */
-
-#if FFI_TYPE_FLOAT != 2 \
- || FFI_TYPE_DOUBLE != 3 \
- || FFI_TYPE_UINT8 != 5 \
- || FFI_TYPE_SINT8 != 6 \
- || FFI_TYPE_UINT16 != 7 \
- || FFI_TYPE_SINT16 != 8 \
- || FFI_TYPE_UINT32 != 9 \
- || FFI_TYPE_SINT32 != 10 \
- || FFI_TYPE_UINT64 != 11 \
- || FFI_TYPE_SINT64 != 12 \
- || FFI_TYPE_STRUCT != 13 \
- || FFI_TYPE_POINTER != 14 \
- || FFI_TYPE_LAST != 14
-#error "osf.S out of sync with ffi.h"
-#endif
-
-#ifdef __ELF__
-# define UA_SI .4byte
-# define FDE_ENCODING 0x1b /* pcrel sdata4 */
-# define FDE_ENCODE(X) .4byte X-.
-# define FDE_ARANGE(X) .4byte X
-#elif defined __osf__
-# define UA_SI .align 0; .long
-# define FDE_ENCODING 0x50 /* aligned absolute */
-# define FDE_ENCODE(X) .align 3; .quad X
-# define FDE_ARANGE(X) .align 0; .quad X
-#endif
-
-#ifdef __ELF__
- .section .eh_frame,EH_FRAME_FLAGS,@progbits
-#elif defined __osf__
- .data
- .align 3
- .globl _GLOBAL__F_ffi_call_osf
-_GLOBAL__F_ffi_call_osf:
-#endif
-__FRAME_BEGIN__:
- UA_SI $LECIE1-$LSCIE1 # Length of Common Information Entry
-$LSCIE1:
- UA_SI 0x0 # CIE Identifier Tag
- .byte 0x1 # CIE Version
- .ascii "zR\0" # CIE Augmentation
- .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
- .byte 0x78 # sleb128 -8; CIE Data Alignment Factor
- .byte 26 # CIE RA Column
- .byte 0x1 # uleb128 0x1; Augmentation size
- .byte FDE_ENCODING # FDE Encoding
- .byte 0xc # DW_CFA_def_cfa
- .byte 30 # uleb128 column 30
- .byte 0 # uleb128 offset 0
- .align 3
-$LECIE1:
-$LSFDE1:
- UA_SI $LEFDE1-$LASFDE1 # FDE Length
-$LASFDE1:
- UA_SI $LASFDE1-__FRAME_BEGIN__ # FDE CIE offset
- FDE_ENCODE($LFB1) # FDE initial location
- FDE_ARANGE($LFE1-$LFB1) # FDE address range
- .byte 0x0 # uleb128 0x0; Augmentation size
-
- .byte 0x4 # DW_CFA_advance_loc4
- UA_SI $LCFI1-$LFB1
- .byte 0x9a # DW_CFA_offset, column 26
- .byte 4 # uleb128 4*-8
- .byte 0x8f # DW_CFA_offset, column 15
- .byte 0x3 # uleb128 3*-8
- .byte 0xc # DW_CFA_def_cfa
- .byte 15 # uleb128 column 15
- .byte 32 # uleb128 offset 32
-
- .byte 0x4 # DW_CFA_advance_loc4
- UA_SI $LCFI2-$LCFI1
- .byte 0xda # DW_CFA_restore, column 26
- .align 3
-$LEFDE1:
-
-$LSFDE3:
- UA_SI $LEFDE3-$LASFDE3 # FDE Length
-$LASFDE3:
- UA_SI $LASFDE3-__FRAME_BEGIN__ # FDE CIE offset
- FDE_ENCODE($LFB2) # FDE initial location
- FDE_ARANGE($LFE2-$LFB2) # FDE address range
- .byte 0x0 # uleb128 0x0; Augmentation size
-
- .byte 0x4 # DW_CFA_advance_loc4
- UA_SI $LCFI5-$LFB2
- .byte 0xe # DW_CFA_def_cfa_offset
- .byte 0x80,0x1 # uleb128 128
-
- .byte 0x4 # DW_CFA_advance_loc4
- UA_SI $LCFI6-$LCFI5
- .byte 0x9a # DW_CFA_offset, column 26
- .byte 16 # uleb128 offset 16*-8
- .align 3
-$LEFDE3:
-#if defined __osf__
- .align 0
- .long 0 # End of Table
-#endif
-
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
#endif
diff --git a/src/arc/ffi.c b/src/arc/ffi.c
index 32f82a7d..4d10b21a 100644
--- a/src/arc/ffi.c
+++ b/src/arc/ffi.c
@@ -46,12 +46,10 @@ void
ffi_prep_args (char *stack, extended_cif * ecif)
{
unsigned int i;
- int tmp;
void **p_argv;
char *argp;
ffi_type **p_arg;
- tmp = 0;
argp = stack;
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
@@ -73,7 +71,7 @@ ffi_prep_args (char *stack, extended_cif * ecif)
/* Align if necessary. */
if ((alignment - 1) & (unsigned) argp)
- argp = (char *) ALIGN (argp, alignment);
+ argp = (char *) FFI_ALIGN (argp, alignment);
z = (*p_arg)->size;
if (z < sizeof (int))
@@ -225,7 +223,7 @@ ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue,
/* Align if necessary. */
if ((alignment - 1) & (unsigned) argp)
- argp = (char *) ALIGN (argp, alignment);
+ argp = (char *) FFI_ALIGN (argp, alignment);
z = (*p_argt)->size;
*p_argv = (void *) argp;
diff --git a/src/arm/ffi.c b/src/arm/ffi.c
index 6691ab57..4e270718 100644
--- a/src/arm/ffi.c
+++ b/src/arm/ffi.c
@@ -28,856 +28,778 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
+#if defined(__arm__) || defined(_M_ARM)
+#include <fficonfig.h>
#include <ffi.h>
#include <ffi_common.h>
-
+#include <stdint.h>
#include <stdlib.h>
+#include "internal.h"
+
+#if defined(_MSC_VER) && defined(_M_ARM)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#if FFI_EXEC_TRAMPOLINE_TABLE
+
+#ifdef __MACH__
+#include <mach/machine/vm_param.h>
+#endif
+
+#else
+#ifndef _M_ARM
+extern unsigned int ffi_arm_trampoline[2] FFI_HIDDEN;
+#else
+extern unsigned int ffi_arm_trampoline[3] FFI_HIDDEN;
+#endif
+#endif
/* Forward declares. */
-static int vfp_type_p (ffi_type *);
+static int vfp_type_p (const ffi_type *);
static void layout_vfp_args (ffi_cif *);
-int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space);
-int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space);
-
-static char* ffi_align(ffi_type **p_arg, char *argp)
+static void *
+ffi_align (ffi_type *ty, void *p)
{
/* Align if necessary */
- register size_t alignment = (*p_arg)->alignment;
- if (alignment < 4)
- {
- alignment = 4;
- }
+ size_t alignment;
#ifdef _WIN32_WCE
- if (alignment > 4)
- {
+ alignment = 4;
+#else
+ alignment = ty->alignment;
+ if (alignment < 4)
alignment = 4;
- }
#endif
- if ((alignment - 1) & (unsigned) argp)
- {
- argp = (char *) ALIGN(argp, alignment);
- }
-
- if ((*p_arg)->type == FFI_TYPE_STRUCT)
- {
- argp = (char *) ALIGN(argp, 4);
- }
- return argp;
+ return (void *) FFI_ALIGN (p, alignment);
}
-static size_t ffi_put_arg(ffi_type **arg_type, void **arg, char *stack)
+static size_t
+ffi_put_arg (ffi_type *ty, void *src, void *dst)
{
- register char* argp = stack;
- register ffi_type **p_arg = arg_type;
- register void **p_argv = arg;
- register size_t z = (*p_arg)->size;
- if (z < sizeof(int))
+ size_t z = ty->size;
+
+ switch (ty->type)
{
- z = sizeof(int);
- switch ((*p_arg)->type)
- {
- case FFI_TYPE_SINT8:
- *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT8:
- *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_SINT16:
- *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT16:
- *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
- break;
-
- case FFI_TYPE_STRUCT:
- memcpy(argp, *p_argv, (*p_arg)->size);
+ case FFI_TYPE_SINT8:
+ *(UINT32 *)dst = *(SINT8 *)src;
+ break;
+ case FFI_TYPE_UINT8:
+ *(UINT32 *)dst = *(UINT8 *)src;
+ break;
+ case FFI_TYPE_SINT16:
+ *(UINT32 *)dst = *(SINT16 *)src;
+ break;
+ case FFI_TYPE_UINT16:
+ *(UINT32 *)dst = *(UINT16 *)src;
+ break;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_POINTER:
+#ifndef _MSC_VER
+ case FFI_TYPE_FLOAT:
+#endif
+ *(UINT32 *)dst = *(UINT32 *)src;
+ break;
+
+#ifdef _MSC_VER
+ // casting a float* to a UINT32* doesn't work on Windows
+ case FFI_TYPE_FLOAT:
+ *(uintptr_t *)dst = 0;
+ *(float *)dst = *(float *)src;
break;
+#endif
- default:
- FFI_ASSERT(0);
- }
- }
- else if (z == sizeof(int))
- {
- if ((*p_arg)->type == FFI_TYPE_FLOAT)
- *(float *) argp = *(float *)(* p_argv);
- else
- *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
- }
- else if (z == sizeof(double) && (*p_arg)->type == FFI_TYPE_DOUBLE)
- {
- *(double *) argp = *(double *)(* p_argv);
- }
- else
- {
- memcpy(argp, *p_argv, z);
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_DOUBLE:
+ *(UINT64 *)dst = *(UINT64 *)src;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_COMPLEX:
+ memcpy (dst, src, z);
+ break;
+
+ default:
+ abort();
}
- return z;
+
+ return FFI_ALIGN (z, 4);
}
-/* ffi_prep_args is called by the assembly routine once stack space
- has been allocated for the function's arguments
-
+
+/* ffi_prep_args is called once stack space has been allocated
+ for the function's arguments.
+
The vfp_space parameter is the load area for VFP regs, the return
value is cif->vfp_used (word bitset of VFP regs used for passing
arguments). These are only used for the VFP hard-float ABI.
*/
-int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space)
+static void
+ffi_prep_args_SYSV (ffi_cif *cif, int flags, void *rvalue,
+ void **avalue, char *argp)
{
- register unsigned int i;
- register void **p_argv;
- register char *argp;
- register ffi_type **p_arg;
- argp = stack;
-
-
- if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
- *(void **) argp = ecif->rvalue;
- argp += 4;
- }
-
- p_argv = ecif->avalue;
-
- for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
- (i != 0);
- i--, p_arg++, p_argv++)
+ ffi_type **arg_types = cif->arg_types;
+ int i, n;
+
+ if (flags == ARM_TYPE_STRUCT)
{
- argp = ffi_align(p_arg, argp);
- argp += ffi_put_arg(p_arg, p_argv, argp);
+ *(void **) argp = rvalue;
+ argp += 4;
}
- return 0;
+ for (i = 0, n = cif->nargs; i < n; i++)
+ {
+ ffi_type *ty = arg_types[i];
+ argp = ffi_align (ty, argp);
+ argp += ffi_put_arg (ty, avalue[i], argp);
+ }
}
-int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space)
+static void
+ffi_prep_args_VFP (ffi_cif *cif, int flags, void *rvalue,
+ void **avalue, char *stack, char *vfp_space)
{
- register unsigned int i, vi = 0;
- register void **p_argv;
- register char *argp, *regp, *eo_regp;
- register ffi_type **p_arg;
+ ffi_type **arg_types = cif->arg_types;
+ int i, n, vi = 0;
+ char *argp, *regp, *eo_regp;
char stack_used = 0;
char done_with_regs = 0;
- char is_vfp_type;
-
- // make sure we are using FFI_VFP
- FFI_ASSERT(ecif->cif->abi == FFI_VFP);
- /* the first 4 words on the stack are used for values passed in core
- * registers. */
+ /* The first 4 words on the stack are used for values
+ passed in core registers. */
regp = stack;
eo_regp = argp = regp + 16;
-
-
- /* if the function returns an FFI_TYPE_STRUCT in memory, that address is
- * passed in r0 to the function */
- if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
- *(void **) regp = ecif->rvalue;
- regp += 4;
- }
- p_argv = ecif->avalue;
+ /* If the function returns an FFI_TYPE_STRUCT in memory,
+ that address is passed in r0 to the function. */
+ if (flags == ARM_TYPE_STRUCT)
+ {
+ *(void **) regp = rvalue;
+ regp += 4;
+ }
- for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
- (i != 0);
- i--, p_arg++, p_argv++)
+ for (i = 0, n = cif->nargs; i < n; i++)
{
- is_vfp_type = vfp_type_p (*p_arg);
+ ffi_type *ty = arg_types[i];
+ void *a = avalue[i];
+ int is_vfp_type = vfp_type_p (ty);
/* Allocated in VFP registers. */
- if(vi < ecif->cif->vfp_nargs && is_vfp_type)
- {
- char *vfp_slot = (char *)(vfp_space + ecif->cif->vfp_args[vi++]);
- ffi_put_arg(p_arg, p_argv, vfp_slot);
- continue;
- }
+ if (vi < cif->vfp_nargs && is_vfp_type)
+ {
+ char *vfp_slot = vfp_space + cif->vfp_args[vi++] * 4;
+ ffi_put_arg (ty, a, vfp_slot);
+ continue;
+ }
/* Try allocating in core registers. */
else if (!done_with_regs && !is_vfp_type)
- {
- char *tregp = ffi_align(p_arg, regp);
- size_t size = (*p_arg)->size;
- size = (size < 4)? 4 : size; // pad
- /* Check if there is space left in the aligned register area to place
- * the argument */
- if(tregp + size <= eo_regp)
- {
- regp = tregp + ffi_put_arg(p_arg, p_argv, tregp);
- done_with_regs = (regp == argp);
- // ensure we did not write into the stack area
- FFI_ASSERT(regp <= argp);
- continue;
- }
- /* In case there are no arguments in the stack area yet,
- the argument is passed in the remaining core registers and on the
- stack. */
- else if (!stack_used)
- {
- stack_used = 1;
- done_with_regs = 1;
- argp = tregp + ffi_put_arg(p_arg, p_argv, tregp);
- FFI_ASSERT(eo_regp < argp);
- continue;
- }
- }
+ {
+ char *tregp = ffi_align (ty, regp);
+ size_t size = ty->size;
+ size = (size < 4) ? 4 : size; // pad
+ /* Check if there is space left in the aligned register
+ area to place the argument. */
+ if (tregp + size <= eo_regp)
+ {
+ regp = tregp + ffi_put_arg (ty, a, tregp);
+ done_with_regs = (regp == argp);
+ // ensure we did not write into the stack area
+ FFI_ASSERT (regp <= argp);
+ continue;
+ }
+ /* In case there are no arguments in the stack area yet,
+ the argument is passed in the remaining core registers
+ and on the stack. */
+ else if (!stack_used)
+ {
+ stack_used = 1;
+ done_with_regs = 1;
+ argp = tregp + ffi_put_arg (ty, a, tregp);
+ FFI_ASSERT (eo_regp < argp);
+ continue;
+ }
+ }
/* Base case, arguments are passed on the stack */
stack_used = 1;
- argp = ffi_align(p_arg, argp);
- argp += ffi_put_arg(p_arg, p_argv, argp);
+ argp = ffi_align (ty, argp);
+ argp += ffi_put_arg (ty, a, argp);
}
- /* Indicate the VFP registers used. */
- return ecif->cif->vfp_used;
}
/* Perform machine dependent cif processing */
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep (ffi_cif *cif)
{
- int type_code;
- /* Round the stack up to a multiple of 8 bytes. This isn't needed
- everywhere, but it is on some platforms, and it doesn't harm anything
- when it isn't needed. */
- cif->bytes = (cif->bytes + 7) & ~7;
+ int flags = 0, cabi = cif->abi;
+ size_t bytes = cif->bytes;
+
+ /* Map out the register placements of VFP register args. The VFP
+ hard-float calling conventions are slightly more sophisticated
+ than the base calling conventions, so we do it here instead of
+ in ffi_prep_args(). */
+ if (cabi == FFI_VFP)
+ layout_vfp_args (cif);
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
- case FFI_TYPE_FLOAT:
- case FFI_TYPE_DOUBLE:
- cif->flags = (unsigned) cif->rtype->type;
+ flags = ARM_TYPE_VOID;
+ break;
+
+ case FFI_TYPE_INT:
+ 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_POINTER:
+ flags = ARM_TYPE_INT;
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
- cif->flags = (unsigned) FFI_TYPE_SINT64;
+ flags = ARM_TYPE_INT64;
+ break;
+
+ case FFI_TYPE_FLOAT:
+ flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_S : ARM_TYPE_INT);
+ break;
+ case FFI_TYPE_DOUBLE:
+ flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_D : ARM_TYPE_INT64);
break;
case FFI_TYPE_STRUCT:
- if (cif->abi == FFI_VFP
- && (type_code = vfp_type_p (cif->rtype)) != 0)
+ case FFI_TYPE_COMPLEX:
+ if (cabi == FFI_VFP)
{
- /* A Composite Type passed in VFP registers, either
- FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */
- cif->flags = (unsigned) type_code;
+ int h = vfp_type_p (cif->rtype);
+
+ flags = ARM_TYPE_VFP_N;
+ if (h == 0x100 + FFI_TYPE_FLOAT)
+ flags = ARM_TYPE_VFP_S;
+ if (h == 0x100 + FFI_TYPE_DOUBLE)
+ flags = ARM_TYPE_VFP_D;
+ if (h != 0)
+ break;
}
- else if (cif->rtype->size <= 4)
- /* A Composite Type not larger than 4 bytes is returned in r0. */
- cif->flags = (unsigned)FFI_TYPE_INT;
+
+ /* A Composite Type not larger than 4 bytes is returned in r0.
+ A Composite Type larger than 4 bytes, or whose size cannot
+ be determined statically ... is stored in memory at an
+ address passed [in r0]. */
+ if (cif->rtype->size <= 4)
+ flags = ARM_TYPE_INT;
else
- /* A Composite Type larger than 4 bytes, or whose size cannot
- be determined statically ... is stored in memory at an
- address passed [in r0]. */
- cif->flags = (unsigned)FFI_TYPE_STRUCT;
+ {
+ flags = ARM_TYPE_STRUCT;
+ bytes += 4;
+ }
break;
default:
- cif->flags = FFI_TYPE_INT;
- break;
+ abort();
}
- /* Map out the register placements of VFP register args.
- The VFP hard-float calling conventions are slightly more sophisticated than
- the base calling conventions, so we do it here instead of in ffi_prep_args(). */
- if (cif->abi == FFI_VFP)
- layout_vfp_args (cif);
+ /* Round the stack up to a multiple of 8 bytes. This isn't needed
+ everywhere, but it is on some platforms, and it doesn't harm anything
+ when it isn't needed. */
+ bytes = FFI_ALIGN (bytes, 8);
+
+ /* Minimum stack space is the 4 register arguments that we pop. */
+ if (bytes < 4*4)
+ bytes = 4*4;
+
+ cif->bytes = bytes;
+ cif->flags = flags;
return FFI_OK;
}
/* Perform machine dependent cif processing for variadic calls */
-ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
- unsigned int nfixedargs,
- unsigned int ntotalargs)
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep_var (ffi_cif * cif,
+ unsigned int nfixedargs, unsigned int ntotalargs)
{
/* VFP variadic calls actually use the SYSV ABI */
if (cif->abi == FFI_VFP)
- cif->abi = FFI_SYSV;
+ cif->abi = FFI_SYSV;
- return ffi_prep_cif_machdep(cif);
+ return ffi_prep_cif_machdep (cif);
}
-/* Prototypes for assembly functions, in sysv.S */
-extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
-extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
+/* Prototypes for assembly functions, in sysv.S. */
-void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+struct call_frame
{
- extended_cif ecif;
-
- int small_struct = (cif->flags == FFI_TYPE_INT
- && cif->rtype->type == FFI_TYPE_STRUCT);
- int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT
- || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE);
-
- unsigned int temp;
-
- ecif.cif = cif;
- ecif.avalue = avalue;
+ void *fp;
+ void *lr;
+ void *rvalue;
+ int flags;
+ void *closure;
+};
- /* If the return value is a struct and we don't have a return */
- /* value address then we need to make one */
+extern void ffi_call_SYSV (void *stack, struct call_frame *,
+ void (*fn) (void)) FFI_HIDDEN;
+extern void ffi_call_VFP (void *vfp_space, struct call_frame *,
+ void (*fn) (void), unsigned vfp_used) FFI_HIDDEN;
- if ((rvalue == NULL) &&
- (cif->flags == FFI_TYPE_STRUCT))
+static void
+ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue,
+ void **avalue, void *closure)
+{
+ int flags = cif->flags;
+ ffi_type *rtype = cif->rtype;
+ size_t bytes, rsize, vfp_size;
+ char *stack, *vfp_space, *new_rvalue;
+ struct call_frame *frame;
+
+ rsize = 0;
+ if (rvalue == NULL)
{
- ecif.rvalue = alloca(cif->rtype->size);
+ /* If the return value is a struct and we don't have a return
+ value address then we need to make one. Otherwise the return
+ value is in registers and we can ignore them. */
+ if (flags == ARM_TYPE_STRUCT)
+ rsize = rtype->size;
+ else
+ flags = ARM_TYPE_VOID;
}
- else if (small_struct)
- ecif.rvalue = &temp;
- else if (vfp_struct)
+ else if (flags == ARM_TYPE_VFP_N)
{
/* Largest case is double x 4. */
- ecif.rvalue = alloca(32);
+ rsize = 32;
}
- else
- ecif.rvalue = rvalue;
+ else if (flags == ARM_TYPE_INT && rtype->type == FFI_TYPE_STRUCT)
+ rsize = 4;
- switch (cif->abi)
- {
- case FFI_SYSV:
- ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
- break;
+ /* Largest case. */
+ vfp_size = (cif->abi == FFI_VFP && cif->vfp_used ? 8*8: 0);
- case FFI_VFP:
-#ifdef __ARM_EABI__
- ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
- break;
-#endif
+ bytes = cif->bytes;
+ stack = alloca (vfp_size + bytes + sizeof(struct call_frame) + rsize);
- default:
- FFI_ASSERT(0);
- break;
- }
- if (small_struct)
+ vfp_space = NULL;
+ if (vfp_size)
{
- FFI_ASSERT(rvalue != NULL);
- memcpy (rvalue, &temp, cif->rtype->size);
+ vfp_space = stack;
+ stack += vfp_size;
}
-
- else if (vfp_struct)
- {
- FFI_ASSERT(rvalue != NULL);
- memcpy (rvalue, ecif.rvalue, cif->rtype->size);
- }
-
-}
-
-/** private members **/
-
-static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
- void** args, ffi_cif* cif, float *vfp_stack);
-
-static void ffi_prep_incoming_args_VFP (char *stack, void **ret,
- void** args, ffi_cif* cif, float *vfp_stack);
-void ffi_closure_SYSV (ffi_closure *);
+ frame = (struct call_frame *)(stack + bytes);
-void ffi_closure_VFP (ffi_closure *);
+ new_rvalue = rvalue;
+ if (rsize)
+ new_rvalue = (void *)(frame + 1);
-/* This function is jumped to by the trampoline */
+ frame->rvalue = new_rvalue;
+ frame->flags = flags;
+ frame->closure = closure;
-unsigned int FFI_HIDDEN
-ffi_closure_inner (ffi_closure *closure,
- void **respp, void *args, void *vfp_args)
-{
- // our various things...
- ffi_cif *cif;
- void **arg_area;
-
- cif = closure->cif;
- arg_area = (void**) alloca (cif->nargs * sizeof (void*));
-
- /* this call will initialize ARG_AREA, such that each
- * element in that array points to the corresponding
- * value on the stack; and if the function returns
- * a structure, it will re-set RESP to point to the
- * structure return address. */
- if (cif->abi == FFI_VFP)
- ffi_prep_incoming_args_VFP(args, respp, arg_area, cif, vfp_args);
+ if (vfp_space)
+ {
+ ffi_prep_args_VFP (cif, flags, new_rvalue, avalue, stack, vfp_space);
+ ffi_call_VFP (vfp_space, frame, fn, cif->vfp_used);
+ }
else
- ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
-
- (closure->fun) (cif, *respp, arg_area, closure->user_data);
+ {
+ ffi_prep_args_SYSV (cif, flags, new_rvalue, avalue, stack);
+ ffi_call_SYSV (stack, frame, fn);
+ }
- return cif->flags;
+ if (rvalue && rvalue != new_rvalue)
+ memcpy (rvalue, new_rvalue, rtype->size);
}
-/*@-exportheader@*/
-static void
-ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
- void **avalue, ffi_cif *cif,
- /* Used only under VFP hard-float ABI. */
- float *vfp_stack)
-/*@=exportheader@*/
+void
+ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
{
- register unsigned int i;
- register void **p_argv;
- register char *argp;
- register ffi_type **p_arg;
-
- argp = stack;
+ ffi_call_int (cif, fn, rvalue, avalue, NULL);
+}
- if ( cif->flags == FFI_TYPE_STRUCT ) {
- *rvalue = *(void **) argp;
- argp += 4;
- }
+void
+ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int (cif, fn, rvalue, avalue, closure);
+}
- p_argv = avalue;
+static void *
+ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue,
+ char *argp, void **avalue)
+{
+ ffi_type **arg_types = cif->arg_types;
+ int i, n;
- for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
+ if (cif->flags == ARM_TYPE_STRUCT)
{
- size_t z;
-
- argp = ffi_align(p_arg, argp);
-
- z = (*p_arg)->size;
-
- /* because we're little endian, this is what it turns into. */
+ rvalue = *(void **) argp;
+ argp += 4;
+ }
+ else
+ {
+ if (cif->rtype->size && cif->rtype->size < 4)
+ *(uint32_t *) rvalue = 0;
+ }
- *p_argv = (void*) argp;
+ for (i = 0, n = cif->nargs; i < n; i++)
+ {
+ ffi_type *ty = arg_types[i];
+ size_t z = ty->size;
- p_argv++;
+ argp = ffi_align (ty, argp);
+ avalue[i] = (void *) argp;
argp += z;
}
-
- return;
+
+ return rvalue;
}
-/*@-exportheader@*/
-static void
-ffi_prep_incoming_args_VFP(char *stack, void **rvalue,
- void **avalue, ffi_cif *cif,
- /* Used only under VFP hard-float ABI. */
- float *vfp_stack)
-/*@=exportheader@*/
+static void *
+ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack,
+ char *vfp_space, void **avalue)
{
- register unsigned int i, vi = 0;
- register void **p_argv;
- register char *argp, *regp, *eo_regp;
- register ffi_type **p_arg;
+ ffi_type **arg_types = cif->arg_types;
+ int i, n, vi = 0;
+ char *argp, *regp, *eo_regp;
char done_with_regs = 0;
char stack_used = 0;
- char is_vfp_type;
- FFI_ASSERT(cif->abi == FFI_VFP);
regp = stack;
eo_regp = argp = regp + 16;
- if ( cif->flags == FFI_TYPE_STRUCT ) {
- *rvalue = *(void **) regp;
- regp += 4;
- }
-
- p_argv = avalue;
-
- for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
+ if (cif->flags == ARM_TYPE_STRUCT)
{
- size_t z;
- is_vfp_type = vfp_type_p (*p_arg);
-
- if(vi < cif->vfp_nargs && is_vfp_type)
- {
- *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]);
- continue;
- }
- else if (!done_with_regs && !is_vfp_type)
- {
- char* tregp = ffi_align(p_arg, regp);
-
- z = (*p_arg)->size;
- z = (z < 4)? 4 : z; // pad
-
- /* if the arguments either fits into the registers or uses registers
- * and stack, while we haven't read other things from the stack */
- if(tregp + z <= eo_regp || !stack_used)
- {
- /* because we're little endian, this is what it turns into. */
- *p_argv = (void*) tregp;
-
- p_argv++;
- regp = tregp + z;
- // if we read past the last core register, make sure we have not read
- // from the stack before and continue reading after regp
- if(regp > eo_regp)
- {
- if(stack_used)
- {
- abort(); // we should never read past the end of the register
- // are if the stack is already in use
- }
- argp = regp;
- }
- if(regp >= eo_regp)
- {
- done_with_regs = 1;
- stack_used = 1;
- }
- continue;
- }
- }
- stack_used = 1;
-
- argp = ffi_align(p_arg, argp);
-
- z = (*p_arg)->size;
-
- /* because we're little endian, this is what it turns into. */
-
- *p_argv = (void*) argp;
-
- p_argv++;
- argp += z;
+ rvalue = *(void **) regp;
+ regp += 4;
}
-
- return;
-}
-
-/* How to make a trampoline. */
-
-extern unsigned int ffi_arm_trampoline[3];
-#if FFI_EXEC_TRAMPOLINE_TABLE
-
-#include <mach/mach.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
+ for (i = 0, n = cif->nargs; i < n; i++)
+ {
+ ffi_type *ty = arg_types[i];
+ int is_vfp_type = vfp_type_p (ty);
+ size_t z = ty->size;
-extern void *ffi_closure_trampoline_table_page;
+ if (vi < cif->vfp_nargs && is_vfp_type)
+ {
+ avalue[i] = vfp_space + cif->vfp_args[vi++] * 4;
+ continue;
+ }
+ else if (!done_with_regs && !is_vfp_type)
+ {
+ char *tregp = ffi_align (ty, regp);
-typedef struct ffi_trampoline_table ffi_trampoline_table;
-typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
+ z = (z < 4) ? 4 : z; // pad
-struct ffi_trampoline_table {
- /* contiguous writable and executable pages */
- vm_address_t config_page;
- vm_address_t trampoline_page;
+ /* If the arguments either fits into the registers or uses registers
+ and stack, while we haven't read other things from the stack */
+ if (tregp + z <= eo_regp || !stack_used)
+ {
+ /* Because we're little endian, this is what it turns into. */
+ avalue[i] = (void *) tregp;
+ regp = tregp + z;
+
+ /* If we read past the last core register, make sure we
+ have not read from the stack before and continue
+ reading after regp. */
+ if (regp > eo_regp)
+ {
+ FFI_ASSERT (!stack_used);
+ argp = regp;
+ }
+ if (regp >= eo_regp)
+ {
+ done_with_regs = 1;
+ stack_used = 1;
+ }
+ continue;
+ }
+ }
- /* free list tracking */
- uint16_t free_count;
- ffi_trampoline_table_entry *free_list;
- ffi_trampoline_table_entry *free_list_pool;
+ stack_used = 1;
+ argp = ffi_align (ty, argp);
+ avalue[i] = (void *) argp;
+ argp += z;
+ }
- ffi_trampoline_table *prev;
- ffi_trampoline_table *next;
-};
+ return rvalue;
+}
-struct ffi_trampoline_table_entry {
- void *(*trampoline)();
- ffi_trampoline_table_entry *next;
+struct closure_frame
+{
+ char vfp_space[8*8] __attribute__((aligned(8)));
+ char result[8*4];
+ char argp[];
};
-/* Override the standard architecture trampoline size */
-// XXX TODO - Fix
-#undef FFI_TRAMPOLINE_SIZE
-#define FFI_TRAMPOLINE_SIZE 12
-
-/* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */
-#define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080));
-
-/* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */
-#define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16
-
-/* Total number of trampolines that fit in one trampoline table */
-#define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE)
-
-static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
-static ffi_trampoline_table *ffi_trampoline_tables = NULL;
-
-static ffi_trampoline_table *
-ffi_trampoline_table_alloc ()
+int FFI_HIDDEN
+ffi_closure_inner_SYSV (ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data,
+ struct closure_frame *frame)
{
- ffi_trampoline_table *table = NULL;
-
- /* Loop until we can allocate two contiguous pages */
- while (table == NULL) {
- vm_address_t config_page = 0x0;
- kern_return_t kt;
-
- /* Try to allocate two pages */
- kt = vm_allocate (mach_task_self (), &config_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE);
- if (kt != KERN_SUCCESS) {
- fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
- break;
- }
+ void **avalue = (void **) alloca (cif->nargs * sizeof (void *));
+ void *rvalue = ffi_prep_incoming_args_SYSV (cif, frame->result,
+ frame->argp, avalue);
+ fun (cif, rvalue, avalue, user_data);
+ return cif->flags;
+}
- /* Now drop the second half of the allocation to make room for the trampoline table */
- vm_address_t trampoline_page = config_page+PAGE_SIZE;
- kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE);
- if (kt != KERN_SUCCESS) {
- fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
- break;
- }
+int FFI_HIDDEN
+ffi_closure_inner_VFP (ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data,
+ struct closure_frame *frame)
+{
+ void **avalue = (void **) alloca (cif->nargs * sizeof (void *));
+ void *rvalue = ffi_prep_incoming_args_VFP (cif, frame->result, frame->argp,
+ frame->vfp_space, avalue);
+ fun (cif, rvalue, avalue, user_data);
+ return cif->flags;
+}
- /* Remap the trampoline table to directly follow the config page */
- vm_prot_t cur_prot;
- vm_prot_t max_prot;
+void ffi_closure_SYSV (void) FFI_HIDDEN;
+void ffi_closure_VFP (void) FFI_HIDDEN;
+void ffi_go_closure_SYSV (void) FFI_HIDDEN;
+void ffi_go_closure_VFP (void) FFI_HIDDEN;
- kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE, mach_task_self (), (vm_address_t) &ffi_closure_trampoline_table_page, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
+/* the cif must already be prep'ed */
- /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
- if (kt != KERN_SUCCESS) {
- /* Log unexpected failures */
- if (kt != KERN_NO_SPACE) {
- fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
- }
+ffi_status
+ffi_prep_closure_loc (ffi_closure * closure,
+ ffi_cif * cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data, void *codeloc)
+{
+ void (*closure_func) (void) = ffi_closure_SYSV;
- vm_deallocate (mach_task_self (), config_page, PAGE_SIZE);
- continue;
+ if (cif->abi == FFI_VFP)
+ {
+ /* We only need take the vfp path if there are vfp arguments. */
+ if (cif->vfp_used)
+ closure_func = ffi_closure_VFP;
}
+ else if (cif->abi != FFI_SYSV)
+ return FFI_BAD_ABI;
- /* We have valid trampoline and config pages */
- table = calloc (1, sizeof(ffi_trampoline_table));
- table->free_count = FFI_TRAMPOLINE_COUNT;
- table->config_page = config_page;
- table->trampoline_page = trampoline_page;
-
- /* Create and initialize the free list */
- table->free_list_pool = calloc(FFI_TRAMPOLINE_COUNT, sizeof(ffi_trampoline_table_entry));
+#if FFI_EXEC_TRAMPOLINE_TABLE
+ void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
+ config[0] = closure;
+ config[1] = closure_func;
+#else
- uint16_t i;
- for (i = 0; i < table->free_count; i++) {
- ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
- entry->trampoline = (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
+#ifndef _M_ARM
+ memcpy(closure->tramp, ffi_arm_trampoline, 8);
+#else
+ // cast away function type so MSVC doesn't set the lower bit of the function pointer
+ memcpy(closure->tramp, (void*)((uintptr_t)ffi_arm_trampoline & 0xFFFFFFFE), FFI_TRAMPOLINE_CLOSURE_OFFSET);
+#endif
- if (i < table->free_count - 1)
- entry->next = &table->free_list_pool[i+1];
- }
+#if defined (__QNX__)
+ msync(closure->tramp, 8, 0x1000000); /* clear data map */
+ msync(codeloc, 8, 0x1000000); /* clear insn map */
+#elif defined(_MSC_VER)
+ FlushInstructionCache(GetCurrentProcess(), closure->tramp, FFI_TRAMPOLINE_SIZE);
+#else
+ __clear_cache(closure->tramp, closure->tramp + 8); /* clear data map */
+ __clear_cache(codeloc, codeloc + 8); /* clear insn map */
+#endif
+#ifdef _M_ARM
+ *(void(**)(void))(closure->tramp + FFI_TRAMPOLINE_CLOSURE_FUNCTION) = closure_func;
+#else
+ *(void (**)(void))(closure->tramp + 8) = closure_func;
+#endif
+#endif
- table->free_list = table->free_list_pool;
- }
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
- return table;
+ return FFI_OK;
}
-void *
-ffi_closure_alloc (size_t size, void **code)
+ffi_status
+ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *))
{
- /* Create the closure */
- ffi_closure *closure = malloc(size);
- if (closure == NULL)
- return NULL;
-
- pthread_mutex_lock(&ffi_trampoline_lock);
-
- /* Check for an active trampoline table with available entries. */
- ffi_trampoline_table *table = ffi_trampoline_tables;
- if (table == NULL || table->free_list == NULL) {
- table = ffi_trampoline_table_alloc ();
- if (table == NULL) {
- free(closure);
- return NULL;
- }
-
- /* Insert the new table at the top of the list */
- table->next = ffi_trampoline_tables;
- if (table->next != NULL)
- table->next->prev = table;
+ void (*closure_func) (void) = ffi_go_closure_SYSV;
- ffi_trampoline_tables = table;
- }
+ if (cif->abi == FFI_VFP)
+ {
+ /* We only need take the vfp path if there are vfp arguments. */
+ if (cif->vfp_used)
+ closure_func = ffi_go_closure_VFP;
+ }
+ else if (cif->abi != FFI_SYSV)
+ return FFI_BAD_ABI;
- /* Claim the free entry */
- ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
- ffi_trampoline_tables->free_list = entry->next;
- ffi_trampoline_tables->free_count--;
- entry->next = NULL;
+ closure->tramp = closure_func;
+ closure->cif = cif;
+ closure->fun = fun;
- pthread_mutex_unlock(&ffi_trampoline_lock);
+ return FFI_OK;
+}
- /* Initialize the return values */
- *code = entry->trampoline;
- closure->trampoline_table = table;
- closure->trampoline_table_entry = entry;
+/* Below are routines for VFP hard-float support. */
- return closure;
-}
+/* A subroutine of vfp_type_p. Given a structure type, return the type code
+ of the first non-structure element. Recurse for structure elements.
+ Return -1 if the structure is in fact empty, i.e. no nested elements. */
-void
-ffi_closure_free (void *ptr)
+static int
+is_hfa0 (const ffi_type *ty)
{
- ffi_closure *closure = ptr;
-
- pthread_mutex_lock(&ffi_trampoline_lock);
-
- /* Fetch the table and entry references */
- ffi_trampoline_table *table = closure->trampoline_table;
- ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
-
- /* Return the entry to the free list */
- entry->next = table->free_list;
- table->free_list = entry;
- table->free_count++;
-
- /* If all trampolines within this table are free, and at least one other table exists, deallocate
- * the table */
- if (table->free_count == FFI_TRAMPOLINE_COUNT && ffi_trampoline_tables != table) {
- /* Remove from the list */
- if (table->prev != NULL)
- table->prev->next = table->next;
-
- if (table->next != NULL)
- table->next->prev = table->prev;
-
- /* Deallocate pages */
- kern_return_t kt;
- kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE);
- if (kt != KERN_SUCCESS)
- fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
-
- kt = vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE);
- if (kt != KERN_SUCCESS)
- fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
-
- /* Deallocate free list */
- free (table->free_list_pool);
- free (table);
- } else if (ffi_trampoline_tables != table) {
- /* Otherwise, bump this table to the top of the list */
- table->prev = NULL;
- table->next = ffi_trampoline_tables;
- if (ffi_trampoline_tables != NULL)
- ffi_trampoline_tables->prev = table;
-
- ffi_trampoline_tables = table;
- }
-
- pthread_mutex_unlock (&ffi_trampoline_lock);
-
- /* Free the closure */
- free (closure);
-}
-
-#else
+ ffi_type **elements = ty->elements;
+ int i, ret = -1;
-#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
-({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
- unsigned int __fun = (unsigned int)(FUN); \
- unsigned int __ctx = (unsigned int)(CTX); \
- unsigned char *insns = (unsigned char *)(CTX); \
- memcpy (__tramp, ffi_arm_trampoline, sizeof ffi_arm_trampoline); \
- *(unsigned int*) &__tramp[12] = __ctx; \
- *(unsigned int*) &__tramp[16] = __fun; \
- __clear_cache((&__tramp[0]), (&__tramp[19])); /* Clear data mapping. */ \
- __clear_cache(insns, insns + 3 * sizeof (unsigned int)); \
- /* Clear instruction \
- mapping. */ \
- })
+ if (elements != NULL)
+ for (i = 0; elements[i]; ++i)
+ {
+ ret = elements[i]->type;
+ if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX)
+ {
+ ret = is_hfa0 (elements[i]);
+ if (ret < 0)
+ continue;
+ }
+ break;
+ }
-#endif
+ return ret;
+}
-/* the cif must already be prep'ed */
+/* A subroutine of vfp_type_p. Given a structure type, return true if all
+ of the non-structure elements are the same as CANDIDATE. */
-ffi_status
-ffi_prep_closure_loc (ffi_closure* closure,
- ffi_cif* cif,
- void (*fun)(ffi_cif*,void*,void**,void*),
- void *user_data,
- void *codeloc)
+static int
+is_hfa1 (const ffi_type *ty, int candidate)
{
- void (*closure_func)(ffi_closure*) = NULL;
-
- if (cif->abi == FFI_SYSV)
- closure_func = &ffi_closure_SYSV;
-#ifdef __ARM_EABI__
- else if (cif->abi == FFI_VFP)
- closure_func = &ffi_closure_VFP;
-#endif
- else
- return FFI_BAD_ABI;
-
-#if FFI_EXEC_TRAMPOLINE_TABLE
- void **config = FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc);
- config[0] = closure;
- config[1] = closure_func;
-#else
- FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
- closure_func, \
- codeloc);
-#endif
+ ffi_type **elements = ty->elements;
+ int i;
- closure->cif = cif;
- closure->user_data = user_data;
- closure->fun = fun;
+ if (elements != NULL)
+ for (i = 0; elements[i]; ++i)
+ {
+ int t = elements[i]->type;
+ if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
+ {
+ if (!is_hfa1 (elements[i], candidate))
+ return 0;
+ }
+ else if (t != candidate)
+ return 0;
+ }
- return FFI_OK;
+ return 1;
}
-/* Below are routines for VFP hard-float support. */
+/* Determine if TY is an homogenous floating point aggregate (HFA).
+ That is, a structure consisting of 1 to 4 members of all the same type,
+ where that type is a floating point scalar.
+
+ Returns non-zero iff TY is an HFA. The result is an encoded value where
+ bits 0-7 contain the type code, and bits 8-10 contain the element count. */
-static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum)
+static int
+vfp_type_p (const ffi_type *ty)
{
- switch (t->type)
+ ffi_type **elements;
+ int candidate, i;
+ size_t size, ele_count;
+
+ /* Quickest tests first. */
+ candidate = ty->type;
+ switch (ty->type)
{
+ default:
+ return 0;
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
- *elt = (int) t->type;
- *elnum = 1;
- return 1;
+ ele_count = 1;
+ goto done;
+ case FFI_TYPE_COMPLEX:
+ candidate = ty->elements[0]->type;
+ if (candidate != FFI_TYPE_FLOAT && candidate != FFI_TYPE_DOUBLE)
+ return 0;
+ ele_count = 2;
+ goto done;
+ case FFI_TYPE_STRUCT:
+ break;
+ }
- case FFI_TYPE_STRUCT_VFP_FLOAT:
- *elt = FFI_TYPE_FLOAT;
- *elnum = t->size / sizeof (float);
- return 1;
+ /* No HFA types are smaller than 4 bytes, or larger than 32 bytes. */
+ size = ty->size;
+ if (size < 4 || size > 32)
+ return 0;
- case FFI_TYPE_STRUCT_VFP_DOUBLE:
- *elt = FFI_TYPE_DOUBLE;
- *elnum = t->size / sizeof (double);
- return 1;
+ /* Find the type of the first non-structure member. */
+ elements = ty->elements;
+ candidate = elements[0]->type;
+ if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX)
+ {
+ for (i = 0; ; ++i)
+ {
+ candidate = is_hfa0 (elements[i]);
+ if (candidate >= 0)
+ break;
+ }
+ }
- case FFI_TYPE_STRUCT:;
- {
- int base_elt = 0, total_elnum = 0;
- ffi_type **el = t->elements;
- while (*el)
- {
- int el_elt = 0, el_elnum = 0;
- if (! rec_vfp_type_p (*el, &el_elt, &el_elnum)
- || (base_elt && base_elt != el_elt)
- || total_elnum + el_elnum > 4)
- return 0;
- base_elt = el_elt;
- total_elnum += el_elnum;
- el++;
- }
- *elnum = total_elnum;
- *elt = base_elt;
- return 1;
- }
- default: ;
+ /* If the first member is not a floating point type, it's not an HFA.
+ Also quickly re-check the size of the structure. */
+ switch (candidate)
+ {
+ case FFI_TYPE_FLOAT:
+ ele_count = size / sizeof(float);
+ if (size != ele_count * sizeof(float))
+ return 0;
+ break;
+ case FFI_TYPE_DOUBLE:
+ ele_count = size / sizeof(double);
+ if (size != ele_count * sizeof(double))
+ return 0;
+ break;
+ default:
+ return 0;
}
- return 0;
-}
+ if (ele_count > 4)
+ return 0;
-static int vfp_type_p (ffi_type *t)
-{
- int elt, elnum;
- if (rec_vfp_type_p (t, &elt, &elnum))
+ /* Finally, make sure that all scalar elements are the same type. */
+ for (i = 0; elements[i]; ++i)
{
- if (t->type == FFI_TYPE_STRUCT)
- {
- if (elnum == 1)
- t->type = elt;
- else
- t->type = (elt == FFI_TYPE_FLOAT
- ? FFI_TYPE_STRUCT_VFP_FLOAT
- : FFI_TYPE_STRUCT_VFP_DOUBLE);
- }
- return (int) t->type;
+ int t = elements[i]->type;
+ if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
+ {
+ if (!is_hfa1 (elements[i], candidate))
+ return 0;
+ }
+ else if (t != candidate)
+ return 0;
}
- return 0;
+
+ /* All tests succeeded. Encode the result. */
+ done:
+ return (ele_count << 8) | candidate;
}
-static int place_vfp_arg (ffi_cif *cif, ffi_type *t)
+static int
+place_vfp_arg (ffi_cif *cif, int h)
{
- short reg = cif->vfp_reg_free;
- int nregs = t->size / sizeof (float);
- int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT
- || t->type == FFI_TYPE_FLOAT) ? 1 : 2);
+ unsigned short reg = cif->vfp_reg_free;
+ int align = 1, nregs = h >> 8;
+
+ if ((h & 0xff) == FFI_TYPE_DOUBLE)
+ align = 2, nregs *= 2;
+
/* Align register number. */
if ((reg & 1) && align == 2)
reg++;
+
while (reg + nregs <= 16)
{
int s, new_used = 0;
@@ -892,7 +814,7 @@ static int place_vfp_arg (ffi_cif *cif, ffi_type *t)
}
/* Found regs to allocate. */
cif->vfp_used |= new_used;
- cif->vfp_args[cif->vfp_nargs++] = reg;
+ cif->vfp_args[cif->vfp_nargs++] = (signed char)reg;
/* Update vfp_reg_free. */
if (cif->vfp_used & (1 << cif->vfp_reg_free))
@@ -903,7 +825,7 @@ static int place_vfp_arg (ffi_cif *cif, ffi_type *t)
cif->vfp_reg_free = reg;
}
return 0;
- next_reg: ;
+ next_reg:;
}
// done, mark all regs as used
cif->vfp_reg_free = 16;
@@ -911,21 +833,22 @@ static int place_vfp_arg (ffi_cif *cif, ffi_type *t)
return 1;
}
-static void layout_vfp_args (ffi_cif *cif)
+static void
+layout_vfp_args (ffi_cif * cif)
{
- int i;
+ unsigned int i;
/* Init VFP fields */
cif->vfp_used = 0;
cif->vfp_nargs = 0;
cif->vfp_reg_free = 0;
- memset (cif->vfp_args, -1, 16); /* Init to -1. */
+ memset (cif->vfp_args, -1, 16); /* Init to -1. */
for (i = 0; i < cif->nargs; i++)
{
- ffi_type *t = cif->arg_types[i];
- if (vfp_type_p (t) && place_vfp_arg (cif, t) == 1)
- {
- break;
- }
+ int h = vfp_type_p (cif->arg_types[i]);
+ if (h && place_vfp_arg (cif, h) == 1)
+ break;
}
}
+
+#endif /* __arm__ or _M_ARM */
diff --git a/src/arm/ffitarget.h b/src/arm/ffitarget.h
index 26d494d6..cb57b848 100644
--- a/src/arm/ffitarget.h
+++ b/src/arm/ffitarget.h
@@ -43,7 +43,7 @@ typedef enum ffi_abi {
FFI_SYSV,
FFI_VFP,
FFI_LAST_ABI,
-#ifdef __ARM_PCS_VFP
+#if defined(__ARM_PCS_VFP) || defined(_M_ARM)
FFI_DEFAULT_ABI = FFI_VFP,
#else
FFI_DEFAULT_ABI = FFI_SYSV,
@@ -53,19 +53,37 @@ typedef enum ffi_abi {
#define FFI_EXTRA_CIF_FIELDS \
int vfp_used; \
- short vfp_reg_free, vfp_nargs; \
+ unsigned short vfp_reg_free, vfp_nargs; \
signed char vfp_args[16] \
-/* Internally used. */
-#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1)
-#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
-
#define FFI_TARGET_SPECIFIC_VARIADIC
+#ifndef _M_ARM
+#define FFI_TARGET_HAS_COMPLEX_TYPE
+#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
-#define FFI_TRAMPOLINE_SIZE 20
+#define FFI_GO_CLOSURES 1
#define FFI_NATIVE_RAW_API 0
+#if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE
+
+#ifdef __MACH__
+#define FFI_TRAMPOLINE_SIZE 12
+#define FFI_TRAMPOLINE_CLOSURE_OFFSET 8
+#else
+#error "No trampoline table implementation"
+#endif
+
+#else
+#ifdef _MSC_VER
+#define FFI_TRAMPOLINE_SIZE 16
+#define FFI_TRAMPOLINE_CLOSURE_FUNCTION 12
+#else
+#define FFI_TRAMPOLINE_SIZE 12
+#endif
+#define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE
+#endif
+
#endif
diff --git a/src/arm/internal.h b/src/arm/internal.h
new file mode 100644
index 00000000..6cf0b2ae
--- /dev/null
+++ b/src/arm/internal.h
@@ -0,0 +1,7 @@
+#define ARM_TYPE_VFP_S 0
+#define ARM_TYPE_VFP_D 1
+#define ARM_TYPE_VFP_N 2
+#define ARM_TYPE_INT64 3
+#define ARM_TYPE_INT 4
+#define ARM_TYPE_VOID 5
+#define ARM_TYPE_STRUCT 6
diff --git a/src/arm/sysv.S b/src/arm/sysv.S
index fcdfd562..63180a46 100644
--- a/src/arm/sysv.S
+++ b/src/arm/sysv.S
@@ -1,8 +1,8 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
Copyright (c) 2011 Plausible Labs Cooperative, Inc.
-
- ARM Foreign Function Interface
+
+ ARM Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -25,466 +25,360 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
-#define LIBFFI_ASM
+#ifdef __arm__
+#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
-#ifdef HAVE_MACHINE_ASM_H
-#include <machine/asm.h>
-#else
-#ifdef __USER_LABEL_PREFIX__
-#define CONCAT1(a, b) CONCAT2(a, b)
-#define CONCAT2(a, b) a ## b
-
-/* Use the right prefix for global labels. */
-#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
-#else
-#define CNAME(x) x
-#endif
-#ifdef __APPLE__
-#define ENTRY(x) .globl _##x; _##x:
-#else
-#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
-#endif /* __APPLE__ */
-#endif
-
-#ifdef __ELF__
-#define LSYM(x) .x
-#else
-#define LSYM(x) x
-#endif
-
-/* Use the SOFTFP return value ABI on Mac OS X, as per the iOS ABI
- Function Call Guide */
-#ifdef __APPLE__
-#define __SOFTFP__
-#endif
-
-/* We need a better way of testing for this, but for now, this is all
- we can do. */
-@ This selects the minimum architecture level required.
-#define __ARM_ARCH__ 3
-
-#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
-# undef __ARM_ARCH__
-# define __ARM_ARCH__ 4
-#endif
-
-#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
- || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
- || defined(__ARM_ARCH_5TEJ__)
-# undef __ARM_ARCH__
-# define __ARM_ARCH__ 5
-#endif
-
-#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
+#include <ffi_cfi.h>
+#include "internal.h"
+
+/* GCC 4.8 provides __ARM_ARCH; construct it otherwise. */
+#ifndef __ARM_ARCH
+# if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
+ || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
+ || defined(__ARM_ARCH_7EM__)
+# define __ARM_ARCH 7
+# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
|| defined(__ARM_ARCH_6M__)
-# undef __ARM_ARCH__
-# define __ARM_ARCH__ 6
-#endif
-
-#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
- || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
- || defined(__ARM_ARCH_7EM__)
-# undef __ARM_ARCH__
-# define __ARM_ARCH__ 7
-#endif
-
-#if __ARM_ARCH__ >= 5
-# define call_reg(x) blx x
-#elif defined (__ARM_ARCH_4T__)
-# define call_reg(x) mov lr, pc ; bx x
-# if defined(__thumb__) || defined(__THUMB_INTERWORK__)
-# define __INTERWORKING__
+# define __ARM_ARCH 6
+# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
+ || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
+ || defined(__ARM_ARCH_5TEJ__)
+# define __ARM_ARCH 5
+# else
+# define __ARM_ARCH 4
# endif
-#else
-# define call_reg(x) mov lr, pc ; mov pc, x
#endif
/* Conditionally compile unwinder directives. */
#ifdef __ARM_EABI__
-#define UNWIND
-#else
-#define UNWIND @
-#endif
-
-.syntax unified
-
-#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
-#define ARM_FUNC_START(name) \
- .text; \
- .align 2; \
- .thumb; \
- .thumb_func; \
- ENTRY(name); \
- bx pc; \
- nop; \
- .arm; \
- UNWIND .fnstart; \
-_L__##name:
+# define UNWIND(...) __VA_ARGS__
#else
-#define ARM_FUNC_START(name) \
- .text; \
- .align 2; \
- .arm; \
- ENTRY(name); \
- UNWIND .fnstart
+# define UNWIND(...)
#endif
-.macro RETLDM regs=, cond=, dirn=ia
-#if defined (__INTERWORKING__)
- .ifc "\regs",""
- ldr\cond lr, [sp], #4
- .else
- ldm\cond\dirn sp!, {\regs, lr}
- .endif
- bx\cond lr
-#else
- .ifc "\regs",""
- ldr\cond pc, [sp], #4
- .else
- ldm\cond\dirn sp!, {\regs, pc}
- .endif
+#if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__)
+ .cfi_sections .debug_frame
#endif
-.endm
-
- @ r0: ffi_prep_args
- @ r1: &ecif
- @ r2: cif->bytes
- @ r3: fig->flags
- @ sp+0: ecif.rvalue
-
- @ This assumes we are using gas.
-ARM_FUNC_START(ffi_call_SYSV)
- @ Save registers
- stmfd sp!, {r0-r3, fp, lr}
- UNWIND .save {r0-r3, fp, lr}
- mov fp, sp
- UNWIND .setfp fp, sp
+#define CONCAT(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
- @ Make room for all of the new args.
- sub sp, fp, r2
+#ifdef __USER_LABEL_PREFIX__
+# define CNAME(X) CONCAT (__USER_LABEL_PREFIX__, X)
+#else
+# define CNAME(X) X
+#endif
+#ifdef __ELF__
+# define SIZE(X) .size CNAME(X), . - CNAME(X)
+# define TYPE(X, Y) .type CNAME(X), Y
+#else
+# define SIZE(X)
+# define TYPE(X, Y)
+#endif
- @ Place all of the ffi_prep_args in position
- mov r0, sp
- @ r1 already set
+#define ARM_FUNC_START_LOCAL(name) \
+ .align 3; \
+ TYPE(CNAME(name), %function); \
+ CNAME(name):
- @ Call ffi_prep_args(stack, &ecif)
- bl CNAME(ffi_prep_args_SYSV)
+#define ARM_FUNC_START(name) \
+ .globl CNAME(name); \
+ FFI_HIDDEN(CNAME(name)); \
+ ARM_FUNC_START_LOCAL(name)
- @ move first 4 parameters in registers
- ldmia sp, {r0-r3}
+#define ARM_FUNC_END(name) \
+ SIZE(name)
- @ and adjust stack
- sub lr, fp, sp @ cif->bytes == fp - sp
- ldr ip, [fp] @ load fn() in advance
- cmp lr, #16
- movhs lr, #16
- add sp, sp, lr
+/* Aid in defining a jump table with 8 bytes between entries. */
+/* ??? The clang assembler doesn't handle .if with symbolic expressions. */
+#ifdef __clang__
+# define E(index)
+#else
+# define E(index) \
+ .if . - 0b - 8*index; \
+ .error "type table out of sync"; \
+ .endif
+#endif
- @ call (fn) (...)
- call_reg(ip)
-
- @ Remove the space we pushed for the args
- mov sp, fp
+ .text
+ .syntax unified
+ .arm
- @ Load r2 with the pointer to storage for the return value
- ldr r2, [sp, #24]
+#ifndef __clang__
+ /* We require interworking on LDM, which implies ARMv5T,
+ which implies the existance of BLX. */
+ .arch armv5t
+#endif
- @ Load r3 with the return type code
- ldr r3, [sp, #12]
+ /* Note that we use STC and LDC to encode VFP instructions,
+ so that we do not need ".fpu vfp", nor get that added to
+ the object file attributes. These will not be executed
+ unless the FFI_VFP abi is used. */
- @ If the return value pointer is NULL, assume no return value.
- cmp r2, #0
- beq LSYM(Lepilogue)
+ @ r0: stack
+ @ r1: frame
+ @ r2: fn
+ @ r3: vfp_used
-@ return INT
- cmp r3, #FFI_TYPE_INT
-#if defined(__SOFTFP__) || defined(__ARM_EABI__)
- cmpne r3, #FFI_TYPE_FLOAT
-#endif
- streq r0, [r2]
- beq LSYM(Lepilogue)
+ARM_FUNC_START(ffi_call_VFP)
+ UNWIND(.fnstart)
+ cfi_startproc
- @ return INT64
- cmp r3, #FFI_TYPE_SINT64
-#if defined(__SOFTFP__) || defined(__ARM_EABI__)
- cmpne r3, #FFI_TYPE_DOUBLE
+ cmp r3, #3 @ load only d0 if possible
+#ifdef __clang__
+ vldrle d0, [sp]
+ vldmgt sp, {d0-d7}
+#else
+ ldcle p11, cr0, [r0] @ vldrle d0, [sp]
+ ldcgt p11, cr0, [r0], {16} @ vldmgt sp, {d0-d7}
#endif
- stmiaeq r2, {r0, r1}
+ add r0, r0, #64 @ discard the vfp register args
+ /* FALLTHRU */
+ARM_FUNC_END(ffi_call_VFP)
-#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
- beq LSYM(Lepilogue)
+ARM_FUNC_START(ffi_call_SYSV)
+ stm r1, {fp, lr}
+ mov fp, r1
+
+ @ This is a bit of a lie wrt the origin of the unwind info, but
+ @ now we've got the usual frame pointer and two saved registers.
+ UNWIND(.save {fp,lr})
+ UNWIND(.setfp fp, sp)
+ cfi_def_cfa(fp, 8)
+ cfi_rel_offset(fp, 0)
+ cfi_rel_offset(lr, 4)
+
+ mov sp, r0 @ install the stack pointer
+ mov lr, r2 @ move the fn pointer out of the way
+ ldr ip, [fp, #16] @ install the static chain
+ ldmia sp!, {r0-r3} @ move first 4 parameters in registers.
+ blx lr @ call fn
-@ return FLOAT
- cmp r3, #FFI_TYPE_FLOAT
- stfeqs f0, [r2]
- beq LSYM(Lepilogue)
+ @ Load r2 with the pointer to storage for the return value
+ @ Load r3 with the return type code
+ ldr r2, [fp, #8]
+ ldr r3, [fp, #12]
-@ return DOUBLE or LONGDOUBLE
- cmp r3, #FFI_TYPE_DOUBLE
- stfeqd f0, [r2]
+ @ Deallocate the stack with the arguments.
+ mov sp, fp
+ cfi_def_cfa_register(sp)
+
+ @ Store values stored in registers.
+ .align 3
+ add pc, pc, r3, lsl #3
+ nop
+0:
+E(ARM_TYPE_VFP_S)
+#ifdef __clang__
+ vstr s0, [r2]
+#else
+ stc p10, cr0, [r2] @ vstr s0, [r2]
#endif
-
-LSYM(Lepilogue):
-#if defined (__INTERWORKING__)
- ldmia sp!, {r0-r3,fp, lr}
- bx lr
+ pop {fp,pc}
+E(ARM_TYPE_VFP_D)
+#ifdef __clang__
+ vstr d0, [r2]
#else
- ldmia sp!, {r0-r3,fp, pc}
+ stc p11, cr0, [r2] @ vstr d0, [r2]
#endif
-
-.ffi_call_SYSV_end:
- UNWIND .fnend
-#ifdef __ELF__
- .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
+ pop {fp,pc}
+E(ARM_TYPE_VFP_N)
+#ifdef __clang__
+ vstm r2, {d0-d3}
+#else
+ stc p11, cr0, [r2], {8} @ vstm r2, {d0-d3}
#endif
+ pop {fp,pc}
+E(ARM_TYPE_INT64)
+ str r1, [r2, #4]
+ nop
+E(ARM_TYPE_INT)
+ str r0, [r2]
+ pop {fp,pc}
+E(ARM_TYPE_VOID)
+ pop {fp,pc}
+ nop
+E(ARM_TYPE_STRUCT)
+ pop {fp,pc}
+
+ cfi_endproc
+ UNWIND(.fnend)
+ARM_FUNC_END(ffi_call_SYSV)
/*
- unsigned int FFI_HIDDEN
- ffi_closure_inner (closure, respp, args)
- ffi_closure *closure;
- void **respp;
- void *args;
+ int ffi_closure_inner_* (cif, fun, user_data, frame)
*/
+ARM_FUNC_START(ffi_go_closure_SYSV)
+ cfi_startproc
+ stmdb sp!, {r0-r3} @ save argument regs
+ cfi_adjust_cfa_offset(16)
+ ldr r0, [ip, #4] @ load cif
+ ldr r1, [ip, #8] @ load fun
+ mov r2, ip @ load user_data
+ b 0f
+ cfi_endproc
+ARM_FUNC_END(ffi_go_closure_SYSV)
+
ARM_FUNC_START(ffi_closure_SYSV)
- UNWIND .pad #16
+ UNWIND(.fnstart)
+ cfi_startproc
+ stmdb sp!, {r0-r3} @ save argument regs
+ cfi_adjust_cfa_offset(16)
+
+#if FFI_EXEC_TRAMPOLINE_TABLE
+ ldr ip, [ip] @ ip points to the config page, dereference to get the ffi_closure*
+#endif
+ ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] @ load cif
+ ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] @ load fun
+ ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] @ load user_data
+0:
+ add ip, sp, #16 @ compute entry sp
+ sub sp, sp, #64+32 @ allocate frame
+ cfi_adjust_cfa_offset(64+32)
+ stmdb sp!, {ip,lr}
+
+ /* Remember that EABI unwind info only applies at call sites.
+ We need do nothing except note the save of the stack pointer
+ and the link registers. */
+ UNWIND(.save {sp,lr})
+ cfi_adjust_cfa_offset(8)
+ cfi_rel_offset(lr, 4)
+
+ add r3, sp, #8 @ load frame
+ bl CNAME(ffi_closure_inner_SYSV)
+
+ @ Load values returned in registers.
+ add r2, sp, #8+64 @ load result
+ adr r3, CNAME(ffi_closure_ret)
+ add pc, r3, r0, lsl #3
+ cfi_endproc
+ UNWIND(.fnend)
+ARM_FUNC_END(ffi_closure_SYSV)
+
+ARM_FUNC_START(ffi_go_closure_VFP)
+ cfi_startproc
+ stmdb sp!, {r0-r3} @ save argument regs
+ cfi_adjust_cfa_offset(16)
+ ldr r0, [ip, #4] @ load cif
+ ldr r1, [ip, #8] @ load fun
+ mov r2, ip @ load user_data
+ b 0f
+ cfi_endproc
+ARM_FUNC_END(ffi_go_closure_VFP)
+
+ARM_FUNC_START(ffi_closure_VFP)
+ UNWIND(.fnstart)
+ cfi_startproc
+ stmdb sp!, {r0-r3} @ save argument regs
+ cfi_adjust_cfa_offset(16)
+
+#if FFI_EXEC_TRAMPOLINE_TABLE
+ ldr ip, [ip] @ ip points to the config page, dereference to get the ffi_closure*
+#endif
+ ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] @ load cif
+ ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] @ load fun
+ ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] @ load user_data
+0:
add ip, sp, #16
- stmfd sp!, {ip, lr}
- UNWIND .save {r0, lr}
- add r2, sp, #8
- UNWIND .pad #16
- sub sp, sp, #16
- str sp, [sp, #8]
- add r1, sp, #8
- bl CNAME(ffi_closure_inner)
- cmp r0, #FFI_TYPE_INT
- beq .Lretint
-
- cmp r0, #FFI_TYPE_FLOAT
-#if defined(__SOFTFP__) || defined(__ARM_EABI__)
- beq .Lretint
+ sub sp, sp, #64+32 @ allocate frame
+ cfi_adjust_cfa_offset(64+32)
+#ifdef __clang__
+ vstm sp, {d0-d7}
#else
- beq .Lretfloat
+ stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7}
#endif
-
- cmp r0, #FFI_TYPE_DOUBLE
-#if defined(__SOFTFP__) || defined(__ARM_EABI__)
- beq .Lretlonglong
+ stmdb sp!, {ip,lr}
+
+ /* See above. */
+ UNWIND(.save {sp,lr})
+ cfi_adjust_cfa_offset(8)
+ cfi_rel_offset(lr, 4)
+
+ add r3, sp, #8 @ load frame
+ bl CNAME(ffi_closure_inner_VFP)
+
+ @ Load values returned in registers.
+ add r2, sp, #8+64 @ load result
+ adr r3, CNAME(ffi_closure_ret)
+ add pc, r3, r0, lsl #3
+ cfi_endproc
+ UNWIND(.fnend)
+ARM_FUNC_END(ffi_closure_VFP)
+
+/* Load values returned in registers for both closure entry points.
+ Note that we use LDM with SP in the register set. This is deprecated
+ by ARM, but not yet unpredictable. */
+
+ARM_FUNC_START_LOCAL(ffi_closure_ret)
+ cfi_startproc
+ cfi_rel_offset(sp, 0)
+ cfi_rel_offset(lr, 4)
+0:
+E(ARM_TYPE_VFP_S)
+#ifdef __clang__
+ vldr s0, [r2]
#else
- beq .Lretdouble
+ ldc p10, cr0, [r2] @ vldr s0, [r2]
#endif
-
- cmp r0, #FFI_TYPE_LONGDOUBLE
-#if defined(__SOFTFP__) || defined(__ARM_EABI__)
- beq .Lretlonglong
+ ldm sp, {sp,pc}
+E(ARM_TYPE_VFP_D)
+#ifdef __clang__
+ vldr d0, [r2]
#else
- beq .Lretlongdouble
+ ldc p11, cr0, [r2] @ vldr d0, [r2]
#endif
-
- cmp r0, #FFI_TYPE_SINT64
- beq .Lretlonglong
-.Lclosure_epilogue:
- add sp, sp, #16
- ldmfd sp, {sp, pc}
-.Lretint:
- ldr r0, [sp]
- b .Lclosure_epilogue
-.Lretlonglong:
- ldr r0, [sp]
- ldr r1, [sp, #4]
- b .Lclosure_epilogue
-
-#if !defined(__SOFTFP__) && !defined(__ARM_EABI__)
-.Lretfloat:
- ldfs f0, [sp]
- b .Lclosure_epilogue
-.Lretdouble:
- ldfd f0, [sp]
- b .Lclosure_epilogue
-.Lretlongdouble:
- ldfd f0, [sp]
- b .Lclosure_epilogue
+ ldm sp, {sp,pc}
+E(ARM_TYPE_VFP_N)
+#ifdef __clang__
+ vldm r2, {d0-d3}
+#else
+ ldc p11, cr0, [r2], {8} @ vldm r2, {d0-d3}
#endif
-
-.ffi_closure_SYSV_end:
- UNWIND .fnend
-#ifdef __ELF__
- .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
+ ldm sp, {sp,pc}
+E(ARM_TYPE_INT64)
+ ldr r1, [r2, #4]
+ nop
+E(ARM_TYPE_INT)
+ ldr r0, [r2]
+ ldm sp, {sp,pc}
+E(ARM_TYPE_VOID)
+ ldm sp, {sp,pc}
+ nop
+E(ARM_TYPE_STRUCT)
+ ldm sp, {sp,pc}
+ cfi_endproc
+ARM_FUNC_END(ffi_closure_ret)
+
+#if FFI_EXEC_TRAMPOLINE_TABLE
+
+#ifdef __MACH__
+#include <mach/machine/vm_param.h>
+
+.align PAGE_MAX_SHIFT
+ARM_FUNC_START(ffi_closure_trampoline_table_page)
+.rept PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE
+ adr ip, #-PAGE_MAX_SIZE @ the config page is PAGE_MAX_SIZE behind the trampoline page
+ sub ip, #8 @ account for pc bias
+ ldr pc, [ip, #4] @ jump to ffi_closure_SYSV or ffi_closure_VFP
+.endr
+ARM_FUNC_END(ffi_closure_trampoline_table_page)
#endif
+#else
-/* Below are VFP hard-float ABI call and closure implementations.
- Add VFP FPU directive here. This is only compiled into the library
- under EABI. */
-#ifdef __ARM_EABI__
- .fpu vfp
-
- @ r0: fn
- @ r1: &ecif
- @ r2: cif->bytes
- @ r3: fig->flags
- @ sp+0: ecif.rvalue
-
-ARM_FUNC_START(ffi_call_VFP)
- @ Save registers
- stmfd sp!, {r0-r3, fp, lr}
- UNWIND .save {r0-r3, fp, lr}
- mov fp, sp
- UNWIND .setfp fp, sp
-
- @ Make room for all of the new args.
- sub sp, sp, r2
-
- @ Make room for loading VFP args
- sub sp, sp, #64
-
- @ Place all of the ffi_prep_args in position
- mov r0, sp
- @ r1 already set
- sub r2, fp, #64 @ VFP scratch space
-
- @ Call ffi_prep_args(stack, &ecif, vfp_space)
- bl CNAME(ffi_prep_args_VFP)
-
- @ Load VFP register args if needed
- cmp r0, #0
- mov ip, fp
- beq LSYM(Lbase_args)
-
- @ Load only d0 if possible
- cmp r0, #3
- sub ip, fp, #64
- flddle d0, [ip]
- vldmiagt ip, {d0-d7}
-
-LSYM(Lbase_args):
- @ move first 4 parameters in registers
- ldmia sp, {r0-r3}
-
- @ and adjust stack
- sub lr, ip, sp @ cif->bytes == (fp - 64) - sp
- ldr ip, [fp] @ load fn() in advance
- cmp lr, #16
- movhs lr, #16
- add sp, sp, lr
-
- @ call (fn) (...)
- call_reg(ip)
-
- @ Remove the space we pushed for the args
- mov sp, fp
-
- @ Load r2 with the pointer to storage for
- @ the return value
- ldr r2, [sp, #24]
-
- @ Load r3 with the return type code
- ldr r3, [sp, #12]
-
- @ If the return value pointer is NULL,
- @ assume no return value.
- cmp r2, #0
- beq LSYM(Lepilogue_vfp)
-
- cmp r3, #FFI_TYPE_INT
- streq r0, [r2]
- beq LSYM(Lepilogue_vfp)
-
- cmp r3, #FFI_TYPE_SINT64
- stmiaeq r2, {r0, r1}
- beq LSYM(Lepilogue_vfp)
-
- cmp r3, #FFI_TYPE_FLOAT
- fstseq s0, [r2]
- beq LSYM(Lepilogue_vfp)
-
- cmp r3, #FFI_TYPE_DOUBLE
- fstdeq d0, [r2]
- beq LSYM(Lepilogue_vfp)
-
- cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT
- cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE
- vstmiaeq r2, {d0-d3}
-
-LSYM(Lepilogue_vfp):
- RETLDM "r0-r3,fp"
-
-.ffi_call_VFP_end:
- UNWIND .fnend
- .size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP)
-
-
-ARM_FUNC_START(ffi_closure_VFP)
- vpush {d0-d7}
- @ r0-r3, then d0-d7
- UNWIND .pad #80
- add ip, sp, #80
- stmfd sp!, {ip, lr}
- UNWIND .save {r0, lr}
- add r2, sp, #72
- add r3, sp, #8
- UNWIND .pad #72
- sub sp, sp, #72
- str sp, [sp, #64]
- add r1, sp, #64
- bl CNAME(ffi_closure_inner)
-
- cmp r0, #FFI_TYPE_INT
- beq .Lretint_vfp
-
- cmp r0, #FFI_TYPE_FLOAT
- beq .Lretfloat_vfp
-
- cmp r0, #FFI_TYPE_DOUBLE
- cmpne r0, #FFI_TYPE_LONGDOUBLE
- beq .Lretdouble_vfp
-
- cmp r0, #FFI_TYPE_SINT64
- beq .Lretlonglong_vfp
-
- cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT
- beq .Lretfloat_struct_vfp
-
- cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE
- beq .Lretdouble_struct_vfp
-
-.Lclosure_epilogue_vfp:
- add sp, sp, #72
- ldmfd sp, {sp, pc}
-
-.Lretfloat_vfp:
- flds s0, [sp]
- b .Lclosure_epilogue_vfp
-.Lretdouble_vfp:
- fldd d0, [sp]
- b .Lclosure_epilogue_vfp
-.Lretint_vfp:
- ldr r0, [sp]
- b .Lclosure_epilogue_vfp
-.Lretlonglong_vfp:
- ldmia sp, {r0, r1}
- b .Lclosure_epilogue_vfp
-.Lretfloat_struct_vfp:
- vldmia sp, {d0-d1}
- b .Lclosure_epilogue_vfp
-.Lretdouble_struct_vfp:
- vldmia sp, {d0-d3}
- b .Lclosure_epilogue_vfp
-
-.ffi_closure_VFP_end:
- UNWIND .fnend
- .size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP)
-#endif
+ARM_FUNC_START(ffi_arm_trampoline)
+0: adr ip, 0b
+ ldr pc, 1f
+1: .long 0
+ARM_FUNC_END(ffi_arm_trampoline)
-ENTRY(ffi_arm_trampoline)
- stmfd sp!, {r0-r3}
- ldr r0, [pc]
- ldr pc, [pc]
+#endif /* FFI_EXEC_TRAMPOLINE_TABLE */
+#endif /* __arm__ */
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",%progbits
diff --git a/src/arm/sysv_msvc_arm32.S b/src/arm/sysv_msvc_arm32.S
new file mode 100644
index 00000000..5c99d020
--- /dev/null
+++ b/src/arm/sysv_msvc_arm32.S
@@ -0,0 +1,311 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
+ Copyright (c) 2011 Plausible Labs Cooperative, Inc.
+ Copyright (c) 2019 Microsoft Corporation.
+
+ ARM Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS 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 <fficonfig.h>
+#include <ffi.h>
+#include <ffi_cfi.h>
+#include "internal.h"
+#include "ksarm.h"
+
+
+ ; 8 byte aligned AREA to support 8 byte aligned jump tables
+ MACRO
+ NESTED_ENTRY_FFI $FuncName, $AreaName, $ExceptHandler
+
+ ; compute the function's labels
+ __DeriveFunctionLabels $FuncName
+
+ ; determine the area we will put the function into
+__FuncArea SETS "|.text|"
+ IF "$AreaName" != ""
+__FuncArea SETS "$AreaName"
+ ENDIF
+
+ ; set up the exception handler itself
+__FuncExceptionHandler SETS ""
+ IF "$ExceptHandler" != ""
+__FuncExceptionHandler SETS "|$ExceptHandler|"
+ ENDIF
+
+ ; switch to the specified area, jump tables require 8 byte alignment
+ AREA $__FuncArea,CODE,CODEALIGN,ALIGN=3,READONLY
+
+ ; export the function name
+ __ExportProc $FuncName
+
+ ; flush any pending literal pool stuff
+ ROUT
+
+ ; reset the state of the unwind code tracking
+ __ResetUnwindState
+
+ MEND
+
+; MACRO
+; TABLE_ENTRY $Type, $Table
+;$Type_$Table
+; MEND
+
+#define E(index,table) return_##index##_##table
+
+ ; r0: stack
+ ; r1: frame
+ ; r2: fn
+ ; r3: vfp_used
+
+ ; fake entry point exists only to generate exists only to
+ ; generate .pdata for exception unwinding
+ NESTED_ENTRY_FFI ffi_call_VFP_fake
+ PROLOG_PUSH {r11, lr} ; save fp and lr for unwind
+
+ ALTERNATE_ENTRY ffi_call_VFP
+ cmp r3, #3 ; load only d0 if possible
+ vldrle d0, [r0]
+ vldmgt r0, {d0-d7}
+ add r0, r0, #64 ; discard the vfp register args
+ b ffi_call_SYSV
+ NESTED_END ffi_call_VFP_fake
+
+ ; fake entry point exists only to generate exists only to
+ ; generate .pdata for exception unwinding
+ NESTED_ENTRY_FFI ffi_call_SYSV_fake
+ PROLOG_PUSH {r11, lr} ; save fp and lr for unwind
+
+ ALTERNATE_ENTRY ffi_call_SYSV
+ stm r1, {fp, lr}
+ mov fp, r1
+
+ mov sp, r0 ; install the stack pointer
+ mov lr, r2 ; move the fn pointer out of the way
+ ldr ip, [fp, #16] ; install the static chain
+ ldmia sp!, {r0-r3} ; move first 4 parameters in registers.
+ blx lr ; call fn
+
+ ; Load r2 with the pointer to storage for the return value
+ ; Load r3 with the return type code
+ ldr r2, [fp, #8]
+ ldr r3, [fp, #12]
+
+ ; Deallocate the stack with the arguments.
+ mov sp, fp
+
+ ; Store values stored in registers.
+ ALIGN 8
+ lsl r3, #3
+ add r3, r3, pc
+ add r3, #8
+ mov pc, r3
+
+
+E(ARM_TYPE_VFP_S, ffi_call)
+ ALIGN 8
+ vstr s0, [r2]
+ pop {fp,pc}
+E(ARM_TYPE_VFP_D, ffi_call)
+ ALIGN 8
+ vstr d0, [r2]
+ pop {fp,pc}
+E(ARM_TYPE_VFP_N, ffi_call)
+ ALIGN 8
+ vstm r2, {d0-d3}
+ pop {fp,pc}
+E(ARM_TYPE_INT64, ffi_call)
+ ALIGN 8
+ str r1, [r2, #4]
+ nop
+E(ARM_TYPE_INT, ffi_call)
+ ALIGN 8
+ str r0, [r2]
+ pop {fp,pc}
+E(ARM_TYPE_VOID, ffi_call)
+ ALIGN 8
+ pop {fp,pc}
+ nop
+E(ARM_TYPE_STRUCT, ffi_call)
+ ALIGN 8
+ cmp r3, #ARM_TYPE_STRUCT
+ pop {fp,pc}
+ NESTED_END ffi_call_SYSV_fake
+
+ IMPORT |ffi_closure_inner_SYSV|
+ /*
+ int ffi_closure_inner_SYSV
+ (
+ cif, ; r0
+ fun, ; r1
+ user_data, ; r2
+ frame ; r3
+ )
+ */
+
+ NESTED_ENTRY_FFI ffi_go_closure_SYSV
+ stmdb sp!, {r0-r3} ; save argument regs
+ ldr r0, [ip, #4] ; load cif
+ ldr r1, [ip, #8] ; load fun
+ mov r2, ip ; load user_data
+ b ffi_go_closure_SYSV_0
+ NESTED_END ffi_go_closure_SYSV
+
+ ; r3: ffi_closure
+
+ ; fake entry point exists only to generate exists only to
+ ; generate .pdata for exception unwinding
+ NESTED_ENTRY_FFI ffi_closure_SYSV_fake
+ PROLOG_PUSH {r11, lr} ; save fp and lr for unwind
+ ALTERNATE_ENTRY ffi_closure_SYSV
+ ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment)
+ stmdb sp!, {r0-r3} ; save argument regs
+
+ ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] ; ffi_closure->cif
+ ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] ; ffi_closure->fun
+ ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] ; ffi_closure->user_data
+
+ ALTERNATE_ENTRY ffi_go_closure_SYSV_0
+ add ip, sp, #16 ; compute entry sp
+
+ sub sp, sp, #64+32 ; allocate frame parameter (sizeof(vfp_space) = 64, sizeof(result) = 32)
+ mov r3, sp ; set frame parameter
+ stmdb sp!, {ip,lr}
+
+ bl ffi_closure_inner_SYSV ; call the Python closure
+
+ ; Load values returned in registers.
+ add r2, sp, #64+8 ; address of closure_frame->result
+ bl ffi_closure_ret ; move result to correct register or memory for type
+
+ ldmfd sp!, {ip,lr}
+ mov sp, ip ; restore stack pointer
+ mov pc, lr
+ NESTED_END ffi_closure_SYSV_fake
+
+ IMPORT |ffi_closure_inner_VFP|
+ /*
+ int ffi_closure_inner_VFP
+ (
+ cif, ; r0
+ fun, ; r1
+ user_data, ; r2
+ frame ; r3
+ )
+ */
+
+ NESTED_ENTRY_FFI ffi_go_closure_VFP
+ stmdb sp!, {r0-r3} ; save argument regs
+ ldr r0, [ip, #4] ; load cif
+ ldr r1, [ip, #8] ; load fun
+ mov r2, ip ; load user_data
+ b ffi_go_closure_VFP_0
+ NESTED_END ffi_go_closure_VFP
+
+ ; fake entry point exists only to generate exists only to
+ ; generate .pdata for exception unwinding
+ ; r3: closure
+ NESTED_ENTRY_FFI ffi_closure_VFP_fake
+ PROLOG_PUSH {r11, lr} ; save fp and lr for unwind
+
+ ALTERNATE_ENTRY ffi_closure_VFP
+ ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment)
+ stmdb sp!, {r0-r3} ; save argument regs
+
+ ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] ; load cif
+ ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] ; load fun
+ ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] ; load user_data
+
+ ALTERNATE_ENTRY ffi_go_closure_VFP_0
+ add ip, sp, #16 ; compute entry sp
+ sub sp, sp, #32 ; save space for closure_frame->result
+ vstmdb sp!, {d0-d7} ; push closure_frame->vfp_space
+
+ mov r3, sp ; save closure_frame
+ stmdb sp!, {ip,lr}
+
+ bl ffi_closure_inner_VFP
+
+ ; Load values returned in registers.
+ add r2, sp, #64+8 ; load result
+ bl ffi_closure_ret
+ ldmfd sp!, {ip,lr}
+ mov sp, ip ; restore stack pointer
+ mov pc, lr
+ NESTED_END ffi_closure_VFP_fake
+
+/* Load values returned in registers for both closure entry points.
+ Note that we use LDM with SP in the register set. This is deprecated
+ by ARM, but not yet unpredictable. */
+
+ NESTED_ENTRY_FFI ffi_closure_ret
+ stmdb sp!, {fp,lr}
+
+ ALIGN 8
+ lsl r0, #3
+ add r0, r0, pc
+ add r0, #8
+ mov pc, r0
+
+E(ARM_TYPE_VFP_S, ffi_closure)
+ ALIGN 8
+ vldr s0, [r2]
+ b call_epilogue
+E(ARM_TYPE_VFP_D, ffi_closure)
+ ALIGN 8
+ vldr d0, [r2]
+ b call_epilogue
+E(ARM_TYPE_VFP_N, ffi_closure)
+ ALIGN 8
+ vldm r2, {d0-d3}
+ b call_epilogue
+E(ARM_TYPE_INT64, ffi_closure)
+ ALIGN 8
+ ldr r1, [r2, #4]
+ nop
+E(ARM_TYPE_INT, ffi_closure)
+ ALIGN 8
+ ldr r0, [r2]
+ b call_epilogue
+E(ARM_TYPE_VOID, ffi_closure)
+ ALIGN 8
+ b call_epilogue
+ nop
+E(ARM_TYPE_STRUCT, ffi_closure)
+ ALIGN 8
+ b call_epilogue
+call_epilogue
+ ldmfd sp!, {fp,pc}
+ NESTED_END ffi_closure_ret
+
+ AREA |.trampoline|, DATA, THUMB, READONLY
+ EXPORT |ffi_arm_trampoline|
+|ffi_arm_trampoline| DATA
+thisproc adr ip, thisproc
+ stmdb sp!, {ip, r0}
+ ldr pc, [pc, #0]
+ DCD 0
+ ;ENDP
+
+ END \ No newline at end of file
diff --git a/src/closures.c b/src/closures.c
index 721ff00e..51200216 100644
--- a/src/closures.c
+++ b/src/closures.c
@@ -1,5 +1,6 @@
/* -----------------------------------------------------------------------
- closures.c - Copyright (c) 2007, 2009, 2010 Red Hat, Inc.
+ closures.c - Copyright (c) 2019 Anthony Green
+ Copyright (c) 2007, 2009, 2010 Red Hat, Inc.
Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc
Copyright (c) 2011 Plausible Labs Cooperative, Inc.
@@ -30,11 +31,88 @@
#define _GNU_SOURCE 1
#endif
+#include <fficonfig.h>
#include <ffi.h>
#include <ffi_common.h>
+#ifdef __NetBSD__
+#include <sys/param.h>
+#endif
+
+#if __NetBSD_Version__ - 0 >= 799007200
+/* NetBSD with PROT_MPROTECT */
+#include <sys/mman.h>
+
+#include <stddef.h>
+#include <unistd.h>
+
+static const size_t overhead =
+ (sizeof(max_align_t) > sizeof(void *) + sizeof(size_t)) ?
+ sizeof(max_align_t)
+ : sizeof(void *) + sizeof(size_t);
+
+#define ADD_TO_POINTER(p, d) ((void *)((uintptr_t)(p) + (d)))
+
+void *
+ffi_closure_alloc (size_t size, void **code)
+{
+ static size_t page_size;
+ size_t rounded_size;
+ void *codeseg, *dataseg;
+ int prot;
+
+ /* Expect that PAX mprotect is active and a separate code mapping is necessary. */
+ if (!code)
+ return NULL;
+
+ /* Obtain system page size. */
+ if (!page_size)
+ page_size = sysconf(_SC_PAGESIZE);
+
+ /* Round allocation size up to the next page, keeping in mind the size field and pointer to code map. */
+ rounded_size = (size + overhead + page_size - 1) & ~(page_size - 1);
+
+ /* Primary mapping is RW, but request permission to switch to PROT_EXEC later. */
+ prot = PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC);
+ dataseg = mmap(NULL, rounded_size, prot, MAP_ANON | MAP_PRIVATE, -1, 0);
+ if (dataseg == MAP_FAILED)
+ return NULL;
+
+ /* Create secondary mapping and switch it to RX. */
+ codeseg = mremap(dataseg, rounded_size, NULL, rounded_size, MAP_REMAPDUP);
+ if (codeseg == MAP_FAILED) {
+ munmap(dataseg, rounded_size);
+ return NULL;
+ }
+ if (mprotect(codeseg, rounded_size, PROT_READ | PROT_EXEC) == -1) {
+ munmap(codeseg, rounded_size);
+ munmap(dataseg, rounded_size);
+ return NULL;
+ }
+
+ /* Remember allocation size and location of the secondary mapping for ffi_closure_free. */
+ memcpy(dataseg, &rounded_size, sizeof(rounded_size));
+ memcpy(ADD_TO_POINTER(dataseg, sizeof(size_t)), &codeseg, sizeof(void *));
+ *code = ADD_TO_POINTER(codeseg, overhead);
+ return ADD_TO_POINTER(dataseg, overhead);
+}
+
+void
+ffi_closure_free (void *ptr)
+{
+ void *codeseg, *dataseg;
+ size_t rounded_size;
+
+ dataseg = ADD_TO_POINTER(ptr, -overhead);
+ memcpy(&rounded_size, dataseg, sizeof(rounded_size));
+ memcpy(&codeseg, ADD_TO_POINTER(dataseg, sizeof(size_t)), sizeof(void *));
+ munmap(dataseg, rounded_size);
+ munmap(codeseg, rounded_size);
+}
+#else /* !NetBSD with PROT_MPROTECT */
+
#if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE
-# if __gnu_linux__ && !defined(__ANDROID__)
+# if __linux__ && !defined(__ANDROID__)
/* This macro indicates it may be forbidden to map anonymous memory
with both write and execute permission. Code compiled when this
option is defined will attempt to map such pages once, but if it
@@ -45,7 +123,7 @@
# define FFI_MMAP_EXEC_WRIT 1
# define HAVE_MNTENT 1
# endif
-# if defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)
+# if defined(X86_WIN32) || defined(X86_WIN64) || defined(_M_ARM64) || defined(__OS2__)
/* Windows systems may have Data Execution Protection (DEP) enabled,
which requires the use of VirtualMalloc/VirtualFree to alloc/free
executable memory. */
@@ -54,7 +132,7 @@
#endif
#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
-# ifdef __linux__
+# if defined(__linux__) && !defined(__ANDROID__)
/* When defined to 1 check for SELinux and if SELinux is active,
don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
might cause audit messages. */
@@ -64,11 +142,216 @@
#if FFI_CLOSURES
-# if FFI_EXEC_TRAMPOLINE_TABLE
+#if FFI_EXEC_TRAMPOLINE_TABLE
+
+#ifdef __MACH__
+
+#include <mach/mach.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void *ffi_closure_trampoline_table_page;
+
+typedef struct ffi_trampoline_table ffi_trampoline_table;
+typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
+
+struct ffi_trampoline_table
+{
+ /* contiguous writable and executable pages */
+ vm_address_t config_page;
+ vm_address_t trampoline_page;
+
+ /* free list tracking */
+ uint16_t free_count;
+ ffi_trampoline_table_entry *free_list;
+ ffi_trampoline_table_entry *free_list_pool;
+
+ ffi_trampoline_table *prev;
+ ffi_trampoline_table *next;
+};
+
+struct ffi_trampoline_table_entry
+{
+ void *(*trampoline) (void);
+ ffi_trampoline_table_entry *next;
+};
+
+/* Total number of trampolines that fit in one trampoline table */
+#define FFI_TRAMPOLINE_COUNT (PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE)
+
+static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
+static ffi_trampoline_table *ffi_trampoline_tables = NULL;
+
+static ffi_trampoline_table *
+ffi_trampoline_table_alloc (void)
+{
+ ffi_trampoline_table *table;
+ vm_address_t config_page;
+ vm_address_t trampoline_page;
+ vm_address_t trampoline_page_template;
+ vm_prot_t cur_prot;
+ vm_prot_t max_prot;
+ kern_return_t kt;
+ uint16_t i;
+
+ /* Allocate two pages -- a config page and a placeholder page */
+ config_page = 0x0;
+ kt = vm_allocate (mach_task_self (), &config_page, PAGE_MAX_SIZE * 2,
+ VM_FLAGS_ANYWHERE);
+ if (kt != KERN_SUCCESS)
+ return NULL;
+
+ /* Remap the trampoline table on top of the placeholder page */
+ trampoline_page = config_page + PAGE_MAX_SIZE;
+ trampoline_page_template = (vm_address_t)&ffi_closure_trampoline_table_page;
+#ifdef __arm__
+ /* ffi_closure_trampoline_table_page can be thumb-biased on some ARM archs */
+ trampoline_page_template &= ~1UL;
+#endif
+ kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_MAX_SIZE, 0x0,
+ VM_FLAGS_OVERWRITE, mach_task_self (), trampoline_page_template,
+ FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
+ if (kt != KERN_SUCCESS)
+ {
+ vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2);
+ return NULL;
+ }
+
+ /* We have valid trampoline and config pages */
+ table = calloc (1, sizeof (ffi_trampoline_table));
+ table->free_count = FFI_TRAMPOLINE_COUNT;
+ table->config_page = config_page;
+ table->trampoline_page = trampoline_page;
+
+ /* Create and initialize the free list */
+ table->free_list_pool =
+ calloc (FFI_TRAMPOLINE_COUNT, sizeof (ffi_trampoline_table_entry));
+
+ for (i = 0; i < table->free_count; i++)
+ {
+ ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
+ entry->trampoline =
+ (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
+
+ if (i < table->free_count - 1)
+ entry->next = &table->free_list_pool[i + 1];
+ }
+
+ table->free_list = table->free_list_pool;
+
+ return table;
+}
+
+static void
+ffi_trampoline_table_free (ffi_trampoline_table *table)
+{
+ /* Remove from the list */
+ if (table->prev != NULL)
+ table->prev->next = table->next;
+
+ if (table->next != NULL)
+ table->next->prev = table->prev;
+
+ /* Deallocate pages */
+ vm_deallocate (mach_task_self (), table->config_page, PAGE_MAX_SIZE * 2);
+
+ /* Deallocate free list */
+ free (table->free_list_pool);
+ free (table);
+}
+
+void *
+ffi_closure_alloc (size_t size, void **code)
+{
+ /* Create the closure */
+ ffi_closure *closure = malloc (size);
+ if (closure == NULL)
+ return NULL;
+
+ pthread_mutex_lock (&ffi_trampoline_lock);
+
+ /* Check for an active trampoline table with available entries. */
+ ffi_trampoline_table *table = ffi_trampoline_tables;
+ if (table == NULL || table->free_list == NULL)
+ {
+ table = ffi_trampoline_table_alloc ();
+ if (table == NULL)
+ {
+ pthread_mutex_unlock (&ffi_trampoline_lock);
+ free (closure);
+ return NULL;
+ }
+
+ /* Insert the new table at the top of the list */
+ table->next = ffi_trampoline_tables;
+ if (table->next != NULL)
+ table->next->prev = table;
+
+ ffi_trampoline_tables = table;
+ }
+
+ /* Claim the free entry */
+ ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
+ ffi_trampoline_tables->free_list = entry->next;
+ ffi_trampoline_tables->free_count--;
+ entry->next = NULL;
+
+ pthread_mutex_unlock (&ffi_trampoline_lock);
+
+ /* Initialize the return values */
+ *code = entry->trampoline;
+ closure->trampoline_table = table;
+ closure->trampoline_table_entry = entry;
+
+ return closure;
+}
+
+void
+ffi_closure_free (void *ptr)
+{
+ ffi_closure *closure = ptr;
+
+ pthread_mutex_lock (&ffi_trampoline_lock);
+
+ /* Fetch the table and entry references */
+ ffi_trampoline_table *table = closure->trampoline_table;
+ ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
+
+ /* Return the entry to the free list */
+ entry->next = table->free_list;
+ table->free_list = entry;
+ table->free_count++;
+
+ /* If all trampolines within this table are free, and at least one other table exists, deallocate
+ * the table */
+ if (table->free_count == FFI_TRAMPOLINE_COUNT
+ && ffi_trampoline_tables != table)
+ {
+ ffi_trampoline_table_free (table);
+ }
+ else if (ffi_trampoline_tables != table)
+ {
+ /* Otherwise, bump this table to the top of the list */
+ table->prev = NULL;
+ table->next = ffi_trampoline_tables;
+ if (ffi_trampoline_tables != NULL)
+ ffi_trampoline_tables->prev = table;
+
+ ffi_trampoline_tables = table;
+ }
+
+ pthread_mutex_unlock (&ffi_trampoline_lock);
+
+ /* Free the closure */
+ free (closure);
+}
+
+#endif
// Per-target implementation; It's unclear what can reasonable be shared between two OS/architecture implementations.
-# elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */
+#elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */
#define USE_LOCKS 1
#define USE_DL_PREFIX 1
@@ -94,14 +377,6 @@
/* Don't allocate more than a page unless needed. */
#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
-#if FFI_CLOSURE_TEST
-/* Don't release single pages, to avoid a worst-case scenario of
- continuously allocating and releasing single pages, but release
- pairs of pages, which should do just as well given that allocations
- are likely to be small. */
-#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
-#endif
-
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -111,7 +386,7 @@
#endif
#include <string.h>
#include <stdio.h>
-#if !defined(X86_WIN32) && !defined(X86_WIN64)
+#if !defined(X86_WIN32) && !defined(X86_WIN64) && !defined(_M_ARM64)
#ifdef HAVE_MNTENT
#include <mntent.h>
#endif /* HAVE_MNTENT */
@@ -237,7 +512,7 @@ static int dlmalloc_trim(size_t) MAYBE_UNUSED;
static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED;
static void dlmalloc_stats(void) MAYBE_UNUSED;
-#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
+#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(_M_ARM64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
/* Use these for mmap and munmap within dlmalloc.c. */
static void *dlmmap(void *, size_t, int, int, int, off_t);
static int dlmunmap(void *, size_t);
@@ -251,7 +526,7 @@ static int dlmunmap(void *, size_t);
#undef mmap
#undef munmap
-#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
+#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(_M_ARM64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
/* A mutex used to synchronize access to *exec* variables in this file. */
static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -308,7 +583,7 @@ open_temp_exec_file_dir (const char *dir)
}
#endif
- lendir = strlen (dir);
+ lendir = (int) strlen (dir);
tempname = __builtin_alloca (lendir + sizeof (suffix));
if (!tempname)
@@ -449,6 +724,36 @@ open_temp_exec_file (void)
return fd;
}
+/* We need to allocate space in a file that will be backing a writable
+ mapping. Several problems exist with the usual approaches:
+ - fallocate() is Linux-only
+ - posix_fallocate() is not available on all platforms
+ - ftruncate() does not allocate space on filesystems with sparse files
+ Failure to allocate the space will cause SIGBUS to be thrown when
+ the mapping is subsequently written to. */
+static int
+allocate_space (int fd, off_t offset, off_t len)
+{
+ static size_t page_size;
+
+ /* Obtain system page size. */
+ if (!page_size)
+ page_size = sysconf(_SC_PAGESIZE);
+
+ unsigned char buf[page_size];
+ memset (buf, 0, page_size);
+
+ while (len > 0)
+ {
+ off_t to_write = (len < page_size) ? len : page_size;
+ if (write (fd, buf, to_write) < to_write)
+ return -1;
+ len -= to_write;
+ }
+
+ return 0;
+}
+
/* Map in a chunk of memory from the temporary exec file into separate
locations in the virtual memory address space, one writable and one
executable. Returns the address of the writable portion, after
@@ -470,7 +775,7 @@ dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
offset = execsize;
- if (ftruncate (execfd, offset + length))
+ if (allocate_space (execfd, offset, length))
return MFAIL;
flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
@@ -485,7 +790,13 @@ dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
close (execfd);
goto retry_open;
}
- ftruncate (execfd, offset);
+ if (ftruncate (execfd, offset) != 0)
+ {
+ /* Fixme : Error logs can be added here. Returning an error for
+ * ftruncte() will not add any advantage as it is being
+ * validating in the error case. */
+ }
+
return MFAIL;
}
else if (!offset
@@ -497,7 +808,12 @@ dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
if (start == MFAIL)
{
munmap (ptr, length);
- ftruncate (execfd, offset);
+ if (ftruncate (execfd, offset) != 0)
+ {
+ /* Fixme : Error logs can be added here. Returning an error for
+ * ftruncte() will not add any advantage as it is being
+ * validating in the error case. */
+ }
return start;
}
@@ -521,10 +837,6 @@ dlmmap (void *start, size_t length, int prot,
&& flags == (MAP_PRIVATE | MAP_ANONYMOUS)
&& fd == -1 && offset == 0);
-#if FFI_CLOSURE_TEST
- printf ("mapping in %zi\n", length);
-#endif
-
if (execfd == -1 && is_emutramp_enabled ())
{
ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
@@ -570,10 +882,6 @@ dlmunmap (void *start, size_t length)
msegmentptr seg = segment_holding (gm, start);
void *code;
-#if FFI_CLOSURE_TEST
- printf ("unmapping %zi\n", length);
-#endif
-
if (seg && (code = add_segment_exec_offset (start, seg)) != start)
{
int ret = munmap (code, length);
@@ -600,7 +908,7 @@ segment_holding_code (mstate m, char* addr)
}
#endif
-#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
+#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(_M_ARM64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
/* Allocate a chunk of memory with the given size. Returns a pointer
to the writable address, and sets *CODE to the executable
@@ -625,6 +933,20 @@ ffi_closure_alloc (size_t size, void **code)
return ptr;
}
+void *
+ffi_data_to_code_pointer (void *data)
+{
+ msegmentptr seg = segment_holding (gm, data);
+ /* We expect closures to be allocated with ffi_closure_alloc(), in
+ which case seg will be non-NULL. However, some users take on the
+ burden of managing this memory themselves, in which case this
+ we'll just return data. */
+ if (seg)
+ return add_segment_exec_offset (data, seg);
+ else
+ return data;
+}
+
/* Release a chunk of memory allocated with ffi_closure_alloc. If
FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
writable or the executable address given. Otherwise, only the
@@ -642,26 +964,6 @@ ffi_closure_free (void *ptr)
dlfree (ptr);
}
-
-#if FFI_CLOSURE_TEST
-/* Do some internal sanity testing to make sure allocation and
- deallocation of pages are working as intended. */
-int main ()
-{
- void *p[3];
-#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
-#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
- GET (0, malloc_getpagesize / 2);
- GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
- PUT (1);
- GET (1, 2 * malloc_getpagesize);
- GET (2, malloc_getpagesize / 2);
- PUT (1);
- PUT (0);
- PUT (2);
- return 0;
-}
-#endif /* FFI_CLOSURE_TEST */
# else /* ! FFI_MMAP_EXEC_WRIT */
/* On many systems, memory returned by malloc is writable and
@@ -684,5 +986,13 @@ ffi_closure_free (void *ptr)
free (ptr);
}
+void *
+ffi_data_to_code_pointer (void *data)
+{
+ return data;
+}
+
# endif /* ! FFI_MMAP_EXEC_WRIT */
#endif /* FFI_CLOSURES */
+
+#endif /* NetBSD with PROT_MPROTECT */
diff --git a/src/cris/ffi.c b/src/cris/ffi.c
index aaca5b1c..9011fdec 100644
--- a/src/cris/ffi.c
+++ b/src/cris/ffi.c
@@ -29,7 +29,7 @@
#include <ffi.h>
#include <ffi_common.h>
-#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
+#define STACK_ARG_SIZE(x) FFI_ALIGN(x, FFI_SIZEOF_ARG)
static ffi_status
initialize_aggregate_packed_struct (ffi_type * arg)
@@ -190,7 +190,7 @@ ffi_prep_cif_core (ffi_cif * cif,
FFI_ASSERT_VALID_TYPE (*ptr);
if (((*ptr)->alignment - 1) & bytes)
- bytes = ALIGN (bytes, (*ptr)->alignment);
+ bytes = FFI_ALIGN (bytes, (*ptr)->alignment);
if ((*ptr)->type == FFI_TYPE_STRUCT)
{
if ((*ptr)->size > 8)
diff --git a/src/dlmalloc.c b/src/dlmalloc.c
index 8725b4fd..d63dd36d 100644
--- a/src/dlmalloc.c
+++ b/src/dlmalloc.c
@@ -438,6 +438,11 @@ DEFAULT_MMAP_THRESHOLD default: 256K
*/
+#if defined __linux__ && !defined _GNU_SOURCE
+/* mremap() on Linux requires this via sys/mman.h */
+#define _GNU_SOURCE 1
+#endif
+
#ifndef WIN32
#ifdef _WIN32
#define WIN32 1
@@ -2291,7 +2296,7 @@ static size_t traverse_and_check(mstate m);
#define treebin_at(M,i) (&((M)->treebins[i]))
/* assign tree index for size S to variable I */
-#if defined(__GNUC__) && defined(i386)
+#if defined(__GNUC__) && defined(__i386__)
#define compute_tree_index(S, I)\
{\
size_t X = S >> TREEBIN_SHIFT;\
@@ -2356,7 +2361,7 @@ static size_t traverse_and_check(mstate m);
/* index corresponding to given bit */
-#if defined(__GNUC__) && defined(i386)
+#if defined(__GNUC__) && defined(__i386__)
#define compute_bit2idx(X, I)\
{\
unsigned int J;\
diff --git a/src/frv/ffi.c b/src/frv/ffi.c
index 5698c89c..ed1c65a1 100644
--- a/src/frv/ffi.c
+++ b/src/frv/ffi.c
@@ -107,7 +107,7 @@ void *ffi_prep_args(char *stack, extended_cif *ecif)
count += z;
}
- return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
+ return (stack + ((count > 24) ? 24 : FFI_ALIGN_DOWN(count, 8)));
}
/* Perform machine dependent cif processing */
@@ -118,7 +118,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
else
cif->flags = cif->rtype->size;
- cif->bytes = ALIGN (cif->bytes, 8);
+ cif->bytes = FFI_ALIGN (cif->bytes, 8);
return FFI_OK;
}
diff --git a/src/ia64/ffi.c b/src/ia64/ffi.c
index b77a836d..b1d04c3e 100644
--- a/src/ia64/ffi.c
+++ b/src/ia64/ffi.c
@@ -220,8 +220,8 @@ hfa_element_type (ffi_type *type, int nested)
/* Perform machine dependent cif processing. */
-ffi_status
-ffi_prep_cif_machdep(ffi_cif *cif)
+static ffi_status
+ffi_prep_cif_machdep_core(ffi_cif *cif)
{
int flags;
@@ -271,6 +271,22 @@ ffi_prep_cif_machdep(ffi_cif *cif)
return FFI_OK;
}
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ cif->nfixedargs = cif->nargs;
+ return ffi_prep_cif_machdep_core(cif);
+}
+
+ffi_status
+ffi_prep_cif_machdep_var(ffi_cif *cif,
+ unsigned int nfixedargs,
+ unsigned int ntotalargs MAYBE_UNUSED)
+{
+ cif->nfixedargs = nfixedargs;
+ return ffi_prep_cif_machdep_core(cif);
+}
+
extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
void
@@ -454,10 +470,11 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
ffi_cif *cif;
void **avalue;
ffi_type **p_arg;
- long i, avn, gpcount, fpcount;
+ long i, avn, gpcount, fpcount, nfixedargs;
cif = closure->cif;
avn = cif->nargs;
+ nfixedargs = cif->nfixedargs;
avalue = alloca (avn * sizeof (void *));
/* If the structure return value is passed in memory get that location
@@ -468,6 +485,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
gpcount = fpcount = 0;
for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
{
+ int named = i < nfixedargs;
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
@@ -491,7 +509,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
break;
case FFI_TYPE_FLOAT:
- if (gpcount < 8 && fpcount < 8)
+ if (named && gpcount < 8 && fpcount < 8)
{
fpreg *addr = &stack->fp_regs[fpcount++];
float result;
@@ -505,7 +523,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
break;
case FFI_TYPE_DOUBLE:
- if (gpcount < 8 && fpcount < 8)
+ if (named && gpcount < 8 && fpcount < 8)
{
fpreg *addr = &stack->fp_regs[fpcount++];
double result;
@@ -521,7 +539,7 @@ ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
case FFI_TYPE_LONGDOUBLE:
if (gpcount & 1)
gpcount++;
- if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
+ if (LDBL_MANT_DIG == 64 && named && gpcount < 8 && fpcount < 8)
{
fpreg *addr = &stack->fp_regs[fpcount++];
__float80 result;
diff --git a/src/ia64/ffitarget.h b/src/ia64/ffitarget.h
index e68cea61..fd5b9a0e 100644
--- a/src/ia64/ffitarget.h
+++ b/src/ia64/ffitarget.h
@@ -50,6 +50,7 @@ typedef enum ffi_abi {
#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */
/* can be interpreted as a C function */
/* descriptor: */
+#define FFI_TARGET_SPECIFIC_VARIADIC 1
+#define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs
#endif
-
diff --git a/src/ia64/unix.S b/src/ia64/unix.S
index 4d2a86d4..e2547e02 100644
--- a/src/ia64/unix.S
+++ b/src/ia64/unix.S
@@ -175,7 +175,6 @@ ffi_call_unix:
;;
.Lst_small_struct:
- add sp = -16, sp
cmp.lt p6, p0 = 8, in3
cmp.lt p7, p0 = 16, in3
cmp.lt p8, p0 = 24, in3
@@ -191,6 +190,12 @@ ffi_call_unix:
(p8) st8 [r18] = r11
mov out1 = sp
mov out2 = in3
+ ;;
+ // ia64 software calling convention requires
+ // top 16 bytes of stack to be scratch space
+ // PLT resolver uses that scratch space at
+ // 'memcpy' symbol reolution time
+ add sp = -16, sp
br.call.sptk.many b0 = memcpy#
;;
mov ar.pfs = loc0
@@ -529,6 +534,7 @@ ffi_closure_unix:
data8 @pcrel(.Lst_int64) // FFI_TYPE_SINT64
data8 @pcrel(.Lst_void) // FFI_TYPE_STRUCT
data8 @pcrel(.Lst_int64) // FFI_TYPE_POINTER
+ data8 @pcrel(.Lst_void) // FFI_TYPE_COMPLEX (not implemented)
data8 @pcrel(.Lst_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT
data8 @pcrel(.Lst_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT
data8 @pcrel(.Lst_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE
@@ -550,6 +556,7 @@ ffi_closure_unix:
data8 @pcrel(.Lld_int) // FFI_TYPE_SINT64
data8 @pcrel(.Lld_void) // FFI_TYPE_STRUCT
data8 @pcrel(.Lld_int) // FFI_TYPE_POINTER
+ data8 @pcrel(.Lld_void) // FFI_TYPE_COMPLEX (not implemented)
data8 @pcrel(.Lld_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT
data8 @pcrel(.Lld_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT
data8 @pcrel(.Lld_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE
diff --git a/src/java_raw_api.c b/src/java_raw_api.c
index 127123d5..114d3e47 100644
--- a/src/java_raw_api.c
+++ b/src/java_raw_api.c
@@ -114,7 +114,7 @@ ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args)
default:
*args = raw;
raw +=
- ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
+ FFI_ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
}
}
@@ -142,7 +142,7 @@ ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args)
#else /* FFI_SIZEOF_JAVA_RAW != 8 */
*args = (void*) raw;
raw +=
- ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
+ FFI_ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
#endif /* FFI_SIZEOF_JAVA_RAW == 8 */
}
@@ -234,7 +234,7 @@ ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw)
#else
memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
raw +=
- ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
+ FFI_ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw);
#endif
}
}
diff --git a/src/m32r/ffi.c b/src/m32r/ffi.c
index 30000634..ab8fc4e4 100644
--- a/src/m32r/ffi.c
+++ b/src/m32r/ffi.c
@@ -61,7 +61,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
/* Align if necessary. */
if (((*p_arg)->alignment - 1) & (unsigned) argp)
- argp = (char *) ALIGN (argp, (*p_arg)->alignment);
+ argp = (char *) FFI_ALIGN (argp, (*p_arg)->alignment);
if (avn != 0)
{
diff --git a/src/m68k/ffi.c b/src/m68k/ffi.c
index 0dee9383..03301848 100644
--- a/src/m68k/ffi.c
+++ b/src/m68k/ffi.c
@@ -105,7 +105,7 @@ ffi_prep_args (void *stack, extended_cif *ecif)
/* Align if necessary. */
if ((sizeof(int) - 1) & z)
- z = ALIGN(z, sizeof(int));
+ z = FFI_ALIGN(z, sizeof(int));
}
p_argv++;
@@ -297,7 +297,7 @@ ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
/* Align if necessary */
if ((sizeof(int) - 1) & z)
- z = ALIGN(z, sizeof(int));
+ z = FFI_ALIGN(z, sizeof(int));
}
p_argv++;
diff --git a/src/m68k/sysv.S b/src/m68k/sysv.S
index ec2b14f3..ea40f110 100644
--- a/src/m68k/sysv.S
+++ b/src/m68k/sysv.S
@@ -3,7 +3,7 @@
sysv.S - Copyright (c) 2012 Alan Hourihane
Copyright (c) 1998, 2012 Andreas Schwab
Copyright (c) 2008 Red Hat, Inc.
- Copyright (c) 2012 Thorsten Glaser
+ Copyright (c) 2012, 2016 Thorsten Glaser
m68k Foreign Function Interface
@@ -72,6 +72,15 @@ CALLFUNC(ffi_call_SYSV):
pea 4(%sp)
#if !defined __PIC__
jsr CALLFUNC(ffi_prep_args)
+#elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__)
+ move.l _current_shared_library_a5_offset_(%a5),%a0
+ move.l CALLFUNC(ffi_prep_args@GOT)(%a0),%a0
+ jsr (%a0)
+#elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__)
+ move.l #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0
+ lea (-6,%pc,%a0),%a0
+ move.l CALLFUNC(ffi_prep_args@GOT)(%a0),%a0
+ jsr (%a0)
#else
bsr.l CALLFUNC(ffi_prep_args@PLTPC)
#endif
@@ -215,6 +224,15 @@ CALLFUNC(ffi_closure_SYSV):
move.l %a0,-(%sp)
#if !defined __PIC__
jsr CALLFUNC(ffi_closure_SYSV_inner)
+#elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__)
+ move.l _current_shared_library_a5_offset_(%a5),%a0
+ move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
+ jsr (%a0)
+#elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__)
+ move.l #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0
+ lea (-6,%pc,%a0),%a0
+ move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
+ jsr (%a0)
#else
bsr.l CALLFUNC(ffi_closure_SYSV_inner@PLTPC)
#endif
@@ -317,6 +335,15 @@ CALLFUNC(ffi_closure_struct_SYSV):
move.l %a0,-(%sp)
#if !defined __PIC__
jsr CALLFUNC(ffi_closure_SYSV_inner)
+#elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__)
+ move.l _current_shared_library_a5_offset_(%a5),%a0
+ move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
+ jsr (%a0)
+#elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__)
+ move.l #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0
+ lea (-6,%pc,%a0),%a0
+ move.l CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
+ jsr (%a0)
#else
bsr.l CALLFUNC(ffi_closure_SYSV_inner@PLTPC)
#endif
diff --git a/src/m88k/ffi.c b/src/m88k/ffi.c
index 68df4949..57b344f4 100644
--- a/src/m88k/ffi.c
+++ b/src/m88k/ffi.c
@@ -134,7 +134,7 @@ ffi_prep_args (void *stack, extended_cif *ecif)
/* Enforce proper stack alignment of 64-bit types */
if (argp == stackp && a > sizeof (int))
{
- stackp = (char *) ALIGN(stackp, a);
+ stackp = (char *) FFI_ALIGN(stackp, a);
argp = stackp;
}
@@ -177,7 +177,7 @@ ffi_prep_args (void *stack, extended_cif *ecif)
/* Align if necessary. */
if ((sizeof (int) - 1) & z)
- z = ALIGN(z, sizeof (int));
+ z = FFI_ALIGN(z, sizeof (int));
p_argv++;
@@ -320,7 +320,7 @@ ffi_prep_closure_args_OBSD (ffi_cif *cif, void **avalue, unsigned int *regp,
/* Enforce proper stack alignment of 64-bit types */
if (argp == stackp && a > sizeof (int))
{
- stackp = (char *) ALIGN(stackp, a);
+ stackp = (char *) FFI_ALIGN(stackp, a);
argp = stackp;
}
@@ -331,7 +331,7 @@ ffi_prep_closure_args_OBSD (ffi_cif *cif, void **avalue, unsigned int *regp,
/* Align if necessary */
if ((sizeof (int) - 1) & z)
- z = ALIGN(z, sizeof (int));
+ z = FFI_ALIGN(z, sizeof (int));
p_argv++;
diff --git a/src/metag/ffi.c b/src/metag/ffi.c
index 46b383e7..3aecb0b8 100644
--- a/src/metag/ffi.c
+++ b/src/metag/ffi.c
@@ -61,7 +61,7 @@ unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
argp -= z;
/* Align if necessary */
- argp = (char *) ALIGN_DOWN(ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
+ argp = (char *) FFI_ALIGN_DOWN(FFI_ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
if (z < sizeof(int)) {
z = sizeof(int);
@@ -93,7 +93,7 @@ unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
/* return the size of the arguments to be passed in registers,
padded to an 8 byte boundary to preserve stack alignment */
- return ALIGN(MIN(stack - argp, 6*4), 8);
+ return FFI_ALIGN(MIN(stack - argp, 6*4), 8);
}
/* Perform machine dependent cif processing */
@@ -112,20 +112,20 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
/* Add any padding if necessary */
if (((*ptr)->alignment - 1) & bytes)
- bytes = ALIGN(bytes, (*ptr)->alignment);
+ bytes = FFI_ALIGN(bytes, (*ptr)->alignment);
- bytes += ALIGN((*ptr)->size, 4);
+ bytes += FFI_ALIGN((*ptr)->size, 4);
}
/* Ensure arg space is aligned to an 8-byte boundary */
- bytes = ALIGN(bytes, 8);
+ bytes = FFI_ALIGN(bytes, 8);
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT) {
bytes += sizeof(void*);
/* Ensure stack is aligned to an 8-byte boundary */
- bytes = ALIGN(bytes, 8);
+ bytes = FFI_ALIGN(bytes, 8);
}
cif->bytes = bytes;
@@ -319,7 +319,7 @@ static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
if (alignment < 4)
alignment = 4;
if ((alignment - 1) & (unsigned)argp)
- argp = (char *) ALIGN(argp, alignment);
+ argp = (char *) FFI_ALIGN(argp, alignment);
z = (*p_arg)->size;
*p_argv = (void*) argp;
diff --git a/src/microblaze/ffi.c b/src/microblaze/ffi.c
index ea962ea4..df6e33c9 100644
--- a/src/microblaze/ffi.c
+++ b/src/microblaze/ffi.c
@@ -35,7 +35,7 @@ extern void ffi_closure_SYSV(void);
#define WORD_SIZE sizeof(unsigned int)
#define ARGS_REGISTER_SIZE (WORD_SIZE * 6)
-#define WORD_ALIGN(x) ALIGN(x, WORD_SIZE)
+#define WORD_FFI_ALIGN(x) FFI_ALIGN(x, WORD_SIZE)
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
@@ -46,12 +46,12 @@ void ffi_prep_args(void* stack, extended_cif* ecif)
void** p_argv;
void* stack_args_p = stack;
- p_argv = ecif->avalue;
-
if (ecif == NULL || ecif->cif == NULL) {
return; /* no description to prepare */
}
+ p_argv = ecif->avalue;
+
if ((ecif->cif->rtype != NULL) &&
(ecif->cif->rtype->type == FFI_TYPE_STRUCT))
{
@@ -74,7 +74,7 @@ void ffi_prep_args(void* stack, extended_cif* ecif)
int type = (*p_arg)->type;
void* value = p_argv[i];
char* addr = stack_args_p;
- int aligned_size = WORD_ALIGN(size);
+ int aligned_size = WORD_FFI_ALIGN(size);
/* force word alignment on the stack */
stack_args_p += aligned_size;
@@ -259,7 +259,7 @@ void ffi_closure_call_SYSV(void* register_args, void* stack_args,
avalue[i] = ptr;
break;
}
- ptr += WORD_ALIGN(arg_types[i]->size);
+ ptr += WORD_FFI_ALIGN(arg_types[i]->size);
}
/* set the return type info passed back to the wrapper */
diff --git a/src/mips/ffi.c b/src/mips/ffi.c
index 5d0dd70c..057b0466 100644
--- a/src/mips/ffi.c
+++ b/src/mips/ffi.c
@@ -29,6 +29,7 @@
#include <ffi.h>
#include <ffi_common.h>
+#include <stdint.h>
#include <stdlib.h>
#ifdef __GNUC__
@@ -116,7 +117,7 @@ static void ffi_prep_args(char *stack,
if ((a - 1) & (unsigned long) argp)
{
- argp = (char *) ALIGN(argp, a);
+ argp = (char *) FFI_ALIGN(argp, a);
FIX_ARGP;
}
@@ -247,7 +248,7 @@ calc_n32_struct_flags(int soft_float, ffi_type *arg,
while ((e = arg->elements[index]))
{
/* Align this object. */
- *loc = ALIGN(*loc, e->alignment);
+ *loc = FFI_ALIGN(*loc, e->alignment);
if (e->type == FFI_TYPE_DOUBLE)
{
/* Already aligned to FFI_SIZEOF_ARG. */
@@ -262,7 +263,7 @@ calc_n32_struct_flags(int soft_float, ffi_type *arg,
index++;
}
/* Next Argument register at alignment of FFI_SIZEOF_ARG. */
- *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ *arg_reg = FFI_ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
return flags;
}
@@ -322,9 +323,10 @@ calc_n32_return_struct_flags(int soft_float, ffi_type *arg)
#endif
/* Perform machine dependent cif processing */
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
{
cif->flags = 0;
+ cif->mips_nfixedargs = nfixedargs;
#ifdef FFI_MIPS_O32
/* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT
@@ -333,7 +335,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32)
{
- if (cif->nargs > 0)
+ if (cif->nargs > 0 && cif->nargs == nfixedargs)
{
switch ((cif->arg_types)[0]->type)
{
@@ -450,7 +452,9 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
while (count-- > 0 && arg_reg < 8)
{
type = (cif->arg_types)[index]->type;
- if (soft_float)
+
+ // Pass variadic arguments in integer registers even if they're floats
+ if (soft_float || index >= nfixedargs)
{
switch (type)
{
@@ -474,9 +478,9 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
break;
case FFI_TYPE_LONGDOUBLE:
/* Align it. */
- arg_reg = ALIGN(arg_reg, 2);
+ arg_reg = FFI_ALIGN(arg_reg, 2);
/* Treat it as two adjacent doubles. */
- if (soft_float)
+ if (soft_float || index >= nfixedargs)
{
arg_reg += 2;
}
@@ -493,7 +497,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
case FFI_TYPE_STRUCT:
loc = arg_reg * FFI_SIZEOF_ARG;
- cif->flags += calc_n32_struct_flags(soft_float,
+ cif->flags += calc_n32_struct_flags(soft_float || index >= nfixedargs,
(cif->arg_types)[index],
&loc, &arg_reg);
break;
@@ -578,17 +582,30 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
return FFI_OK;
}
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ return ffi_prep_cif_machdep_int(cif, cif->nargs);
+}
+
+ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
+ unsigned nfixedargs,
+ unsigned ntotalargs MAYBE_UNUSED)
+{
+ return ffi_prep_cif_machdep_int(cif, nfixedargs);
+}
+
/* Low level routine for calling O32 functions */
extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int),
extended_cif *, unsigned,
- unsigned, unsigned *, void (*)(void));
+ unsigned, unsigned *, void (*)(void), void *closure);
/* Low level routine for calling N32 functions */
extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int),
extended_cif *, unsigned,
- unsigned, void *, void (*)(void));
+ unsigned, void *, void (*)(void), void *closure);
-void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+void ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
{
extended_cif ecif;
@@ -610,7 +627,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
case FFI_O32:
case FFI_O32_SOFT_FLOAT:
ffi_call_O32(ffi_prep_args, &ecif, cif->bytes,
- cif->flags, ecif.rvalue, fn);
+ cif->flags, ecif.rvalue, fn, closure);
break;
#endif
@@ -642,7 +659,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
#endif
}
ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
- cif->flags, rvalue_copy, fn);
+ cif->flags, rvalue_copy, fn, closure);
if (copy_rvalue)
memcpy(ecif.rvalue, rvalue_copy + copy_offset, cif->rtype->size);
}
@@ -655,11 +672,27 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
}
+void
+ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ ffi_call_int (cif, fn, rvalue, avalue, NULL);
+}
+
+void
+ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int (cif, fn, rvalue, avalue, closure);
+}
+
+
#if FFI_CLOSURES
#if defined(FFI_MIPS_O32)
extern void ffi_closure_O32(void);
+extern void ffi_go_closure_O32(void);
#else
extern void ffi_closure_N32(void);
+extern void ffi_go_closure_N32(void);
#endif /* FFI_MIPS_O32 */
ffi_status
@@ -698,7 +731,11 @@ ffi_prep_closure_loc (ffi_closure *closure,
/* lui $12,high(codeloc) */
tramp[2] = 0x3c0c0000 | ((unsigned)codeloc >> 16);
/* jr $25 */
+#if !defined(__mips_isa_rev) || (__mips_isa_rev<6)
tramp[3] = 0x03200008;
+#else
+ tramp[3] = 0x03200009;
+#endif
/* ori $12,low(codeloc) */
tramp[4] = 0x358c0000 | ((unsigned)codeloc & 0xffff);
#else
@@ -726,7 +763,11 @@ ffi_prep_closure_loc (ffi_closure *closure,
/* ori $25,low(fn) */
tramp[10] = 0x37390000 | ((unsigned long)fn & 0xffff);
/* jr $25 */
+#if !defined(__mips_isa_rev) || (__mips_isa_rev<6)
tramp[11] = 0x03200008;
+#else
+ tramp[11] = 0x03200009;
+#endif
/* ori $12,low(codeloc) */
tramp[12] = 0x358c0000 | ((unsigned long)codeloc & 0xffff);
@@ -762,27 +803,28 @@ ffi_prep_closure_loc (ffi_closure *closure,
* Based on the similar routine for sparc.
*/
int
-ffi_closure_mips_inner_O32 (ffi_closure *closure,
+ffi_closure_mips_inner_O32 (ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
void *rvalue, ffi_arg *ar,
double *fpr)
{
- ffi_cif *cif;
void **avaluep;
ffi_arg *avalue;
ffi_type **arg_types;
int i, avn, argn, seen_int;
- cif = closure->cif;
avalue = alloca (cif->nargs * sizeof (ffi_arg));
avaluep = alloca (cif->nargs * sizeof (ffi_arg));
- seen_int = (cif->abi == FFI_O32_SOFT_FLOAT);
+ seen_int = (cif->abi == FFI_O32_SOFT_FLOAT) || (cif->mips_nfixedargs != cif->nargs);
argn = 0;
if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT)
{
- rvalue = (void *)(UINT32)ar[0];
+ rvalue = (void *)(uintptr_t)ar[0];
argn = 1;
+ seen_int = 1;
}
i = 0;
@@ -791,6 +833,8 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure,
while (i < avn)
{
+ if (arg_types[i]->alignment == 8 && (argn & 0x1))
+ argn++;
if (i < 2 && !seen_int &&
(arg_types[i]->type == FFI_TYPE_FLOAT ||
arg_types[i]->type == FFI_TYPE_DOUBLE ||
@@ -805,8 +849,6 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure,
}
else
{
- if (arg_types[i]->alignment == 8 && (argn & 0x1))
- argn++;
switch (arg_types[i]->type)
{
case FFI_TYPE_SINT8:
@@ -835,12 +877,12 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure,
}
seen_int = 1;
}
- argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ argn += FFI_ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
i++;
}
/* Invoke the closure. */
- (closure->fun) (cif, rvalue, avaluep, closure->user_data);
+ fun(cif, rvalue, avaluep, user_data);
if (cif->abi == FFI_O32_SOFT_FLOAT)
{
@@ -876,7 +918,7 @@ copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
char *argp;
char *fpp;
- o = ALIGN(offset, elt_type->alignment);
+ o = FFI_ALIGN(offset, elt_type->alignment);
arg_offset += o - offset;
offset = o;
argn += arg_offset / sizeof(ffi_arg);
@@ -916,11 +958,12 @@ copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
*
*/
int
-ffi_closure_mips_inner_N32 (ffi_closure *closure,
+ffi_closure_mips_inner_N32 (ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
void *rvalue, ffi_arg *ar,
ffi_arg *fpr)
{
- ffi_cif *cif;
void **avaluep;
ffi_arg *avalue;
ffi_type **arg_types;
@@ -928,7 +971,6 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
int soft_float;
ffi_arg *argp;
- cif = closure->cif;
soft_float = cif->abi == FFI_N64_SOFT_FLOAT
|| cif->abi == FFI_N32_SOFT_FLOAT;
avalue = alloca (cif->nargs * sizeof (ffi_arg));
@@ -956,10 +998,10 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
|| arg_types[i]->type == FFI_TYPE_DOUBLE
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE)
{
- argp = (argn >= 8 || soft_float) ? ar + argn : fpr + argn;
- if ((arg_types[i]->type == FFI_TYPE_LONGDOUBLE) && ((unsigned)argp & (arg_types[i]->alignment-1)))
+ argp = (argn >= 8 || i >= cif->mips_nfixedargs || soft_float) ? ar + argn : fpr + argn;
+ if ((arg_types[i]->type == FFI_TYPE_LONGDOUBLE) && ((uintptr_t)argp & (arg_types[i]->alignment-1)))
{
- argp=(ffi_arg*)ALIGN(argp,arg_types[i]->alignment);
+ argp=(ffi_arg*)FFI_ALIGN(argp,arg_types[i]->alignment);
argn++;
}
#if defined(__MIPSEB__) || defined(_MIPSEB)
@@ -974,7 +1016,7 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
unsigned type = arg_types[i]->type;
if (arg_types[i]->alignment > sizeof(ffi_arg))
- argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
+ argn = FFI_ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
argp = ar + argn;
@@ -1025,7 +1067,7 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
it was passed in registers. */
avaluep[i] = alloca(arg_types[i]->size);
copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i],
- argn, 0, ar, fpr, soft_float);
+ argn, 0, ar, fpr, i >= cif->mips_nfixedargs || soft_float);
break;
}
@@ -1035,16 +1077,54 @@ ffi_closure_mips_inner_N32 (ffi_closure *closure,
break;
}
}
- argn += ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg);
+ argn += FFI_ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg);
i++;
}
/* Invoke the closure. */
- (closure->fun) (cif, rvalue, avaluep, closure->user_data);
+ fun (cif, rvalue, avaluep, user_data);
return cif->flags >> (FFI_FLAG_BITS * 8);
}
#endif /* FFI_MIPS_N32 */
+#if defined(FFI_MIPS_O32)
+extern void ffi_closure_O32(void);
+extern void ffi_go_closure_O32(void);
+#else
+extern void ffi_closure_N32(void);
+extern void ffi_go_closure_N32(void);
+#endif /* FFI_MIPS_O32 */
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*))
+{
+ void * fn;
+
+#if defined(FFI_MIPS_O32)
+ if (cif->abi != FFI_O32 && cif->abi != FFI_O32_SOFT_FLOAT)
+ return FFI_BAD_ABI;
+ fn = ffi_go_closure_O32;
+#else
+#if _MIPS_SIM ==_ABIN32
+ if (cif->abi != FFI_N32
+ && cif->abi != FFI_N32_SOFT_FLOAT)
+ return FFI_BAD_ABI;
+#else
+ if (cif->abi != FFI_N64
+ && cif->abi != FFI_N64_SOFT_FLOAT)
+ return FFI_BAD_ABI;
+#endif
+ fn = ffi_go_closure_N32;
+#endif /* FFI_MIPS_O32 */
+
+ closure->tramp = (void *)fn;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
#endif /* FFI_CLOSURES */
diff --git a/src/mips/ffitarget.h b/src/mips/ffitarget.h
index 717d6595..fffdb977 100644
--- a/src/mips/ffitarget.h
+++ b/src/mips/ffitarget.h
@@ -32,7 +32,7 @@
#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
#endif
-#ifdef linux
+#ifdef __linux__
# include <asm/sgidefs.h>
#elif defined(__rtems__)
/*
@@ -224,24 +224,21 @@ typedef enum ffi_abi {
#endif
} ffi_abi;
-#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag
+#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag; unsigned mips_nfixedargs
+#define FFI_TARGET_SPECIFIC_VARIADIC
#endif /* !LIBFFI_ASM */
/* ---- Definitions for closures ----------------------------------------- */
-#if defined(FFI_MIPS_O32)
#define FFI_CLOSURES 1
-#define FFI_TRAMPOLINE_SIZE 20
-#else
-/* N32/N64. */
-# define FFI_CLOSURES 1
-#if _MIPS_SIM==_ABI64
-#define FFI_TRAMPOLINE_SIZE 52
+#define FFI_GO_CLOSURES 1
+#define FFI_NATIVE_RAW_API 0
+
+#if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32)
+# define FFI_TRAMPOLINE_SIZE 20
#else
-#define FFI_TRAMPOLINE_SIZE 20
+# define FFI_TRAMPOLINE_SIZE 56
#endif
-#endif /* FFI_MIPS_O32 */
-#define FFI_NATIVE_RAW_API 0
#endif
diff --git a/src/mips/n32.S b/src/mips/n32.S
index c6985d30..1a940b6d 100644
--- a/src/mips/n32.S
+++ b/src/mips/n32.S
@@ -37,36 +37,43 @@
#define flags a3
#define raddr a4
#define fn a5
+#define closure a6
-#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG )
+/* Note: to keep stack 16 byte aligned we need even number slots
+ used 9 slots here
+*/
+#define SIZEOF_FRAME ( 10 * FFI_SIZEOF_ARG )
#ifdef __GNUC__
.abicalls
#endif
+#if !defined(__mips_isa_rev) || (__mips_isa_rev<6)
.set mips4
+#endif
.text
.align 2
.globl ffi_call_N32
.ent ffi_call_N32
ffi_call_N32:
-.LFB3:
+.LFB0:
.frame $fp, SIZEOF_FRAME, ra
.mask 0xc0000000,-FFI_SIZEOF_ARG
.fmask 0x00000000,0
# Prologue
SUBU $sp, SIZEOF_FRAME # Frame size
-.LCFI0:
+.LCFI00:
REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
-.LCFI1:
+.LCFI01:
move $fp, $sp
-.LCFI3:
+.LCFI02:
move t9, callback # callback function pointer
REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags
REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn
+ REG_S closure, 6*FFI_SIZEOF_ARG($fp) # closure
# Allocate at least 4 words in the argstack
move v0, bytes
@@ -107,6 +114,16 @@ loadregs:
REG_L t6, 3*FFI_SIZEOF_ARG($fp) # load the flags word into t6.
+#ifdef __mips_soft_float
+ REG_L a0, 0*FFI_SIZEOF_ARG(t9)
+ REG_L a1, 1*FFI_SIZEOF_ARG(t9)
+ REG_L a2, 2*FFI_SIZEOF_ARG(t9)
+ REG_L a3, 3*FFI_SIZEOF_ARG(t9)
+ REG_L a4, 4*FFI_SIZEOF_ARG(t9)
+ REG_L a5, 5*FFI_SIZEOF_ARG(t9)
+ REG_L a6, 6*FFI_SIZEOF_ARG(t9)
+ REG_L a7, 7*FFI_SIZEOF_ARG(t9)
+#else
and t4, t6, ((1<<FFI_FLAG_BITS)-1)
REG_L a0, 0*FFI_SIZEOF_ARG(t9)
beqz t4, arg1_next
@@ -193,11 +210,15 @@ arg7_next:
arg8_doublep:
l.d $f19, 7*FFI_SIZEOF_ARG(t9)
arg8_next:
+#endif
callit:
# Load the function pointer
REG_L t9, 5*FFI_SIZEOF_ARG($fp)
+ # install the static chain(t7=$15)
+ REG_L t7, 6*FFI_SIZEOF_ARG($fp)
+
# If the return value pointer is NULL, assume no return value.
REG_L t5, 4*FFI_SIZEOF_ARG($fp)
beqz t5, noretval
@@ -214,6 +235,7 @@ retint:
b epilogue
retfloat:
+#ifndef __mips_soft_float
bne t6, FFI_TYPE_FLOAT, retdouble
jal t9
REG_L t4, 4*FFI_SIZEOF_ARG($fp)
@@ -272,6 +294,7 @@ retstruct_f_d:
s.s $f0, 0(t4)
s.d $f2, 8(t4)
b epilogue
+#endif
retstruct_d_soft:
bne t6, FFI_TYPE_STRUCT_D_SOFT, retstruct_f_soft
@@ -346,7 +369,7 @@ epilogue:
ADDU $sp, SIZEOF_FRAME # Fix stack pointer
j ra
-.LFE3:
+.LFE0:
.end ffi_call_N32
/* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
@@ -406,6 +429,41 @@ epilogue:
#define GP_OFF2 (0 * FFI_SIZEOF_ARG)
.align 2
+ .globl ffi_go_closure_N32
+ .ent ffi_go_closure_N32
+ffi_go_closure_N32:
+.LFB1:
+ .frame $sp, SIZEOF_FRAME2, ra
+ .mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
+ .fmask 0x00000000,0
+ SUBU $sp, SIZEOF_FRAME2
+.LCFI10:
+ .cpsetup t9, GP_OFF2, ffi_go_closure_N32
+ REG_S ra, RA_OFF2($sp) # Save return address
+.LCFI11:
+
+ REG_S a0, A0_OFF2($sp)
+ REG_S a1, A1_OFF2($sp)
+ REG_S a2, A2_OFF2($sp)
+ REG_S a3, A3_OFF2($sp)
+ REG_S a4, A4_OFF2($sp)
+ REG_S a5, A5_OFF2($sp)
+
+ # Call ffi_closure_mips_inner_N32 to do the real work.
+ LA t9, ffi_closure_mips_inner_N32
+ REG_L a0, 8($15) # cif
+ REG_L a1, 16($15) # fun
+ move a2, t7 # userdata=closure
+ ADDU a3, $sp, V0_OFF2 # rvalue
+ ADDU a4, $sp, A0_OFF2 # ar
+ ADDU a5, $sp, F12_OFF2 # fpr
+
+ b $do_closure
+
+.LFE1:
+ .end ffi_go_closure_N32
+
+ .align 2
.globl ffi_closure_N32
.ent ffi_closure_N32
ffi_closure_N32:
@@ -414,21 +472,33 @@ ffi_closure_N32:
.mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
.fmask 0x00000000,0
SUBU $sp, SIZEOF_FRAME2
-.LCFI5:
+.LCFI20:
.cpsetup t9, GP_OFF2, ffi_closure_N32
REG_S ra, RA_OFF2($sp) # Save return address
-.LCFI6:
- # Store all possible argument registers. If there are more than
- # fit in registers, then they were stored on the stack.
+.LCFI21:
REG_S a0, A0_OFF2($sp)
REG_S a1, A1_OFF2($sp)
REG_S a2, A2_OFF2($sp)
REG_S a3, A3_OFF2($sp)
REG_S a4, A4_OFF2($sp)
REG_S a5, A5_OFF2($sp)
+
+ # Call ffi_closure_mips_inner_N32 to do the real work.
+ LA t9, ffi_closure_mips_inner_N32
+ REG_L a0, 56($12) # cif
+ REG_L a1, 64($12) # fun
+ REG_L a2, 72($12) # user_data
+ ADDU a3, $sp, V0_OFF2
+ ADDU a4, $sp, A0_OFF2
+ ADDU a5, $sp, F12_OFF2
+
+$do_closure:
+ # Store all possible argument registers. If there are more than
+ # fit in registers, then they were stored on the stack.
REG_S a6, A6_OFF2($sp)
REG_S a7, A7_OFF2($sp)
+#ifndef __mips_soft_float
# Store all possible float/double registers.
s.d $f12, F12_OFF2($sp)
s.d $f13, F13_OFF2($sp)
@@ -438,13 +508,8 @@ ffi_closure_N32:
s.d $f17, F17_OFF2($sp)
s.d $f18, F18_OFF2($sp)
s.d $f19, F19_OFF2($sp)
+#endif
- # Call ffi_closure_mips_inner_N32 to do the real work.
- LA t9, ffi_closure_mips_inner_N32
- move a0, $12 # Pointer to the ffi_closure
- ADDU a1, $sp, V0_OFF2
- ADDU a2, $sp, A0_OFF2
- ADDU a3, $sp, F12_OFF2
jalr t9
# Return flags are in v0
@@ -458,6 +523,7 @@ cls_retint:
b cls_epilogue
cls_retfloat:
+#ifndef __mips_soft_float
bne v0, FFI_TYPE_FLOAT, cls_retdouble
l.s $f0, V0_OFF2($sp)
b cls_epilogue
@@ -500,6 +566,7 @@ cls_retstruct_f_d:
l.s $f0, V0_OFF2($sp)
l.d $f2, V1_OFF2($sp)
b cls_epilogue
+#endif
cls_retstruct_small2:
REG_L v0, V0_OFF2($sp)
@@ -531,46 +598,66 @@ cls_epilogue:
.align EH_FRAME_ALIGN
.LECIE1:
-.LSFDE1:
- .4byte .LEFDE1-.LASFDE1 # length.
-.LASFDE1:
- .4byte .LASFDE1-.Lframe1 # CIE_pointer.
- FDE_ADDR_BYTES .LFB3 # initial_location.
- FDE_ADDR_BYTES .LFE3-.LFB3 # address_range.
+.LSFDE0:
+ .4byte .LEFDE0-.LASFDE0 # length.
+.LASFDE0:
+ .4byte .LASFDE0-.Lframe1 # CIE_pointer.
+ FDE_ADDR_BYTES .LFB0 # initial_location.
+ FDE_ADDR_BYTES .LFE0-.LFB0 # address_range.
.byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI0-.LFB3 # to .LCFI0
+ .4byte .LCFI00-.LFB0 # to .LCFI00
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 SIZEOF_FRAME # adjust stack.by SIZEOF_FRAME
.byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI1-.LCFI0 # to .LCFI1
+ .4byte .LCFI01-.LCFI00 # to .LCFI01
.byte 0x9e # DW_CFA_offset of $fp
.uleb128 2*FFI_SIZEOF_ARG/4 #
.byte 0x9f # DW_CFA_offset of ra
.uleb128 1*FFI_SIZEOF_ARG/4 #
.byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI3-.LCFI1 # to .LCFI3
+ .4byte .LCFI02-.LCFI01 # to .LCFI02
.byte 0xd # DW_CFA_def_cfa_register
.uleb128 0x1e # in $fp
.align EH_FRAME_ALIGN
+.LEFDE0:
+
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 # length
+.LASFDE1:
+ .4byte .LASFDE1-.Lframe1 # CIE_pointer.
+ FDE_ADDR_BYTES .LFB1 # initial_location.
+ FDE_ADDR_BYTES .LFE1-.LFB1 # address_range.
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI10-.LFB1 # to .LCFI10
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI11-.LCFI10 # to .LCFI11
+ .byte 0x9c # DW_CFA_offset of $gp ($28)
+ .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
+ .byte 0x9f # DW_CFA_offset of ra ($31)
+ .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
+ .align EH_FRAME_ALIGN
.LEFDE1:
-.LSFDE3:
- .4byte .LEFDE3-.LASFDE3 # length
-.LASFDE3:
- .4byte .LASFDE3-.Lframe1 # CIE_pointer.
+
+.LSFDE2:
+ .4byte .LEFDE2-.LASFDE2 # length
+.LASFDE2:
+ .4byte .LASFDE2-.Lframe1 # CIE_pointer.
FDE_ADDR_BYTES .LFB2 # initial_location.
FDE_ADDR_BYTES .LFE2-.LFB2 # address_range.
.byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI5-.LFB2 # to .LCFI5
+ .4byte .LCFI20-.LFB2 # to .LCFI20
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME
.byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI6-.LCFI5 # to .LCFI6
+ .4byte .LCFI21-.LCFI20 # to .LCFI21
.byte 0x9c # DW_CFA_offset of $gp ($28)
.uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
.byte 0x9f # DW_CFA_offset of ra ($31)
.uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
.align EH_FRAME_ALIGN
-.LEFDE3:
+.LEFDE2:
#endif /* __GNUC__ */
#endif
diff --git a/src/mips/o32.S b/src/mips/o32.S
index eb279813..44e74cb9 100644
--- a/src/mips/o32.S
+++ b/src/mips/o32.S
@@ -50,14 +50,14 @@ ffi_call_O32:
$LFB0:
# Prologue
SUBU $sp, SIZEOF_FRAME # Frame size
-$LCFI0:
+$LCFI00:
REG_S $fp, FP_OFF($sp) # Save frame pointer
-$LCFI1:
+$LCFI01:
REG_S ra, RA_OFF($sp) # Save return address
-$LCFI2:
+$LCFI02:
move $fp, $sp
-$LCFI3:
+$LCFI03:
move t9, callback # callback function pointer
REG_S flags, A3_OFF($fp) # flags
@@ -82,13 +82,16 @@ sixteen:
ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
+#ifndef __mips_soft_float
bnez t0, pass_d # make it quick for int
+#endif
REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
REG_L a2, 2*FFI_SIZEOF_ARG($sp)
REG_L a3, 3*FFI_SIZEOF_ARG($sp)
b call_it
+#ifndef __mips_soft_float
pass_d:
bne t0, FFI_ARGS_D, pass_f
l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
@@ -130,8 +133,12 @@ pass_f_d:
# bne t0, FFI_ARGS_F_D, call_it
l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
+#endif
call_it:
+ # Load the static chain pointer
+ REG_L t7, SIZEOF_FRAME + 6*FFI_SIZEOF_ARG($fp)
+
# Load the function pointer
REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
@@ -158,14 +165,23 @@ retfloat:
bne t2, FFI_TYPE_FLOAT, retdouble
jalr t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+#ifndef __mips_soft_float
s.s $f0, 0(t0)
+#else
+ REG_S v0, 0(t0)
+#endif
b epilogue
retdouble:
bne t2, FFI_TYPE_DOUBLE, noretval
jalr t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+#ifndef __mips_soft_float
s.d $f0, 0(t0)
+#else
+ REG_S v1, 4(t0)
+ REG_S v0, 0(t0)
+#endif
b epilogue
noretval:
@@ -204,13 +220,15 @@ $LFE0:
-8 - f14 (le low, be high)
-9 - f12 (le high, be low)
-10 - f12 (le low, be high)
- -11 - Called function a3 save
- -12 - Called function a2 save
- -13 - Called function a1 save
- -14 - Called function a0 save, our sp and fp point here
+ -11 - Called function a5 save
+ -12 - Called function a4 save
+ -13 - Called function a3 save
+ -14 - Called function a2 save
+ -15 - Called function a1 save
+ -16 - Called function a0 save, our sp and fp point here
*/
-#define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG)
+#define SIZEOF_FRAME2 (16 * FFI_SIZEOF_ARG)
#define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
#define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
#define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
@@ -225,13 +243,71 @@ $LFE0:
#define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
#define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
#define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
+#define CALLED_A5_OFF2 (SIZEOF_FRAME2 - 11 * FFI_SIZEOF_ARG)
+#define CALLED_A4_OFF2 (SIZEOF_FRAME2 - 12 * FFI_SIZEOF_ARG)
.text
+
+ .align 2
+ .globl ffi_go_closure_O32
+ .ent ffi_go_closure_O32
+ffi_go_closure_O32:
+$LFB1:
+ # Prologue
+ .frame $fp, SIZEOF_FRAME2, ra
+ .set noreorder
+ .cpload t9
+ .set reorder
+ SUBU $sp, SIZEOF_FRAME2
+ .cprestore GP_OFF2
+$LCFI10:
+
+ REG_S $16, S0_OFF2($sp) # Save s0
+ REG_S $fp, FP_OFF2($sp) # Save frame pointer
+ REG_S ra, RA_OFF2($sp) # Save return address
+$LCFI11:
+
+ move $fp, $sp
+$LCFI12:
+
+ REG_S a0, A0_OFF2($fp)
+ REG_S a1, A1_OFF2($fp)
+ REG_S a2, A2_OFF2($fp)
+ REG_S a3, A3_OFF2($fp)
+
+ # Load ABI enum to s0
+ REG_L $16, 4($15) # cif
+ REG_L $16, 0($16) # abi is first member.
+
+ li $13, 1 # FFI_O32
+ bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
+
+ # Store all possible float/double registers.
+ s.d $f12, FA_0_0_OFF2($fp)
+ s.d $f14, FA_1_0_OFF2($fp)
+1:
+ # prepare arguments for ffi_closure_mips_inner_O32
+ REG_L a0, 4($15) # cif
+ REG_L a1, 8($15) # fun
+ move a2, $15 # user_data = go closure
+ addu a3, $fp, V0_OFF2 # rvalue
+
+ addu t9, $fp, A0_OFF2 # ar
+ REG_S t9, CALLED_A4_OFF2($fp)
+
+ addu t9, $fp, FA_0_0_OFF2 #fpr
+ REG_S t9, CALLED_A5_OFF2($fp)
+
+ b $do_closure
+
+$LFE1:
+ .end ffi_go_closure_O32
+
.align 2
.globl ffi_closure_O32
.ent ffi_closure_O32
ffi_closure_O32:
-$LFB1:
+$LFB2:
# Prologue
.frame $fp, SIZEOF_FRAME2, ra
.set noreorder
@@ -239,14 +315,14 @@ $LFB1:
.set reorder
SUBU $sp, SIZEOF_FRAME2
.cprestore GP_OFF2
-$LCFI4:
+$LCFI20:
REG_S $16, S0_OFF2($sp) # Save s0
REG_S $fp, FP_OFF2($sp) # Save frame pointer
REG_S ra, RA_OFF2($sp) # Save return address
-$LCFI6:
+$LCFI21:
move $fp, $sp
-$LCFI7:
+$LCFI22:
# Store all possible argument registers. If there are more than
# four arguments, then they are stored above where we put a3.
REG_S a0, A0_OFF2($fp)
@@ -261,16 +337,27 @@ $LCFI7:
li $13, 1 # FFI_O32
bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
+#ifndef __mips_soft_float
# Store all possible float/double registers.
s.d $f12, FA_0_0_OFF2($fp)
s.d $f14, FA_1_0_OFF2($fp)
+#endif
1:
- # Call ffi_closure_mips_inner_O32 to do the work.
+ # prepare arguments for ffi_closure_mips_inner_O32
+ REG_L a0, 20($12) # cif pointer follows tramp.
+ REG_L a1, 24($12) # fun
+ REG_L a2, 28($12) # user_data
+ addu a3, $fp, V0_OFF2 # rvalue
+
+ addu t9, $fp, A0_OFF2 # ar
+ REG_S t9, CALLED_A4_OFF2($fp)
+
+ addu t9, $fp, FA_0_0_OFF2 #fpr
+ REG_S t9, CALLED_A5_OFF2($fp)
+
+$do_closure:
la t9, ffi_closure_mips_inner_O32
- move a0, $12 # Pointer to the ffi_closure
- addu a1, $fp, V0_OFF2
- addu a2, $fp, A0_OFF2
- addu a3, $fp, FA_0_0_OFF2
+ # Call ffi_closure_mips_inner_O32 to do the work.
jalr t9
# Load the return value into the appropriate register.
@@ -281,6 +368,7 @@ $LCFI7:
li $13, 1 # FFI_O32
bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT
+#ifndef __mips_soft_float
li $9, FFI_TYPE_FLOAT
l.s $f0, V0_OFF2($fp)
beq $8, $9, closure_done
@@ -288,6 +376,7 @@ $LCFI7:
li $9, FFI_TYPE_DOUBLE
l.d $f0, V0_OFF2($fp)
beq $8, $9, closure_done
+#endif
1:
REG_L $3, V1_OFF2($fp)
REG_L $2, V0_OFF2($fp)
@@ -300,7 +389,7 @@ closure_done:
REG_L ra, RA_OFF2($sp) # Restore return address
ADDU $sp, SIZEOF_FRAME2
j ra
-$LFE1:
+$LFE2:
.end ffi_closure_O32
/* DWARF-2 unwind info. */
@@ -322,6 +411,7 @@ $LSCIE0:
.uleb128 0x0
.align 2
$LECIE0:
+
$LSFDE0:
.4byte $LEFDE0-$LASFDE0 # FDE Length
$LASFDE0:
@@ -330,11 +420,11 @@ $LASFDE0:
.4byte $LFE0-$LFB0 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
- .4byte $LCFI0-$LFB0
+ .4byte $LCFI00-$LFB0
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 0x18
.byte 0x4 # DW_CFA_advance_loc4
- .4byte $LCFI2-$LCFI0
+ .4byte $LCFI01-$LCFI00
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x1e # $fp
.sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
@@ -342,12 +432,13 @@ $LASFDE0:
.uleb128 0x1f # $ra
.sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
.byte 0x4 # DW_CFA_advance_loc4
- .4byte $LCFI3-$LCFI2
+ .4byte $LCFI02-$LCFI01
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1e
.uleb128 0x18
.align 2
$LEFDE0:
+
$LSFDE1:
.4byte $LEFDE1-$LASFDE1 # FDE Length
$LASFDE1:
@@ -356,11 +447,11 @@ $LASFDE1:
.4byte $LFE1-$LFB1 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
- .4byte $LCFI4-$LFB1
+ .4byte $LCFI10-$LFB1
.byte 0xe # DW_CFA_def_cfa_offset
- .uleb128 0x38
+ .uleb128 SIZEOF_FRAME2
.byte 0x4 # DW_CFA_advance_loc4
- .4byte $LCFI6-$LCFI4
+ .4byte $LCFI11-$LCFI10
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x10 # $16
.sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
@@ -371,11 +462,41 @@ $LASFDE1:
.uleb128 0x1f # $ra
.sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
.byte 0x4 # DW_CFA_advance_loc4
- .4byte $LCFI7-$LCFI6
+ .4byte $LCFI12-$LCFI11
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1e
- .uleb128 0x38
+ .uleb128 SIZEOF_FRAME2
.align 2
$LEFDE1:
+$LSFDE2:
+ .4byte $LEFDE2-$LASFDE2 # FDE Length
+$LASFDE2:
+ .4byte $LASFDE2-$Lframe0 # FDE CIE offset
+ .4byte $LFB2 # FDE initial location
+ .4byte $LFE2-$LFB2 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI20-$LFB2
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 SIZEOF_FRAME2
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI21-$LCFI20
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x10 # $16
+ .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1e # $fp
+ .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1f # $ra
+ .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI22-$LCFI21
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1e
+ .uleb128 SIZEOF_FRAME2
+ .align 2
+$LEFDE2:
+
#endif
diff --git a/src/moxie/eabi.S b/src/moxie/eabi.S
index ac7aceb1..10cfb044 100644
--- a/src/moxie/eabi.S
+++ b/src/moxie/eabi.S
@@ -59,7 +59,7 @@ ffi_call_EABI:
mov $r6, $r4 /* Save result buffer */
mov $r7, $r5 /* Save the target fn */
mov $r8, $r3 /* Save the flags */
- sub.l $sp, $r2 /* Allocate stack space */
+ sub $sp, $r2 /* Allocate stack space */
mov $r0, $sp /* We can stomp over $r0 */
/* $r1 is already set up */
jsra ffi_prep_args
diff --git a/src/moxie/ffi.c b/src/moxie/ffi.c
index 540a0429..16d2bb37 100644
--- a/src/moxie/ffi.c
+++ b/src/moxie/ffi.c
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
- ffi.c - Copyright (C) 2012, 2013 Anthony Green
+ ffi.c - Copyright (C) 2012, 2013, 2018 Anthony Green
Moxie Foreign Function Interface
@@ -100,7 +100,7 @@ void *ffi_prep_args(char *stack, extended_cif *ecif)
count += z;
}
- return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
+ return (stack + ((count > 24) ? 24 : FFI_ALIGN_DOWN(count, 8)));
}
/* Perform machine dependent cif processing */
@@ -111,7 +111,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
else
cif->flags = cif->rtype->size;
- cif->bytes = ALIGN (cif->bytes, 8);
+ cif->bytes = FFI_ALIGN (cif->bytes, 8);
return FFI_OK;
}
@@ -159,7 +159,7 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
unsigned arg4, unsigned arg5, unsigned arg6)
{
/* This function is called by a trampoline. The trampoline stows a
- pointer to the ffi_closure object in $r7. We must save this
+ pointer to the ffi_closure object in $r12. We must save this
pointer in a place that will persist while we do our work. */
register ffi_closure *creg __asm__ ("$r12");
ffi_closure *closure = creg;
@@ -215,7 +215,18 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
break;
default:
/* This is an 8-byte value. */
- avalue[i] = ptr;
+ if (ptr == (char *) &register_args[5])
+ {
+ /* The value is split across two locations */
+ unsigned *ip = alloca(8);
+ avalue[i] = ip;
+ ip[0] = *(unsigned *) ptr;
+ ip[1] = *(unsigned *) stack_args;
+ }
+ else
+ {
+ avalue[i] = ptr;
+ }
ptr += 4;
break;
}
@@ -223,8 +234,10 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
/* If we've handled more arguments than fit in registers,
start looking at the those passed on the stack. */
- if (ptr == &register_args[6])
+ if (ptr == (char *) &register_args[6])
ptr = stack_args;
+ else if (ptr == (char *) &register_args[7])
+ ptr = stack_args + 4;
}
/* Invoke the closure. */
@@ -257,7 +270,7 @@ ffi_prep_closure_loc (ffi_closure* closure,
fn = (unsigned long) ffi_closure_eabi;
- tramp[0] = 0x01e0; /* ldi.l $r7, .... */
+ tramp[0] = 0x01e0; /* ldi.l $r12, .... */
tramp[1] = cls >> 16;
tramp[2] = cls & 0xffff;
tramp[3] = 0x1a00; /* jmpa .... */
diff --git a/src/nios2/ffi.c b/src/nios2/ffi.c
index 2efa033f..721080d4 100644
--- a/src/nios2/ffi.c
+++ b/src/nios2/ffi.c
@@ -101,7 +101,7 @@ void ffi_prep_args (char *stack, extended_cif *ecif)
/* Align argp as appropriate for the argument type. */
if ((alignment - 1) & (unsigned) argp)
- argp = (char *) ALIGN (argp, alignment);
+ argp = (char *) FFI_ALIGN (argp, alignment);
/* Copy the argument, promoting integral types smaller than a
word to word size. */
@@ -230,7 +230,7 @@ ffi_closure_helper (unsigned char *args,
/* Align argp as appropriate for the argument type. */
if ((alignment - 1) & (unsigned) argp)
- argp = (char *) ALIGN (argp, alignment);
+ argp = (char *) FFI_ALIGN (argp, alignment);
/* Arguments smaller than an int are promoted to int. */
if (size < sizeof (int))
diff --git a/src/pa/linux.S b/src/pa/linux.S
index f11ae768..ab04c75f 100644
--- a/src/pa/linux.S
+++ b/src/pa/linux.S
@@ -297,10 +297,18 @@ ffi_closure_pa32:
.LSCIE1:
.word 0x0 ;# CIE Identifier Tag
.byte 0x1 ;# CIE Version
+#ifdef __PIC__
+ .ascii "zR\0" ;# CIE Augmentation: 'z' - data, 'R' - DW_EH_PE_... data
+#else
.ascii "\0" ;# CIE Augmentation
+#endif
.uleb128 0x1 ;# CIE Code Alignment Factor
.sleb128 4 ;# CIE Data Alignment Factor
.byte 0x2 ;# CIE RA Column
+#ifdef __PIC__
+ .uleb128 0x1 ;# Augmentation size
+ .byte 0x1b ;# FDE Encoding (DW_EH_PE_pcrel|DW_EH_PE_sdata4)
+#endif
.byte 0xc ;# DW_CFA_def_cfa
.uleb128 0x1e
.uleb128 0x0
@@ -310,9 +318,15 @@ ffi_closure_pa32:
.word .LEFDE1-.LASFDE1 ;# FDE Length
.LASFDE1:
.word .LASFDE1-.Lframe1 ;# FDE CIE offset
- .word .LFB1 ;# FDE initial location
+#ifdef __PIC__
+ .word .LFB1-. ;# FDE initial location
+#else
+ .word .LFB1 ;# FDE initial location
+#endif
.word .LFE1-.LFB1 ;# FDE address range
-
+#ifdef __PIC__
+ .uleb128 0x0 ;# Augmentation size: no data
+#endif
.byte 0x4 ;# DW_CFA_advance_loc4
.word .LCFI11-.LFB1
.byte 0x83 ;# DW_CFA_offset, column 0x3
@@ -338,8 +352,15 @@ ffi_closure_pa32:
.word .LEFDE2-.LASFDE2 ;# FDE Length
.LASFDE2:
.word .LASFDE2-.Lframe1 ;# FDE CIE offset
+#ifdef __PIC__
+ .word .LFB2-. ;# FDE initial location
+#else
.word .LFB2 ;# FDE initial location
+#endif
.word .LFE2-.LFB2 ;# FDE address range
+#ifdef __PIC__
+ .uleb128 0x0 ;# Augmentation size: no data
+#endif
.byte 0x4 ;# DW_CFA_advance_loc4
.word .LCFI21-.LFB2
.byte 0x83 ;# DW_CFA_offset, column 0x3
diff --git a/src/powerpc/aix.S b/src/powerpc/aix.S
index 349e78c2..7ba54159 100644
--- a/src/powerpc/aix.S
+++ b/src/powerpc/aix.S
@@ -106,6 +106,10 @@ ffi_call_AIX:
.llong .ffi_call_AIX, TOC[tc0], 0
.csect .text[PR]
.ffi_call_AIX:
+ .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0
+ .bf __LINE__
+ .line 1
+LFB..0:
/* Save registers we use. */
mflr r0
@@ -115,8 +119,10 @@ ffi_call_AIX:
std r31, -8(r1)
std r0, 16(r1)
+LCFI..0:
mr r28, r1 /* our AP. */
stdux r1, r1, r4
+LCFI..1:
/* Save arguments over call... */
mr r31, r5 /* flags, */
@@ -202,12 +208,16 @@ L(fp_return_value):
L(float_return_value):
stfs f1, 0(r30)
b L(done_return_value)
-
+LFE..0:
#else /* ! __64BIT__ */
.long .ffi_call_AIX, TOC[tc0], 0
.csect .text[PR]
.ffi_call_AIX:
+ .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0
+ .bf __LINE__
+ .line 1
+LFB..0:
/* Save registers we use. */
mflr r0
@@ -217,8 +227,10 @@ L(float_return_value):
stw r31, -4(r1)
stw r0, 8(r1)
+LCFI..0:
mr r28, r1 /* out AP. */
stwux r1, r1, r4
+LCFI..1:
/* Save arguments over call... */
mr r31, r5 /* flags, */
@@ -304,11 +316,144 @@ L(fp_return_value):
L(float_return_value):
stfs f1, 0(r30)
b L(done_return_value)
+LFE..0:
#endif
+ .ef __LINE__
.long 0
.byte 0,0,0,1,128,4,0,0
/* END(ffi_call_AIX) */
+ /* void ffi_call_go_AIX(extended_cif *ecif, unsigned long bytes,
+ * unsigned int flags, unsigned int *rvalue,
+ * void (*fn)(),
+ * void (*prep_args)(extended_cif*, unsigned *const),
+ * void *closure);
+ * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args, r9=closure
+ */
+
+.csect .text[PR]
+ .align 2
+ .globl ffi_call_go_AIX
+ .globl .ffi_call_go_AIX
+.csect ffi_call_go_AIX[DS]
+ffi_call_go_AIX:
+#ifdef __64BIT__
+ .llong .ffi_call_go_AIX, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_call_go_AIX:
+ .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1
+ .bf __LINE__
+ .line 1
+LFB..1:
+ /* Save registers we use. */
+ mflr r0
+
+ std r28,-32(r1)
+ std r29,-24(r1)
+ std r30,-16(r1)
+ std r31, -8(r1)
+
+ std r9, 8(r1) /* closure, saved in cr field. */
+ std r0, 16(r1)
+LCFI..2:
+ mr r28, r1 /* our AP. */
+ stdux r1, r1, r4
+LCFI..3:
+
+ /* Save arguments over call... */
+ mr r31, r5 /* flags, */
+ mr r30, r6 /* rvalue, */
+ mr r29, r7 /* function address, */
+ std r2, 40(r1)
+
+ /* Call ffi_prep_args. */
+ mr r4, r1
+ bl .ffi_prep_args
+ nop
+
+ /* Now do the call. */
+ ld r0, 0(r29)
+ ld r2, 8(r29)
+ ld r11, 8(r28) /* closure */
+ /* Set up cr1 with bits 4-7 of the flags. */
+ mtcrf 0x40, r31
+ mtctr r0
+ /* Load all those argument registers. */
+ /* We have set up a nice stack frame, just load it into registers. */
+ ld r3, 40+(1*8)(r1)
+ ld r4, 40+(2*8)(r1)
+ ld r5, 40+(3*8)(r1)
+ ld r6, 40+(4*8)(r1)
+ nop
+ ld r7, 40+(5*8)(r1)
+ ld r8, 40+(6*8)(r1)
+ ld r9, 40+(7*8)(r1)
+ ld r10,40+(8*8)(r1)
+
+ b L1
+LFE..1:
+#else /* ! __64BIT__ */
+
+ .long .ffi_call_go_AIX, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_call_go_AIX:
+ .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1
+ .bf __LINE__
+ .line 1
+ /* Save registers we use. */
+LFB..1:
+ mflr r0
+
+ stw r28,-16(r1)
+ stw r29,-12(r1)
+ stw r30, -8(r1)
+ stw r31, -4(r1)
+
+ stw r9, 4(r1) /* closure, saved in cr field. */
+ stw r0, 8(r1)
+LCFI..2:
+ mr r28, r1 /* out AP. */
+ stwux r1, r1, r4
+LCFI..3:
+
+ /* Save arguments over call... */
+ mr r31, r5 /* flags, */
+ mr r30, r6 /* rvalue, */
+ mr r29, r7 /* function address, */
+ stw r2, 20(r1)
+
+ /* Call ffi_prep_args. */
+ mr r4, r1
+ bl .ffi_prep_args
+ nop
+
+ /* Now do the call. */
+ lwz r0, 0(r29)
+ lwz r2, 4(r29)
+ lwz r11, 4(r28) /* closure */
+ /* Set up cr1 with bits 4-7 of the flags. */
+ mtcrf 0x40, r31
+ mtctr r0
+ /* Load all those argument registers. */
+ /* We have set up a nice stack frame, just load it into registers. */
+ lwz r3, 20+(1*4)(r1)
+ lwz r4, 20+(2*4)(r1)
+ lwz r5, 20+(3*4)(r1)
+ lwz r6, 20+(4*4)(r1)
+ nop
+ lwz r7, 20+(5*4)(r1)
+ lwz r8, 20+(6*4)(r1)
+ lwz r9, 20+(7*4)(r1)
+ lwz r10,20+(8*4)(r1)
+
+ b L1
+LFE..1:
+#endif
+ .ef __LINE__
+ .long 0
+ .byte 0,0,0,1,128,4,0,0
+/* END(ffi_call_go_AIX) */
+
.csect .text[PR]
.align 2
.globl ffi_call_DARWIN
@@ -326,3 +471,96 @@ ffi_call_DARWIN:
.long 0
.byte 0,0,0,0,0,0,0,0
/* END(ffi_call_DARWIN) */
+
+/* EH frame stuff. */
+
+#define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */
+#ifdef __64BIT__
+#define PTRSIZE 8
+#define LOG2_PTRSIZE 3
+#define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */
+#define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */
+#else
+#define PTRSIZE 4
+#define LOG2_PTRSIZE 2
+#define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */
+#define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */
+#endif
+ .csect _unwind.ro_[RO],4
+ .align LOG2_PTRSIZE
+ .globl _GLOBAL__F_libffi_src_powerpc_aix
+_GLOBAL__F_libffi_src_powerpc_aix:
+Lframe..1:
+ .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */
+LSCIE..1:
+ .vbyte 4,0 /* CIE Identifier Tag */
+ .byte 0x3 /* CIE Version */
+ .byte "zR" /* CIE Augmentation */
+ .byte 0
+ .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
+ .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */
+ .byte 0x41 /* CIE RA Column */
+ .byte 0x1 /* uleb128 0x1; Augmentation size */
+ .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .byte 0x1 /* uleb128 0x1; Register r1 */
+ .byte 0 /* uleb128 0x0; Offset 0 */
+ .align LOG2_PTRSIZE
+LECIE..1:
+LSFDE..1:
+ .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */
+LASFDE..1:
+ .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */
+ .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */
+ .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */
+ .byte 0 /* uleb128 0x0; Augmentation size */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..0-LFB..0
+ .byte 0x11 /* DW_CFA_def_offset_extended_sf */
+ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */
+ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */
+ .byte 0x9f /* DW_CFA_offset Register r31 */
+ .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */
+ .byte 0x9e /* DW_CFA_offset Register r30 */
+ .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */
+ .byte 0x9d /* DW_CFA_offset Register r29 */
+ .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */
+ .byte 0x9c /* DW_CFA_offset Register r28 */
+ .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..1-LCFI..0
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0x1c /* uleb128 28; Register r28 */
+ .align LOG2_PTRSIZE
+LEFDE..1:
+LSFDE..2:
+ .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */
+LASFDE..2:
+ .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */
+ .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */
+ .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */
+ .byte 0 /* uleb128 0x0; Augmentation size */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..2-LFB..1
+ .byte 0x11 /* DW_CFA_def_offset_extended_sf */
+ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */
+ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */
+ .byte 0x9f /* DW_CFA_offset Register r31 */
+ .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */
+ .byte 0x9e /* DW_CFA_offset Register r30 */
+ .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */
+ .byte 0x9d /* DW_CFA_offset Register r29 */
+ .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */
+ .byte 0x9c /* DW_CFA_offset Register r28 */
+ .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..3-LCFI..2
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0x1c /* uleb128 28; Register r28 */
+ .align LOG2_PTRSIZE
+LEFDE..2:
+ .vbyte 4,0 /* End of FDEs */
+
+ .csect .text[PR]
+ .ref _GLOBAL__F_libffi_src_powerpc_aix /* Prevents garbage collection by AIX linker */
+
diff --git a/src/powerpc/aix_closure.S b/src/powerpc/aix_closure.S
index aabd3c3c..132c785e 100644
--- a/src/powerpc/aix_closure.S
+++ b/src/powerpc/aix_closure.S
@@ -80,6 +80,7 @@
.set f21,21
.extern .ffi_closure_helper_DARWIN
+ .extern .ffi_go_closure_helper_DARWIN
#define LIBFFI_ASM
#define JUMPTARGET(name) name
@@ -101,6 +102,10 @@ ffi_closure_ASM:
.llong .ffi_closure_ASM, TOC[tc0], 0
.csect .text[PR]
.ffi_closure_ASM:
+ .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0
+ .bf __LINE__
+ .line 1
+LFB..0:
/* we want to build up an area for the parameters passed */
/* in registers (both floating point and integer) */
@@ -117,8 +122,7 @@ ffi_closure_ASM:
std r9, 48+(6*8)(r1)
std r10, 48+(7*8)(r1)
std r0, 16(r1) /* save the return address */
-
-
+LCFI..0:
/* 48 Bytes (Linkage Area) */
/* 64 Bytes (params) */
/* 16 Bytes (result) */
@@ -128,6 +132,7 @@ ffi_closure_ASM:
stdu r1, -240(r1) /* skip over caller save area
keep stack aligned to 16 */
+LCFI..1:
/* next save fpr 1 to fpr 13 (aligned to 8) */
stfd f1, 128+(0*8)(r1)
@@ -161,6 +166,8 @@ ffi_closure_ASM:
bl .ffi_closure_helper_DARWIN
nop
+.Ldoneclosure:
+
/* now r3 contains the return type */
/* so use it to look up in a table */
/* so we know how to deal with each type */
@@ -270,12 +277,17 @@ L..finish:
mtlr r0
addi r1, r1, 240
blr
+LFE..0:
#else /* ! __64BIT__ */
.long .ffi_closure_ASM, TOC[tc0], 0
.csect .text[PR]
.ffi_closure_ASM:
+ .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0
+ .bf __LINE__
+ .line 1
+LFB..0:
/* we want to build up an area for the parameters passed */
/* in registers (both floating point and integer) */
@@ -292,7 +304,7 @@ L..finish:
stw r9, 24+(6*4)(r1)
stw r10, 24+(7*4)(r1)
stw r0, 8(r1)
-
+LCFI..0:
/* 24 Bytes (Linkage Area) */
/* 32 Bytes (params) */
/* 16 Bytes (result) */
@@ -301,6 +313,7 @@ L..finish:
stwu r1, -176(r1) /* skip over caller save area
keep stack aligned to 16 */
+LCFI..1:
/* next save fpr 1 to fpr 13 (aligned to 8) */
stfd f1, 72+(0*8)(r1)
@@ -334,6 +347,8 @@ L..finish:
bl .ffi_closure_helper_DARWIN
nop
+.Ldoneclosure:
+
/* now r3 contains the return type */
/* so use it to look up in a table */
/* so we know how to deal with each type */
@@ -443,5 +458,237 @@ L..60:
L..finish:
addi r1, r1, 176
blr
+LFE..0:
#endif
+ .ef __LINE__
/* END(ffi_closure_ASM) */
+
+
+.csect .text[PR]
+ .align 2
+ .globl ffi_go_closure_ASM
+ .globl .ffi_go_closure_ASM
+.csect ffi_go_closure_ASM[DS]
+ffi_go_closure_ASM:
+#ifdef __64BIT__
+ .llong .ffi_go_closure_ASM, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_go_closure_ASM:
+ .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1
+ .bf __LINE__
+ .line 1
+LFB..1:
+/* we want to build up an area for the parameters passed */
+/* in registers (both floating point and integer) */
+
+ /* we store gpr 3 to gpr 10 (aligned to 4)
+ in the parents outgoing 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)
+ mflr r0
+
+ std r7, 48+(4*8)(r1)
+ std r8, 48+(5*8)(r1)
+ std r9, 48+(6*8)(r1)
+ std r10, 48+(7*8)(r1)
+ std r0, 16(r1) /* save the return address */
+LCFI..2:
+ /* 48 Bytes (Linkage Area) */
+ /* 64 Bytes (params) */
+ /* 16 Bytes (result) */
+ /* 104 Bytes (13*8 from FPR) */
+ /* 8 Bytes (alignment) */
+ /* 240 Bytes */
+
+ stdu r1, -240(r1) /* skip over caller save area
+ keep stack aligned to 16 */
+LCFI..3:
+
+ /* next save fpr 1 to fpr 13 (aligned to 8) */
+ stfd f1, 128+(0*8)(r1)
+ stfd f2, 128+(1*8)(r1)
+ stfd f3, 128+(2*8)(r1)
+ stfd f4, 128+(3*8)(r1)
+ stfd f5, 128+(4*8)(r1)
+ stfd f6, 128+(5*8)(r1)
+ stfd f7, 128+(6*8)(r1)
+ stfd f8, 128+(7*8)(r1)
+ stfd f9, 128+(8*8)(r1)
+ stfd f10, 128+(9*8)(r1)
+ stfd f11, 128+(10*8)(r1)
+ stfd f12, 128+(11*8)(r1)
+ stfd f13, 128+(12*8)(r1)
+
+ /* set up registers for the routine that actually does the work */
+ mr r3, r11 /* go closure */
+
+ /* now load up the pointer to the result storage */
+ addi r4, r1, 112
+
+ /* now load up the pointer to the saved gpr registers */
+ addi r5, r1, 288
+
+ /* now load up the pointer to the saved fpr registers */
+ addi r6, r1, 128
+
+ /* make the call */
+ bl .ffi_go_closure_helper_DARWIN
+ nop
+
+ b .Ldoneclosure
+LFE..1:
+
+#else /* ! __64BIT__ */
+
+ .long .ffi_go_closure_ASM, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_go_closure_ASM:
+ .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1
+ .bf __LINE__
+ .line 1
+LFB..1:
+/* we want to build up an area for the parameters passed */
+/* in registers (both floating point and integer) */
+
+ /* we store gpr 3 to gpr 10 (aligned to 4)
+ in the parents outgoing area */
+ stw r3, 24+(0*4)(r1)
+ stw r4, 24+(1*4)(r1)
+ stw r5, 24+(2*4)(r1)
+ stw r6, 24+(3*4)(r1)
+ mflr r0
+
+ stw r7, 24+(4*4)(r1)
+ stw r8, 24+(5*4)(r1)
+ stw r9, 24+(6*4)(r1)
+ stw r10, 24+(7*4)(r1)
+ stw r0, 8(r1)
+LCFI..2:
+ /* 24 Bytes (Linkage Area) */
+ /* 32 Bytes (params) */
+ /* 16 Bytes (result) */
+ /* 104 Bytes (13*8 from FPR) */
+ /* 176 Bytes */
+
+ stwu r1, -176(r1) /* skip over caller save area
+ keep stack aligned to 16 */
+LCFI..3:
+
+ /* next save fpr 1 to fpr 13 (aligned to 8) */
+ stfd f1, 72+(0*8)(r1)
+ stfd f2, 72+(1*8)(r1)
+ stfd f3, 72+(2*8)(r1)
+ stfd f4, 72+(3*8)(r1)
+ stfd f5, 72+(4*8)(r1)
+ stfd f6, 72+(5*8)(r1)
+ stfd f7, 72+(6*8)(r1)
+ stfd f8, 72+(7*8)(r1)
+ stfd f9, 72+(8*8)(r1)
+ stfd f10, 72+(9*8)(r1)
+ stfd f11, 72+(10*8)(r1)
+ stfd f12, 72+(11*8)(r1)
+ stfd f13, 72+(12*8)(r1)
+
+ /* set up registers for the routine that actually does the work */
+ mr r3, 11 /* go closure */
+
+ /* now load up the pointer to the result storage */
+ addi r4, r1, 56
+
+ /* now load up the pointer to the saved gpr registers */
+ addi r5, r1, 200
+
+ /* now load up the pointer to the saved fpr registers */
+ addi r6, r1, 72
+
+ /* make the call */
+ bl .ffi_go_closure_helper_DARWIN
+ nop
+
+ b .Ldoneclosure
+LFE..1:
+#endif
+ .ef __LINE__
+/* END(ffi_go_closure_ASM) */
+
+/* EH frame stuff. */
+
+#define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */
+#ifdef __64BIT__
+#define PTRSIZE 8
+#define LOG2_PTRSIZE 3
+#define CFA_OFFSET 0xf0,0x01 /* LEB128 240 */
+#define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */
+#define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */
+#else
+#define PTRSIZE 4
+#define LOG2_PTRSIZE 2
+#define CFA_OFFSET 0xb0,0x01 /* LEB128 176 */
+#define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */
+#define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */
+#endif
+
+ .csect _unwind.ro_[RO],4
+ .align LOG2_PTRSIZE
+ .globl _GLOBAL__F_libffi_src_powerpc_aix_closure
+_GLOBAL__F_libffi_src_powerpc_aix_closure:
+Lframe..1:
+ .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */
+LSCIE..1:
+ .vbyte 4,0 /* CIE Identifier Tag */
+ .byte 0x3 /* CIE Version */
+ .byte "zR" /* CIE Augmentation */
+ .byte 0
+ .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
+ .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */
+ .byte LR_REGNO /* CIE RA Column */
+ .byte 0x1 /* uleb128 0x1; Augmentation size */
+ .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .byte 0x1 /* uleb128 0x1; Register r1 */
+ .byte 0 /* uleb128 0x0; Offset 0 */
+ .align LOG2_PTRSIZE
+LECIE..1:
+LSFDE..1:
+ .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */
+LASFDE..1:
+ .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */
+ .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */
+ .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */
+ .byte 0 /* uleb128 0x0; Augmentation size */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..1-LCFI..0
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte CFA_OFFSET /* uleb128 176/240 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..0-LFB..0
+ .byte 0x11 /* DW_CFA_offset_extended_sf */
+ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */
+ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */
+ .align LOG2_PTRSIZE
+LEFDE..1:
+LSFDE..2:
+ .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */
+LASFDE..2:
+ .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */
+ .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */
+ .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */
+ .byte 0 /* uleb128 0x0; Augmentation size */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..3-LCFI..2
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte CFA_OFFSET /* uleb128 176/240 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..2-LFB..1
+ .byte 0x11 /* DW_CFA_offset_extended_sf */
+ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */
+ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */
+ .align LOG2_PTRSIZE
+LEFDE..2:
+ .vbyte 4,0 /* End of FDEs */
+
+ .csect .text[PR]
+ .ref _GLOBAL__F_libffi_src_powerpc_aix_closure /* Prevents garbage collection by AIX linker */
+
diff --git a/src/powerpc/asm.h b/src/powerpc/asm.h
index 994f62d0..27b22f67 100644
--- a/src/powerpc/asm.h
+++ b/src/powerpc/asm.h
@@ -93,7 +93,7 @@
/* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes
past a 2^align boundary. */
#ifdef PROF
-#define EALIGN(name, alignt, words) \
+#define EFFI_ALIGN(name, alignt, words) \
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
.align ALIGNARG(2); \
@@ -104,7 +104,7 @@
EALIGN_W_##words; \
0:
#else /* PROF */
-#define EALIGN(name, alignt, words) \
+#define EFFI_ALIGN(name, alignt, words) \
ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
.align ALIGNARG(alignt); \
diff --git a/src/powerpc/darwin_closure.S b/src/powerpc/darwin_closure.S
index c7734d41..3121e6ac 100644
--- a/src/powerpc/darwin_closure.S
+++ b/src/powerpc/darwin_closure.S
@@ -353,7 +353,7 @@ Lret_type13:
bgt Lstructend ; not a special small case
b Lsmallstruct ; see if we need more.
#else
- cmpi 0,r0,4
+ cmpwi 0,r0,4
bgt Lfinish ; not by value
lg r3,0(r5)
b Lfinish
@@ -494,8 +494,8 @@ LSFDE1:
LASFDE1:
.long LASFDE1-EH_frame1 ; FDE CIE offset
.g_long Lstartcode-. ; FDE initial location
- .set L$set$3,LFE1-Lstartcode
- .g_long L$set$3 ; FDE address range
+ .set L$set$2,LFE1-Lstartcode
+ .g_long L$set$2 ; FDE address range
.byte 0x0 ; uleb128 0x0; Augmentation size
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$3,LCFI1-LCFI0
diff --git a/src/powerpc/ffi.c b/src/powerpc/ffi.c
index efb441bb..a19bcbbf 100644
--- a/src/powerpc/ffi.c
+++ b/src/powerpc/ffi.c
@@ -70,8 +70,12 @@ ffi_prep_cif_machdep_var (ffi_cif *cif,
#endif
}
-void
-ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+static void
+ffi_call_int (ffi_cif *cif,
+ void (*fn) (void),
+ void *rvalue,
+ void **avalue,
+ void *closure)
{
/* The final SYSV ABI says that structures smaller or equal 8 bytes
are returned in r3/r4. A draft ABI used by linux instead returns
@@ -81,8 +85,9 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
can write r3 and r4 to memory without worrying about struct size.
For ELFv2 ABI, use a bounce buffer for homogeneous structs too,
- for similar reasons. */
- unsigned long smst_buffer[8];
+ for similar reasons. This bounce buffer must be aligned to 16
+ bytes for use with homogeneous structs of vectors (float128). */
+ float128 smst_buffer[8];
extended_cif ecif;
ecif.cif = cif;
@@ -97,9 +102,10 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
ecif.rvalue = alloca (cif->rtype->size);
#ifdef POWERPC64
- ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn);
+ ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure,
+ -(long) cif->bytes);
#else
- ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
+ ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes);
#endif
/* Check for a bounce-buffered return value */
@@ -116,8 +122,9 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
# endif
/* The SYSV ABI returns a structure of up to 8 bytes in size
left-padded in r3/r4, and the ELFv2 ABI similarly returns a
- structure of up to 8 bytes in size left-padded in r3. */
- if (rsize <= 8)
+ structure of up to 8 bytes in size left-padded in r3. But
+ note that a structure of a single float is not paddded. */
+ if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0)
memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
else
#endif
@@ -125,6 +132,18 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
}
+void
+ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
+{
+ ffi_call_int (cif, fn, rvalue, avalue, NULL);
+}
+
+void
+ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
+ void *closure)
+{
+ ffi_call_int (cif, fn, rvalue, avalue, closure);
+}
ffi_status
ffi_prep_closure_loc (ffi_closure *closure,
@@ -139,3 +158,18 @@ ffi_prep_closure_loc (ffi_closure *closure,
return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc);
#endif
}
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure *closure,
+ ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *))
+{
+#ifdef POWERPC64
+ closure->tramp = ffi_go_closure_linux64;
+#else
+ closure->tramp = ffi_go_closure_sysv;
+#endif
+ closure->cif = cif;
+ closure->fun = fun;
+ return FFI_OK;
+}
diff --git a/src/powerpc/ffi_darwin.c b/src/powerpc/ffi_darwin.c
index cf6fb6d4..61a18c49 100644
--- a/src/powerpc/ffi_darwin.c
+++ b/src/powerpc/ffi_darwin.c
@@ -33,6 +33,7 @@
#include <stdlib.h>
extern void ffi_closure_ASM (void);
+extern void ffi_go_closure_ASM (void);
enum {
/* The assembly depends on these exact flags.
@@ -255,7 +256,7 @@ ffi_prep_args (extended_cif *ecif, unsigned long *const stack)
case FFI_TYPE_STRUCT:
size_al = (*ptr)->size;
#if defined(POWERPC_DARWIN64)
- next_arg = (unsigned long *)ALIGN((char *)next_arg, (*ptr)->alignment);
+ next_arg = (unsigned long *)FFI_ALIGN((char *)next_arg, (*ptr)->alignment);
darwin64_pass_struct_by_value (*ptr, (char *) *p_argv,
(unsigned) size_al,
(unsigned int *) &fparg_count,
@@ -266,7 +267,7 @@ ffi_prep_args (extended_cif *ecif, unsigned long *const stack)
/* If the first member of the struct is a double, then include enough
padding in the struct size to align it to double-word. */
if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE)
- size_al = ALIGN((*ptr)->size, 8);
+ size_al = FFI_ALIGN((*ptr)->size, 8);
# if defined(POWERPC64)
FFI_ASSERT (abi != FFI_DARWIN);
@@ -352,7 +353,7 @@ darwin64_struct_size_exceeds_gprs_p (ffi_type *s, char *src, unsigned *nfpr)
ffi_type *p = s->elements[i];
/* Find the start of this item (0 for the first one). */
if (i > 0)
- struct_offset = ALIGN(struct_offset, p->alignment);
+ struct_offset = FFI_ALIGN(struct_offset, p->alignment);
item_base = src + struct_offset;
@@ -436,7 +437,7 @@ darwin64_pass_struct_floats (ffi_type *s, char *src,
ffi_type *p = s->elements[i];
/* Find the start of this item (0 for the first one). */
if (i > 0)
- struct_offset = ALIGN(struct_offset, p->alignment);
+ struct_offset = FFI_ALIGN(struct_offset, p->alignment);
item_base = src + struct_offset;
switch (p->type)
@@ -527,7 +528,7 @@ darwin64_struct_floats_to_mem (ffi_type *s, char *dest, double *fprs, unsigned *
ffi_type *p = s->elements[i];
/* Find the start of this item (0 for the first one). */
if (i > 0)
- struct_offset = ALIGN(struct_offset, p->alignment);
+ struct_offset = FFI_ALIGN(struct_offset, p->alignment);
item_base = dest + struct_offset;
switch (p->type)
@@ -604,10 +605,10 @@ darwin_adjust_aggregate_sizes (ffi_type *s)
align = 4;
#endif
/* Pad, if necessary, before adding the current item. */
- s->size = ALIGN(s->size, align) + p->size;
+ s->size = FFI_ALIGN(s->size, align) + p->size;
}
- s->size = ALIGN(s->size, s->alignment);
+ s->size = FFI_ALIGN(s->size, s->alignment);
/* This should not be necessary on m64, but harmless. */
if (s->elements[0]->type == FFI_TYPE_UINT64
@@ -640,10 +641,10 @@ aix_adjust_aggregate_sizes (ffi_type *s)
align = p->alignment;
if (i != 0 && p->type == FFI_TYPE_DOUBLE)
align = 4;
- s->size = ALIGN(s->size, align) + p->size;
+ s->size = FFI_ALIGN(s->size, align) + p->size;
}
- s->size = ALIGN(s->size, s->alignment);
+ s->size = FFI_ALIGN(s->size, s->alignment);
if (s->elements[0]->type == FFI_TYPE_UINT64
|| s->elements[0]->type == FFI_TYPE_SINT64
@@ -809,9 +810,9 @@ ffi_prep_cif_machdep (ffi_cif *cif)
16-byte-aligned. */
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
#if defined (POWERPC64)
- intarg_count = ALIGN(intarg_count, 2);
+ intarg_count = FFI_ALIGN(intarg_count, 2);
#else
- intarg_count = ALIGN(intarg_count, 4);
+ intarg_count = FFI_ALIGN(intarg_count, 4);
#endif
break;
#endif
@@ -838,7 +839,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
#if defined(POWERPC_DARWIN64)
align_words = (*ptr)->alignment >> 3;
if (align_words)
- intarg_count = ALIGN(intarg_count, align_words);
+ intarg_count = FFI_ALIGN(intarg_count, align_words);
/* Base size of the struct. */
intarg_count += (size_al + 7) / 8;
/* If 16 bytes then don't worry about floats. */
@@ -848,11 +849,11 @@ ffi_prep_cif_machdep (ffi_cif *cif)
#else
align_words = (*ptr)->alignment >> 2;
if (align_words)
- intarg_count = ALIGN(intarg_count, align_words);
+ intarg_count = FFI_ALIGN(intarg_count, align_words);
/* If the first member of the struct is a double, then align
the struct to double-word.
if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE)
- size_al = ALIGN((*ptr)->size, 8); */
+ size_al = FFI_ALIGN((*ptr)->size, 8); */
# ifdef POWERPC64
intarg_count += (size_al + 7) / 8;
# else
@@ -897,7 +898,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
bytes += NUM_GPR_ARG_REGISTERS * sizeof(long);
/* The stack space allocated needs to be a multiple of 16 bytes. */
- bytes = ALIGN(bytes, 16) ;
+ bytes = FFI_ALIGN(bytes, 16) ;
cif->flags = flags;
cif->bytes = bytes;
@@ -908,6 +909,9 @@ ffi_prep_cif_machdep (ffi_cif *cif)
extern void ffi_call_AIX(extended_cif *, long, unsigned, unsigned *,
void (*fn)(void), void (*fn2)(void));
+extern void ffi_call_go_AIX(extended_cif *, long, unsigned, unsigned *,
+ void (*fn)(void), void (*fn2)(void), void *closure);
+
extern void ffi_call_DARWIN(extended_cif *, long, unsigned, unsigned *,
void (*fn)(void), void (*fn2)(void), ffi_type*);
@@ -946,6 +950,38 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
}
+void
+ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
+ void *closure)
+{
+ extended_cif ecif;
+
+ 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) &&
+ (cif->rtype->type == FFI_TYPE_STRUCT))
+ {
+ ecif.rvalue = alloca (cif->rtype->size);
+ }
+ else
+ ecif.rvalue = rvalue;
+
+ switch (cif->abi)
+ {
+ case FFI_AIX:
+ ffi_call_go_AIX(&ecif, -(long)cif->bytes, cif->flags, ecif.rvalue, fn,
+ FFI_FN(ffi_prep_args), closure);
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
static void flush_icache(char *);
static void flush_range(char *, int);
@@ -1074,6 +1110,30 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*))
+{
+ switch (cif->abi)
+ {
+ case FFI_AIX:
+
+ FFI_ASSERT (cif->abi == FFI_AIX);
+
+ closure->tramp = (void *)ffi_go_closure_ASM;
+ closure->cif = cif;
+ closure->fun = fun;
+ return FFI_OK;
+
+ // For now, ffi_prep_go_closure is only implemented for AIX, not for Darwin
+ default:
+ return FFI_BAD_ABI;
+ break;
+ }
+ return FFI_OK;
+}
+
static void
flush_icache(char *addr)
{
@@ -1108,6 +1168,10 @@ ffi_type *
ffi_closure_helper_DARWIN (ffi_closure *, void *,
unsigned long *, ffi_dblfl *);
+ffi_type *
+ffi_go_closure_helper_DARWIN (ffi_go_closure*, void *,
+ unsigned long *, ffi_dblfl *);
+
/* Basically the trampoline invokes ffi_closure_ASM, and on
entry, r11 holds the address of the closure.
After storing the registers that could possibly contain
@@ -1115,8 +1179,10 @@ ffi_closure_helper_DARWIN (ffi_closure *, void *,
up space for a return value, ffi_closure_ASM invokes the
following helper function to do most of the work. */
-ffi_type *
-ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
+static ffi_type *
+ffi_closure_helper_common (ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data, void *rvalue,
unsigned long *pgr, ffi_dblfl *pfr)
{
/* rvalue is the pointer to space for return value in closure assembly
@@ -1134,14 +1200,12 @@ ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
void ** avalue;
ffi_type ** arg_types;
long i, avn;
- ffi_cif * cif;
ffi_dblfl * end_pfr = pfr + NUM_FPR_ARG_REGISTERS;
unsigned size_al;
#if defined(POWERPC_DARWIN64)
unsigned fpsused = 0;
#endif
- cif = closure->cif;
avalue = alloca (cif->nargs * sizeof(void *));
if (cif->rtype->type == FFI_TYPE_STRUCT)
@@ -1208,7 +1272,7 @@ ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
case FFI_TYPE_STRUCT:
size_al = arg_types[i]->size;
#if defined(POWERPC_DARWIN64)
- pgr = (unsigned long *)ALIGN((char *)pgr, arg_types[i]->alignment);
+ pgr = (unsigned long *)FFI_ALIGN((char *)pgr, arg_types[i]->alignment);
if (size_al < 3 || size_al == 4)
{
avalue[i] = ((char *)pgr)+8-size_al;
@@ -1233,7 +1297,7 @@ ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
/* If the first member of the struct is a double, then align
the struct to double-word. */
if (arg_types[i]->elements[0]->type == FFI_TYPE_DOUBLE)
- size_al = ALIGN(arg_types[i]->size, 8);
+ size_al = FFI_ALIGN(arg_types[i]->size, 8);
# if defined(POWERPC64)
FFI_ASSERT (cif->abi != FFI_DARWIN);
avalue[i] = pgr;
@@ -1352,8 +1416,25 @@ ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
i++;
}
- (closure->fun) (cif, rvalue, avalue, closure->user_data);
+ (fun) (cif, rvalue, avalue, user_data);
/* Tell ffi_closure_ASM to perform return type promotions. */
return cif->rtype;
}
+
+ffi_type *
+ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
+ unsigned long *pgr, ffi_dblfl *pfr)
+{
+ return ffi_closure_helper_common (closure->cif, closure->fun,
+ closure->user_data, rvalue, pgr, pfr);
+}
+
+ffi_type *
+ffi_go_closure_helper_DARWIN (ffi_go_closure *closure, void *rvalue,
+ unsigned long *pgr, ffi_dblfl *pfr)
+{
+ return ffi_closure_helper_common (closure->cif, closure->fun,
+ closure, rvalue, pgr, pfr);
+}
+
diff --git a/src/powerpc/ffi_linux64.c b/src/powerpc/ffi_linux64.c
index b087af8c..de0d0337 100644
--- a/src/powerpc/ffi_linux64.c
+++ b/src/powerpc/ffi_linux64.c
@@ -38,7 +38,8 @@
/* About the LINUX64 ABI. */
enum {
NUM_GPR_ARG_REGISTERS64 = 8,
- NUM_FPR_ARG_REGISTERS64 = 13
+ NUM_FPR_ARG_REGISTERS64 = 13,
+ NUM_VEC_ARG_REGISTERS64 = 12,
};
enum { ASM_NEEDS_REGISTERS64 = 4 };
@@ -62,12 +63,32 @@ ffi_prep_types_linux64 (ffi_abi abi)
#endif
-#if _CALL_ELF == 2
static unsigned int
-discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
+discover_homogeneous_aggregate (ffi_abi abi,
+ const ffi_type *t,
+ unsigned int *elnum)
{
switch (t->type)
{
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ /* 64-bit long doubles are equivalent to doubles. */
+ if ((abi & FFI_LINUX_LONG_DOUBLE_128) == 0)
+ {
+ *elnum = 1;
+ return FFI_TYPE_DOUBLE;
+ }
+ /* IBM extended precision values use unaligned pairs
+ of FPRs, but according to the ABI must be considered
+ distinct from doubles. They are also limited to a
+ maximum of four members in a homogeneous aggregate. */
+ else if ((abi & FFI_LINUX_LONG_DOUBLE_IEEE128) == 0)
+ {
+ *elnum = 2;
+ return FFI_TYPE_LONGDOUBLE;
+ }
+ /* Fall through. */
+#endif
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
*elnum = 1;
@@ -80,14 +101,19 @@ discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
while (*el)
{
unsigned int el_elt, el_elnum = 0;
- el_elt = discover_homogeneous_aggregate (*el, &el_elnum);
+ el_elt = discover_homogeneous_aggregate (abi, *el, &el_elnum);
if (el_elt == 0
|| (base_elt && base_elt != el_elt))
return 0;
base_elt = el_elt;
total_elnum += el_elnum;
+#if _CALL_ELF == 2
if (total_elnum > 8)
return 0;
+#else
+ if (total_elnum > 1)
+ return 0;
+#endif
el++;
}
*elnum = total_elnum;
@@ -98,7 +124,6 @@ discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
return 0;
}
}
-#endif
/* Perform machine dependent cif processing */
@@ -107,15 +132,23 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
{
ffi_type **ptr;
unsigned bytes;
- unsigned i, fparg_count = 0, intarg_count = 0;
+ unsigned i, fparg_count = 0, intarg_count = 0, vecarg_count = 0;
unsigned flags = cif->flags;
-#if _CALL_ELF == 2
- unsigned int elt, elnum;
-#endif
+ unsigned elt, elnum, rtype;
#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
- /* If compiled without long double support.. */
- if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
+ /* If compiled without long double support... */
+ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0 ||
+ (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ return FFI_BAD_ABI;
+#elif !defined(__VEC__)
+ /* If compiled without vector register support (used by assembly)... */
+ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ return FFI_BAD_ABI;
+#else
+ /* If the IEEE128 flag is set, but long double is only 64 bits wide... */
+ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) == 0 &&
+ (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
return FFI_BAD_ABI;
#endif
@@ -137,10 +170,19 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
#endif
/* Return value handling. */
- switch (cif->rtype->type)
+ rtype = cif->rtype->type;
+#if _CALL_ELF == 2
+homogeneous:
+#endif
+ switch (rtype)
{
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
+ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ {
+ flags |= FLAG_RETURNS_VEC;
+ break;
+ }
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
flags |= FLAG_RETURNS_128BITS;
/* Fall through. */
@@ -157,24 +199,24 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
/* Fall through. */
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
+ case FFI_TYPE_POINTER:
flags |= FLAG_RETURNS_64BITS;
break;
case FFI_TYPE_STRUCT:
#if _CALL_ELF == 2
- elt = discover_homogeneous_aggregate (cif->rtype, &elnum);
+ elt = discover_homogeneous_aggregate (cif->abi, cif->rtype, &elnum);
if (elt)
- {
- if (elt == FFI_TYPE_DOUBLE)
- flags |= FLAG_RETURNS_64BITS;
- flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST;
- break;
- }
+ {
+ flags |= FLAG_RETURNS_SMST;
+ rtype = elt;
+ goto homogeneous;
+ }
if (cif->rtype->size <= 16)
- {
- flags |= FLAG_RETURNS_SMST;
- break;
- }
+ {
+ flags |= FLAG_RETURNS_SMST;
+ break;
+ }
#endif
intarg_count++;
flags |= FLAG_RETVAL_REFERENCE;
@@ -196,6 +238,15 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
{
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
+ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ {
+ vecarg_count++;
+ /* Align to 16 bytes, plus the 16-byte argument. */
+ intarg_count = (intarg_count + 3) & ~0x1;
+ if (vecarg_count > NUM_VEC_ARG_REGISTERS64)
+ flags |= FLAG_ARG_NEEDS_PSAVE;
+ break;
+ }
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
{
fparg_count++;
@@ -219,11 +270,21 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
align = 16;
align = align / 8;
if (align > 1)
- intarg_count = ALIGN (intarg_count, align);
+ intarg_count = FFI_ALIGN (intarg_count, align);
}
intarg_count += ((*ptr)->size + 7) / 8;
-#if _CALL_ELF == 2
- elt = discover_homogeneous_aggregate (*ptr, &elnum);
+ elt = discover_homogeneous_aggregate (cif->abi, *ptr, &elnum);
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (elt == FFI_TYPE_LONGDOUBLE &&
+ (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ {
+ vecarg_count += elnum;
+ if (vecarg_count > NUM_VEC_ARG_REGISTERS64)
+ flags |= FLAG_ARG_NEEDS_PSAVE;
+ break;
+ }
+ else
+#endif
if (elt)
{
fparg_count += elnum;
@@ -231,7 +292,6 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
flags |= FLAG_ARG_NEEDS_PSAVE;
}
else
-#endif
{
if (intarg_count > NUM_GPR_ARG_REGISTERS64)
flags |= FLAG_ARG_NEEDS_PSAVE;
@@ -263,10 +323,17 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
flags |= FLAG_FP_ARGUMENTS;
if (intarg_count > 4)
flags |= FLAG_4_GPR_ARGUMENTS;
+ if (vecarg_count != 0)
+ flags |= FLAG_VEC_ARGUMENTS;
/* Space for the FPR registers, if needed. */
if (fparg_count != 0)
bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
+ /* Space for the vector registers, if needed, aligned to 16 bytes. */
+ if (vecarg_count != 0) {
+ bytes = (bytes + 15) & ~0xF;
+ bytes += NUM_VEC_ARG_REGISTERS64 * sizeof (float128);
+ }
/* Stack space. */
#if _CALL_ELF == 2
@@ -349,6 +416,8 @@ ffi_prep_cif_linux64_var (ffi_cif *cif,
|--------------------------------------------| |
| FPR registers f1-f13 (optional) 13*8 | |
|--------------------------------------------| |
+ | VEC registers v2-v13 (optional) 12*16 | |
+ |--------------------------------------------| |
| Parameter save area | |
|--------------------------------------------| |
| TOC save area 8 | |
@@ -378,6 +447,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
unsigned long *ul;
float *f;
double *d;
+ float128 *f128;
size_t p;
} valp;
@@ -391,11 +461,16 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
valp rest;
valp next_arg;
- /* 'fpr_base' points at the space for fpr3, and grows upwards as
+ /* 'fpr_base' points at the space for f1, and grows upwards as
we use FPR registers. */
valp fpr_base;
unsigned int fparg_count;
+ /* 'vec_base' points at the space for v2, and grows upwards as
+ we use vector registers. */
+ valp vec_base;
+ unsigned int vecarg_count;
+
unsigned int i, words, nargs, nfixedargs;
ffi_type **ptr;
double double_tmp;
@@ -412,6 +487,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
unsigned long **ul;
float **f;
double **d;
+ float128 **f128;
} p_argv;
unsigned long gprvalue;
unsigned long align;
@@ -426,11 +502,21 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
#endif
fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
fparg_count = 0;
+ /* Place the vector args below the FPRs, if used, else the GPRs. */
+ if (ecif->cif->flags & FLAG_FP_ARGUMENTS)
+ vec_base.p = fpr_base.p & ~0xF;
+ else
+ vec_base.p = gpr_base.p;
+ vec_base.f128 -= NUM_VEC_ARG_REGISTERS64;
+ vecarg_count = 0;
next_arg.ul = gpr_base.ul;
/* Check that everything starts aligned properly. */
FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
+ FFI_ASSERT (((unsigned long) gpr_base.c & 0xF) == 0);
+ FFI_ASSERT (((unsigned long) gpr_end.c & 0xF) == 0);
+ FFI_ASSERT (((unsigned long) vec_base.c & 0xF) == 0);
FFI_ASSERT ((bytes & 0xF) == 0);
/* Deal with return values that are actually pass-by-reference. */
@@ -449,14 +535,28 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
i < nargs;
i++, ptr++, p_argv.v++)
{
-#if _CALL_ELF == 2
unsigned int elt, elnum;
-#endif
switch ((*ptr)->type)
{
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
+ if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ {
+ next_arg.p = FFI_ALIGN (next_arg.p, 16);
+ if (next_arg.ul == gpr_end.ul)
+ next_arg.ul = rest.ul;
+ if (vecarg_count < NUM_VEC_ARG_REGISTERS64 && i < nfixedargs)
+ *vec_base.f128++ = **p_argv.f128;
+ else
+ *next_arg.f128 = **p_argv.f128;
+ if (++next_arg.f128 == gpr_end.f128)
+ next_arg.f128 = rest.f128;
+ vecarg_count++;
+ FFI_ASSERT (__LDBL_MANT_DIG__ == 113);
+ FFI_ASSERT (flags & FLAG_VEC_ARGUMENTS);
+ break;
+ }
if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
{
double_tmp = (*p_argv.d)[0];
@@ -494,6 +594,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
/* Fall through. */
#endif
case FFI_TYPE_DOUBLE:
+#if _CALL_ELF != 2
+ do_double:
+#endif
double_tmp = **p_argv.d;
if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
{
@@ -512,17 +615,32 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
break;
case FFI_TYPE_FLOAT:
+#if _CALL_ELF != 2
+ do_float:
+#endif
double_tmp = **p_argv.f;
if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
{
*fpr_base.d++ = double_tmp;
#if _CALL_ELF != 2
if ((flags & FLAG_COMPAT) != 0)
- *next_arg.f = (float) double_tmp;
+ {
+# ifndef __LITTLE_ENDIAN__
+ next_arg.f[1] = (float) double_tmp;
+# else
+ next_arg.f[0] = (float) double_tmp;
+# endif
+ }
#endif
}
else
- *next_arg.f = (float) double_tmp;
+ {
+# ifndef __LITTLE_ENDIAN__
+ next_arg.f[1] = (float) double_tmp;
+# else
+ next_arg.f[0] = (float) double_tmp;
+# endif
+ }
if (++next_arg.ul == gpr_end.ul)
next_arg.ul = rest.ul;
fparg_count++;
@@ -536,19 +654,43 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
if (align > 16)
align = 16;
if (align > 1)
- next_arg.p = ALIGN (next_arg.p, align);
+ {
+ next_arg.p = FFI_ALIGN (next_arg.p, align);
+ if (next_arg.ul == gpr_end.ul)
+ next_arg.ul = rest.ul;
+ }
}
-#if _CALL_ELF == 2
- elt = discover_homogeneous_aggregate (*ptr, &elnum);
+ elt = discover_homogeneous_aggregate (ecif->cif->abi, *ptr, &elnum);
if (elt)
{
+#if _CALL_ELF == 2
union {
void *v;
float *f;
double *d;
+ float128 *f128;
} arg;
arg.v = *p_argv.v;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (elt == FFI_TYPE_LONGDOUBLE &&
+ (ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ {
+ do
+ {
+ if (vecarg_count < NUM_VEC_ARG_REGISTERS64
+ && i < nfixedargs)
+ *vec_base.f128++ = *arg.f128++;
+ else
+ *next_arg.f128 = *arg.f128++;
+ if (++next_arg.f128 == gpr_end.f128)
+ next_arg.f128 = rest.f128;
+ vecarg_count++;
+ }
+ while (--elnum != 0);
+ }
+ else
+#endif
if (elt == FFI_TYPE_FLOAT)
{
do
@@ -564,11 +706,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
fparg_count++;
}
while (--elnum != 0);
- if ((next_arg.p & 3) != 0)
- {
- if (++next_arg.f == gpr_end.f)
- next_arg.f = rest.f;
- }
+ if ((next_arg.p & 7) != 0)
+ if (++next_arg.f == gpr_end.f)
+ next_arg.f = rest.f;
}
else
do
@@ -583,9 +723,14 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
fparg_count++;
}
while (--elnum != 0);
+#else
+ if (elt == FFI_TYPE_FLOAT)
+ goto do_float;
+ else
+ goto do_double;
+#endif
}
else
-#endif
{
words = ((*ptr)->size + 7) / 8;
if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
@@ -667,7 +812,8 @@ flush_icache (char *wraddr, char *xaddr, int size)
}
#endif
-ffi_status
+
+ffi_status FFI_HIDDEN
ffi_prep_closure_loc_linux64 (ffi_closure *closure,
ffi_cif *cif,
void (*fun) (ffi_cif *, void *, void **, void *),
@@ -688,17 +834,17 @@ ffi_prep_closure_loc_linux64 (ffi_closure *closure,
/* 2: .quad context */
*(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
*(void **) &tramp[6] = codeloc;
- flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE);
+ flush_icache ((char *) tramp, (char *) codeloc, 4 * 4);
#else
void **tramp = (void **) &closure->tramp[0];
if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
return FFI_BAD_ABI;
- /* Copy function address and TOC from ffi_closure_LINUX64. */
- memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
- tramp[2] = tramp[1];
+ /* Copy function address and TOC from ffi_closure_LINUX64 OPD. */
+ memcpy (&tramp[0], (void **) ffi_closure_LINUX64, sizeof (void *));
tramp[1] = codeloc;
+ memcpy (&tramp[2], (void **) ffi_closure_LINUX64 + 1, sizeof (void *));
#endif
closure->cif = cif;
@@ -710,22 +856,27 @@ ffi_prep_closure_loc_linux64 (ffi_closure *closure,
int FFI_HIDDEN
-ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
- unsigned long *pst, ffi_dblfl *pfr)
+ffi_closure_helper_LINUX64 (ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data,
+ void *rvalue,
+ unsigned long *pst,
+ ffi_dblfl *pfr,
+ float128 *pvec)
{
/* 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 */
+ /* pvec is the pointer to where v2-v13 are stored in ffi_closure_LINUX64 */
void **avalue;
ffi_type **arg_types;
unsigned long i, avn, nfixedargs;
- ffi_cif *cif;
ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
+ float128 *end_pvec = pvec + NUM_VEC_ARG_REGISTERS64;
unsigned long align;
- cif = closure->cif;
avalue = alloca (cif->nargs * sizeof (void *));
/* Copy the caller's structure return value address so that the
@@ -791,19 +942,18 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
if (align > 16)
align = 16;
if (align > 1)
- pst = (unsigned long *) ALIGN ((size_t) pst, align);
+ pst = (unsigned long *) FFI_ALIGN ((size_t) pst, align);
}
- elt = 0;
-#if _CALL_ELF == 2
- elt = discover_homogeneous_aggregate (arg_types[i], &elnum);
-#endif
+ elt = discover_homogeneous_aggregate (cif->abi, arg_types[i], &elnum);
if (elt)
{
+#if _CALL_ELF == 2
union {
void *v;
unsigned long *ul;
float *f;
double *d;
+ float128 *f128;
size_t p;
} to, from;
@@ -811,6 +961,17 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
aggregate size is not greater than the space taken by
the registers so store back to the register/parameter
save arrays. */
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (elt == FFI_TYPE_LONGDOUBLE &&
+ (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ {
+ if (pvec + elnum <= end_pvec)
+ to.v = pvec;
+ else
+ to.v = pst;
+ }
+ else
+#endif
if (pfr + elnum <= end_pfr)
to.v = pfr;
else
@@ -818,6 +979,23 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
avalue[i] = to.v;
from.ul = pst;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (elt == FFI_TYPE_LONGDOUBLE &&
+ (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ {
+ do
+ {
+ if (pvec < end_pvec && i < nfixedargs)
+ *to.f128 = *pvec++;
+ else
+ *to.f128 = *from.f128;
+ to.f128++;
+ from.f128++;
+ }
+ while (--elnum != 0);
+ }
+ else
+#endif
if (elt == FFI_TYPE_FLOAT)
{
do
@@ -850,6 +1028,12 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
}
while (--elnum != 0);
}
+#else
+ if (elt == FFI_TYPE_FLOAT)
+ goto do_float;
+ else
+ goto do_double;
+#endif
}
else
{
@@ -867,7 +1051,18 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
- if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
+ if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
+ {
+ if (((unsigned long) pst & 0xF) != 0)
+ ++pst;
+ if (pvec < end_pvec && i < nfixedargs)
+ avalue[i] = pvec++;
+ else
+ avalue[i] = pst;
+ pst += 2;
+ break;
+ }
+ else if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
{
if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
{
@@ -891,6 +1086,9 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
/* Fall through. */
#endif
case FFI_TYPE_DOUBLE:
+#if _CALL_ELF != 2
+ do_double:
+#endif
/* On the outgoing stack all values are aligned to 8 */
/* there are 13 64bit floating point registers */
@@ -905,6 +1103,9 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
break;
case FFI_TYPE_FLOAT:
+#if _CALL_ELF != 2
+ do_float:
+#endif
if (pfr < end_pfr && i < nfixedargs)
{
/* Float values are stored as doubles in the
@@ -914,7 +1115,13 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
pfr++;
}
else
- avalue[i] = pst;
+ {
+#ifndef __LITTLE_ENDIAN__
+ avalue[i] = (char *) pst + 4;
+#else
+ avalue[i] = pst;
+#endif
+ }
pst++;
break;
@@ -925,19 +1132,22 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
i++;
}
-
- (closure->fun) (cif, rvalue, avalue, closure->user_data);
+ (*fun) (cif, rvalue, avalue, user_data);
/* Tell ffi_closure_LINUX64 how to perform return type promotions. */
if ((cif->flags & FLAG_RETURNS_SMST) != 0)
{
- if ((cif->flags & FLAG_RETURNS_FP) == 0)
+ if ((cif->flags & (FLAG_RETURNS_FP | FLAG_RETURNS_VEC)) == 0)
return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
+ else if ((cif->flags & FLAG_RETURNS_VEC) != 0)
+ return FFI_V2_TYPE_VECTOR_HOMOG;
else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
return FFI_V2_TYPE_DOUBLE_HOMOG;
else
return FFI_V2_TYPE_FLOAT_HOMOG;
}
+ if ((cif->flags & FLAG_RETURNS_VEC) != 0)
+ return FFI_V2_TYPE_VECTOR;
return cif->rtype->type;
}
#endif
diff --git a/src/powerpc/ffi_powerpc.h b/src/powerpc/ffi_powerpc.h
index 2e61653d..5ee2a709 100644
--- a/src/powerpc/ffi_powerpc.h
+++ b/src/powerpc/ffi_powerpc.h
@@ -31,22 +31,24 @@
enum {
/* The assembly depends on these exact flags. */
/* These go in cr7 */
- FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */
+ FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */
FLAG_RETURNS_NOTHING = 1 << (31-30),
FLAG_RETURNS_FP = 1 << (31-29),
- FLAG_RETURNS_64BITS = 1 << (31-28),
+ FLAG_RETURNS_VEC = 1 << (31-28),
- /* This goes in cr6 */
- FLAG_RETURNS_128BITS = 1 << (31-27),
+ /* These go in cr6 */
+ FLAG_RETURNS_64BITS = 1 << (31-27),
+ FLAG_RETURNS_128BITS = 1 << (31-26),
- FLAG_COMPAT = 1 << (31- 8), /* Not used by assembly */
+ FLAG_COMPAT = 1 << (31- 8), /* Not used by assembly */
/* These go in cr1 */
FLAG_ARG_NEEDS_COPY = 1 << (31- 7), /* Used by sysv code */
FLAG_ARG_NEEDS_PSAVE = FLAG_ARG_NEEDS_COPY, /* Used by linux64 code */
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
- FLAG_RETVAL_REFERENCE = 1 << (31- 4)
+ FLAG_RETVAL_REFERENCE = 1 << (31- 4),
+ FLAG_VEC_ARGUMENTS = 1 << (31- 3),
};
typedef union
@@ -55,23 +57,49 @@ typedef union
double d;
} ffi_dblfl;
+#if defined(__FLOAT128_TYPE__)
+typedef _Float128 float128;
+#elif defined(__FLOAT128__)
+typedef __float128 float128;
+#else
+typedef __int128 float128;
+#endif
+
void FFI_HIDDEN ffi_closure_SYSV (void);
-void FFI_HIDDEN ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *,
- void (*)(void));
+void FFI_HIDDEN ffi_go_closure_sysv (void);
+void FFI_HIDDEN ffi_call_SYSV(extended_cif *, void (*)(void), void *,
+ unsigned, void *, int);
void FFI_HIDDEN ffi_prep_types_sysv (ffi_abi);
ffi_status FFI_HIDDEN ffi_prep_cif_sysv (ffi_cif *);
-int FFI_HIDDEN ffi_closure_helper_SYSV (ffi_closure *, void *, unsigned long *,
+ffi_status FFI_HIDDEN ffi_prep_closure_loc_sysv (ffi_closure *,
+ ffi_cif *,
+ void (*) (ffi_cif *, void *,
+ void **, void *),
+ void *, void *);
+int FFI_HIDDEN ffi_closure_helper_SYSV (ffi_cif *,
+ void (*) (ffi_cif *, void *,
+ void **, void *),
+ void *, void *, unsigned long *,
ffi_dblfl *, unsigned long *);
-void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long, unsigned long,
- unsigned long *, void (*)(void));
+void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, void (*) (void), void *,
+ unsigned long, void *, long);
void FFI_HIDDEN ffi_closure_LINUX64 (void);
+void FFI_HIDDEN ffi_go_closure_linux64 (void);
void FFI_HIDDEN ffi_prep_types_linux64 (ffi_abi);
ffi_status FFI_HIDDEN ffi_prep_cif_linux64 (ffi_cif *);
ffi_status FFI_HIDDEN ffi_prep_cif_linux64_var (ffi_cif *, unsigned int,
unsigned int);
void FFI_HIDDEN ffi_prep_args64 (extended_cif *, unsigned long *const);
-int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,
- unsigned long *, ffi_dblfl *);
+ffi_status FFI_HIDDEN ffi_prep_closure_loc_linux64 (ffi_closure *, ffi_cif *,
+ void (*) (ffi_cif *, void *,
+ void **, void *),
+ void *, void *);
+int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_cif *,
+ void (*) (ffi_cif *, void *,
+ void **, void *),
+ void *, void *,
+ unsigned long *, ffi_dblfl *,
+ float128 *);
diff --git a/src/powerpc/ffi_sysv.c b/src/powerpc/ffi_sysv.c
index fbe85fe9..4078e751 100644
--- a/src/powerpc/ffi_sysv.c
+++ b/src/powerpc/ffi_sysv.c
@@ -36,7 +36,7 @@
/* About the SYSV ABI. */
-#define ASM_NEEDS_REGISTERS 4
+#define ASM_NEEDS_REGISTERS 6
#define NUM_GPR_ARG_REGISTERS 8
#define NUM_FPR_ARG_REGISTERS 8
@@ -93,7 +93,7 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
{
ffi_type **ptr;
unsigned bytes;
- unsigned i, fparg_count = 0, intarg_count = 0;
+ unsigned i, fpr_count = 0, gpr_count = 0, stack_count = 0;
unsigned flags = cif->flags;
unsigned struct_copy_size = 0;
unsigned type = cif->rtype->type;
@@ -155,7 +155,7 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
flags |= FLAG_RETURNS_SMST;
break;
}
- intarg_count++;
+ gpr_count++;
flags |= FLAG_RETVAL_REFERENCE;
/* Fall through. */
case FFI_TYPE_VOID:
@@ -182,24 +182,41 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
{
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
- fparg_count++;
- /* Fall thru */
+ if (fpr_count >= NUM_FPR_ARG_REGISTERS - 1)
+ {
+ fpr_count = NUM_FPR_ARG_REGISTERS;
+ /* 8-byte align long doubles. */
+ stack_count += stack_count & 1;
+ stack_count += 4;
+ }
+ else
+ fpr_count += 2;
+#ifdef __NO_FPRS__
+ return FFI_BAD_ABI;
#endif
+ break;
+#endif
+
case FFI_TYPE_DOUBLE:
- fparg_count++;
- /* If this FP arg is going on the stack, it must be
- 8-byte-aligned. */
- if (fparg_count > NUM_FPR_ARG_REGISTERS
- && intarg_count >= NUM_GPR_ARG_REGISTERS
- && intarg_count % 2 != 0)
- intarg_count++;
+ if (fpr_count >= NUM_FPR_ARG_REGISTERS)
+ {
+ /* 8-byte align doubles. */
+ stack_count += stack_count & 1;
+ stack_count += 2;
+ }
+ else
+ fpr_count += 1;
#ifdef __NO_FPRS__
return FFI_BAD_ABI;
#endif
break;
case FFI_TYPE_FLOAT:
- fparg_count++;
+ if (fpr_count >= NUM_FPR_ARG_REGISTERS)
+ /* Yes, we don't follow the ABI, but neither does gcc. */
+ stack_count += 1;
+ else
+ fpr_count += 1;
#ifdef __NO_FPRS__
return FFI_BAD_ABI;
#endif
@@ -208,11 +225,13 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
case FFI_TYPE_UINT128:
/* A long double in FFI_LINUX_SOFT_FLOAT can use only a set
of four consecutive gprs. If we do not have enough, we
- have to adjust the intarg_count value. */
- if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
- && intarg_count < NUM_GPR_ARG_REGISTERS)
- intarg_count = NUM_GPR_ARG_REGISTERS;
- intarg_count += 4;
+ have to adjust the gpr_count value. */
+ if (gpr_count >= NUM_GPR_ARG_REGISTERS - 3)
+ gpr_count = NUM_GPR_ARG_REGISTERS;
+ if (gpr_count >= NUM_GPR_ARG_REGISTERS)
+ stack_count += 4;
+ else
+ gpr_count += 4;
break;
case FFI_TYPE_UINT64:
@@ -225,10 +244,14 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
Also, only certain register pairs can be used for
passing long long int -- specifically (r3,r4), (r5,r6),
(r7,r8), (r9,r10). */
- if (intarg_count == NUM_GPR_ARG_REGISTERS-1
- || intarg_count % 2 != 0)
- intarg_count++;
- intarg_count += 2;
+ gpr_count += gpr_count & 1;
+ if (gpr_count >= NUM_GPR_ARG_REGISTERS)
+ {
+ stack_count += stack_count & 1;
+ stack_count += 2;
+ }
+ else
+ gpr_count += 2;
break;
case FFI_TYPE_STRUCT:
@@ -249,7 +272,10 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
case FFI_TYPE_SINT8:
/* Everything else is passed as a 4-byte word in a GPR, either
the object itself or a pointer to it. */
- intarg_count++;
+ if (gpr_count >= NUM_GPR_ARG_REGISTERS)
+ stack_count += 1;
+ else
+ gpr_count += 1;
break;
default:
@@ -257,22 +283,19 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
}
}
- if (fparg_count != 0)
+ if (fpr_count != 0)
flags |= FLAG_FP_ARGUMENTS;
- if (intarg_count > 4)
+ if (gpr_count > 4)
flags |= FLAG_4_GPR_ARGUMENTS;
if (struct_copy_size != 0)
flags |= FLAG_ARG_NEEDS_COPY;
/* Space for the FPR registers, if needed. */
- if (fparg_count != 0)
+ if (fpr_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);
+ bytes += stack_count * sizeof (int);
/* The stack space allocated needs to be a multiple of 16 bytes. */
bytes = (bytes + 15) & ~0xF;
@@ -367,13 +390,13 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
/* 'gpr_base' points at the space for gpr3, and grows upwards as
we use GPR registers. */
valp gpr_base;
- int intarg_count;
+ valp gpr_end;
#ifndef __NO_FPRS__
/* 'fpr_base' points at the space for fpr1, and grows upwards as
we use FPR registers. */
valp fpr_base;
- int fparg_count;
+ valp fpr_end;
#endif
/* 'copy_space' grows down as we put structures in it. It should
@@ -405,11 +428,11 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
unsigned gprvalue;
stacktop.c = (char *) stack + bytes;
- gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
- intarg_count = 0;
+ gpr_end.u = stacktop.u - ASM_NEEDS_REGISTERS;
+ gpr_base.u = gpr_end.u - NUM_GPR_ARG_REGISTERS;
#ifndef __NO_FPRS__
- fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS;
- fparg_count = 0;
+ fpr_end.d = gpr_base.d;
+ fpr_base.d = fpr_end.d - NUM_FPR_ARG_REGISTERS;
copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
#else
copy_space.c = gpr_base.c;
@@ -425,10 +448,7 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
/* Deal with return values that are actually pass-by-reference. */
if (flags & FLAG_RETVAL_REFERENCE)
- {
- *gpr_base.u++ = (unsigned long) (char *) ecif->rvalue;
- intarg_count++;
- }
+ *gpr_base.u++ = (unsigned) (char *) ecif->rvalue;
/* Now for the arguments. */
p_argv.v = ecif->avalue;
@@ -448,14 +468,11 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
case FFI_TYPE_LONGDOUBLE:
double_tmp = (*p_argv.d)[0];
- if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
+ if (fpr_base.d >= fpr_end.d - 1)
{
- if (intarg_count >= NUM_GPR_ARG_REGISTERS
- && intarg_count % 2 != 0)
- {
- intarg_count++;
- next_arg.u++;
- }
+ fpr_base.d = fpr_end.d;
+ if (((next_arg.u - stack) & 1) != 0)
+ next_arg.u += 1;
*next_arg.d = double_tmp;
next_arg.u += 2;
double_tmp = (*p_argv.d)[1];
@@ -468,42 +485,33 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
double_tmp = (*p_argv.d)[1];
*fpr_base.d++ = double_tmp;
}
-
- fparg_count += 2;
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
break;
# endif
case FFI_TYPE_DOUBLE:
double_tmp = **p_argv.d;
- if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ if (fpr_base.d >= fpr_end.d)
{
- if (intarg_count >= NUM_GPR_ARG_REGISTERS
- && intarg_count % 2 != 0)
- {
- intarg_count++;
- next_arg.u++;
- }
+ if (((next_arg.u - stack) & 1) != 0)
+ next_arg.u += 1;
*next_arg.d = double_tmp;
next_arg.u += 2;
}
else
*fpr_base.d++ = double_tmp;
- fparg_count++;
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
break;
case FFI_TYPE_FLOAT:
double_tmp = **p_argv.f;
- if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ if (fpr_base.d >= fpr_end.d)
{
*next_arg.f = (float) double_tmp;
next_arg.u += 1;
- intarg_count++;
}
else
*fpr_base.d++ = double_tmp;
- fparg_count++;
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
break;
#endif /* have FPRs */
@@ -513,42 +521,34 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
is passed in four consecutive GPRs if available. A maximum of 2
long doubles can be passed in gprs. If we do not have 4 GPRs
left, the long double is passed on the stack, 4-byte aligned. */
- {
- unsigned int int_tmp;
- unsigned int ii;
- if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3)
- {
- if (intarg_count < NUM_GPR_ARG_REGISTERS)
- intarg_count = NUM_GPR_ARG_REGISTERS;
- for (ii = 0; ii < 4; ii++)
- {
- int_tmp = (*p_argv.ui)[ii];
- *next_arg.u++ = int_tmp;
- }
- }
- else
- {
- for (ii = 0; ii < 4; ii++)
- {
- int_tmp = (*p_argv.ui)[ii];
- *gpr_base.u++ = int_tmp;
- }
- }
- intarg_count += 4;
- break;
- }
+ if (gpr_base.u >= gpr_end.u - 3)
+ {
+ unsigned int ii;
+ gpr_base.u = gpr_end.u;
+ for (ii = 0; ii < 4; ii++)
+ {
+ unsigned int int_tmp = (*p_argv.ui)[ii];
+ *next_arg.u++ = int_tmp;
+ }
+ }
+ else
+ {
+ unsigned int ii;
+ for (ii = 0; ii < 4; ii++)
+ {
+ unsigned int int_tmp = (*p_argv.ui)[ii];
+ *gpr_base.u++ = int_tmp;
+ }
+ }
+ break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
- if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
- intarg_count++;
- if (intarg_count >= NUM_GPR_ARG_REGISTERS)
+ if (gpr_base.u >= gpr_end.u - 1)
{
- if (intarg_count % 2 != 0)
- {
- intarg_count++;
- next_arg.u++;
- }
+ gpr_base.u = gpr_end.u;
+ if (((next_arg.u - stack) & 1) != 0)
+ next_arg.u++;
*next_arg.ll = **p_argv.ll;
next_arg.u += 2;
}
@@ -559,14 +559,10 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
(r5,r6), (r7,r8), (r9,r10). If next arg is long long
but not correct starting register of pair then skip
until the proper starting register. */
- if (intarg_count % 2 != 0)
- {
- intarg_count ++;
- gpr_base.u++;
- }
+ if (((gpr_end.u - gpr_base.u) & 1) != 0)
+ gpr_base.u++;
*gpr_base.ll++ = **p_argv.ll;
}
- intarg_count += 2;
break;
case FFI_TYPE_STRUCT:
@@ -601,29 +597,22 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
gprvalue = **p_argv.ui;
putgpr:
- if (intarg_count >= NUM_GPR_ARG_REGISTERS)
+ if (gpr_base.u >= gpr_end.u)
*next_arg.u++ = gprvalue;
else
*gpr_base.u++ = gprvalue;
- intarg_count++;
break;
}
}
/* Check that we didn't overrun the stack... */
FFI_ASSERT (copy_space.c >= next_arg.c);
- FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS);
- /* The assert below is testing that the number of integer arguments agrees
- with the number found in ffi_prep_cif_machdep(). However, intarg_count
- is incremented whenever we place an FP arg on the stack, so account for
- that before our assert test. */
+ FFI_ASSERT (gpr_base.u <= gpr_end.u);
#ifndef __NO_FPRS__
- if (fparg_count > NUM_FPR_ARG_REGISTERS)
- intarg_count -= fparg_count - NUM_FPR_ARG_REGISTERS;
- FFI_ASSERT (fpr_base.u
- <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
+ FFI_ASSERT (fpr_base.u <= fpr_end.u);
#endif
- FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
+ FFI_ASSERT (((flags & FLAG_4_GPR_ARGUMENTS) != 0)
+ == (gpr_end.u - gpr_base.u < 4));
}
#define MIN_CACHE_LINE_SIZE 8
@@ -654,18 +643,18 @@ ffi_prep_closure_loc_sysv (ffi_closure *closure,
tramp = (unsigned int *) &closure->tramp[0];
tramp[0] = 0x7c0802a6; /* mflr r0 */
- tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */
- tramp[4] = 0x7d6802a6; /* mflr r11 */
- tramp[5] = 0x7c0803a6; /* mtlr r0 */
- tramp[6] = 0x800b0000; /* lwz r0,0(r11) */
- tramp[7] = 0x816b0004; /* lwz r11,4(r11) */
- tramp[8] = 0x7c0903a6; /* mtctr r0 */
- tramp[9] = 0x4e800420; /* bctr */
- *(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */
- *(void **) &tramp[3] = codeloc; /* context */
+ tramp[1] = 0x429f0005; /* bcl 20,31,.+4 */
+ tramp[2] = 0x7d6802a6; /* mflr r11 */
+ tramp[3] = 0x7c0803a6; /* mtlr r0 */
+ tramp[4] = 0x800b0018; /* lwz r0,24(r11) */
+ tramp[5] = 0x816b001c; /* lwz r11,28(r11) */
+ tramp[6] = 0x7c0903a6; /* mtctr r0 */
+ tramp[7] = 0x4e800420; /* bctr */
+ *(void **) &tramp[8] = (void *) ffi_closure_SYSV; /* function */
+ *(void **) &tramp[9] = codeloc; /* context */
/* Flush the icache. */
- flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE);
+ flush_icache ((char *)tramp, (char *)codeloc, 8 * 4);
closure->cif = cif;
closure->fun = fun;
@@ -682,8 +671,12 @@ ffi_prep_closure_loc_sysv (ffi_closure *closure,
following helper function to do most of the work. */
int
-ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
- unsigned long *pgr, ffi_dblfl *pfr,
+ffi_closure_helper_SYSV (ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data,
+ void *rvalue,
+ unsigned long *pgr,
+ ffi_dblfl *pfr,
unsigned long *pst)
{
/* rvalue is the pointer to space for return value in closure assembly */
@@ -699,7 +692,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
#endif
long ng = 0; /* number of general registers already used */
- ffi_cif *cif = closure->cif;
unsigned size = cif->rtype->size;
unsigned short rtypenum = cif->rtype->type;
@@ -915,7 +907,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
i++;
}
- (closure->fun) (cif, rvalue, avalue, closure->user_data);
+ (*fun) (cif, rvalue, avalue, user_data);
/* Tell ffi_closure_SYSV how to perform return type promotions.
Because the FFI_SYSV ABI returns the structures <= 8 bytes in
diff --git a/src/powerpc/ffitarget.h b/src/powerpc/ffitarget.h
index b47b0f5d..7fb9a939 100644
--- a/src/powerpc/ffitarget.h
+++ b/src/powerpc/ffitarget.h
@@ -91,15 +91,19 @@ typedef enum ffi_abi {
/* This and following bits can reuse FFI_COMPAT values. */
FFI_LINUX_STRUCT_ALIGN = 1,
FFI_LINUX_LONG_DOUBLE_128 = 2,
+ FFI_LINUX_LONG_DOUBLE_IEEE128 = 4,
FFI_DEFAULT_ABI = (FFI_LINUX
# ifdef __STRUCT_PARM_ALIGN__
| FFI_LINUX_STRUCT_ALIGN
# endif
# ifdef __LONG_DOUBLE_128__
| FFI_LINUX_LONG_DOUBLE_128
+# ifdef __LONG_DOUBLE_IEEE128__
+ | FFI_LINUX_LONG_DOUBLE_IEEE128
+# endif
# endif
),
- FFI_LAST_ABI = 12
+ FFI_LAST_ABI = 16
# else
/* This bit, always set in new code, must not be set in any of the
@@ -138,23 +142,40 @@ typedef enum ffi_abi {
#define FFI_CLOSURES 1
#define FFI_NATIVE_RAW_API 0
#if defined (POWERPC) || defined (POWERPC_FREEBSD)
+# define FFI_GO_CLOSURES 1
# define FFI_TARGET_SPECIFIC_VARIADIC 1
# define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs
#endif
+#if defined (POWERPC_AIX)
+# define FFI_GO_CLOSURES 1
+#endif
+
+/* ppc_closure.S and linux64_closure.S expect this. */
+#define FFI_PPC_TYPE_LAST FFI_TYPE_POINTER
-/* For additional types like the below, take care about the order in
- ppc_closures.S. They must follow after the FFI_TYPE_LAST. */
+/* We define additional types below. If generic types are added that
+ must be supported by powerpc libffi then it is likely that
+ FFI_PPC_TYPE_LAST needs increasing *and* the jump tables in
+ ppc_closure.S and linux64_closure.S be extended. */
+
+#if !(FFI_TYPE_LAST == FFI_PPC_TYPE_LAST \
+ || (FFI_TYPE_LAST == FFI_TYPE_COMPLEX \
+ && !defined FFI_TARGET_HAS_COMPLEX_TYPE))
+# error "You likely have a broken powerpc libffi"
+#endif
/* Needed for soft-float long-double-128 support. */
-#define FFI_TYPE_UINT128 (FFI_TYPE_LAST + 1)
+#define FFI_TYPE_UINT128 (FFI_PPC_TYPE_LAST + 1)
/* Needed for FFI_SYSV small structure returns. */
-#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2)
+#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2)
/* Used by ELFv2 for homogenous structure returns. */
-#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_TYPE_LAST + 1)
-#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_TYPE_LAST + 2)
-#define FFI_V2_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 3)
+#define FFI_V2_TYPE_VECTOR (FFI_PPC_TYPE_LAST + 1)
+#define FFI_V2_TYPE_VECTOR_HOMOG (FFI_PPC_TYPE_LAST + 2)
+#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 3)
+#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 4)
+#define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 5)
#if _CALL_ELF == 2
# define FFI_TRAMPOLINE_SIZE 32
diff --git a/src/powerpc/linux64.S b/src/powerpc/linux64.S
index d2acb700..c99889c1 100644
--- a/src/powerpc/linux64.S
+++ b/src/powerpc/linux64.S
@@ -32,8 +32,9 @@
#ifdef POWERPC64
.hidden ffi_call_LINUX64
.globl ffi_call_LINUX64
-# if _CALL_ELF == 2
.text
+ .cfi_startproc
+# if _CALL_ELF == 2
ffi_call_LINUX64:
addis %r2, %r12, .TOC.-ffi_call_LINUX64@ha
addi %r2, %r2, .TOC.-ffi_call_LINUX64@l
@@ -57,20 +58,26 @@ ffi_call_LINUX64:
.ffi_call_LINUX64:
# endif
# endif
-.LFB1:
mflr %r0
std %r28, -32(%r1)
std %r29, -24(%r1)
std %r30, -16(%r1)
std %r31, -8(%r1)
+ std %r7, 8(%r1) /* closure, saved in cr field. */
std %r0, 16(%r1)
mr %r28, %r1 /* our AP. */
-.LCFI0:
- stdux %r1, %r1, %r4
- mr %r31, %r5 /* flags, */
- mr %r30, %r6 /* rvalue, */
- mr %r29, %r7 /* function address. */
+ .cfi_def_cfa_register 28
+ .cfi_offset 65, 16
+ .cfi_offset 31, -8
+ .cfi_offset 30, -16
+ .cfi_offset 29, -24
+ .cfi_offset 28, -32
+
+ stdux %r1, %r1, %r8
+ mr %r31, %r6 /* flags, */
+ mr %r30, %r5 /* rvalue, */
+ mr %r29, %r4 /* function address. */
/* Save toc pointer, not for the ffi_prep_args64 call, but for the later
bctrl function call. */
# if _CALL_ELF == 2
@@ -92,44 +99,74 @@ ffi_call_LINUX64:
# else
ld %r12, 0(%r29)
ld %r2, 8(%r29)
- ld %r11, 16(%r29)
# endif
/* Now do the call. */
- /* Set up cr1 with bits 4-7 of the flags. */
- mtcrf 0x40, %r31
+ /* Set up cr1 with bits 3-7 of the flags. */
+ mtcrf 0xc0, %r31
/* Get the address to call into CTR. */
mtctr %r12
/* 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)
+ addi %r29, %r28, -32-(8*8)
+ ld %r3, (0*8)(%r29)
+ ld %r4, (1*8)(%r29)
+ ld %r5, (2*8)(%r29)
+ ld %r6, (3*8)(%r29)
bf- 5, 1f
- ld %r7, -32-(4*8)(%r28)
- ld %r8, -32-(3*8)(%r28)
- ld %r9, -32-(2*8)(%r28)
- ld %r10, -32-(1*8)(%r28)
+ ld %r7, (4*8)(%r29)
+ ld %r8, (5*8)(%r29)
+ ld %r9, (6*8)(%r29)
+ ld %r10, (7*8)(%r29)
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)
+ addi %r29, %r29, -(14*8)
+ lfd %f1, ( 1*8)(%r29)
+ lfd %f2, ( 2*8)(%r29)
+ lfd %f3, ( 3*8)(%r29)
+ lfd %f4, ( 4*8)(%r29)
+ lfd %f5, ( 5*8)(%r29)
+ lfd %f6, ( 6*8)(%r29)
+ lfd %f7, ( 7*8)(%r29)
+ lfd %f8, ( 8*8)(%r29)
+ lfd %f9, ( 9*8)(%r29)
+ lfd %f10, (10*8)(%r29)
+ lfd %f11, (11*8)(%r29)
+ lfd %f12, (12*8)(%r29)
+ lfd %f13, (13*8)(%r29)
2:
+ /* Load all the vector registers. */
+ bf- 3, 3f
+ addi %r29, %r29, -16
+ lvx %v13, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v12, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v11, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v10, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v9, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v8, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v7, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v6, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v5, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v4, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v3, 0, %r29
+ addi %r29, %r29, -16
+ lvx %v2, 0, %r29
+3:
+
/* Make the call. */
+ ld %r11, 8(%r28)
bctrl
/* This must follow the call immediately, the unwinder
@@ -145,12 +182,14 @@ ffi_call_LINUX64:
bt 31, .Lstruct_return_value
bt 30, .Ldone_return_value
bt 29, .Lfp_return_value
+ bt 28, .Lvec_return_value
std %r3, 0(%r30)
/* Fall through... */
.Ldone_return_value:
/* Restore the registers we used and return. */
mr %r1, %r28
+ .cfi_def_cfa_register 1
ld %r0, 16(%r28)
ld %r28, -32(%r28)
mtlr %r0
@@ -159,11 +198,16 @@ ffi_call_LINUX64:
ld %r31, -8(%r1)
blr
+.Lvec_return_value:
+ stvx %v2, 0, %r30
+ b .Ldone_return_value
+
.Lfp_return_value:
- bf 28, .Lfloat_return_value
- stfd %f1, 0(%r30)
+ .cfi_def_cfa_register 28
mtcrf 0x02, %r31 /* cr6 */
- bf 27, .Ldone_return_value
+ bf 27, .Lfloat_return_value
+ stfd %f1, 0(%r30)
+ bf 26, .Ldone_return_value
stfd %f2, 8(%r30)
b .Ldone_return_value
.Lfloat_return_value:
@@ -171,8 +215,9 @@ ffi_call_LINUX64:
b .Ldone_return_value
.Lstruct_return_value:
- bf 29, .Lsmall_struct
- bf 28, .Lfloat_homog_return_value
+ bf 29, .Lvec_homog_or_small_struct
+ mtcrf 0x02, %r31 /* cr6 */
+ bf 27, .Lfloat_homog_return_value
stfd %f1, 0(%r30)
stfd %f2, 8(%r30)
stfd %f3, 16(%r30)
@@ -194,66 +239,43 @@ ffi_call_LINUX64:
stfs %f8, 28(%r30)
b .Ldone_return_value
+.Lvec_homog_or_small_struct:
+ bf 28, .Lsmall_struct
+ stvx %v2, 0, %r30
+ addi %r30, %r30, 16
+ stvx %v3, 0, %r30
+ addi %r30, %r30, 16
+ stvx %v4, 0, %r30
+ addi %r30, %r30, 16
+ stvx %v5, 0, %r30
+ addi %r30, %r30, 16
+ stvx %v6, 0, %r30
+ addi %r30, %r30, 16
+ stvx %v7, 0, %r30
+ addi %r30, %r30, 16
+ stvx %v8, 0, %r30
+ addi %r30, %r30, 16
+ stvx %v9, 0, %r30
+ b .Ldone_return_value
+
.Lsmall_struct:
std %r3, 0(%r30)
std %r4, 8(%r30)
b .Ldone_return_value
-.LFE1:
- .long 0
- .byte 0,12,0,1,128,4,0,0
+ .cfi_endproc
# if _CALL_ELF == 2
.size ffi_call_LINUX64,.-ffi_call_LINUX64
# else
# ifdef _CALL_LINUX
.size ffi_call_LINUX64,.-.L.ffi_call_LINUX64
# else
+ .long 0
+ .byte 0,12,0,1,128,4,0,0
.size .ffi_call_LINUX64,.-.ffi_call_LINUX64
# endif
# endif
- .section .eh_frame,EH_FRAME_FLAGS,@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
#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
diff --git a/src/powerpc/linux64_closure.S b/src/powerpc/linux64_closure.S
index 97421a43..d67e4bbb 100644
--- a/src/powerpc/linux64_closure.S
+++ b/src/powerpc/linux64_closure.S
@@ -33,8 +33,9 @@
#ifdef POWERPC64
FFI_HIDDEN (ffi_closure_LINUX64)
.globl ffi_closure_LINUX64
-# if _CALL_ELF == 2
.text
+ .cfi_startproc
+# if _CALL_ELF == 2
ffi_closure_LINUX64:
addis %r2, %r12, .TOC.-ffi_closure_LINUX64@ha
addi %r2, %r2, .TOC.-ffi_closure_LINUX64@l
@@ -60,9 +61,15 @@ ffi_closure_LINUX64:
# endif
# if _CALL_ELF == 2
-# 32 byte special reg save area + 64 byte parm save area
-# + 64 byte retval area + 13*8 fpr save area + round to 16
-# define STACKFRAME 272
+# ifdef __VEC__
+# 32 byte special reg save area + 64 byte parm save area
+# + 128 byte retval area + 13*8 fpr save area + 12*16 vec save area + round to 16
+# define STACKFRAME 528
+# else
+# 32 byte special reg save area + 64 byte parm save area
+# + 64 byte retval area + 13*8 fpr save area + round to 16
+# define STACKFRAME 272
+# endif
# define PARMSAVE 32
# define RETVAL PARMSAVE+64
# else
@@ -73,20 +80,18 @@ ffi_closure_LINUX64:
# define RETVAL PARMSAVE+64
# endif
-.LFB1:
# if _CALL_ELF == 2
ld %r12, FFI_TRAMPOLINE_SIZE(%r11) # closure->cif
mflr %r0
lwz %r12, 28(%r12) # cif->flags
mtcrf 0x40, %r12
addi %r12, %r1, PARMSAVE
- bt 7, .Lparmsave
+ bt 7, 0f
# Our caller has not allocated a parameter save area.
# We need to allocate one here and use it to pass gprs to
# ffi_closure_helper_LINUX64.
addi %r12, %r1, -STACKFRAME+PARMSAVE
-.Lparmsave:
- std %r0, 16(%r1)
+0:
# Save general regs into parm save area
std %r3, 0(%r12)
std %r4, 8(%r12)
@@ -98,11 +103,11 @@ ffi_closure_LINUX64:
std %r10, 56(%r12)
# load up the pointer to the parm save area
- mr %r5, %r12
+ mr %r7, %r12
# else
# copy r2 to r11 and load TOC into r2
mr %r11, %r2
- ld %r2, 16(%r11)
+ ld %r2, 16(%r2)
mflr %r0
# Save general regs into parm save area
@@ -116,12 +121,19 @@ ffi_closure_LINUX64:
std %r9, PARMSAVE+48(%r1)
std %r10, PARMSAVE+56(%r1)
- std %r0, 16(%r1)
-
# load up the pointer to the parm save area
- addi %r5, %r1, PARMSAVE
+ addi %r7, %r1, PARMSAVE
# endif
+ std %r0, 16(%r1)
+ # closure->cif
+ ld %r3, FFI_TRAMPOLINE_SIZE(%r11)
+ # closure->fun
+ ld %r4, FFI_TRAMPOLINE_SIZE+8(%r11)
+ # closure->user_data
+ ld %r5, FFI_TRAMPOLINE_SIZE+16(%r11)
+
+.Ldoclosure:
# next save fpr 1 to fpr 13
stfd %f1, -104+(0*8)(%r1)
stfd %f2, -104+(1*8)(%r1)
@@ -137,17 +149,44 @@ ffi_closure_LINUX64:
stfd %f12, -104+(11*8)(%r1)
stfd %f13, -104+(12*8)(%r1)
- # load up the pointer to the saved fpr registers */
- addi %r6, %r1, -104
+ # load up the pointer to the saved fpr registers
+ addi %r8, %r1, -104
+
+# ifdef __VEC__
+ # load up the pointer to the saved vector registers
+ # 8 bytes padding for 16-byte alignment at -112(%r1)
+ addi %r9, %r8, -24
+ stvx %v13, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v12, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v11, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v10, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v9, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v8, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v7, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v6, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v5, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v4, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v3, 0, %r9
+ addi %r9, %r9, -16
+ stvx %v2, 0, %r9
+# endif
# load up the pointer to the result storage
- addi %r4, %r1, -STACKFRAME+RETVAL
+ addi %r6, %r1, -STACKFRAME+RETVAL
stdu %r1, -STACKFRAME(%r1)
-.LCFI0:
-
- # get the context pointer from the trampoline
- mr %r3, %r11
+ .cfi_def_cfa_offset STACKFRAME
+ .cfi_offset 65, 16
# make the call
# if defined _CALL_LINUX || _CALL_ELF == 2
@@ -182,7 +221,9 @@ ffi_closure_LINUX64:
# case FFI_TYPE_VOID
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
nop
# case FFI_TYPE_INT
# ifdef __LITTLE_ENDIAN__
@@ -192,17 +233,23 @@ ffi_closure_LINUX64:
# endif
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_FLOAT
lfs %f1, RETVAL+0(%r1)
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_DOUBLE
lfd %f1, RETVAL+0(%r1)
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_LONGDOUBLE
lfd %f1, RETVAL+0(%r1)
mtlr %r0
@@ -216,7 +263,9 @@ ffi_closure_LINUX64:
# endif
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_SINT8
# ifdef __LITTLE_ENDIAN__
lbz %r3, RETVAL+0(%r1)
@@ -235,7 +284,9 @@ ffi_closure_LINUX64:
mtlr %r0
.Lfinish:
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_SINT16
# ifdef __LITTLE_ENDIAN__
lha %r3, RETVAL+0(%r1)
@@ -244,7 +295,9 @@ ffi_closure_LINUX64:
# endif
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_UINT32
# ifdef __LITTLE_ENDIAN__
lwz %r3, RETVAL+0(%r1)
@@ -253,7 +306,9 @@ ffi_closure_LINUX64:
# endif
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_SINT32
# ifdef __LITTLE_ENDIAN__
lwa %r3, RETVAL+0(%r1)
@@ -262,27 +317,47 @@ ffi_closure_LINUX64:
# endif
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_UINT64
ld %r3, RETVAL+0(%r1)
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_SINT64
ld %r3, RETVAL+0(%r1)
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
# case FFI_TYPE_STRUCT
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
nop
# case FFI_TYPE_POINTER
ld %r3, RETVAL+0(%r1)
mtlr %r0
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
+# case FFI_V2_TYPE_VECTOR
+ addi %r3, %r1, RETVAL
+ lvx %v2, 0, %r3
+ mtlr %r0
+ b .Lfinish
+# case FFI_V2_TYPE_VECTOR_HOMOG
+ addi %r3, %r1, RETVAL
+ lvx %v2, 0, %r3
+ addi %r3, %r3, 16
+ b .Lmorevector
# case FFI_V2_TYPE_FLOAT_HOMOG
lfs %f1, RETVAL+0(%r1)
lfs %f2, RETVAL+4(%r1)
@@ -299,7 +374,28 @@ ffi_closure_LINUX64:
lfd %f7, RETVAL+48(%r1)
lfd %f8, RETVAL+56(%r1)
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
+ blr
+ .cfi_def_cfa_offset STACKFRAME
+.Lmorevector:
+ lvx %v3, 0, %r3
+ addi %r3, %r3, 16
+ lvx %v4, 0, %r3
+ addi %r3, %r3, 16
+ lvx %v5, 0, %r3
+ mtlr %r0
+ addi %r3, %r3, 16
+ lvx %v6, 0, %r3
+ addi %r3, %r3, 16
+ lvx %v7, 0, %r3
+ addi %r3, %r3, 16
+ lvx %v8, 0, %r3
+ addi %r3, %r3, 16
+ lvx %v9, 0, %r3
+ addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
.Lmorefloat:
lfs %f4, RETVAL+12(%r1)
mtlr %r0
@@ -308,13 +404,16 @@ ffi_closure_LINUX64:
lfs %f7, RETVAL+24(%r1)
lfs %f8, RETVAL+28(%r1)
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
.Lsmall:
# ifdef __LITTLE_ENDIAN__
ld %r3,RETVAL+0(%r1)
mtlr %r0
ld %r4,RETVAL+8(%r1)
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
# else
# A struct smaller than a dword is returned in the low bits of r3
@@ -328,63 +427,124 @@ ffi_closure_LINUX64:
mtlr %r0
ld %r4,RETVAL+8(%r1)
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset STACKFRAME
.Lsmalldown:
addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7
mtlr %r0
sldi %r5, %r5, 3
addi %r1, %r1, STACKFRAME
+ .cfi_def_cfa_offset 0
srd %r3, %r3, %r5
blr
# endif
-.LFE1:
- .long 0
- .byte 0,12,0,1,128,0,0,0
+ .cfi_endproc
# if _CALL_ELF == 2
.size ffi_closure_LINUX64,.-ffi_closure_LINUX64
# else
# ifdef _CALL_LINUX
.size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64
# else
+ .long 0
+ .byte 0,12,0,1,128,0,0,0
.size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64
# endif
# endif
- .section .eh_frame,EH_FRAME_FLAGS,@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 STACKFRAME
- .byte 0x11 # DW_CFA_offset_extended_sf
- .uleb128 0x41
- .sleb128 -2
- .align 3
-.LEFDE1:
+ FFI_HIDDEN (ffi_go_closure_linux64)
+ .globl ffi_go_closure_linux64
+ .text
+ .cfi_startproc
+# if _CALL_ELF == 2
+ffi_go_closure_linux64:
+ addis %r2, %r12, .TOC.-ffi_go_closure_linux64@ha
+ addi %r2, %r2, .TOC.-ffi_go_closure_linux64@l
+ .localentry ffi_go_closure_linux64, . - ffi_go_closure_linux64
+# else
+ .section ".opd","aw"
+ .align 3
+ffi_go_closure_linux64:
+# ifdef _CALL_LINUX
+ .quad .L.ffi_go_closure_linux64,.TOC.@tocbase,0
+ .type ffi_go_closure_linux64,@function
+ .text
+.L.ffi_go_closure_linux64:
+# else
+ FFI_HIDDEN (.ffi_go_closure_linux64)
+ .globl .ffi_go_closure_linux64
+ .quad .ffi_go_closure_linux64,.TOC.@tocbase,0
+ .size ffi_go_closure_linux64,24
+ .type .ffi_go_closure_linux64,@function
+ .text
+.ffi_go_closure_linux64:
+# endif
+# endif
+
+# if _CALL_ELF == 2
+ ld %r12, 8(%r11) # closure->cif
+ mflr %r0
+ lwz %r12, 28(%r12) # cif->flags
+ mtcrf 0x40, %r12
+ addi %r12, %r1, PARMSAVE
+ bt 7, 0f
+ # Our caller has not allocated a parameter save area.
+ # We need to allocate one here and use it to pass gprs to
+ # ffi_closure_helper_LINUX64.
+ addi %r12, %r1, -STACKFRAME+PARMSAVE
+0:
+ # Save general regs into parm save area
+ std %r3, 0(%r12)
+ std %r4, 8(%r12)
+ std %r5, 16(%r12)
+ std %r6, 24(%r12)
+ std %r7, 32(%r12)
+ std %r8, 40(%r12)
+ std %r9, 48(%r12)
+ std %r10, 56(%r12)
+
+ # load up the pointer to the parm save area
+ mr %r7, %r12
+# else
+ mflr %r0
+ # Save general regs into parm save area
+ # This is the parameter save area set up by our caller.
+ std %r3, PARMSAVE+0(%r1)
+ std %r4, PARMSAVE+8(%r1)
+ std %r5, PARMSAVE+16(%r1)
+ std %r6, PARMSAVE+24(%r1)
+ std %r7, PARMSAVE+32(%r1)
+ std %r8, PARMSAVE+40(%r1)
+ std %r9, PARMSAVE+48(%r1)
+ std %r10, PARMSAVE+56(%r1)
+
+ # load up the pointer to the parm save area
+ addi %r7, %r1, PARMSAVE
+# endif
+ std %r0, 16(%r1)
+
+ # closure->cif
+ ld %r3, 8(%r11)
+ # closure->fun
+ ld %r4, 16(%r11)
+ # user_data
+ mr %r5, %r11
+ b .Ldoclosure
+
+ .cfi_endproc
+# if _CALL_ELF == 2
+ .size ffi_go_closure_linux64,.-ffi_go_closure_linux64
+# else
+# ifdef _CALL_LINUX
+ .size ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64
+# else
+ .long 0
+ .byte 0,12,0,1,128,0,0,0
+ .size .ffi_go_closure_linux64,.-.ffi_go_closure_linux64
+# endif
+# endif
#endif
#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
diff --git a/src/powerpc/ppc_closure.S b/src/powerpc/ppc_closure.S
index 075922cb..b6d209de 100644
--- a/src/powerpc/ppc_closure.S
+++ b/src/powerpc/ppc_closure.S
@@ -33,13 +33,14 @@
#ifndef POWERPC64
+FFI_HIDDEN(ffi_closure_SYSV)
ENTRY(ffi_closure_SYSV)
-.LFB1:
+ .cfi_startproc
stwu %r1,-144(%r1)
-.LCFI0:
+ .cfi_def_cfa_offset 144
mflr %r0
-.LCFI1:
stw %r0,148(%r1)
+ .cfi_offset 65, 4
# we want to build up an areas for the parameters passed
# in registers (both floating point and integer)
@@ -48,6 +49,17 @@ ENTRY(ffi_closure_SYSV)
stw %r3, 16(%r1)
stw %r4, 20(%r1)
stw %r5, 24(%r1)
+
+ # set up registers for the routine that does the work
+
+ # closure->cif
+ lwz %r3,FFI_TRAMPOLINE_SIZE(%r11)
+ # closure->fun
+ lwz %r4,FFI_TRAMPOLINE_SIZE+4(%r11)
+ # closure->user_data
+ lwz %r5,FFI_TRAMPOLINE_SIZE+8(%r11)
+
+.Ldoclosure:
stw %r6, 28(%r1)
stw %r7, 32(%r1)
stw %r8, 36(%r1)
@@ -66,23 +78,18 @@ ENTRY(ffi_closure_SYSV)
stfd %f8, 104(%r1)
#endif
- # set up registers for the routine that actually does the work
- # get the context pointer from the trampoline
- mr %r3,%r11
+ # pointer to the result storage
+ addi %r6,%r1,112
- # now load up the pointer to the result storage
- addi %r4,%r1,112
+ # pointer to the saved gpr registers
+ addi %r7,%r1,16
- # now load up the pointer to the saved gpr registers
- addi %r5,%r1,16
+ # pointer to the saved fpr registers
+ addi %r8,%r1,48
- # now load up the pointer to the saved fpr registers */
- addi %r6,%r1,48
-
- # now load up the pointer to the outgoing parameter
- # stack in the previous frame
+ # pointer to the outgoing parameter save area in the previous frame
# i.e. the previous frame pointer + 8
- addi %r7,%r1,152
+ addi %r9,%r1,152
# make the call
bl ffi_closure_helper_SYSV@local
@@ -101,7 +108,6 @@ ENTRY(ffi_closure_SYSV)
add %r3,%r3,%r4 # add contents of table to table address
mtctr %r3
bctr # jump to it
-.LFE1:
# 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
@@ -111,7 +117,9 @@ ENTRY(ffi_closure_SYSV)
.Lret_type0:
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
nop
# case FFI_TYPE_INT
@@ -119,31 +127,33 @@ ENTRY(ffi_closure_SYSV)
mtlr %r0
.Lfinish:
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_TYPE_FLOAT
#ifndef __NO_FPRS__
lfs %f1,112+0(%r1)
- mtlr %r0
- addi %r1,%r1,144
#else
nop
- nop
- nop
#endif
+ mtlr %r0
+ addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_TYPE_DOUBLE
#ifndef __NO_FPRS__
lfd %f1,112+0(%r1)
- mtlr %r0
- addi %r1,%r1,144
#else
nop
- nop
- nop
#endif
+ mtlr %r0
+ addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_TYPE_LONGDOUBLE
#ifndef __NO_FPRS__
@@ -152,10 +162,12 @@ ENTRY(ffi_closure_SYSV)
mtlr %r0
b .Lfinish
#else
- nop
- nop
- nop
+ mtlr %r0
+ addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
+ nop
#endif
# case FFI_TYPE_UINT8
@@ -166,7 +178,9 @@ ENTRY(ffi_closure_SYSV)
#endif
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_TYPE_SINT8
#ifdef __LITTLE_ENDIAN__
@@ -186,7 +200,9 @@ ENTRY(ffi_closure_SYSV)
#endif
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_TYPE_SINT16
#ifdef __LITTLE_ENDIAN__
@@ -196,19 +212,25 @@ ENTRY(ffi_closure_SYSV)
#endif
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_TYPE_UINT32
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_TYPE_SINT32
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_TYPE_UINT64
lwz %r3,112+0(%r1)
@@ -225,14 +247,18 @@ ENTRY(ffi_closure_SYSV)
# case FFI_TYPE_STRUCT
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
nop
# case FFI_TYPE_POINTER
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_TYPE_UINT128
lwz %r3,112+0(%r1)
@@ -245,20 +271,26 @@ ENTRY(ffi_closure_SYSV)
lbz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
lhz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
lwz %r3,112+0(%r1)
#ifdef __LITTLE_ENDIAN__
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
#else
srwi %r3,%r3,8
mtlr %r0
@@ -269,7 +301,9 @@ ENTRY(ffi_closure_SYSV)
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
lwz %r3,112+0(%r1)
@@ -319,64 +353,43 @@ ENTRY(ffi_closure_SYSV)
or %r4,%r6,%r4
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
+ .cfi_def_cfa_offset 144
#endif
.Luint128:
lwz %r6,112+12(%r1)
mtlr %r0
addi %r1,%r1,144
+ .cfi_def_cfa_offset 0
blr
-
+ .cfi_endproc
END(ffi_closure_SYSV)
- .section ".eh_frame",EH_FRAME_FLAGS,@progbits
-.Lframe1:
- .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
-.LSCIE1:
- .4byte 0x0 # CIE Identifier Tag
- .byte 0x1 # CIE Version
-#if defined _RELOCATABLE || defined __PIC__
- .ascii "zR\0" # CIE Augmentation
-#else
- .ascii "\0" # CIE Augmentation
-#endif
- .uleb128 0x1 # CIE Code Alignment Factor
- .sleb128 -4 # CIE Data Alignment Factor
- .byte 0x41 # CIE RA Column
-#if defined _RELOCATABLE || defined __PIC__
- .uleb128 0x1 # Augmentation size
- .byte 0x1b # FDE Encoding (pcrel sdata4)
-#endif
- .byte 0xc # DW_CFA_def_cfa
- .uleb128 0x1
- .uleb128 0x0
- .align 2
-.LECIE1:
-.LSFDE1:
- .4byte .LEFDE1-.LASFDE1 # FDE Length
-.LASFDE1:
- .4byte .LASFDE1-.Lframe1 # FDE CIE offset
-#if defined _RELOCATABLE || defined __PIC__
- .4byte .LFB1-. # FDE initial location
-#else
- .4byte .LFB1 # FDE initial location
-#endif
- .4byte .LFE1-.LFB1 # FDE address range
-#if defined _RELOCATABLE || defined __PIC__
- .uleb128 0x0 # Augmentation size
-#endif
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI0-.LFB1
- .byte 0xe # DW_CFA_def_cfa_offset
- .uleb128 144
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI1-.LCFI0
- .byte 0x11 # DW_CFA_offset_extended_sf
- .uleb128 0x41
- .sleb128 -1
- .align 2
-.LEFDE1:
+
+FFI_HIDDEN(ffi_go_closure_sysv)
+ENTRY(ffi_go_closure_sysv)
+ .cfi_startproc
+ stwu %r1,-144(%r1)
+ .cfi_def_cfa_offset 144
+ mflr %r0
+ stw %r0,148(%r1)
+ .cfi_offset 65, 4
+
+ stw %r3, 16(%r1)
+ stw %r4, 20(%r1)
+ stw %r5, 24(%r1)
+
+ # closure->cif
+ lwz %r3,4(%r11)
+ # closure->fun
+ lwz %r4,8(%r11)
+ # user_data
+ mr %r5,%r11
+ b .Ldoclosure
+ .cfi_endproc
+END(ffi_go_closure_sysv)
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
diff --git a/src/powerpc/sysv.S b/src/powerpc/sysv.S
index fed2380c..1474ce70 100644
--- a/src/powerpc/sysv.S
+++ b/src/powerpc/sysv.S
@@ -31,34 +31,35 @@
#include <powerpc/asm.h>
#ifndef POWERPC64
- .globl ffi_prep_args_SYSV
+FFI_HIDDEN(ffi_call_SYSV)
ENTRY(ffi_call_SYSV)
-.LFB1:
+ .cfi_startproc
/* Save the old stack pointer as AP. */
- mr %r8,%r1
+ mr %r10,%r1
+ .cfi_def_cfa_register 10
-.LCFI0:
/* Allocate the stack space we need. */
- stwux %r1,%r1,%r4
+ stwux %r1,%r1,%r8
/* Save registers we use. */
mflr %r9
- stw %r28,-16(%r8)
-.LCFI1:
- stw %r29,-12(%r8)
-.LCFI2:
- stw %r30, -8(%r8)
-.LCFI3:
- stw %r31, -4(%r8)
-.LCFI4:
- stw %r9, 4(%r8)
-.LCFI5:
+ stw %r28,-16(%r10)
+ stw %r29,-12(%r10)
+ stw %r30, -8(%r10)
+ stw %r31, -4(%r10)
+ stw %r9, 4(%r10)
+ .cfi_offset 65, 4
+ .cfi_offset 31, -4
+ .cfi_offset 30, -8
+ .cfi_offset 29, -12
+ .cfi_offset 28, -16
/* Save arguments over call... */
- mr %r31,%r5 /* flags, */
- mr %r30,%r6 /* rvalue, */
- mr %r29,%r7 /* function address, */
- mr %r28,%r8 /* our AP. */
-.LCFI6:
+ stw %r7, -20(%r10) /* closure, */
+ mr %r31,%r6 /* flags, */
+ mr %r30,%r5 /* rvalue, */
+ mr %r29,%r4 /* function address, */
+ mr %r28,%r10 /* our AP. */
+ .cfi_def_cfa_register 28
/* Call ffi_prep_args_SYSV. */
mr %r4,%r1
@@ -70,35 +71,36 @@ ENTRY(ffi_call_SYSV)
/* Get the address to call into CTR. */
mtctr %r29
/* Load all those argument registers. */
- lwz %r3,-16-(8*4)(%r28)
- lwz %r4,-16-(7*4)(%r28)
- lwz %r5,-16-(6*4)(%r28)
- lwz %r6,-16-(5*4)(%r28)
+ lwz %r3,-24-(8*4)(%r28)
+ lwz %r4,-24-(7*4)(%r28)
+ lwz %r5,-24-(6*4)(%r28)
+ lwz %r6,-24-(5*4)(%r28)
bf- 5,1f
nop
- lwz %r7,-16-(4*4)(%r28)
- lwz %r8,-16-(3*4)(%r28)
- lwz %r9,-16-(2*4)(%r28)
- lwz %r10,-16-(1*4)(%r28)
+ lwz %r7,-24-(4*4)(%r28)
+ lwz %r8,-24-(3*4)(%r28)
+ lwz %r9,-24-(2*4)(%r28)
+ lwz %r10,-24-(1*4)(%r28)
nop
1:
#ifndef __NO_FPRS__
/* Load all the FP registers. */
bf- 6,2f
- lfd %f1,-16-(8*4)-(8*8)(%r28)
- lfd %f2,-16-(8*4)-(7*8)(%r28)
- lfd %f3,-16-(8*4)-(6*8)(%r28)
- lfd %f4,-16-(8*4)-(5*8)(%r28)
+ lfd %f1,-24-(8*4)-(8*8)(%r28)
+ lfd %f2,-24-(8*4)-(7*8)(%r28)
+ lfd %f3,-24-(8*4)-(6*8)(%r28)
+ lfd %f4,-24-(8*4)-(5*8)(%r28)
nop
- lfd %f5,-16-(8*4)-(4*8)(%r28)
- lfd %f6,-16-(8*4)-(3*8)(%r28)
- lfd %f7,-16-(8*4)-(2*8)(%r28)
- lfd %f8,-16-(8*4)-(1*8)(%r28)
+ lfd %f5,-24-(8*4)-(4*8)(%r28)
+ lfd %f6,-24-(8*4)-(3*8)(%r28)
+ lfd %f7,-24-(8*4)-(2*8)(%r28)
+ lfd %f8,-24-(8*4)-(1*8)(%r28)
#endif
2:
/* Make the call. */
+ lwz %r11, -20(%r28)
bctrl
/* Now, deal with the return value. */
@@ -125,11 +127,24 @@ L(done_return_value):
lwz %r30, -8(%r28)
lwz %r29,-12(%r28)
lwz %r28,-16(%r28)
+ .cfi_remember_state
+ /* At this point we don't have a cfa register. Say all our
+ saved regs have been restored. */
+ .cfi_same_value 65
+ .cfi_same_value 31
+ .cfi_same_value 30
+ .cfi_same_value 29
+ .cfi_same_value 28
+ /* Hopefully this works.. */
+ .cfi_def_cfa_register 1
+ .cfi_offset 1, 0
lwz %r1,0(%r1)
+ .cfi_same_value 1
blr
#ifndef __NO_FPRS__
L(fp_return_value):
+ .cfi_restore_state
bf 28,L(float_return_value)
stfd %f1,0(%r30)
mtcrf 0x02,%r31 /* cr6 */
@@ -150,70 +165,10 @@ L(small_struct_return_value):
stw %r3, 0(%r30)
stw %r4, 4(%r30)
b L(done_return_value)
+ .cfi_endproc
-.LFE1:
END(ffi_call_SYSV)
- .section ".eh_frame",EH_FRAME_FLAGS,@progbits
-.Lframe1:
- .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
-.LSCIE1:
- .4byte 0x0 /* CIE Identifier Tag */
- .byte 0x1 /* CIE Version */
-#if defined _RELOCATABLE || defined __PIC__
- .ascii "zR\0" /* CIE Augmentation */
-#else
- .ascii "\0" /* CIE Augmentation */
-#endif
- .uleb128 0x1 /* CIE Code Alignment Factor */
- .sleb128 -4 /* CIE Data Alignment Factor */
- .byte 0x41 /* CIE RA Column */
-#if defined _RELOCATABLE || defined __PIC__
- .uleb128 0x1 /* Augmentation size */
- .byte 0x1b /* FDE Encoding (pcrel sdata4) */
-#endif
- .byte 0xc /* DW_CFA_def_cfa */
- .uleb128 0x1
- .uleb128 0x0
- .align 2
-.LECIE1:
-.LSFDE1:
- .4byte .LEFDE1-.LASFDE1 /* FDE Length */
-.LASFDE1:
- .4byte .LASFDE1-.Lframe1 /* FDE CIE offset */
-#if defined _RELOCATABLE || defined __PIC__
- .4byte .LFB1-. /* FDE initial location */
-#else
- .4byte .LFB1 /* FDE initial location */
-#endif
- .4byte .LFE1-.LFB1 /* FDE address range */
-#if defined _RELOCATABLE || defined __PIC__
- .uleb128 0x0 /* Augmentation size */
-#endif
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .4byte .LCFI0-.LFB1
- .byte 0xd /* DW_CFA_def_cfa_register */
- .uleb128 0x08
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .4byte .LCFI5-.LCFI0
- .byte 0x11 /* DW_CFA_offset_extended_sf */
- .uleb128 0x41
- .sleb128 -1
- .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
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .4byte .LCFI6-.LCFI5
- .byte 0xd /* DW_CFA_def_cfa_register */
- .uleb128 0x1c
- .align 2
-.LEFDE1:
-
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
#endif
diff --git a/src/prep_cif.c b/src/prep_cif.c
index be5eae37..06c65440 100644
--- a/src/prep_cif.c
+++ b/src/prep_cif.c
@@ -29,12 +29,12 @@
/* Round up to FFI_SIZEOF_ARG. */
-#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
+#define STACK_ARG_SIZE(x) FFI_ALIGN(x, FFI_SIZEOF_ARG)
/* Perform machine independent initialization of aggregate type
specifications. */
-static ffi_status initialize_aggregate(ffi_type *arg)
+static ffi_status initialize_aggregate(ffi_type *arg, size_t *offsets)
{
ffi_type **ptr;
@@ -52,13 +52,15 @@ static ffi_status initialize_aggregate(ffi_type *arg)
while ((*ptr) != NULL)
{
if (UNLIKELY(((*ptr)->size == 0)
- && (initialize_aggregate((*ptr)) != FFI_OK)))
+ && (initialize_aggregate((*ptr), NULL) != FFI_OK)))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type */
FFI_ASSERT_VALID_TYPE(*ptr);
- arg->size = ALIGN(arg->size, (*ptr)->alignment);
+ arg->size = FFI_ALIGN(arg->size, (*ptr)->alignment);
+ if (offsets)
+ *offsets++ = arg->size;
arg->size += (*ptr)->size;
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
@@ -74,7 +76,7 @@ static ffi_status initialize_aggregate(ffi_type *arg)
struct A { long a; char b; }; struct B { struct A x; char y; };
should find y at an offset of 2*sizeof(long) and result in a
total size of 3*sizeof(long). */
- arg->size = ALIGN (arg->size, arg->alignment);
+ arg->size = FFI_ALIGN (arg->size, arg->alignment);
/* On some targets, the ABI defines that structures have an additional
alignment beyond the "natural" one based on their elements. */
@@ -127,13 +129,16 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
cif->rtype = rtype;
cif->flags = 0;
-
+#ifdef _M_ARM64
+ cif->is_variadic = isvariadic;
+#endif
#if HAVE_LONG_DOUBLE_VARIANT
ffi_prep_types (abi);
#endif
/* Initialize the return type if necessary */
- if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
+ if ((cif->rtype->size == 0)
+ && (initialize_aggregate(cif->rtype, NULL) != FFI_OK))
return FFI_BAD_TYPEDEF;
#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
@@ -147,9 +152,6 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
-#ifdef SPARC
- && (cif->abi != FFI_V9 || cif->rtype->size > 32)
-#endif
#ifdef TILE
&& (cif->rtype->size > 10 * FFI_SIZEOF_ARG)
#endif
@@ -167,7 +169,8 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
{
/* Initialize any uninitialized aggregate type definitions */
- if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
+ if (((*ptr)->size == 0)
+ && (initialize_aggregate((*ptr), NULL) != FFI_OK))
return FFI_BAD_TYPEDEF;
#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
@@ -179,18 +182,10 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
FFI_ASSERT_VALID_TYPE(*ptr);
#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
-#ifdef SPARC
- if (((*ptr)->type == FFI_TYPE_STRUCT
- && ((*ptr)->size > 16 || cif->abi != FFI_V9))
- || ((*ptr)->type == FFI_TYPE_LONGDOUBLE
- && cif->abi != FFI_V9))
- bytes += sizeof(void*);
- else
-#endif
{
/* Add any padding if necessary */
if (((*ptr)->alignment - 1) & bytes)
- bytes = (unsigned)ALIGN(bytes, (*ptr)->alignment);
+ bytes = (unsigned)FFI_ALIGN(bytes, (*ptr)->alignment);
#ifdef TILE
if (bytes < 10 * FFI_SIZEOF_ARG &&
@@ -206,7 +201,7 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
bytes = 6*4;
#endif
- bytes += STACK_ARG_SIZE((*ptr)->size);
+ bytes += (unsigned int)STACK_ARG_SIZE((*ptr)->size);
}
#endif
}
@@ -251,3 +246,18 @@ ffi_prep_closure (ffi_closure* closure,
}
#endif
+
+ffi_status
+ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type, size_t *offsets)
+{
+ if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
+ return FFI_BAD_ABI;
+ if (struct_type->type != FFI_TYPE_STRUCT)
+ return FFI_BAD_TYPEDEF;
+
+#if HAVE_LONG_DOUBLE_VARIANT
+ ffi_prep_types (abi);
+#endif
+
+ return initialize_aggregate(struct_type, offsets);
+}
diff --git a/src/raw_api.c b/src/raw_api.c
index 276cb228..be156116 100644
--- a/src/raw_api.c
+++ b/src/raw_api.c
@@ -43,10 +43,10 @@ ffi_raw_size (ffi_cif *cif)
{
#if !FFI_NO_STRUCTS
if ((*at)->type == FFI_TYPE_STRUCT)
- result += ALIGN (sizeof (void*), FFI_SIZEOF_ARG);
+ result += FFI_ALIGN (sizeof (void*), FFI_SIZEOF_ARG);
else
#endif
- result += ALIGN ((*at)->size, FFI_SIZEOF_ARG);
+ result += FFI_ALIGN ((*at)->size, FFI_SIZEOF_ARG);
}
return result;
@@ -98,7 +98,7 @@ ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
default:
*args = raw;
- raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ raw += FFI_ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
@@ -123,7 +123,7 @@ ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
else
{
*args = (void*) raw;
- raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
+ raw += FFI_ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
}
}
@@ -186,7 +186,7 @@ ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
default:
memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
- raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ raw += FFI_ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
}
diff --git a/src/riscv/ffi.c b/src/riscv/ffi.c
new file mode 100644
index 00000000..c9108588
--- /dev/null
+++ b/src/riscv/ffi.c
@@ -0,0 +1,481 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
+ 2015 Andrew Waterman <waterman@cs.berkeley.edu>
+ 2018 Stef O'Rear <sorear2@gmail.com>
+ Based on MIPS N32/64 port
+
+ RISC-V Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS 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>
+#include <stdint.h>
+
+#if __riscv_float_abi_double
+#define ABI_FLEN 64
+#define ABI_FLOAT double
+#elif __riscv_float_abi_single
+#define ABI_FLEN 32
+#define ABI_FLOAT float
+#endif
+
+#define NARGREG 8
+#define STKALIGN 16
+#define MAXCOPYARG (2 * sizeof(double))
+
+typedef struct call_context
+{
+#if ABI_FLEN
+ ABI_FLOAT fa[8];
+#endif
+ size_t a[8];
+ /* used by the assembly code to in-place construct its own stack frame */
+ char frame[16];
+} call_context;
+
+typedef struct call_builder
+{
+ call_context *aregs;
+ int used_integer;
+ int used_float;
+ size_t *used_stack;
+} call_builder;
+
+/* integer (not pointer) less than ABI XLEN */
+/* FFI_TYPE_INT does not appear to be used */
+#if __SIZEOF_POINTER__ == 8
+#define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT64)
+#else
+#define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT32)
+#endif
+
+#if ABI_FLEN
+typedef struct {
+ char as_elements, type1, offset2, type2;
+} float_struct_info;
+
+#if ABI_FLEN >= 64
+#define IS_FLOAT(type) ((type) >= FFI_TYPE_FLOAT && (type) <= FFI_TYPE_DOUBLE)
+#else
+#define IS_FLOAT(type) ((type) == FFI_TYPE_FLOAT)
+#endif
+
+static ffi_type **flatten_struct(ffi_type *in, ffi_type **out, ffi_type **out_end) {
+ int i;
+ if (out == out_end) return out;
+ if (in->type != FFI_TYPE_STRUCT) {
+ *(out++) = in;
+ } else {
+ for (i = 0; in->elements[i]; i++)
+ out = flatten_struct(in->elements[i], out, out_end);
+ }
+ return out;
+}
+
+/* Structs with at most two fields after flattening, one of which is of
+ floating point type, are passed in multiple registers if sufficient
+ registers are available. */
+static float_struct_info struct_passed_as_elements(call_builder *cb, ffi_type *top) {
+ float_struct_info ret = {0, 0, 0, 0};
+ ffi_type *fields[3];
+ int num_floats, num_ints;
+ int num_fields = flatten_struct(top, fields, fields + 3) - fields;
+
+ if (num_fields == 1) {
+ if (IS_FLOAT(fields[0]->type)) {
+ ret.as_elements = 1;
+ ret.type1 = fields[0]->type;
+ }
+ } else if (num_fields == 2) {
+ num_floats = IS_FLOAT(fields[0]->type) + IS_FLOAT(fields[1]->type);
+ num_ints = IS_INT(fields[0]->type) + IS_INT(fields[1]->type);
+ if (num_floats == 0 || num_floats + num_ints != 2)
+ return ret;
+ if (cb->used_float + num_floats > NARGREG || cb->used_integer + (2 - num_floats) > NARGREG)
+ return ret;
+ if (!IS_FLOAT(fields[0]->type) && !IS_FLOAT(fields[1]->type))
+ return ret;
+
+ ret.type1 = fields[0]->type;
+ ret.type2 = fields[1]->type;
+ ret.offset2 = FFI_ALIGN(fields[0]->size, fields[1]->alignment);
+ ret.as_elements = 1;
+ }
+
+ return ret;
+}
+#endif
+
+/* allocates a single register, float register, or XLEN-sized stack slot to a datum */
+static void marshal_atom(call_builder *cb, int type, void *data) {
+ size_t value = 0;
+ switch (type) {
+ case FFI_TYPE_UINT8: value = *(uint8_t *)data; break;
+ case FFI_TYPE_SINT8: value = *(int8_t *)data; break;
+ case FFI_TYPE_UINT16: value = *(uint16_t *)data; break;
+ case FFI_TYPE_SINT16: value = *(int16_t *)data; break;
+ /* 32-bit quantities are always sign-extended in the ABI */
+ case FFI_TYPE_UINT32: value = *(int32_t *)data; break;
+ case FFI_TYPE_SINT32: value = *(int32_t *)data; break;
+#if __SIZEOF_POINTER__ == 8
+ case FFI_TYPE_UINT64: value = *(uint64_t *)data; break;
+ case FFI_TYPE_SINT64: value = *(int64_t *)data; break;
+#endif
+ case FFI_TYPE_POINTER: value = *(size_t *)data; break;
+
+ /* float values may be recoded in an implementation-defined way
+ by hardware conforming to 2.1 or earlier, so use asm to
+ reinterpret floats as doubles */
+#if ABI_FLEN >= 32
+ case FFI_TYPE_FLOAT:
+ asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : "0"(*(float *)data));
+ return;
+#endif
+#if ABI_FLEN >= 64
+ case FFI_TYPE_DOUBLE:
+ asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : "0"(*(double *)data));
+ return;
+#endif
+ default: FFI_ASSERT(0); break;
+ }
+
+ if (cb->used_integer == NARGREG) {
+ *cb->used_stack++ = value;
+ } else {
+ cb->aregs->a[cb->used_integer++] = value;
+ }
+}
+
+static void unmarshal_atom(call_builder *cb, int type, void *data) {
+ size_t value;
+ switch (type) {
+#if ABI_FLEN >= 32
+ case FFI_TYPE_FLOAT:
+ asm("" : "=f"(*(float *)data) : "0"(cb->aregs->fa[cb->used_float++]));
+ return;
+#endif
+#if ABI_FLEN >= 64
+ case FFI_TYPE_DOUBLE:
+ asm("" : "=f"(*(double *)data) : "0"(cb->aregs->fa[cb->used_float++]));
+ return;
+#endif
+ }
+
+ if (cb->used_integer == NARGREG) {
+ value = *cb->used_stack++;
+ } else {
+ value = cb->aregs->a[cb->used_integer++];
+ }
+
+ switch (type) {
+ case FFI_TYPE_UINT8: *(uint8_t *)data = value; break;
+ case FFI_TYPE_SINT8: *(uint8_t *)data = value; break;
+ case FFI_TYPE_UINT16: *(uint16_t *)data = value; break;
+ case FFI_TYPE_SINT16: *(uint16_t *)data = value; break;
+ case FFI_TYPE_UINT32: *(uint32_t *)data = value; break;
+ case FFI_TYPE_SINT32: *(uint32_t *)data = value; break;
+#if __SIZEOF_POINTER__ == 8
+ case FFI_TYPE_UINT64: *(uint64_t *)data = value; break;
+ case FFI_TYPE_SINT64: *(uint64_t *)data = value; break;
+#endif
+ case FFI_TYPE_POINTER: *(size_t *)data = value; break;
+ default: FFI_ASSERT(0); break;
+ }
+}
+
+/* adds an argument to a call, or a not by reference return value */
+static void marshal(call_builder *cb, ffi_type *type, int var, void *data) {
+ size_t realign[2];
+
+#if ABI_FLEN
+ if (!var && type->type == FFI_TYPE_STRUCT) {
+ float_struct_info fsi = struct_passed_as_elements(cb, type);
+ if (fsi.as_elements) {
+ marshal_atom(cb, fsi.type1, data);
+ if (fsi.offset2)
+ marshal_atom(cb, fsi.type2, ((char*)data) + fsi.offset2);
+ return;
+ }
+ }
+
+ if (!var && cb->used_float < NARGREG && IS_FLOAT(type->type)) {
+ marshal_atom(cb, type->type, data);
+ return;
+ }
+#endif
+
+ if (type->size > 2 * __SIZEOF_POINTER__) {
+ /* pass by reference */
+ marshal_atom(cb, FFI_TYPE_POINTER, &data);
+ } else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) {
+ marshal_atom(cb, type->type, data);
+ } else {
+ /* overlong integers, soft-float floats, and structs without special
+ float handling are treated identically from this point on */
+
+ /* variadics are aligned even in registers */
+ if (type->alignment > __SIZEOF_POINTER__) {
+ if (var)
+ cb->used_integer = FFI_ALIGN(cb->used_integer, 2);
+ cb->used_stack = (size_t *)FFI_ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__);
+ }
+
+ memcpy(realign, data, type->size);
+ if (type->size > 0)
+ marshal_atom(cb, FFI_TYPE_POINTER, realign);
+ if (type->size > __SIZEOF_POINTER__)
+ marshal_atom(cb, FFI_TYPE_POINTER, realign + 1);
+ }
+}
+
+/* for arguments passed by reference returns the pointer, otherwise the arg is copied (up to MAXCOPYARG bytes) */
+static void *unmarshal(call_builder *cb, ffi_type *type, int var, void *data) {
+ size_t realign[2];
+ void *pointer;
+
+#if ABI_FLEN
+ if (!var && type->type == FFI_TYPE_STRUCT) {
+ float_struct_info fsi = struct_passed_as_elements(cb, type);
+ if (fsi.as_elements) {
+ unmarshal_atom(cb, fsi.type1, data);
+ if (fsi.offset2)
+ unmarshal_atom(cb, fsi.type2, ((char*)data) + fsi.offset2);
+ return data;
+ }
+ }
+
+ if (!var && cb->used_float < NARGREG && IS_FLOAT(type->type)) {
+ unmarshal_atom(cb, type->type, data);
+ return data;
+ }
+#endif
+
+ if (type->size > 2 * __SIZEOF_POINTER__) {
+ /* pass by reference */
+ unmarshal_atom(cb, FFI_TYPE_POINTER, (char*)&pointer);
+ return pointer;
+ } else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) {
+ unmarshal_atom(cb, type->type, data);
+ return data;
+ } else {
+ /* overlong integers, soft-float floats, and structs without special
+ float handling are treated identically from this point on */
+
+ /* variadics are aligned even in registers */
+ if (type->alignment > __SIZEOF_POINTER__) {
+ if (var)
+ cb->used_integer = FFI_ALIGN(cb->used_integer, 2);
+ cb->used_stack = (size_t *)FFI_ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__);
+ }
+
+ if (type->size > 0)
+ unmarshal_atom(cb, FFI_TYPE_POINTER, realign);
+ if (type->size > __SIZEOF_POINTER__)
+ unmarshal_atom(cb, FFI_TYPE_POINTER, realign + 1);
+ memcpy(data, realign, type->size);
+ return data;
+ }
+}
+
+static int passed_by_ref(call_builder *cb, ffi_type *type, int var) {
+#if ABI_FLEN
+ if (!var && type->type == FFI_TYPE_STRUCT) {
+ float_struct_info fsi = struct_passed_as_elements(cb, type);
+ if (fsi.as_elements) return 0;
+ }
+#endif
+
+ return type->size > 2 * __SIZEOF_POINTER__;
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif) {
+ cif->riscv_nfixedargs = cif->nargs;
+ return FFI_OK;
+}
+
+/* Perform machine dependent cif processing when we have a variadic function */
+
+ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, unsigned int ntotalargs) {
+ cif->riscv_nfixedargs = nfixedargs;
+ return FFI_OK;
+}
+
+/* Low level routine for calling functions */
+extern void ffi_call_asm (void *stack, struct call_context *regs,
+ void (*fn) (void), void *closure) FFI_HIDDEN;
+
+static void
+ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
+ void *closure)
+{
+ /* this is a conservative estimate, assuming a complex return value and
+ that all remaining arguments are long long / __int128 */
+ size_t arg_bytes = cif->nargs <= 3 ? 0 :
+ FFI_ALIGN(2 * sizeof(size_t) * (cif->nargs - 3), STKALIGN);
+ size_t rval_bytes = 0;
+ if (rvalue == NULL && cif->rtype->size > 2*__SIZEOF_POINTER__)
+ rval_bytes = FFI_ALIGN(cif->rtype->size, STKALIGN);
+ size_t alloc_size = arg_bytes + rval_bytes + sizeof(call_context);
+
+ /* the assembly code will deallocate all stack data at lower addresses
+ than the argument region, so we need to allocate the frame and the
+ return value after the arguments in a single allocation */
+ size_t alloc_base;
+ /* Argument region must be 16-byte aligned */
+ if (_Alignof(max_align_t) >= STKALIGN) {
+ /* since sizeof long double is normally 16, the compiler will
+ guarantee alloca alignment to at least that much */
+ alloc_base = (size_t)alloca(alloc_size);
+ } else {
+ alloc_base = FFI_ALIGN(alloca(alloc_size + STKALIGN - 1), STKALIGN);
+ }
+
+ if (rval_bytes)
+ rvalue = (void*)(alloc_base + arg_bytes);
+
+ call_builder cb;
+ cb.used_float = cb.used_integer = 0;
+ cb.aregs = (call_context*)(alloc_base + arg_bytes + rval_bytes);
+ cb.used_stack = (void*)alloc_base;
+
+ int return_by_ref = passed_by_ref(&cb, cif->rtype, 0);
+ if (return_by_ref)
+ marshal(&cb, &ffi_type_pointer, 0, &rvalue);
+
+ int i;
+ for (i = 0; i < cif->nargs; i++)
+ marshal(&cb, cif->arg_types[i], i >= cif->riscv_nfixedargs, avalue[i]);
+
+ ffi_call_asm ((void *) alloc_base, cb.aregs, fn, closure);
+
+ cb.used_float = cb.used_integer = 0;
+ if (!return_by_ref && rvalue)
+ unmarshal(&cb, cif->rtype, 0, rvalue);
+}
+
+void
+ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, NULL);
+}
+
+void
+ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, closure);
+}
+
+extern void ffi_closure_asm(void) FFI_HIDDEN;
+
+ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void *codeloc)
+{
+ uint32_t *tramp = (uint32_t *) &closure->tramp[0];
+ uint64_t fn = (uint64_t) (uintptr_t) ffi_closure_asm;
+
+ if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI)
+ return FFI_BAD_ABI;
+
+ /* we will call ffi_closure_inner with codeloc, not closure, but as long
+ as the memory is readable it should work */
+
+ tramp[0] = 0x00000317; /* auipc t1, 0 (i.e. t0 <- codeloc) */
+#if __SIZEOF_POINTER__ == 8
+ tramp[1] = 0x01033383; /* ld t2, 16(t1) */
+#else
+ tramp[1] = 0x01032383; /* lw t2, 16(t1) */
+#endif
+ tramp[2] = 0x00038067; /* jr t2 */
+ tramp[3] = 0x00000013; /* nop */
+ tramp[4] = fn;
+ tramp[5] = fn >> 32;
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ __builtin___clear_cache(codeloc, codeloc + FFI_TRAMPOLINE_SIZE);
+
+ return FFI_OK;
+}
+
+extern void ffi_go_closure_asm (void) FFI_HIDDEN;
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *))
+{
+ if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI)
+ return FFI_BAD_ABI;
+
+ closure->tramp = (void *) ffi_go_closure_asm;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+/* Called by the assembly code with aregs pointing to saved argument registers
+ and stack pointing to the stacked arguments. Return values passed in
+ registers will be reloaded from aregs. */
+void FFI_HIDDEN
+ffi_closure_inner (ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data,
+ size_t *stack, call_context *aregs)
+{
+ void **avalue = alloca(cif->nargs * sizeof(void*));
+ /* storage for arguments which will be copied by unmarshal(). We could
+ theoretically avoid the copies in many cases and use at most 128 bytes
+ of memory, but allocating disjoint storage for each argument is
+ simpler. */
+ char *astorage = alloca(cif->nargs * MAXCOPYARG);
+ void *rvalue;
+ call_builder cb;
+ int return_by_ref;
+ int i;
+
+ cb.aregs = aregs;
+ cb.used_integer = cb.used_float = 0;
+ cb.used_stack = stack;
+
+ return_by_ref = passed_by_ref(&cb, cif->rtype, 0);
+ if (return_by_ref)
+ unmarshal(&cb, &ffi_type_pointer, 0, &rvalue);
+ else
+ rvalue = alloca(cif->rtype->size);
+
+ for (i = 0; i < cif->nargs; i++)
+ avalue[i] = unmarshal(&cb, cif->arg_types[i],
+ i >= cif->riscv_nfixedargs, astorage + i*MAXCOPYARG);
+
+ fun (cif, rvalue, avalue, user_data);
+
+ if (!return_by_ref && cif->rtype->type != FFI_TYPE_VOID) {
+ cb.used_integer = cb.used_float = 0;
+ marshal(&cb, cif->rtype, 0, rvalue);
+ }
+}
diff --git a/src/riscv/ffitarget.h b/src/riscv/ffitarget.h
new file mode 100644
index 00000000..75e6462f
--- /dev/null
+++ b/src/riscv/ffitarget.h
@@ -0,0 +1,69 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - 2014 Michael Knyszek
+
+ Target configuration macros for RISC-V.
+
+ 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 AUTHORS OR COPYRIGHT
+ HOLDERS 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.
+
+ ----------------------------------------------------------------------- */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+#ifndef LIBFFI_H
+#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
+#endif
+
+#ifndef __riscv
+#error "libffi was configured for a RISC-V target but this does not appear to be a RISC-V compiler."
+#endif
+
+#ifndef LIBFFI_ASM
+
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+/* FFI_UNUSED_NN and riscv_unused are to maintain ABI compatibility with a
+ distributed Berkeley patch from 2014, and can be removed at SONAME bump */
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_UNUSED_1,
+ FFI_UNUSED_2,
+ FFI_UNUSED_3,
+ FFI_LAST_ABI,
+
+ FFI_DEFAULT_ABI = FFI_SYSV
+} ffi_abi;
+
+#endif /* LIBFFI_ASM */
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_GO_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_NATIVE_RAW_API 0
+#define FFI_EXTRA_CIF_FIELDS unsigned riscv_nfixedargs; unsigned riscv_unused;
+#define FFI_TARGET_SPECIFIC_VARIADIC
+
+#endif
+
diff --git a/src/riscv/sysv.S b/src/riscv/sysv.S
new file mode 100644
index 00000000..522d0b00
--- /dev/null
+++ b/src/riscv/sysv.S
@@ -0,0 +1,293 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
+ 2015 Andrew Waterman <waterman@cs.berkeley.edu>
+ 2018 Stef O'Rear <sorear2@gmail.com>
+
+ RISC-V Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS 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 <fficonfig.h>
+#include <ffi.h>
+
+/* Define aliases so that we can handle all ABIs uniformly */
+
+#if __SIZEOF_POINTER__ == 8
+#define PTRS 8
+#define LARG ld
+#define SARG sd
+#else
+#define PTRS 4
+#define LARG lw
+#define SARG sw
+#endif
+
+#if __riscv_float_abi_double
+#define FLTS 8
+#define FLARG fld
+#define FSARG fsd
+#elif __riscv_float_abi_single
+#define FLTS 4
+#define FLARG flw
+#define FSARG fsw
+#else
+#define FLTS 0
+#endif
+
+#define fp s0
+
+ .text
+ .globl ffi_call_asm
+ .type ffi_call_asm, @function
+ .hidden ffi_call_asm
+/*
+ struct call_context {
+ floatreg fa[8];
+ intreg a[8];
+ intreg pad[rv32 ? 2 : 0];
+ intreg save_fp, save_ra;
+ }
+ void ffi_call_asm (size_t *stackargs, struct call_context *regargs,
+ void (*fn) (void), void *closure);
+*/
+
+#define FRAME_LEN (8 * FLTS + 8 * PTRS + 16)
+
+ffi_call_asm:
+ .cfi_startproc
+
+ /*
+ We are NOT going to set up an ordinary stack frame. In order to pass
+ the stacked args to the called function, we adjust our stack pointer to
+ a0, which is in the _caller's_ alloca area. We establish our own stack
+ frame at the end of the call_context.
+
+ Anything below the arguments will be freed at this point, although we
+ preserve the call_context so that it can be read back in the caller.
+ */
+
+ .cfi_def_cfa 11, FRAME_LEN # interim CFA based on a1
+ SARG fp, FRAME_LEN - 2*PTRS(a1)
+ .cfi_offset 8, -2*PTRS
+ SARG ra, FRAME_LEN - 1*PTRS(a1)
+ .cfi_offset 1, -1*PTRS
+
+ addi fp, a1, FRAME_LEN
+ mv sp, a0
+ .cfi_def_cfa 8, 0 # our frame is fully set up
+
+ # Load arguments
+ mv t1, a2
+ mv t2, a3
+
+#if FLTS
+ FLARG fa0, -FRAME_LEN+0*FLTS(fp)
+ FLARG fa1, -FRAME_LEN+1*FLTS(fp)
+ FLARG fa2, -FRAME_LEN+2*FLTS(fp)
+ FLARG fa3, -FRAME_LEN+3*FLTS(fp)
+ FLARG fa4, -FRAME_LEN+4*FLTS(fp)
+ FLARG fa5, -FRAME_LEN+5*FLTS(fp)
+ FLARG fa6, -FRAME_LEN+6*FLTS(fp)
+ FLARG fa7, -FRAME_LEN+7*FLTS(fp)
+#endif
+
+ LARG a0, -FRAME_LEN+8*FLTS+0*PTRS(fp)
+ LARG a1, -FRAME_LEN+8*FLTS+1*PTRS(fp)
+ LARG a2, -FRAME_LEN+8*FLTS+2*PTRS(fp)
+ LARG a3, -FRAME_LEN+8*FLTS+3*PTRS(fp)
+ LARG a4, -FRAME_LEN+8*FLTS+4*PTRS(fp)
+ LARG a5, -FRAME_LEN+8*FLTS+5*PTRS(fp)
+ LARG a6, -FRAME_LEN+8*FLTS+6*PTRS(fp)
+ LARG a7, -FRAME_LEN+8*FLTS+7*PTRS(fp)
+
+ /* Call */
+ jalr t1
+
+ /* Save return values - only a0/a1 (fa0/fa1) are used */
+#if FLTS
+ FSARG fa0, -FRAME_LEN+0*FLTS(fp)
+ FSARG fa1, -FRAME_LEN+1*FLTS(fp)
+#endif
+
+ SARG a0, -FRAME_LEN+8*FLTS+0*PTRS(fp)
+ SARG a1, -FRAME_LEN+8*FLTS+1*PTRS(fp)
+
+ /* Restore and return */
+ addi sp, fp, -FRAME_LEN
+ .cfi_def_cfa 2, FRAME_LEN
+ LARG ra, -1*PTRS(fp)
+ .cfi_restore 1
+ LARG fp, -2*PTRS(fp)
+ .cfi_restore 8
+ ret
+ .cfi_endproc
+ .size ffi_call_asm, .-ffi_call_asm
+
+
+/*
+ ffi_closure_asm. Expects address of the passed-in ffi_closure in t1.
+ void ffi_closure_inner (ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data,
+ size_t *stackargs, struct call_context *regargs)
+*/
+
+ .globl ffi_closure_asm
+ .hidden ffi_closure_asm
+ .type ffi_closure_asm, @function
+ffi_closure_asm:
+ .cfi_startproc
+
+ addi sp, sp, -FRAME_LEN
+ .cfi_def_cfa_offset FRAME_LEN
+
+ /* make a frame */
+ SARG fp, FRAME_LEN - 2*PTRS(sp)
+ .cfi_offset 8, -2*PTRS
+ SARG ra, FRAME_LEN - 1*PTRS(sp)
+ .cfi_offset 1, -1*PTRS
+ addi fp, sp, FRAME_LEN
+
+ /* save arguments */
+#if FLTS
+ FSARG fa0, 0*FLTS(sp)
+ FSARG fa1, 1*FLTS(sp)
+ FSARG fa2, 2*FLTS(sp)
+ FSARG fa3, 3*FLTS(sp)
+ FSARG fa4, 4*FLTS(sp)
+ FSARG fa5, 5*FLTS(sp)
+ FSARG fa6, 6*FLTS(sp)
+ FSARG fa7, 7*FLTS(sp)
+#endif
+
+ SARG a0, 8*FLTS+0*PTRS(sp)
+ SARG a1, 8*FLTS+1*PTRS(sp)
+ SARG a2, 8*FLTS+2*PTRS(sp)
+ SARG a3, 8*FLTS+3*PTRS(sp)
+ SARG a4, 8*FLTS+4*PTRS(sp)
+ SARG a5, 8*FLTS+5*PTRS(sp)
+ SARG a6, 8*FLTS+6*PTRS(sp)
+ SARG a7, 8*FLTS+7*PTRS(sp)
+
+ /* enter C */
+ LARG a0, FFI_TRAMPOLINE_SIZE+0*PTRS(t1)
+ LARG a1, FFI_TRAMPOLINE_SIZE+1*PTRS(t1)
+ LARG a2, FFI_TRAMPOLINE_SIZE+2*PTRS(t1)
+ addi a3, sp, FRAME_LEN
+ mv a4, sp
+
+ call ffi_closure_inner
+
+ /* return values */
+#if FLTS
+ FLARG fa0, 0*FLTS(sp)
+ FLARG fa1, 1*FLTS(sp)
+#endif
+
+ LARG a0, 8*FLTS+0*PTRS(sp)
+ LARG a1, 8*FLTS+1*PTRS(sp)
+
+ /* restore and return */
+ LARG ra, FRAME_LEN-1*PTRS(sp)
+ .cfi_restore 1
+ LARG fp, FRAME_LEN-2*PTRS(sp)
+ .cfi_restore 8
+ addi sp, sp, FRAME_LEN
+ .cfi_def_cfa_offset 0
+ ret
+ .cfi_endproc
+ .size ffi_closure_asm, .-ffi_closure_asm
+
+/*
+ ffi_go_closure_asm. Expects address of the passed-in ffi_go_closure in t2.
+ void ffi_closure_inner (ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data,
+ size_t *stackargs, struct call_context *regargs)
+*/
+
+ .globl ffi_go_closure_asm
+ .hidden ffi_go_closure_asm
+ .type ffi_go_closure_asm, @function
+ffi_go_closure_asm:
+ .cfi_startproc
+
+ addi sp, sp, -FRAME_LEN
+ .cfi_def_cfa_offset FRAME_LEN
+
+ /* make a frame */
+ SARG fp, FRAME_LEN - 2*PTRS(sp)
+ .cfi_offset 8, -2*PTRS
+ SARG ra, FRAME_LEN - 1*PTRS(sp)
+ .cfi_offset 1, -1*PTRS
+ addi fp, sp, FRAME_LEN
+
+ /* save arguments */
+#if FLTS
+ FSARG fa0, 0*FLTS(sp)
+ FSARG fa1, 1*FLTS(sp)
+ FSARG fa2, 2*FLTS(sp)
+ FSARG fa3, 3*FLTS(sp)
+ FSARG fa4, 4*FLTS(sp)
+ FSARG fa5, 5*FLTS(sp)
+ FSARG fa6, 6*FLTS(sp)
+ FSARG fa7, 7*FLTS(sp)
+#endif
+
+ SARG a0, 8*FLTS+0*PTRS(sp)
+ SARG a1, 8*FLTS+1*PTRS(sp)
+ SARG a2, 8*FLTS+2*PTRS(sp)
+ SARG a3, 8*FLTS+3*PTRS(sp)
+ SARG a4, 8*FLTS+4*PTRS(sp)
+ SARG a5, 8*FLTS+5*PTRS(sp)
+ SARG a6, 8*FLTS+6*PTRS(sp)
+ SARG a7, 8*FLTS+7*PTRS(sp)
+
+ /* enter C */
+ LARG a0, 1*PTRS(t2)
+ LARG a1, 2*PTRS(t2)
+ mv a2, t2
+ addi a3, sp, FRAME_LEN
+ mv a4, sp
+
+ call ffi_closure_inner
+
+ /* return values */
+#if FLTS
+ FLARG fa0, 0*FLTS(sp)
+ FLARG fa1, 1*FLTS(sp)
+#endif
+
+ LARG a0, 8*FLTS+0*PTRS(sp)
+ LARG a1, 8*FLTS+1*PTRS(sp)
+
+ /* restore and return */
+ LARG ra, FRAME_LEN-1*PTRS(sp)
+ .cfi_restore 1
+ LARG fp, FRAME_LEN-2*PTRS(sp)
+ .cfi_restore 8
+ addi sp, sp, FRAME_LEN
+ .cfi_def_cfa_offset 0
+ ret
+ .cfi_endproc
+ .size ffi_go_closure_asm, .-ffi_go_closure_asm
diff --git a/src/s390/ffi.c b/src/s390/ffi.c
index 520ec7c6..4035b6e3 100644
--- a/src/s390/ffi.c
+++ b/src/s390/ffi.c
@@ -1,9 +1,9 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2000, 2007 Software AG
Copyright (c) 2008 Red Hat, Inc
-
+
S390 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
@@ -11,10 +11,10 @@
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.
@@ -27,24 +27,23 @@
/* Includes */
/* -------- */
/*====================================================================*/
-
+
#include <ffi.h>
#include <ffi_common.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-
+#include <stdint.h>
+#include "internal.h"
+
/*====================== End of Includes =============================*/
-
+
/*====================================================================*/
/* Defines */
/* ------- */
/*====================================================================*/
-/* Maximum number of GPRs available for argument passing. */
+/* Maximum number of GPRs available for argument passing. */
#define MAX_GPRARGS 5
-/* Maximum number of FPRs available for argument passing. */
+/* Maximum number of FPRs available for argument passing. */
#ifdef __s390x__
#define MAX_FPRARGS 4
#else
@@ -54,47 +53,30 @@
/* Round to multiple of 16. */
#define ROUND_SIZE(size) (((size) + 15) & ~15)
-/* If these values change, sysv.S must be adapted! */
-#define FFI390_RET_VOID 0
-#define FFI390_RET_STRUCT 1
-#define FFI390_RET_FLOAT 2
-#define FFI390_RET_DOUBLE 3
-#define FFI390_RET_INT32 4
-#define FFI390_RET_INT64 5
-
/*===================== End of Defines ===============================*/
-
-/*====================================================================*/
-/* Prototypes */
-/* ---------- */
-/*====================================================================*/
-
-static void ffi_prep_args (unsigned char *, extended_cif *);
-void
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
-__attribute__ ((visibility ("hidden")))
-#endif
-ffi_closure_helper_SYSV (ffi_closure *, unsigned long *,
- unsigned long long *, unsigned long *);
-/*====================== End of Prototypes ===========================*/
-
/*====================================================================*/
/* Externals */
/* --------- */
/*====================================================================*/
-
-extern void ffi_call_SYSV(unsigned,
- extended_cif *,
- void (*)(unsigned char *, extended_cif *),
- unsigned,
- void *,
- void (*fn)(void));
+
+struct call_frame
+{
+ void *back_chain;
+ void *eos;
+ unsigned long gpr_args[5];
+ unsigned long gpr_save[9];
+ unsigned long long fpr_args[4];
+};
+
+extern void FFI_HIDDEN ffi_call_SYSV(struct call_frame *, unsigned, void *,
+ void (*fn)(void), void *);
extern void ffi_closure_SYSV(void);
-
+extern void ffi_go_closure_SYSV(void);
+
/*====================== End of Externals ============================*/
-
+
/*====================================================================*/
/* */
/* Name - ffi_check_struct_type. */
@@ -103,7 +85,7 @@ extern void ffi_closure_SYSV(void);
/* general purpose or floating point register. */
/* */
/*====================================================================*/
-
+
static int
ffi_check_struct_type (ffi_type *arg)
{
@@ -111,7 +93,7 @@ ffi_check_struct_type (ffi_type *arg)
/* If the struct has just one element, look at that element
to find out whether to consider the struct as floating point. */
- while (arg->type == FFI_TYPE_STRUCT
+ while (arg->type == FFI_TYPE_STRUCT
&& arg->elements[0] && !arg->elements[1])
arg = arg->elements[0];
@@ -144,193 +126,9 @@ ffi_check_struct_type (ffi_type *arg)
/* Other structs are passed via a pointer to the data. */
return FFI_TYPE_POINTER;
}
-
-/*======================== End of Routine ============================*/
-
-/*====================================================================*/
-/* */
-/* Name - ffi_prep_args. */
-/* */
-/* Function - Prepare parameters for call to function. */
-/* */
-/* ffi_prep_args is called by the assembly routine once stack space */
-/* has been allocated for the function's arguments. */
-/* */
-/*====================================================================*/
-
-static void
-ffi_prep_args (unsigned char *stack, extended_cif *ecif)
-{
- /* The stack space will be filled with those areas:
-
- FPR argument register save area (highest addresses)
- GPR argument register save area
- temporary struct copies
- overflow argument area (lowest addresses)
-
- We set up the following pointers:
-
- p_fpr: bottom of the FPR area (growing upwards)
- p_gpr: bottom of the GPR area (growing upwards)
- p_ov: bottom of the overflow area (growing upwards)
- p_struct: top of the struct copy area (growing downwards)
-
- All areas are kept aligned to twice the word size. */
-
- int gpr_off = ecif->cif->bytes;
- int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));
-
- unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off);
- unsigned long *p_gpr = (unsigned long *)(stack + gpr_off);
- unsigned char *p_struct = (unsigned char *)p_gpr;
- unsigned long *p_ov = (unsigned long *)stack;
-
- int n_fpr = 0;
- int n_gpr = 0;
- int n_ov = 0;
-
- ffi_type **ptr;
- void **p_argv = ecif->avalue;
- int i;
-
- /* If we returning a structure then we set the first parameter register
- to the address of where we are returning this structure. */
-
- if (ecif->cif->flags == FFI390_RET_STRUCT)
- p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
-
- /* Now for the arguments. */
-
- for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
- i > 0;
- i--, ptr++, p_argv++)
- {
- void *arg = *p_argv;
- int type = (*ptr)->type;
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- /* 16-byte long double is passed like a struct. */
- if (type == FFI_TYPE_LONGDOUBLE)
- type = FFI_TYPE_STRUCT;
-#endif
-
- /* Check how a structure type is passed. */
- if (type == FFI_TYPE_STRUCT || type == FFI_TYPE_COMPLEX)
- {
- if (type == FFI_TYPE_COMPLEX)
- type = FFI_TYPE_POINTER;
- else
- type = ffi_check_struct_type (*ptr);
-
- /* If we pass the struct via pointer, copy the data. */
- if (type == FFI_TYPE_POINTER)
- {
- p_struct -= ROUND_SIZE ((*ptr)->size);
- memcpy (p_struct, (char *)arg, (*ptr)->size);
- arg = &p_struct;
- }
- }
-
- /* Now handle all primitive int/pointer/float data types. */
- switch (type)
- {
- case FFI_TYPE_DOUBLE:
- if (n_fpr < MAX_FPRARGS)
- p_fpr[n_fpr++] = *(unsigned long long *) arg;
- else
-#ifdef __s390x__
- p_ov[n_ov++] = *(unsigned long *) arg;
-#else
- p_ov[n_ov++] = ((unsigned long *) arg)[0],
- p_ov[n_ov++] = ((unsigned long *) arg)[1];
-#endif
- break;
-
- case FFI_TYPE_FLOAT:
- if (n_fpr < MAX_FPRARGS)
- p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32;
- else
- p_ov[n_ov++] = *(unsigned int *) arg;
- break;
-
- case FFI_TYPE_POINTER:
- if (n_gpr < MAX_GPRARGS)
- p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
- else
- p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
- break;
-
- case FFI_TYPE_UINT64:
- case FFI_TYPE_SINT64:
-#ifdef __s390x__
- if (n_gpr < MAX_GPRARGS)
- p_gpr[n_gpr++] = *(unsigned long *) arg;
- else
- p_ov[n_ov++] = *(unsigned long *) arg;
-#else
- if (n_gpr == MAX_GPRARGS-1)
- n_gpr = MAX_GPRARGS;
- if (n_gpr < MAX_GPRARGS)
- p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
- p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
- else
- p_ov[n_ov++] = ((unsigned long *) arg)[0],
- p_ov[n_ov++] = ((unsigned long *) arg)[1];
-#endif
- break;
-
- case FFI_TYPE_UINT32:
- if (n_gpr < MAX_GPRARGS)
- p_gpr[n_gpr++] = *(unsigned int *) arg;
- else
- p_ov[n_ov++] = *(unsigned int *) arg;
- break;
-
- case FFI_TYPE_INT:
- case FFI_TYPE_SINT32:
- if (n_gpr < MAX_GPRARGS)
- p_gpr[n_gpr++] = *(signed int *) arg;
- else
- p_ov[n_ov++] = *(signed int *) arg;
- break;
-
- case FFI_TYPE_UINT16:
- if (n_gpr < MAX_GPRARGS)
- p_gpr[n_gpr++] = *(unsigned short *) arg;
- else
- p_ov[n_ov++] = *(unsigned short *) arg;
- break;
-
- case FFI_TYPE_SINT16:
- if (n_gpr < MAX_GPRARGS)
- p_gpr[n_gpr++] = *(signed short *) arg;
- else
- p_ov[n_ov++] = *(signed short *) arg;
- break;
-
- case FFI_TYPE_UINT8:
- if (n_gpr < MAX_GPRARGS)
- p_gpr[n_gpr++] = *(unsigned char *) arg;
- else
- p_ov[n_ov++] = *(unsigned char *) arg;
- break;
-
- case FFI_TYPE_SINT8:
- if (n_gpr < MAX_GPRARGS)
- p_gpr[n_gpr++] = *(signed char *) arg;
- else
- p_ov[n_ov++] = *(signed char *) arg;
- break;
-
- default:
- FFI_ASSERT (0);
- break;
- }
- }
-}
/*======================== End of Routine ============================*/
-
+
/*====================================================================*/
/* */
/* Name - ffi_prep_cif_machdep. */
@@ -338,8 +136,8 @@ ffi_prep_args (unsigned char *stack, extended_cif *ecif)
/* Function - Perform machine dependent CIF processing. */
/* */
/*====================================================================*/
-
-ffi_status
+
+ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif *cif)
{
size_t struct_size = 0;
@@ -350,7 +148,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
ffi_type **ptr;
int i;
- /* Determine return value handling. */
+ /* Determine return value handling. */
switch (cif->rtype->type)
{
@@ -364,7 +162,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
case FFI_TYPE_COMPLEX:
cif->flags = FFI390_RET_STRUCT;
n_gpr++; /* We need one GPR to pass the pointer. */
- break;
+ break;
/* Floating point values are returned in fpr 0. */
case FFI_TYPE_FLOAT:
@@ -403,14 +201,14 @@ ffi_prep_cif_machdep(ffi_cif *cif)
cif->flags = FFI390_RET_INT32;
#endif
break;
-
+
default:
FFI_ASSERT (0);
break;
}
/* Now for the arguments. */
-
+
for (ptr = cif->arg_types, i = cif->nargs;
i > 0;
i--, ptr++)
@@ -438,7 +236,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
}
/* Now handle all primitive int/float data types. */
- switch (type)
+ switch (type)
{
/* The first MAX_FPRARGS floating point arguments
go in FPRs, the rest overflow to the stack. */
@@ -449,7 +247,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
else
n_ov += sizeof (double) / sizeof (long);
break;
-
+
case FFI_TYPE_FLOAT:
if (n_fpr < MAX_FPRARGS)
n_fpr++;
@@ -459,9 +257,9 @@ ffi_prep_cif_machdep(ffi_cif *cif)
/* On 31-bit machines, 64-bit integers are passed in GPR pairs,
if one is still available, or else on the stack. If only one
- register is free, skip the register (it won't be used for any
+ register is free, skip the register (it won't be used for any
subsequent argument either). */
-
+
#ifndef __s390x__
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
@@ -477,7 +275,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
/* Everything else is passed in GPRs (until MAX_GPRARGS
have been used) or overflows to the stack. */
- default:
+ default:
if (n_gpr < MAX_GPRARGS)
n_gpr++;
else
@@ -490,12 +288,12 @@ ffi_prep_cif_machdep(ffi_cif *cif)
and temporary structure copies. */
cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
-
+
return FFI_OK;
}
-
+
/*======================== End of Routine ============================*/
-
+
/*====================================================================*/
/* */
/* Name - ffi_call. */
@@ -503,42 +301,195 @@ ffi_prep_cif_machdep(ffi_cif *cif)
/* Function - Call the FFI routine. */
/* */
/*====================================================================*/
-
-void
-ffi_call(ffi_cif *cif,
- void (*fn)(void),
- void *rvalue,
- void **avalue)
+
+static void
+ffi_call_int(ffi_cif *cif,
+ void (*fn)(void),
+ void *rvalue,
+ void **avalue,
+ void *closure)
{
int ret_type = cif->flags;
- extended_cif ecif;
-
- ecif.cif = cif;
- ecif.avalue = avalue;
- ecif.rvalue = rvalue;
+ size_t rsize = 0, bytes = cif->bytes;
+ unsigned char *stack, *p_struct;
+ struct call_frame *frame;
+ unsigned long *p_ov, *p_gpr;
+ unsigned long long *p_fpr;
+ int n_fpr, n_gpr, n_ov, i, n;
+ ffi_type **arg_types;
+
+ FFI_ASSERT (cif->abi == FFI_SYSV);
/* If we don't have a return value, we need to fake one. */
if (rvalue == NULL)
{
- if (ret_type == FFI390_RET_STRUCT)
- ecif.rvalue = alloca (cif->rtype->size);
+ if (ret_type & FFI390_RET_IN_MEM)
+ rsize = cif->rtype->size;
else
ret_type = FFI390_RET_VOID;
- }
+ }
+
+ /* The stack space will be filled with those areas:
- switch (cif->abi)
+ dummy structure return (highest addresses)
+ FPR argument register save area
+ GPR argument register save area
+ stack frame for ffi_call_SYSV
+ temporary struct copies
+ overflow argument area (lowest addresses)
+
+ We set up the following pointers:
+
+ p_fpr: bottom of the FPR area (growing upwards)
+ p_gpr: bottom of the GPR area (growing upwards)
+ p_ov: bottom of the overflow area (growing upwards)
+ p_struct: top of the struct copy area (growing downwards)
+
+ All areas are kept aligned to twice the word size.
+
+ Note that we're going to create the stack frame for both
+ ffi_call_SYSV _and_ the target function right here. This
+ works because we don't make any function calls with more
+ than 5 arguments (indeed only memcpy and ffi_call_SYSV),
+ and thus we don't have any stacked outgoing parameters. */
+
+ stack = alloca (bytes + sizeof(struct call_frame) + rsize);
+ frame = (struct call_frame *)(stack + bytes);
+ if (rsize)
+ rvalue = frame + 1;
+
+ /* Link the new frame back to the one from this function. */
+ frame->back_chain = __builtin_frame_address (0);
+
+ /* Fill in all of the argument stuff. */
+ p_ov = (unsigned long *)stack;
+ p_struct = (unsigned char *)frame;
+ p_gpr = frame->gpr_args;
+ p_fpr = frame->fpr_args;
+ n_fpr = n_gpr = n_ov = 0;
+
+ /* If we returning a structure then we set the first parameter register
+ to the address of where we are returning this structure. */
+ if (cif->flags & FFI390_RET_IN_MEM)
+ p_gpr[n_gpr++] = (uintptr_t) rvalue;
+
+ /* Now for the arguments. */
+ arg_types = cif->arg_types;
+ for (i = 0, n = cif->nargs; i < n; ++i)
{
- case FFI_SYSV:
- ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
- ret_type, ecif.rvalue, fn);
- break;
-
- default:
- FFI_ASSERT (0);
- break;
+ ffi_type *ty = arg_types[i];
+ void *arg = avalue[i];
+ int type = ty->type;
+ ffi_arg val;
+
+ restart:
+ switch (type)
+ {
+ case FFI_TYPE_SINT8:
+ val = *(SINT8 *)arg;
+ goto do_int;
+ case FFI_TYPE_UINT8:
+ val = *(UINT8 *)arg;
+ goto do_int;
+ case FFI_TYPE_SINT16:
+ val = *(SINT16 *)arg;
+ goto do_int;
+ case FFI_TYPE_UINT16:
+ val = *(UINT16 *)arg;
+ goto do_int;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ val = *(SINT32 *)arg;
+ goto do_int;
+ case FFI_TYPE_UINT32:
+ val = *(UINT32 *)arg;
+ goto do_int;
+ case FFI_TYPE_POINTER:
+ val = *(uintptr_t *)arg;
+ do_int:
+ *(n_gpr < MAX_GPRARGS ? p_gpr + n_gpr++ : p_ov + n_ov++) = val;
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+#ifdef __s390x__
+ val = *(UINT64 *)arg;
+ goto do_int;
+#else
+ if (n_gpr == MAX_GPRARGS-1)
+ n_gpr = MAX_GPRARGS;
+ if (n_gpr < MAX_GPRARGS)
+ p_gpr[n_gpr++] = ((UINT32 *) arg)[0],
+ p_gpr[n_gpr++] = ((UINT32 *) arg)[1];
+ else
+ p_ov[n_ov++] = ((UINT32 *) arg)[0],
+ p_ov[n_ov++] = ((UINT32 *) arg)[1];
+#endif
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ if (n_fpr < MAX_FPRARGS)
+ p_fpr[n_fpr++] = *(UINT64 *) arg;
+ else
+ {
+#ifdef __s390x__
+ p_ov[n_ov++] = *(UINT64 *) arg;
+#else
+ p_ov[n_ov++] = ((UINT32 *) arg)[0],
+ p_ov[n_ov++] = ((UINT32 *) arg)[1];
+#endif
+ }
+ break;
+
+ case FFI_TYPE_FLOAT:
+ val = *(UINT32 *)arg;
+ if (n_fpr < MAX_FPRARGS)
+ p_fpr[n_fpr++] = (UINT64)val << 32;
+ else
+ p_ov[n_ov++] = val;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ /* Check how a structure type is passed. */
+ type = ffi_check_struct_type (ty);
+ /* Some structures are passed via a type they contain. */
+ if (type != FFI_TYPE_POINTER)
+ goto restart;
+ /* ... otherwise, passed by reference. fallthru. */
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ /* 16-byte long double is passed via reference. */
+#endif
+ case FFI_TYPE_COMPLEX:
+ /* Complex types are passed via reference. */
+ p_struct -= ROUND_SIZE (ty->size);
+ memcpy (p_struct, arg, ty->size);
+ val = (uintptr_t)p_struct;
+ goto do_int;
+
+ default:
+ FFI_ASSERT (0);
+ break;
+ }
}
+
+ ffi_call_SYSV (frame, ret_type & FFI360_RET_MASK, rvalue, fn, closure);
}
-
+
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, NULL);
+}
+
+void
+ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, closure);
+}
+
/*======================== End of Routine ============================*/
/*====================================================================*/
@@ -548,9 +499,11 @@ ffi_call(ffi_cif *cif,
/* Function - Call a FFI closure target function. */
/* */
/*====================================================================*/
-
-void
-ffi_closure_helper_SYSV (ffi_closure *closure,
+
+void FFI_HIDDEN
+ffi_closure_helper_SYSV (ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data,
unsigned long *p_gpr,
unsigned long long *p_fpr,
unsigned long *p_ov)
@@ -569,21 +522,16 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
int i;
/* Allocate buffer for argument list pointers. */
+ p_arg = avalue = alloca (cif->nargs * sizeof (void *));
- p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));
-
- /* If we returning a structure, pass the structure address
- directly to the target function. Otherwise, have the target
+ /* If we returning a structure, pass the structure address
+ directly to the target function. Otherwise, have the target
function store the return value to the GPR save area. */
-
- if (closure->cif->flags == FFI390_RET_STRUCT)
+ if (cif->flags & FFI390_RET_IN_MEM)
rvalue = (void *) p_gpr[n_gpr++];
/* Now for the arguments. */
-
- for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
- i > 0;
- i--, p_arg++, ptr++)
+ for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, p_arg++, ptr++)
{
int deref_struct_pointer = 0;
int type = (*ptr)->type;
@@ -602,7 +550,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
else
type = ffi_check_struct_type (*ptr);
- /* If we pass the struct via pointer, remember to
+ /* If we pass the struct via pointer, remember to
retrieve the pointer later. */
if (type == FFI_TYPE_POINTER)
deref_struct_pointer = 1;
@@ -610,30 +558,32 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
/* Pointers are passed like UINTs of the same size. */
if (type == FFI_TYPE_POINTER)
+ {
#ifdef __s390x__
- type = FFI_TYPE_UINT64;
+ type = FFI_TYPE_UINT64;
#else
- type = FFI_TYPE_UINT32;
+ type = FFI_TYPE_UINT32;
#endif
+ }
/* Now handle all primitive int/float data types. */
- switch (type)
+ switch (type)
{
case FFI_TYPE_DOUBLE:
if (n_fpr < MAX_FPRARGS)
*p_arg = &p_fpr[n_fpr++];
else
- *p_arg = &p_ov[n_ov],
+ *p_arg = &p_ov[n_ov],
n_ov += sizeof (double) / sizeof (long);
break;
-
+
case FFI_TYPE_FLOAT:
if (n_fpr < MAX_FPRARGS)
*p_arg = &p_fpr[n_fpr++];
else
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
break;
-
+
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
#ifdef __s390x__
@@ -650,7 +600,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
*p_arg = &p_ov[n_ov], n_ov += 2;
#endif
break;
-
+
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
@@ -659,7 +609,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
else
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
break;
-
+
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
if (n_gpr < MAX_GPRARGS)
@@ -675,7 +625,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
else
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
break;
-
+
default:
FFI_ASSERT (0);
break;
@@ -689,10 +639,10 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
/* Call the target function. */
- (closure->fun) (closure->cif, rvalue, avalue, closure->user_data);
+ (fun) (cif, rvalue, avalue, user_data);
/* Convert the return value. */
- switch (closure->cif->rtype->type)
+ switch (cif->rtype->type)
{
/* Void is easy, and so is struct. */
case FFI_TYPE_VOID:
@@ -743,7 +693,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
break;
}
}
-
+
/*======================== End of Routine ============================*/
/*====================================================================*/
@@ -753,7 +703,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
/* Function - Prepare a FFI closure. */
/* */
/*====================================================================*/
-
+
ffi_status
ffi_prep_closure_loc (ffi_closure *closure,
ffi_cif *cif,
@@ -761,32 +711,46 @@ ffi_prep_closure_loc (ffi_closure *closure,
void *user_data,
void *codeloc)
{
+ static unsigned short const template[] = {
+ 0x0d10, /* basr %r1,0 */
+#ifndef __s390x__
+ 0x9801, 0x1006, /* lm %r0,%r1,6(%r1) */
+#else
+ 0xeb01, 0x100e, 0x0004, /* lmg %r0,%r1,14(%r1) */
+#endif
+ 0x07f1 /* br %r1 */
+ };
+
+ unsigned long *tramp = (unsigned long *)&closure->tramp;
+
if (cif->abi != FFI_SYSV)
return FFI_BAD_ABI;
-#ifndef __s390x__
- *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
- *(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */
- *(short *)&closure->tramp [4] = 0x1006;
- *(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */
- *(long *)&closure->tramp [8] = (long)codeloc;
- *(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
-#else
- *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
- *(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */
- *(short *)&closure->tramp [4] = 0x100e;
- *(short *)&closure->tramp [6] = 0x0004;
- *(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */
- *(long *)&closure->tramp[16] = (long)codeloc;
- *(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
-#endif
-
+ memcpy (tramp, template, sizeof(template));
+ tramp[2] = (unsigned long)codeloc;
+ tramp[3] = (unsigned long)&ffi_closure_SYSV;
+
closure->cif = cif;
- closure->user_data = user_data;
closure->fun = fun;
-
+ closure->user_data = user_data;
+
return FFI_OK;
}
/*======================== End of Routine ============================*/
-
+
+/* Build a Go language closure. */
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,void**,void*))
+{
+ if (cif->abi != FFI_SYSV)
+ return FFI_BAD_ABI;
+
+ closure->tramp = ffi_go_closure_SYSV;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
diff --git a/src/s390/ffitarget.h b/src/s390/ffitarget.h
index 0e4868a1..d8a4ee4b 100644
--- a/src/s390/ffitarget.h
+++ b/src/s390/ffitarget.h
@@ -58,6 +58,7 @@ typedef enum ffi_abi {
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
+#define FFI_GO_CLOSURES 1
#ifdef S390X
#define FFI_TRAMPOLINE_SIZE 32
#else
diff --git a/src/s390/internal.h b/src/s390/internal.h
new file mode 100644
index 00000000..b8755786
--- /dev/null
+++ b/src/s390/internal.h
@@ -0,0 +1,11 @@
+/* If these values change, sysv.S must be adapted! */
+#define FFI390_RET_DOUBLE 0
+#define FFI390_RET_FLOAT 1
+#define FFI390_RET_INT64 2
+#define FFI390_RET_INT32 3
+#define FFI390_RET_VOID 4
+
+#define FFI360_RET_MASK 7
+#define FFI390_RET_IN_MEM 8
+
+#define FFI390_RET_STRUCT (FFI390_RET_VOID | FFI390_RET_IN_MEM)
diff --git a/src/s390/sysv.S b/src/s390/sysv.S
index 4731a317..c4b5006a 100644
--- a/src/s390/sysv.S
+++ b/src/s390/sysv.S
@@ -1,9 +1,9 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 2000 Software AG
Copyright (c) 2008 Red Hat, Inc.
-
+
S390 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
@@ -11,10 +11,10 @@
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
@@ -29,405 +29,296 @@
#include <fficonfig.h>
#include <ffi.h>
+ .text
+
#ifndef __s390x__
-
-.text
-
- # r2: cif->bytes
- # r3: &ecif
- # r4: ffi_prep_args
- # r5: ret_type
- # r6: ecif.rvalue
- # ov: fn
-
+
+ # r2: frame
+ # r3: ret_type
+ # r4: ret_addr
+ # r5: fun
+ # r6: closure
+
# This assumes we are using gas.
+ .balign 8
.globl ffi_call_SYSV
+ FFI_HIDDEN(ffi_call_SYSV)
.type ffi_call_SYSV,%function
ffi_call_SYSV:
-.LFB1:
- stm %r6,%r15,24(%r15) # Save registers
-.LCFI0:
- basr %r13,0 # Set up base register
-.Lbase:
- lr %r11,%r15 # Set up frame pointer
-.LCFI1:
- sr %r15,%r2
- ahi %r15,-96-48 # Allocate stack
- lr %r8,%r6 # Save ecif.rvalue
- sr %r9,%r9
- ic %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address
- l %r7,96(%r11) # Load function address
- st %r11,0(%r15) # Set up back chain
- ahi %r11,-48 # Register save area
-.LCFI2:
-
- la %r2,96(%r15) # Save area
- # r3 already holds &ecif
- basr %r14,%r4 # Call ffi_prep_args
-
- lm %r2,%r6,0(%r11) # Load arguments
- ld %f0,32(%r11)
- ld %f2,40(%r11)
- la %r14,0(%r13,%r9) # Set return address
- br %r7 # ... and call function
-
-.LretNone: # Return void
- l %r4,48+56(%r11)
- lm %r6,%r15,48+24(%r11)
- br %r4
-
-.LretFloat:
- l %r4,48+56(%r11)
- ste %f0,0(%r8) # Return float
- lm %r6,%r15,48+24(%r11)
- br %r4
-
-.LretDouble:
- l %r4,48+56(%r11)
- std %f0,0(%r8) # Return double
- lm %r6,%r15,48+24(%r11)
- br %r4
-
-.LretInt32:
- l %r4,48+56(%r11)
- st %r2,0(%r8) # Return int
- lm %r6,%r15,48+24(%r11)
- br %r4
-
-.LretInt64:
- l %r4,48+56(%r11)
- stm %r2,%r3,0(%r8) # Return long long
- lm %r6,%r15,48+24(%r11)
- br %r4
-
+ .cfi_startproc
+ st %r6,44(%r2) # Save registers
+ stm %r12,%r14,48(%r2)
+ lr %r13,%r2 # Install frame pointer
+ .cfi_rel_offset r6, 44
+ .cfi_rel_offset r12, 48
+ .cfi_rel_offset r13, 52
+ .cfi_rel_offset r14, 56
+ .cfi_def_cfa_register r13
+ st %r2,0(%r15) # Set up back chain
+ sla %r3,3 # ret_type *= 8
+ lr %r12,%r4 # Save ret_addr
+ lr %r1,%r5 # Save fun
+ lr %r0,%r6 # Install static chain
+
+ # Set return address, so that there is only one indirect jump.
+#ifdef HAVE_AS_S390_ZARCH
+ larl %r14,.Ltable
+ ar %r14,%r3
+#else
+ basr %r14,0
+0: la %r14,.Ltable-0b(%r14,%r3)
+#endif
+
+ lm %r2,%r6,8(%r13) # Load arguments
+ ld %f0,64(%r13)
+ ld %f2,72(%r13)
+ br %r1 # ... and call function
+
+ .balign 8
.Ltable:
- .byte .LretNone-.Lbase # FFI390_RET_VOID
- .byte .LretNone-.Lbase # FFI390_RET_STRUCT
- .byte .LretFloat-.Lbase # FFI390_RET_FLOAT
- .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE
- .byte .LretInt32-.Lbase # FFI390_RET_INT32
- .byte .LretInt64-.Lbase # FFI390_RET_INT64
+# FFI390_RET_DOUBLE
+ std %f0,0(%r12)
+ j .Ldone
+
+ .balign 8
+# FFI390_RET_FLOAT
+ ste %f0,0(%r12)
+ j .Ldone
+
+ .balign 8
+# FFI390_RET_INT64
+ st %r3,4(%r12)
+ nop
+ # fallthru
+
+ .balign 8
+# FFI390_RET_INT32
+ st %r2,0(%r12)
+ nop
+ # fallthru
+
+ .balign 8
+# FFI390_RET_VOID
+.Ldone:
+ l %r14,56(%r13)
+ l %r12,48(%r13)
+ l %r6,44(%r13)
+ l %r13,52(%r13)
+ .cfi_restore 14
+ .cfi_restore 13
+ .cfi_restore 12
+ .cfi_restore 6
+ .cfi_def_cfa r15, 96
+ br %r14
+ .cfi_endproc
+ .size ffi_call_SYSV,.-ffi_call_SYSV
-.LFE1:
-.ffi_call_SYSV_end:
- .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
+ .balign 8
+ .globl ffi_go_closure_SYSV
+ FFI_HIDDEN(ffi_go_closure_SYSV)
+ .type ffi_go_closure_SYSV,%function
+ffi_go_closure_SYSV:
+ .cfi_startproc
+ stm %r2,%r6,8(%r15) # Save arguments
+ lr %r4,%r0 # Load closure -> user_data
+ l %r2,4(%r4) # ->cif
+ l %r3,8(%r4) # ->fun
+ j .Ldoclosure
+ .cfi_endproc
+ .balign 8
.globl ffi_closure_SYSV
+ FFI_HIDDEN(ffi_closure_SYSV)
.type ffi_closure_SYSV,%function
ffi_closure_SYSV:
-.LFB2:
+ .cfi_startproc
+ stm %r2,%r6,8(%r15) # Save arguments
+ lr %r4,%r0 # Closure
+ l %r2,16(%r4) # ->cif
+ l %r3,20(%r4) # ->fun
+ l %r4,24(%r4) # ->user_data
+.Ldoclosure:
stm %r12,%r15,48(%r15) # Save registers
-.LCFI10:
+ lr %r12,%r15
+ .cfi_def_cfa_register r12
+ .cfi_rel_offset r6, 24
+ .cfi_rel_offset r12, 48
+ .cfi_rel_offset r13, 52
+ .cfi_rel_offset r14, 56
+ .cfi_rel_offset r15, 60
+#ifndef HAVE_AS_S390_ZARCH
basr %r13,0 # Set up base register
.Lcbase:
- stm %r2,%r6,8(%r15) # Save arguments
- std %f0,64(%r15)
- std %f2,72(%r15)
- lr %r1,%r15 # Set up stack frame
- ahi %r15,-96
-.LCFI11:
- l %r12,.Lchelper-.Lcbase(%r13) # Get helper function
- lr %r2,%r0 # Closure
- la %r3,8(%r1) # GPRs
- la %r4,64(%r1) # FPRs
- la %r5,96(%r1) # Overflow
- st %r1,0(%r15) # Set up back chain
-
- bas %r14,0(%r12,%r13) # Call helper
-
- l %r4,96+56(%r15)
- ld %f0,96+64(%r15) # Load return registers
- lm %r2,%r3,96+8(%r15)
- lm %r12,%r15,96+48(%r15)
- br %r4
+ l %r1,.Lchelper-.Lcbase(%r13) # Get helper function
+#endif
+ ahi %r15,-96-8 # Set up stack frame
+ st %r12,0(%r15) # Set up back chain
+
+ std %f0,64(%r12) # Save fp arguments
+ std %f2,72(%r12)
+
+ la %r5,96(%r12) # Overflow
+ st %r5,96(%r15)
+ la %r6,64(%r12) # FPRs
+ la %r5,8(%r12) # GPRs
+#ifdef HAVE_AS_S390_ZARCH
+ brasl %r14,ffi_closure_helper_SYSV
+#else
+ bas %r14,0(%r1,%r13) # Call helper
+#endif
+ lr %r15,%r12
+ .cfi_def_cfa_register r15
+ lm %r12,%r14,48(%r12) # Restore saved registers
+ l %r6,24(%r15)
+ ld %f0,64(%r15) # Load return registers
+ lm %r2,%r3,8(%r15)
+ br %r14
+ .cfi_endproc
+
+#ifndef HAVE_AS_S390_ZARCH
.align 4
.Lchelper:
.long ffi_closure_helper_SYSV-.Lcbase
+#endif
-.LFE2:
-
-.ffi_closure_SYSV_end:
- .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
-
-
- .section .eh_frame,EH_FRAME_FLAGS,@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 -4 # CIE Data Alignment Factor
- .byte 0xe # CIE RA Column
- .uleb128 0x1 # Augmentation size
- .byte 0x1b # FDE Encoding (pcrel sdata4)
- .byte 0xc # DW_CFA_def_cfa
- .uleb128 0xf
- .uleb128 0x60
- .align 4
-.LECIE1:
-.LSFDE1:
- .4byte .LEFDE1-.LASFDE1 # FDE Length
-.LASFDE1:
- .4byte .LASFDE1-.Lframe1 # FDE CIE offset
- .4byte .LFB1-. # FDE initial location
- .4byte .LFE1-.LFB1 # FDE address range
- .uleb128 0x0 # Augmentation size
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI0-.LFB1
- .byte 0x8f # DW_CFA_offset, column 0xf
- .uleb128 0x9
- .byte 0x8e # DW_CFA_offset, column 0xe
- .uleb128 0xa
- .byte 0x8d # DW_CFA_offset, column 0xd
- .uleb128 0xb
- .byte 0x8c # DW_CFA_offset, column 0xc
- .uleb128 0xc
- .byte 0x8b # DW_CFA_offset, column 0xb
- .uleb128 0xd
- .byte 0x8a # DW_CFA_offset, column 0xa
- .uleb128 0xe
- .byte 0x89 # DW_CFA_offset, column 0x9
- .uleb128 0xf
- .byte 0x88 # DW_CFA_offset, column 0x8
- .uleb128 0x10
- .byte 0x87 # DW_CFA_offset, column 0x7
- .uleb128 0x11
- .byte 0x86 # DW_CFA_offset, column 0x6
- .uleb128 0x12
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI1-.LCFI0
- .byte 0xd # DW_CFA_def_cfa_register
- .uleb128 0xb
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI2-.LCFI1
- .byte 0xe # DW_CFA_def_cfa_offset
- .uleb128 0x90
- .align 4
-.LEFDE1:
-.LSFDE2:
- .4byte .LEFDE2-.LASFDE2 # FDE Length
-.LASFDE2:
- .4byte .LASFDE2-.Lframe1 # FDE CIE offset
- .4byte .LFB2-. # FDE initial location
- .4byte .LFE2-.LFB2 # FDE address range
- .uleb128 0x0 # Augmentation size
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI10-.LFB2
- .byte 0x8f # DW_CFA_offset, column 0xf
- .uleb128 0x9
- .byte 0x8e # DW_CFA_offset, column 0xe
- .uleb128 0xa
- .byte 0x8d # DW_CFA_offset, column 0xd
- .uleb128 0xb
- .byte 0x8c # DW_CFA_offset, column 0xc
- .uleb128 0xc
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI11-.LCFI10
- .byte 0xe # DW_CFA_def_cfa_offset
- .uleb128 0xc0
- .align 4
-.LEFDE2:
+ .size ffi_closure_SYSV,.-ffi_closure_SYSV
#else
-
-.text
-
- # r2: cif->bytes
- # r3: &ecif
- # r4: ffi_prep_args
- # r5: ret_type
- # r6: ecif.rvalue
- # ov: fn
-
+
+ # r2: frame
+ # r3: ret_type
+ # r4: ret_addr
+ # r5: fun
+ # r6: closure
+
# This assumes we are using gas.
+ .balign 8
.globl ffi_call_SYSV
+ FFI_HIDDEN(ffi_call_SYSV)
.type ffi_call_SYSV,%function
ffi_call_SYSV:
-.LFB1:
- stmg %r6,%r15,48(%r15) # Save registers
-.LCFI0:
- larl %r13,.Lbase # Set up base register
- lgr %r11,%r15 # Set up frame pointer
-.LCFI1:
- sgr %r15,%r2
- aghi %r15,-160-80 # Allocate stack
- lgr %r8,%r6 # Save ecif.rvalue
- llgc %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address
- lg %r7,160(%r11) # Load function address
- stg %r11,0(%r15) # Set up back chain
- aghi %r11,-80 # Register save area
-.LCFI2:
-
- la %r2,160(%r15) # Save area
- # r3 already holds &ecif
- basr %r14,%r4 # Call ffi_prep_args
-
- lmg %r2,%r6,0(%r11) # Load arguments
- ld %f0,48(%r11)
- ld %f2,56(%r11)
- ld %f4,64(%r11)
- ld %f6,72(%r11)
- la %r14,0(%r13,%r9) # Set return address
- br %r7 # ... and call function
-
-.Lbase:
-.LretNone: # Return void
- lg %r4,80+112(%r11)
- lmg %r6,%r15,80+48(%r11)
- br %r4
-
-.LretFloat:
- lg %r4,80+112(%r11)
- ste %f0,0(%r8) # Return float
- lmg %r6,%r15,80+48(%r11)
- br %r4
-
-.LretDouble:
- lg %r4,80+112(%r11)
- std %f0,0(%r8) # Return double
- lmg %r6,%r15,80+48(%r11)
- br %r4
-
-.LretInt32:
- lg %r4,80+112(%r11)
- st %r2,0(%r8) # Return int
- lmg %r6,%r15,80+48(%r11)
- br %r4
-
-.LretInt64:
- lg %r4,80+112(%r11)
- stg %r2,0(%r8) # Return long
- lmg %r6,%r15,80+48(%r11)
- br %r4
-
+ .cfi_startproc
+ stg %r6,88(%r2) # Save registers
+ stmg %r12,%r14,96(%r2)
+ lgr %r13,%r2 # Install frame pointer
+ .cfi_rel_offset r6, 88
+ .cfi_rel_offset r12, 96
+ .cfi_rel_offset r13, 104
+ .cfi_rel_offset r14, 112
+ .cfi_def_cfa_register r13
+ stg %r2,0(%r15) # Set up back chain
+ larl %r14,.Ltable # Set up return address
+ slag %r3,%r3,3 # ret_type *= 8
+ lgr %r12,%r4 # Save ret_addr
+ lgr %r1,%r5 # Save fun
+ lgr %r0,%r6 # Install static chain
+ agr %r14,%r3
+ lmg %r2,%r6,16(%r13) # Load arguments
+ ld %f0,128(%r13)
+ ld %f2,136(%r13)
+ ld %f4,144(%r13)
+ ld %f6,152(%r13)
+ br %r1 # ... and call function
+
+ .balign 8
.Ltable:
- .byte .LretNone-.Lbase # FFI390_RET_VOID
- .byte .LretNone-.Lbase # FFI390_RET_STRUCT
- .byte .LretFloat-.Lbase # FFI390_RET_FLOAT
- .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE
- .byte .LretInt32-.Lbase # FFI390_RET_INT32
- .byte .LretInt64-.Lbase # FFI390_RET_INT64
+# FFI390_RET_DOUBLE
+ std %f0,0(%r12)
+ j .Ldone
+
+ .balign 8
+# FFI390_RET_DOUBLE
+ ste %f0,0(%r12)
+ j .Ldone
+
+ .balign 8
+# FFI390_RET_INT64
+ stg %r2,0(%r12)
+
+ .balign 8
+# FFI390_RET_INT32
+ # Never used, as we always store type ffi_arg.
+ # But the stg above is 6 bytes and we cannot
+ # jump around this case, so fall through.
+ nop
+ nop
+
+ .balign 8
+# FFI390_RET_VOID
+.Ldone:
+ lg %r14,112(%r13)
+ lg %r12,96(%r13)
+ lg %r6,88(%r13)
+ lg %r13,104(%r13)
+ .cfi_restore r14
+ .cfi_restore r13
+ .cfi_restore r12
+ .cfi_restore r6
+ .cfi_def_cfa r15, 160
+ br %r14
+ .cfi_endproc
+ .size ffi_call_SYSV,.-ffi_call_SYSV
-.LFE1:
-.ffi_call_SYSV_end:
- .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
+
+ .balign 8
+ .globl ffi_go_closure_SYSV
+ FFI_HIDDEN(ffi_go_closure_SYSV)
+ .type ffi_go_closure_SYSV,%function
+ffi_go_closure_SYSV:
+ .cfi_startproc
+ stmg %r2,%r6,16(%r15) # Save arguments
+ lgr %r4,%r0 # Load closure -> user_data
+ lg %r2,8(%r4) # ->cif
+ lg %r3,16(%r4) # ->fun
+ j .Ldoclosure
+ .cfi_endproc
+ .size ffi_go_closure_SYSV,.-ffi_go_closure_SYSV
+ .balign 8
.globl ffi_closure_SYSV
+ FFI_HIDDEN(ffi_closure_SYSV)
.type ffi_closure_SYSV,%function
ffi_closure_SYSV:
-.LFB2:
- stmg %r14,%r15,112(%r15) # Save registers
-.LCFI10:
+ .cfi_startproc
stmg %r2,%r6,16(%r15) # Save arguments
- std %f0,128(%r15)
- std %f2,136(%r15)
- std %f4,144(%r15)
- std %f6,152(%r15)
- lgr %r1,%r15 # Set up stack frame
- aghi %r15,-160
-.LCFI11:
- lgr %r2,%r0 # Closure
- la %r3,16(%r1) # GPRs
- la %r4,128(%r1) # FPRs
- la %r5,160(%r1) # Overflow
- stg %r1,0(%r15) # Set up back chain
-
+ lgr %r4,%r0 # Load closure
+ lg %r2,32(%r4) # ->cif
+ lg %r3,40(%r4) # ->fun
+ lg %r4,48(%r4) # ->user_data
+.Ldoclosure:
+ stmg %r13,%r15,104(%r15) # Save registers
+ lgr %r13,%r15
+ .cfi_def_cfa_register r13
+ .cfi_rel_offset r6, 48
+ .cfi_rel_offset r13, 104
+ .cfi_rel_offset r14, 112
+ .cfi_rel_offset r15, 120
+ aghi %r15,-160-16 # Set up stack frame
+ stg %r13,0(%r15) # Set up back chain
+
+ std %f0,128(%r13) # Save fp arguments
+ std %f2,136(%r13)
+ std %f4,144(%r13)
+ std %f6,152(%r13)
+ la %r5,160(%r13) # Overflow
+ stg %r5,160(%r15)
+ la %r6,128(%r13) # FPRs
+ la %r5,16(%r13) # GPRs
brasl %r14,ffi_closure_helper_SYSV # Call helper
- lg %r14,160+112(%r15)
- ld %f0,160+128(%r15) # Load return registers
- lg %r2,160+16(%r15)
- la %r15,160(%r15)
+ lgr %r15,%r13
+ .cfi_def_cfa_register r15
+ lmg %r13,%r14,104(%r13) # Restore saved registers
+ lg %r6,48(%r15)
+ ld %f0,128(%r15) # Load return registers
+ lg %r2,16(%r15)
br %r14
-.LFE2:
-
-.ffi_closure_SYSV_end:
- .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
-
-
-
- .section .eh_frame,EH_FRAME_FLAGS,@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 0xe # CIE RA Column
- .uleb128 0x1 # Augmentation size
- .byte 0x1b # FDE Encoding (pcrel sdata4)
- .byte 0xc # DW_CFA_def_cfa
- .uleb128 0xf
- .uleb128 0xa0
- .align 8
-.LECIE1:
-.LSFDE1:
- .4byte .LEFDE1-.LASFDE1 # FDE Length
-.LASFDE1:
- .4byte .LASFDE1-.Lframe1 # FDE CIE offset
- .4byte .LFB1-. # FDE initial location
- .4byte .LFE1-.LFB1 # FDE address range
- .uleb128 0x0 # Augmentation size
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI0-.LFB1
- .byte 0x8f # DW_CFA_offset, column 0xf
- .uleb128 0x5
- .byte 0x8e # DW_CFA_offset, column 0xe
- .uleb128 0x6
- .byte 0x8d # DW_CFA_offset, column 0xd
- .uleb128 0x7
- .byte 0x8c # DW_CFA_offset, column 0xc
- .uleb128 0x8
- .byte 0x8b # DW_CFA_offset, column 0xb
- .uleb128 0x9
- .byte 0x8a # DW_CFA_offset, column 0xa
- .uleb128 0xa
- .byte 0x89 # DW_CFA_offset, column 0x9
- .uleb128 0xb
- .byte 0x88 # DW_CFA_offset, column 0x8
- .uleb128 0xc
- .byte 0x87 # DW_CFA_offset, column 0x7
- .uleb128 0xd
- .byte 0x86 # DW_CFA_offset, column 0x6
- .uleb128 0xe
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI1-.LCFI0
- .byte 0xd # DW_CFA_def_cfa_register
- .uleb128 0xb
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI2-.LCFI1
- .byte 0xe # DW_CFA_def_cfa_offset
- .uleb128 0xf0
- .align 8
-.LEFDE1:
-.LSFDE2:
- .4byte .LEFDE2-.LASFDE2 # FDE Length
-.LASFDE2:
- .4byte .LASFDE2-.Lframe1 # FDE CIE offset
- .4byte .LFB2-. # FDE initial location
- .4byte .LFE2-.LFB2 # FDE address range
- .uleb128 0x0 # Augmentation size
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI10-.LFB2
- .byte 0x8f # DW_CFA_offset, column 0xf
- .uleb128 0x5
- .byte 0x8e # DW_CFA_offset, column 0xe
- .uleb128 0x6
- .byte 0x4 # DW_CFA_advance_loc4
- .4byte .LCFI11-.LCFI10
- .byte 0xe # DW_CFA_def_cfa_offset
- .uleb128 0x140
- .align 8
-.LEFDE2:
-
-#endif
+ .cfi_endproc
+ .size ffi_closure_SYSV,.-ffi_closure_SYSV
+#endif /* !s390x */
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
diff --git a/src/sparc/ffi.c b/src/sparc/ffi.c
index 9f0fded4..9e406d0a 100644
--- a/src/sparc/ffi.c
+++ b/src/sparc/ffi.c
@@ -27,655 +27,442 @@
#include <ffi.h>
#include <ffi_common.h>
-
#include <stdlib.h>
+#include "internal.h"
+#ifndef SPARC64
-/* ffi_prep_args is called by the assembly routine once stack space
- has been allocated for the function's arguments */
-
-void ffi_prep_args_v8(char *stack, extended_cif *ecif)
-{
- int i;
- void **p_argv;
- char *argp;
- ffi_type **p_arg;
-
- /* Skip 16 words for the window save area */
- argp = stack + 16*sizeof(int);
-
- /* This should only really be done when we are returning a structure,
- however, it's faster just to do it all the time...
-
- if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
- *(int *) argp = (long)ecif->rvalue;
-
- /* And 1 word for the structure return value. */
- argp += sizeof(int);
-
-#ifdef USING_PURIFY
- /* Purify will probably complain in our assembly routine, unless we
- zero out this memory. */
-
- ((int*)argp)[0] = 0;
- ((int*)argp)[1] = 0;
- ((int*)argp)[2] = 0;
- ((int*)argp)[3] = 0;
- ((int*)argp)[4] = 0;
- ((int*)argp)[5] = 0;
-#endif
-
- p_argv = ecif->avalue;
-
- for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
- {
- size_t z;
-
- if ((*p_arg)->type == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
-#endif
- )
- {
- *(unsigned int *) argp = (unsigned long)(* p_argv);
- z = sizeof(int);
- }
- else
- {
- z = (*p_arg)->size;
- if (z < sizeof(int))
- {
- z = sizeof(int);
- switch ((*p_arg)->type)
- {
- case FFI_TYPE_SINT8:
- *(signed int *) argp = *(SINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT8:
- *(unsigned int *) argp = *(UINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_SINT16:
- *(signed int *) argp = *(SINT16 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT16:
- *(unsigned int *) argp = *(UINT16 *)(* p_argv);
- break;
-
- default:
- FFI_ASSERT(0);
- }
- }
- else
- {
- memcpy(argp, *p_argv, z);
- }
- }
- p_argv++;
- argp += z;
- }
-
- return;
-}
-
-int ffi_prep_args_v9(char *stack, extended_cif *ecif)
-{
- int i, ret = 0;
- int tmp;
- void **p_argv;
- char *argp;
- ffi_type **p_arg;
-
- tmp = 0;
-
- /* Skip 16 words for the window save area */
- argp = stack + 16*sizeof(long long);
-
-#ifdef USING_PURIFY
- /* Purify will probably complain in our assembly routine, unless we
- zero out this memory. */
-
- ((long long*)argp)[0] = 0;
- ((long long*)argp)[1] = 0;
- ((long long*)argp)[2] = 0;
- ((long long*)argp)[3] = 0;
- ((long long*)argp)[4] = 0;
- ((long long*)argp)[5] = 0;
-#endif
-
- p_argv = ecif->avalue;
-
- if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
- ecif->cif->rtype->size > 32)
- {
- *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
- argp += sizeof(long long);
- tmp = 1;
- }
-
- for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
- i++, p_arg++)
- {
- size_t z;
-
- z = (*p_arg)->size;
- switch ((*p_arg)->type)
- {
- case FFI_TYPE_STRUCT:
- if (z > 16)
- {
- /* For structures larger than 16 bytes we pass reference. */
- *(unsigned long long *) argp = (unsigned long)* p_argv;
- argp += sizeof(long long);
- tmp++;
- p_argv++;
- continue;
- }
- /* FALLTHROUGH */
- case FFI_TYPE_FLOAT:
- case FFI_TYPE_DOUBLE:
+/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
+ all further uses in this file will refer to the 128-bit type. */
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
+# if FFI_TYPE_LONGDOUBLE != 4
+# error FFI_TYPE_LONGDOUBLE out of date
+# endif
+#else
+# undef FFI_TYPE_LONGDOUBLE
+# define FFI_TYPE_LONGDOUBLE 4
#endif
- ret = 1; /* We should promote into FP regs as well as integer. */
- break;
- }
- if (z < sizeof(long long))
- {
- switch ((*p_arg)->type)
- {
- case FFI_TYPE_SINT8:
- *(signed long long *) argp = *(SINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT8:
- *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_SINT16:
- *(signed long long *) argp = *(SINT16 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT16:
- *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
- break;
-
- case FFI_TYPE_SINT32:
- *(signed long long *) argp = *(SINT32 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT32:
- *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
- break;
-
- case FFI_TYPE_FLOAT:
- *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
- break;
-
- case FFI_TYPE_STRUCT:
- memcpy(argp, *p_argv, z);
- break;
-
- default:
- FFI_ASSERT(0);
- }
- z = sizeof(long long);
- tmp++;
- }
- else if (z == sizeof(long long))
- {
- memcpy(argp, *p_argv, z);
- z = sizeof(long long);
- tmp++;
- }
- else
- {
- if ((tmp & 1) && (*p_arg)->alignment > 8)
- {
- tmp++;
- argp += sizeof(long long);
- }
- memcpy(argp, *p_argv, z);
- z = 2 * sizeof(long long);
- tmp += 2;
- }
- p_argv++;
- argp += z;
- }
-
- return ret;
-}
/* Perform machine dependent cif processing */
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep(ffi_cif *cif)
{
- int wordsize;
-
- if (cif->abi != FFI_V9)
- {
- wordsize = 4;
-
- /* If we are returning a struct, this will already have been added.
- Otherwise we need to add it because it's always got to be there! */
-
- if (cif->rtype->type != FFI_TYPE_STRUCT)
- cif->bytes += wordsize;
-
- /* sparc call frames require that space is allocated for 6 args,
- even if they aren't used. Make that space if necessary. */
-
- if (cif->bytes < 4*6+4)
- cif->bytes = 4*6+4;
- }
- else
- {
- wordsize = 8;
-
- /* sparc call frames require that space is allocated for 6 args,
- even if they aren't used. Make that space if necessary. */
-
- if (cif->bytes < 8*6)
- cif->bytes = 8*6;
- }
-
- /* Adjust cif->bytes. to include 16 words for the window save area,
- and maybe the struct/union return pointer area, */
-
- cif->bytes += 16 * wordsize;
-
- /* The stack must be 2 word aligned, so round bytes up
- appropriately. */
-
- cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
+ ffi_type *rtype = cif->rtype;
+ int rtt = rtype->type;
+ size_t bytes;
+ int i, n, flags;
/* Set the return type flag */
- switch (cif->rtype->type)
+ switch (rtt)
{
case FFI_TYPE_VOID:
+ flags = SPARC_RET_VOID;
+ break;
case FFI_TYPE_FLOAT:
+ flags = SPARC_RET_F_1;
+ break;
case FFI_TYPE_DOUBLE:
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
-#endif
- cif->flags = cif->rtype->type;
+ flags = SPARC_RET_F_2;
break;
-
+ case FFI_TYPE_LONGDOUBLE:
case FFI_TYPE_STRUCT:
- if (cif->abi == FFI_V9 && cif->rtype->size > 32)
- cif->flags = FFI_TYPE_VOID;
- else
- cif->flags = FFI_TYPE_STRUCT;
+ flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT;
+ flags |= SPARC_RET_STRUCT;
break;
-
case FFI_TYPE_SINT8:
+ flags = SPARC_RET_SINT8;
+ break;
case FFI_TYPE_UINT8:
+ flags = SPARC_RET_UINT8;
+ break;
case FFI_TYPE_SINT16:
+ flags = SPARC_RET_SINT16;
+ break;
case FFI_TYPE_UINT16:
- if (cif->abi == FFI_V9)
- cif->flags = FFI_TYPE_INT;
- else
- cif->flags = cif->rtype->type;
+ flags = SPARC_RET_UINT16;
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_POINTER:
+ flags = SPARC_RET_UINT32;
break;
-
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
- if (cif->abi == FFI_V9)
- cif->flags = FFI_TYPE_INT;
- else
- cif->flags = FFI_TYPE_SINT64;
+ flags = SPARC_RET_INT64;
break;
-
- default:
- cif->flags = FFI_TYPE_INT;
+ case FFI_TYPE_COMPLEX:
+ rtt = rtype->elements[0]->type;
+ switch (rtt)
+ {
+ case FFI_TYPE_FLOAT:
+ flags = SPARC_RET_F_2;
+ break;
+ case FFI_TYPE_DOUBLE:
+ flags = SPARC_RET_F_4;
+ break;
+ case FFI_TYPE_LONGDOUBLE:
+ flags = SPARC_RET_F_8;
+ break;
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ flags = SPARC_RET_INT128;
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ flags = SPARC_RET_INT64;
+ break;
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ flags = SP_V8_RET_CPLX16;
+ break;
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ flags = SP_V8_RET_CPLX8;
+ break;
+ default:
+ abort();
+ }
break;
+ default:
+ abort();
}
- return FFI_OK;
-}
-
-int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
-{
- ffi_type **ptr = &arg->elements[0];
+ cif->flags = flags;
- while (*ptr != NULL)
+ bytes = 0;
+ for (i = 0, n = cif->nargs; i < n; ++i)
{
- if (off & ((*ptr)->alignment - 1))
- off = ALIGN(off, (*ptr)->alignment);
+ ffi_type *ty = cif->arg_types[i];
+ size_t z = ty->size;
+ int tt = ty->type;
- switch ((*ptr)->type)
+ switch (tt)
{
case FFI_TYPE_STRUCT:
- off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
- off = ALIGN(off, FFI_SIZEOF_ARG);
- break;
- case FFI_TYPE_FLOAT:
- case FFI_TYPE_DOUBLE:
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
-#endif
- memmove(ret + off, flt + off, (*ptr)->size);
- off += (*ptr)->size;
+ by_reference:
+ /* Passed by reference. */
+ z = 4;
break;
+
+ case FFI_TYPE_COMPLEX:
+ tt = ty->elements[0]->type;
+ if (tt == FFI_TYPE_FLOAT || z > 8)
+ goto by_reference;
+ /* FALLTHRU */
+
default:
- memmove(ret + off, intg + off, (*ptr)->size);
- off += (*ptr)->size;
- break;
+ z = FFI_ALIGN(z, 4);
}
- ptr++;
+ bytes += z;
}
- return off;
-}
+ /* Sparc call frames require that space is allocated for 6 args,
+ even if they aren't used. Make that space if necessary. */
+ if (bytes < 6 * 4)
+ bytes = 6 * 4;
-#ifdef SPARC64
-extern int ffi_call_v9(void *, extended_cif *, unsigned,
- unsigned, unsigned *, void (*fn)(void));
-#else
-extern int ffi_call_v8(void *, extended_cif *, unsigned,
- unsigned, unsigned *, void (*fn)(void));
-#endif
+ /* The ABI always requires space for the struct return pointer. */
+ bytes += 4;
-#ifndef __GNUC__
-void ffi_flush_icache (void *, size_t);
-#endif
+ /* The stack must be 2 word aligned, so round bytes up appropriately. */
+ bytes = FFI_ALIGN(bytes, 2 * 4);
-void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
-{
- extended_cif ecif;
- void *rval = rvalue;
+ /* Include the call frame to prep_args. */
+ bytes += 4*16 + 4*8;
+ cif->bytes = bytes;
- ecif.cif = cif;
- ecif.avalue = avalue;
+ return FFI_OK;
+}
+
+extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
- /* If the return value is a struct and we don't have a return */
- /* value address then we need to make one */
+int FFI_HIDDEN
+ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
+{
+ ffi_type **p_arg;
+ int flags = cif->flags;
+ int i, nargs;
- ecif.rvalue = rvalue;
- if (cif->rtype->type == FFI_TYPE_STRUCT)
+ if (rvalue == NULL)
{
- if (cif->rtype->size <= 32)
- rval = alloca(64);
+ if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
+ {
+ /* Since we pass the pointer to the callee, we need a value.
+ We allowed for this space in ffi_call, before ffi_call_v8
+ alloca'd the space. */
+ rvalue = (char *)argp + cif->bytes;
+ }
else
{
- rval = NULL;
- if (rvalue == NULL)
- ecif.rvalue = alloca(cif->rtype->size);
+ /* Otherwise, we can ignore the return value. */
+ flags = SPARC_RET_VOID;
}
}
- switch (cif->abi)
- {
- case FFI_V8:
-#ifdef SPARC64
- /* We don't yet support calling 32bit code from 64bit */
- FFI_ASSERT(0);
-#else
- if (rvalue && (cif->rtype->type == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- || cif->flags == FFI_TYPE_LONGDOUBLE
+ /* This could only really be done when we are returning a structure.
+ However, the space is reserved so we can do it unconditionally. */
+ *argp++ = (unsigned long)rvalue;
+
+#ifdef USING_PURIFY
+ /* Purify will probably complain in our assembly routine,
+ unless we zero out this memory. */
+ memset(argp, 0, 6*4);
#endif
- ))
+
+ p_arg = cif->arg_types;
+ for (i = 0, nargs = cif->nargs; i < nargs; i++)
+ {
+ ffi_type *ty = p_arg[i];
+ void *a = avalue[i];
+ int tt = ty->type;
+ size_t z;
+
+ switch (tt)
{
- /* For v8, we need an "unimp" with size of returning struct */
- /* behind "call", so we alloc some executable space for it. */
- /* l7 is used, we need to make sure v8.S doesn't use %l7. */
- unsigned int *call_struct = NULL;
- ffi_closure_alloc(32, (void **)&call_struct);
- if (call_struct)
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_LONGDOUBLE:
+ by_reference:
+ *argp++ = (unsigned long)a;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ memcpy(argp, a, 8);
+ argp += 2;
+ break;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_POINTER:
+ *argp++ = *(unsigned *)a;
+ break;
+
+ case FFI_TYPE_UINT8:
+ *argp++ = *(UINT8 *)a;
+ break;
+ case FFI_TYPE_SINT8:
+ *argp++ = *(SINT8 *)a;
+ break;
+ case FFI_TYPE_UINT16:
+ *argp++ = *(UINT16 *)a;
+ break;
+ case FFI_TYPE_SINT16:
+ *argp++ = *(SINT16 *)a;
+ break;
+
+ case FFI_TYPE_COMPLEX:
+ tt = ty->elements[0]->type;
+ z = ty->size;
+ if (tt == FFI_TYPE_FLOAT || z > 8)
+ goto by_reference;
+ if (z < 4)
{
- unsigned long f = (unsigned long)fn;
- call_struct[0] = 0xae10001f; /* mov %i7, %l7 */
- call_struct[1] = 0xbe10000f; /* mov %o7, %i7 */
- call_struct[2] = 0x03000000 | f >> 10; /* sethi %hi(fn), %g1 */
- call_struct[3] = 0x9fc06000 | (f & 0x3ff); /* jmp %g1+%lo(fn), %o7 */
- call_struct[4] = 0x01000000; /* nop */
- if (cif->rtype->size < 0x7f)
- call_struct[5] = cif->rtype->size; /* unimp */
- else
- call_struct[5] = 0x01000000; /* nop */
- call_struct[6] = 0x81c7e008; /* ret */
- call_struct[7] = 0xbe100017; /* mov %l7, %i7 */
-#ifdef __GNUC__
- asm volatile ("iflush %0; iflush %0+8; iflush %0+16; iflush %0+24" : :
- "r" (call_struct) : "memory");
- /* SPARC v8 requires 5 instructions for flush to be visible */
- asm volatile ("nop; nop; nop; nop; nop");
-#else
- ffi_flush_icache (call_struct, 32);
-#endif
- ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
- cif->flags, rvalue, call_struct);
- ffi_closure_free(call_struct);
+ memcpy((char *)argp + 4 - z, a, z);
+ argp++;
}
else
{
- ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
- cif->flags, rvalue, fn);
+ memcpy(argp, a, z);
+ argp += z / 4;
}
+ break;
+
+ default:
+ abort();
}
- else
- {
- ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
- cif->flags, rvalue, fn);
- }
-#endif
- break;
- case FFI_V9:
-#ifdef SPARC64
- ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
- cif->flags, rval, fn);
- if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
- ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
-#else
- /* And vice versa */
- FFI_ASSERT(0);
-#endif
- break;
- default:
- FFI_ASSERT(0);
- break;
}
+
+ return flags;
+}
+
+static void
+ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ size_t bytes = cif->bytes;
+
+ FFI_ASSERT (cif->abi == FFI_V8);
+
+ /* If we've not got a return value, we need to create one if we've
+ got to pass the return value to the callee. Otherwise ignore it. */
+ if (rvalue == NULL
+ && (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
+ bytes += FFI_ALIGN (cif->rtype->size, 8);
+
+ ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
}
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ ffi_call_int (cif, fn, rvalue, avalue, NULL);
+}
-#ifdef SPARC64
-extern void ffi_closure_v9(void);
+void
+ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int (cif, fn, rvalue, avalue, closure);
+}
+
+#ifdef __GNUC__
+static inline void
+ffi_flush_icache (void *p)
+{
+ /* SPARC v8 requires 5 instructions for flush to be visible */
+ asm volatile ("iflush %0; iflush %0+8; nop; nop; nop; nop; nop"
+ : : "r" (p) : "memory");
+}
#else
-extern void ffi_closure_v8(void);
+extern void ffi_flush_icache (void *) FFI_HIDDEN;
#endif
+extern void ffi_closure_v8(void) FFI_HIDDEN;
+extern void ffi_go_closure_v8(void) FFI_HIDDEN;
+
ffi_status
-ffi_prep_closure_loc (ffi_closure* closure,
- ffi_cif* cif,
+ffi_prep_closure_loc (ffi_closure *closure,
+ ffi_cif *cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *codeloc)
{
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
- unsigned long fn;
-#ifdef SPARC64
- /* Trampoline address is equal to the closure address. We take advantage
- of that to reduce the trampoline size by 8 bytes. */
- if (cif->abi != FFI_V9)
- return FFI_BAD_ABI;
- fn = (unsigned long) ffi_closure_v9;
- tramp[0] = 0x83414000; /* rd %pc, %g1 */
- tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
- tramp[2] = 0x81c14000; /* jmp %g5 */
- tramp[3] = 0x01000000; /* nop */
- *((unsigned long *) &tramp[4]) = fn;
-#else
- unsigned long ctx = (unsigned long) codeloc;
+ unsigned long ctx = (unsigned long) closure;
+ unsigned long fn = (unsigned long) ffi_closure_v8;
+
if (cif->abi != FFI_V8)
return FFI_BAD_ABI;
- fn = (unsigned long) ffi_closure_v8;
+
tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
-#endif
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
- /* Flush the Icache. closure is 8 bytes aligned. */
-#ifdef __GNUC__
-#ifdef SPARC64
- asm volatile ("flush %0; flush %0+8" : : "r" (closure) : "memory");
-#else
- asm volatile ("iflush %0; iflush %0+8" : : "r" (closure) : "memory");
- /* SPARC v8 requires 5 instructions for flush to be visible */
- asm volatile ("nop; nop; nop; nop; nop");
-#endif
-#else
- ffi_flush_icache (closure, 16);
-#endif
+ ffi_flush_icache (closure);
return FFI_OK;
}
-int
-ffi_closure_sparc_inner_v8(ffi_closure *closure,
- void *rvalue, unsigned long *gpr, unsigned long *scratch)
+ffi_status
+ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*))
{
- ffi_cif *cif;
- ffi_type **arg_types;
- void **avalue;
- int i, argn;
-
- cif = closure->cif;
- arg_types = cif->arg_types;
- avalue = alloca(cif->nargs * sizeof(void *));
-
- /* Copy the caller's structure return address so that the closure
- returns the data directly to the caller. */
- if (cif->flags == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- || cif->flags == FFI_TYPE_LONGDOUBLE
-#endif
- )
- rvalue = (void *) gpr[0];
-
- /* Always skip the structure return address. */
- argn = 1;
-
- /* Grab the addresses of the arguments from the stack frame. */
- for (i = 0; i < cif->nargs; i++)
- {
- if (arg_types[i]->type == FFI_TYPE_STRUCT
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
-#endif
- )
- {
- /* Straight copy of invisible reference. */
- avalue[i] = (void *)gpr[argn++];
- }
- else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
- || arg_types[i]->type == FFI_TYPE_SINT64
- || arg_types[i]->type == FFI_TYPE_UINT64)
- /* gpr is 8-byte aligned. */
- && (argn % 2) != 0)
- {
- /* Align on a 8-byte boundary. */
- scratch[0] = gpr[argn];
- scratch[1] = gpr[argn+1];
- avalue[i] = scratch;
- scratch -= 2;
- argn += 2;
- }
- else
- {
- /* Always right-justify. */
- argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
- avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
- }
- }
+ if (cif->abi != FFI_V8)
+ return FFI_BAD_ABI;
- /* Invoke the closure. */
- (closure->fun) (cif, rvalue, avalue, closure->user_data);
+ closure->tramp = ffi_go_closure_v8;
+ closure->cif = cif;
+ closure->fun = fun;
- /* Tell ffi_closure_sparc how to perform return type promotions. */
- return cif->rtype->type;
+ return FFI_OK;
}
-int
-ffi_closure_sparc_inner_v9(ffi_closure *closure,
- void *rvalue, unsigned long *gpr, double *fpr)
+int FFI_HIDDEN
+ffi_closure_sparc_inner_v8(ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data, void *rvalue,
+ unsigned long *argp)
{
- ffi_cif *cif;
ffi_type **arg_types;
void **avalue;
- int i, argn, fp_slot_max;
+ int i, nargs, flags;
- cif = closure->cif;
arg_types = cif->arg_types;
- avalue = alloca(cif->nargs * sizeof(void *));
+ nargs = cif->nargs;
+ flags = cif->flags;
+ avalue = alloca(nargs * sizeof(void *));
/* Copy the caller's structure return address so that the closure
- returns the data directly to the caller. */
- if (cif->flags == FFI_TYPE_VOID
- && cif->rtype->type == FFI_TYPE_STRUCT)
+ returns the data directly to the caller. Also install it so we
+ can return the address in %o0. */
+ if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
{
- rvalue = (void *) gpr[0];
- /* Skip the structure return address. */
- argn = 1;
+ void *new_rvalue = (void *)*argp;
+ *(void **)rvalue = new_rvalue;
+ rvalue = new_rvalue;
}
- else
- argn = 0;
- fp_slot_max = 16 - argn;
+ /* Always skip the structure return address. */
+ argp++;
/* Grab the addresses of the arguments from the stack frame. */
- for (i = 0; i < cif->nargs; i++)
+ for (i = 0; i < nargs; i++)
{
- if (arg_types[i]->type == FFI_TYPE_STRUCT)
+ ffi_type *ty = arg_types[i];
+ int tt = ty->type;
+ void *a = argp;
+ size_t z;
+
+ switch (tt)
{
- if (arg_types[i]->size > 16)
- {
- /* Straight copy of invisible reference. */
- avalue[i] = (void *)gpr[argn++];
- }
- else
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_LONGDOUBLE:
+ by_reference:
+ /* Straight copy of invisible reference. */
+ a = (void *)*argp;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ if ((unsigned long)a & 7)
{
- /* Left-justify. */
- ffi_v9_layout_struct(arg_types[i],
- 0,
- (char *) &gpr[argn],
- (char *) &gpr[argn],
- (char *) &fpr[argn]);
- avalue[i] = &gpr[argn];
- argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ /* Align on a 8-byte boundary. */
+ UINT64 *tmp = alloca(8);
+ *tmp = ((UINT64)argp[0] << 32) | argp[1];
+ a = tmp;
}
- }
- else
- {
- /* Right-justify. */
- argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ argp++;
+ break;
- /* Align on a 16-byte boundary. */
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- if (arg_types[i]->type == FFI_TYPE_LONGDOUBLE && (argn % 2) != 0)
- argn++;
-#endif
- if (i < fp_slot_max
- && (arg_types[i]->type == FFI_TYPE_FLOAT
- || arg_types[i]->type == FFI_TYPE_DOUBLE
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
-#endif
- ))
- avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
- else
- avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_POINTER:
+ break;
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ a += 2;
+ break;
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ a += 3;
+ break;
+
+ case FFI_TYPE_COMPLEX:
+ tt = ty->elements[0]->type;
+ z = ty->size;
+ if (tt == FFI_TYPE_FLOAT || z > 8)
+ goto by_reference;
+ if (z < 4)
+ a += 4 - z;
+ else if (z > 4)
+ argp++;
+ break;
+
+ default:
+ abort();
}
+ argp++;
+ avalue[i] = a;
}
/* Invoke the closure. */
- (closure->fun) (cif, rvalue, avalue, closure->user_data);
+ fun (cif, rvalue, avalue, user_data);
/* Tell ffi_closure_sparc how to perform return type promotions. */
- return cif->rtype->type;
+ return flags;
}
+#endif /* !SPARC64 */
diff --git a/src/sparc/ffi64.c b/src/sparc/ffi64.c
new file mode 100644
index 00000000..9e04061a
--- /dev/null
+++ b/src/sparc/ffi64.c
@@ -0,0 +1,608 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2011, 2013 Anthony Green
+ Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
+
+ SPARC Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS 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>
+#include "internal.h"
+
+/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
+ all further uses in this file will refer to the 128-bit type. */
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+# if FFI_TYPE_LONGDOUBLE != 4
+# error FFI_TYPE_LONGDOUBLE out of date
+# endif
+#else
+# undef FFI_TYPE_LONGDOUBLE
+# define FFI_TYPE_LONGDOUBLE 4
+#endif
+
+#ifdef SPARC64
+
+/* Flatten the contents of a structure to the parts that are passed in
+ floating point registers. The return is a bit mask wherein bit N
+ set means bytes [4*n, 4*n+3] are passed in %fN.
+
+ We encode both the (running) size (maximum 32) and mask (maxumum 255)
+ into one integer. The size is placed in the low byte, so that align
+ and addition work correctly. The mask is placed in the second byte. */
+
+static int
+ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
+{
+ ffi_type **elts;
+ ffi_type *t;
+
+ if (outer_type->type == FFI_TYPE_COMPLEX)
+ {
+ int m = 0, tt = outer_type->elements[0]->type;
+ size_t z = outer_type->size;
+
+ if (tt == FFI_TYPE_FLOAT
+ || tt == FFI_TYPE_DOUBLE
+ || tt == FFI_TYPE_LONGDOUBLE)
+ m = (1 << (z / 4)) - 1;
+ return (m << 8) | z;
+ }
+ FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT);
+
+ for (elts = outer_type->elements; (t = *elts) != NULL; elts++)
+ {
+ size_t z = t->size;
+ int o, m, tt;
+
+ size_mask = FFI_ALIGN(size_mask, t->alignment);
+ switch (t->type)
+ {
+ case FFI_TYPE_STRUCT:
+ size_mask = ffi_struct_float_mask (t, size_mask);
+ continue;
+ case FFI_TYPE_COMPLEX:
+ tt = t->elements[0]->type;
+ if (tt != FFI_TYPE_FLOAT
+ && tt != FFI_TYPE_DOUBLE
+ && tt != FFI_TYPE_LONGDOUBLE)
+ break;
+ /* FALLTHRU */
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ m = (1 << (z / 4)) - 1; /* compute mask for type */
+ o = (size_mask >> 2) & 0x3f; /* extract word offset */
+ size_mask |= m << (o + 8); /* insert mask into place */
+ break;
+ }
+ size_mask += z;
+ }
+
+ size_mask = FFI_ALIGN(size_mask, outer_type->alignment);
+ FFI_ASSERT ((size_mask & 0xff) == outer_type->size);
+
+ return size_mask;
+}
+
+/* Merge floating point data into integer data. If the structure is
+ entirely floating point, simply return a pointer to the fp data. */
+
+static void *
+ffi_struct_float_merge (int size_mask, void *vi, void *vf)
+{
+ int size = size_mask & 0xff;
+ int mask = size_mask >> 8;
+ int n = size >> 2;
+
+ if (mask == 0)
+ return vi;
+ else if (mask == (1 << n) - 1)
+ return vf;
+ else
+ {
+ unsigned int *wi = vi, *wf = vf;
+ int i;
+
+ for (i = 0; i < n; ++i)
+ if ((mask >> i) & 1)
+ wi[i] = wf[i];
+
+ return vi;
+ }
+}
+
+/* Similar, but place the data into VD in the end. */
+
+void FFI_HIDDEN
+ffi_struct_float_copy (int size_mask, void *vd, void *vi, void *vf)
+{
+ int size = size_mask & 0xff;
+ int mask = size_mask >> 8;
+ int n = size >> 2;
+
+ if (mask == 0)
+ ;
+ else if (mask == (1 << n) - 1)
+ vi = vf;
+ else
+ {
+ unsigned int *wd = vd, *wi = vi, *wf = vf;
+ int i;
+
+ for (i = 0; i < n; ++i)
+ wd[i] = ((mask >> i) & 1 ? wf : wi)[i];
+ return;
+ }
+ memcpy (vd, vi, size);
+}
+
+/* Perform machine dependent cif processing */
+
+static ffi_status
+ffi_prep_cif_machdep_core(ffi_cif *cif)
+{
+ ffi_type *rtype = cif->rtype;
+ int rtt = rtype->type;
+ size_t bytes = 0;
+ int i, n, flags;
+
+ /* Set the return type flag */
+ switch (rtt)
+ {
+ case FFI_TYPE_VOID:
+ flags = SPARC_RET_VOID;
+ break;
+ case FFI_TYPE_FLOAT:
+ flags = SPARC_RET_F_1;
+ break;
+ case FFI_TYPE_DOUBLE:
+ flags = SPARC_RET_F_2;
+ break;
+ case FFI_TYPE_LONGDOUBLE:
+ flags = SPARC_RET_F_4;
+ break;
+
+ case FFI_TYPE_COMPLEX:
+ case FFI_TYPE_STRUCT:
+ if (rtype->size > 32)
+ {
+ flags = SPARC_RET_VOID | SPARC_FLAG_RET_IN_MEM;
+ bytes = 8;
+ }
+ else
+ {
+ int size_mask = ffi_struct_float_mask (rtype, 0);
+ int word_size = (size_mask >> 2) & 0x3f;
+ int all_mask = (1 << word_size) - 1;
+ int fp_mask = size_mask >> 8;
+
+ flags = (size_mask << SPARC_SIZEMASK_SHIFT) | SPARC_RET_STRUCT;
+
+ /* For special cases of all-int or all-fp, we can return
+ the value directly without popping through a struct copy. */
+ if (fp_mask == 0)
+ {
+ if (rtype->alignment >= 8)
+ {
+ if (rtype->size == 8)
+ flags = SPARC_RET_INT64;
+ else if (rtype->size == 16)
+ flags = SPARC_RET_INT128;
+ }
+ }
+ else if (fp_mask == all_mask)
+ switch (word_size)
+ {
+ case 1: flags = SPARC_RET_F_1; break;
+ case 2: flags = SPARC_RET_F_2; break;
+ case 3: flags = SP_V9_RET_F_3; break;
+ case 4: flags = SPARC_RET_F_4; break;
+ /* 5 word structures skipped; handled via RET_STRUCT. */
+ case 6: flags = SPARC_RET_F_6; break;
+ /* 7 word structures skipped; handled via RET_STRUCT. */
+ case 8: flags = SPARC_RET_F_8; break;
+ }
+ }
+ break;
+
+ case FFI_TYPE_SINT8:
+ flags = SPARC_RET_SINT8;
+ break;
+ case FFI_TYPE_UINT8:
+ flags = SPARC_RET_UINT8;
+ break;
+ case FFI_TYPE_SINT16:
+ flags = SPARC_RET_SINT16;
+ break;
+ case FFI_TYPE_UINT16:
+ flags = SPARC_RET_UINT16;
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ flags = SP_V9_RET_SINT32;
+ break;
+ case FFI_TYPE_UINT32:
+ flags = SPARC_RET_UINT32;
+ break;
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ flags = SPARC_RET_INT64;
+ break;
+
+ default:
+ abort();
+ }
+
+ bytes = 0;
+ for (i = 0, n = cif->nargs; i < n; ++i)
+ {
+ ffi_type *ty = cif->arg_types[i];
+ size_t z = ty->size;
+ size_t a = ty->alignment;
+
+ switch (ty->type)
+ {
+ case FFI_TYPE_COMPLEX:
+ case FFI_TYPE_STRUCT:
+ /* Large structs passed by reference. */
+ if (z > 16)
+ {
+ a = z = 8;
+ break;
+ }
+ /* Small structs may be passed in integer or fp regs or both. */
+ if (bytes >= 16*8)
+ break;
+ if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0)
+ break;
+ /* FALLTHRU */
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ flags |= SPARC_FLAG_FP_ARGS;
+ break;
+ }
+ bytes = FFI_ALIGN(bytes, a);
+ bytes += FFI_ALIGN(z, 8);
+ }
+
+ /* Sparc call frames require that space is allocated for 6 args,
+ even if they aren't used. Make that space if necessary. */
+ if (bytes < 6 * 8)
+ bytes = 6 * 8;
+
+ /* The stack must be 2 word aligned, so round bytes up appropriately. */
+ bytes = FFI_ALIGN(bytes, 16);
+
+ /* Include the call frame to prep_args. */
+ bytes += 8*16 + 8*8;
+
+ cif->bytes = bytes;
+ cif->flags = flags;
+ return FFI_OK;
+}
+
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ cif->nfixedargs = cif->nargs;
+ return ffi_prep_cif_machdep_core(cif);
+}
+
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs)
+{
+ cif->nfixedargs = nfixedargs;
+ return ffi_prep_cif_machdep_core(cif);
+}
+
+extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+int FFI_HIDDEN
+ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
+{
+ ffi_type **p_arg;
+ int flags = cif->flags;
+ int i, nargs;
+
+ if (rvalue == NULL)
+ {
+ if (flags & SPARC_FLAG_RET_IN_MEM)
+ {
+ /* Since we pass the pointer to the callee, we need a value.
+ We allowed for this space in ffi_call, before ffi_call_v8
+ alloca'd the space. */
+ rvalue = (char *)argp + cif->bytes;
+ }
+ else
+ {
+ /* Otherwise, we can ignore the return value. */
+ flags = SPARC_RET_VOID;
+ }
+ }
+
+#ifdef USING_PURIFY
+ /* Purify will probably complain in our assembly routine,
+ unless we zero out this memory. */
+ memset(argp, 0, 6*8);
+#endif
+
+ if (flags & SPARC_FLAG_RET_IN_MEM)
+ *argp++ = (unsigned long)rvalue;
+
+ p_arg = cif->arg_types;
+ for (i = 0, nargs = cif->nargs; i < nargs; i++)
+ {
+ ffi_type *ty = p_arg[i];
+ void *a = avalue[i];
+ size_t z;
+
+ switch (ty->type)
+ {
+ case FFI_TYPE_SINT8:
+ *argp++ = *(SINT8 *)a;
+ break;
+ case FFI_TYPE_UINT8:
+ *argp++ = *(UINT8 *)a;
+ break;
+ case FFI_TYPE_SINT16:
+ *argp++ = *(SINT16 *)a;
+ break;
+ case FFI_TYPE_UINT16:
+ *argp++ = *(UINT16 *)a;
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ *argp++ = *(SINT32 *)a;
+ break;
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_FLOAT:
+ *argp++ = *(UINT32 *)a;
+ break;
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_DOUBLE:
+ *argp++ = *(UINT64 *)a;
+ break;
+
+ case FFI_TYPE_LONGDOUBLE:
+ case FFI_TYPE_COMPLEX:
+ case FFI_TYPE_STRUCT:
+ z = ty->size;
+ if (z > 16)
+ {
+ /* For structures larger than 16 bytes we pass reference. */
+ *argp++ = (unsigned long)a;
+ break;
+ }
+ if (((unsigned long)argp & 15) && ty->alignment > 8)
+ argp++;
+ memcpy(argp, a, z);
+ argp += FFI_ALIGN(z, 8) / 8;
+ break;
+
+ default:
+ abort();
+ }
+ }
+
+ return flags;
+}
+
+static void
+ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ size_t bytes = cif->bytes;
+
+ FFI_ASSERT (cif->abi == FFI_V9);
+
+ if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM))
+ bytes += FFI_ALIGN (cif->rtype->size, 16);
+
+ ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure);
+}
+
+void
+ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, NULL);
+}
+
+void
+ffi_call_go(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, closure);
+}
+
+#ifdef __GNUC__
+static inline void
+ffi_flush_icache (void *p)
+{
+ asm volatile ("flush %0; flush %0+8" : : "r" (p) : "memory");
+}
+#else
+extern void ffi_flush_icache (void *) FFI_HIDDEN;
+#endif
+
+extern void ffi_closure_v9(void) FFI_HIDDEN;
+extern void ffi_go_closure_v9(void) FFI_HIDDEN;
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ void *codeloc)
+{
+ unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+ unsigned long fn;
+
+ if (cif->abi != FFI_V9)
+ return FFI_BAD_ABI;
+
+ /* Trampoline address is equal to the closure address. We take advantage
+ of that to reduce the trampoline size by 8 bytes. */
+ fn = (unsigned long) ffi_closure_v9;
+ tramp[0] = 0x83414000; /* rd %pc, %g1 */
+ tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
+ tramp[2] = 0x81c14000; /* jmp %g5 */
+ tramp[3] = 0x01000000; /* nop */
+ *((unsigned long *) &tramp[4]) = fn;
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ ffi_flush_icache (closure);
+
+ return FFI_OK;
+}
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*))
+{
+ if (cif->abi != FFI_V9)
+ return FFI_BAD_ABI;
+
+ closure->tramp = ffi_go_closure_v9;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+int FFI_HIDDEN
+ffi_closure_sparc_inner_v9(ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data, void *rvalue,
+ unsigned long *gpr, unsigned long *fpr)
+{
+ ffi_type **arg_types;
+ void **avalue;
+ int i, argn, argx, nargs, flags, nfixedargs;
+
+ arg_types = cif->arg_types;
+ nargs = cif->nargs;
+ flags = cif->flags;
+ nfixedargs = cif->nfixedargs;
+
+ avalue = alloca(nargs * sizeof(void *));
+
+ /* Copy the caller's structure return address so that the closure
+ returns the data directly to the caller. */
+ if (flags & SPARC_FLAG_RET_IN_MEM)
+ {
+ rvalue = (void *) gpr[0];
+ /* Skip the structure return address. */
+ argn = 1;
+ }
+ else
+ argn = 0;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ for (i = 0; i < nargs; i++, argn = argx)
+ {
+ int named = i < nfixedargs;
+ ffi_type *ty = arg_types[i];
+ void *a = &gpr[argn];
+ size_t z;
+
+ argx = argn + 1;
+ switch (ty->type)
+ {
+ case FFI_TYPE_COMPLEX:
+ case FFI_TYPE_STRUCT:
+ z = ty->size;
+ if (z > 16)
+ a = *(void **)a;
+ else
+ {
+ argx = argn + FFI_ALIGN (z, 8) / 8;
+ if (named && argn < 16)
+ {
+ int size_mask = ffi_struct_float_mask (ty, 0);
+ int argn_mask = (0xffff00 >> argn) & 0xff00;
+
+ /* Eliminate fp registers off the end. */
+ size_mask = (size_mask & 0xff) | (size_mask & argn_mask);
+ a = ffi_struct_float_merge (size_mask, gpr+argn, fpr+argn);
+ }
+ }
+ break;
+
+ case FFI_TYPE_LONGDOUBLE:
+ argn = FFI_ALIGN (argn, 2);
+ a = (named && argn < 16 ? fpr : gpr) + argn;
+ argx = argn + 2;
+ break;
+ case FFI_TYPE_DOUBLE:
+ if (named && argn < 16)
+ a = fpr + argn;
+ break;
+ case FFI_TYPE_FLOAT:
+ if (named && argn < 16)
+ a = fpr + argn;
+ a += 4;
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_POINTER:
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ a += 4;
+ break;
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ a += 6;
+ break;
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ a += 7;
+ break;
+
+ default:
+ abort();
+ }
+ avalue[i] = a;
+ }
+
+ /* Invoke the closure. */
+ fun (cif, rvalue, avalue, user_data);
+
+ /* Tell ffi_closure_sparc how to perform return type promotions. */
+ return flags;
+}
+#endif /* SPARC64 */
diff --git a/src/sparc/ffitarget.h b/src/sparc/ffitarget.h
index d89f7877..2f4cd9a7 100644
--- a/src/sparc/ffitarget.h
+++ b/src/sparc/ffitarget.h
@@ -46,21 +46,29 @@ typedef signed long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
- FFI_V8,
- FFI_V8PLUS,
- FFI_V9,
- FFI_LAST_ABI,
#ifdef SPARC64
- FFI_DEFAULT_ABI = FFI_V9
+ FFI_V9,
+ FFI_DEFAULT_ABI = FFI_V9,
#else
- FFI_DEFAULT_ABI = FFI_V8
+ FFI_V8,
+ FFI_DEFAULT_ABI = FFI_V8,
#endif
+ FFI_LAST_ABI
} ffi_abi;
#endif
+#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION 1
+#define FFI_TARGET_HAS_COMPLEX_TYPE 1
+
+#ifdef SPARC64
+# define FFI_TARGET_SPECIFIC_VARIADIC 1
+# define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs
+#endif
+
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
+#define FFI_GO_CLOSURES 1
#define FFI_NATIVE_RAW_API 0
#ifdef SPARC64
diff --git a/src/sparc/internal.h b/src/sparc/internal.h
new file mode 100644
index 00000000..0a66472b
--- /dev/null
+++ b/src/sparc/internal.h
@@ -0,0 +1,26 @@
+#define SPARC_RET_VOID 0
+#define SPARC_RET_STRUCT 1
+#define SPARC_RET_UINT8 2
+#define SPARC_RET_SINT8 3
+#define SPARC_RET_UINT16 4
+#define SPARC_RET_SINT16 5
+#define SPARC_RET_UINT32 6
+#define SP_V9_RET_SINT32 7 /* v9 only */
+#define SP_V8_RET_CPLX16 7 /* v8 only */
+#define SPARC_RET_INT64 8
+#define SPARC_RET_INT128 9
+
+/* Note that F_7 is missing, and is handled by SPARC_RET_STRUCT. */
+#define SPARC_RET_F_8 10
+#define SPARC_RET_F_6 11
+#define SPARC_RET_F_4 12
+#define SPARC_RET_F_2 13
+#define SP_V9_RET_F_3 14 /* v9 only */
+#define SP_V8_RET_CPLX8 14 /* v8 only */
+#define SPARC_RET_F_1 15
+
+#define SPARC_FLAG_RET_MASK 15
+#define SPARC_FLAG_RET_IN_MEM 32
+#define SPARC_FLAG_FP_ARGS 64
+
+#define SPARC_SIZEMASK_SHIFT 8
diff --git a/src/sparc/v8.S b/src/sparc/v8.S
index 6bf7ac05..a2e4908f 100644
--- a/src/sparc/v8.S
+++ b/src/sparc/v8.S
@@ -1,8 +1,8 @@
/* -----------------------------------------------------------------------
v8.S - Copyright (c) 2013 The Written Word, Inc.
Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc.
-
- SPARC Foreign Function Interface
+
+ SPARC Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -25,179 +25,253 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
-#define LIBFFI_ASM
+#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
+#include "internal.h"
+
+#ifndef SPARC64
-#define STACKFRAME 96 /* Minimum stack framesize for SPARC */
-#define ARGS (64+4) /* Offset of register area in frame */
+#define C2(X, Y) X ## Y
+#define C1(X, Y) C2(X, Y)
+
+#ifdef __USER_LABEL_PREFIX__
+# define C(Y) C1(__USER_LABEL_PREFIX__, Y)
+#else
+# define C(Y) Y
+#endif
+#define L(Y) C1(.L, Y)
-#ifndef __GNUC__
.text
+
+#ifndef __GNUC__
.align 8
-.globl ffi_flush_icache
-.globl _ffi_flush_icache
-
-ffi_flush_icache:
-_ffi_flush_icache:
- add %o0, %o1, %o2
-#ifdef SPARC64
-1: flush %o0
-#else
+ .globl C(ffi_flush_icache)
+ .type C(ffi_flush_icache),#function
+ FFI_HIDDEN(C(ffi_flush_icache))
+
+C(ffi_flush_icache):
1: iflush %o0
-#endif
- add %o0, 8, %o0
- cmp %o0, %o2
- blt 1b
+ iflush %o+8
nop
nop
nop
nop
nop
retl
- nop
-.ffi_flush_icache_end:
- .size ffi_flush_icache,.ffi_flush_icache_end-ffi_flush_icache
+ nop
+ .size C(ffi_flush_icache), . - C(ffi_flush_icache)
+#endif
+
+#if defined(__sun__) && defined(__svr4__)
+# define E(INDEX) .align 16
+#else
+# define E(INDEX) .align 16; .org 2b + INDEX * 16
#endif
- .text
.align 8
-.globl ffi_call_v8
-.globl _ffi_call_v8
-
-ffi_call_v8:
-_ffi_call_v8:
-.LLFB1:
- save %sp, -STACKFRAME, %sp
-.LLCFI0:
-
- sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
- add %sp, STACKFRAME, %l0 ! %l0 has start of
- ! frame to set up
-
- mov %l0, %o0 ! call routine to set up frame
- call %i0
- mov %i1, %o1 ! (delay)
-
- ld [%l0+ARGS], %o0 ! call foreign function
- ld [%l0+ARGS+4], %o1
- ld [%l0+ARGS+8], %o2
- ld [%l0+ARGS+12], %o3
- ld [%l0+ARGS+16], %o4
- ld [%l0+ARGS+20], %o5
- call %i5
- mov %l0, %sp ! (delay) switch to frame
- nop ! STRUCT returning functions skip 12 instead of 8 bytes
-
- ! If the return value pointer is NULL, assume no return value.
- tst %i4
- bz done
+ .globl C(ffi_call_v8)
+ .type C(ffi_call_v8),#function
+ FFI_HIDDEN(C(ffi_call_v8))
+
+C(ffi_call_v8):
+.LUW0:
+ ! Allocate a stack frame sized by ffi_call.
+ save %sp, %o4, %sp
+.LUW1:
+ mov %i0, %o0 ! copy cif
+ add %sp, 64+32, %o1 ! load args area
+ mov %i2, %o2 ! copy rvalue
+ call C(ffi_prep_args_v8)
+ mov %i3, %o3 ! copy avalue
+
+ add %sp, 32, %sp ! deallocate prep frame
+ and %o0, SPARC_FLAG_RET_MASK, %l0 ! save return type
+ srl %o0, SPARC_SIZEMASK_SHIFT, %l1 ! save return size
+ ld [%sp+64+4], %o0 ! load all argument registers
+ ld [%sp+64+8], %o1
+ ld [%sp+64+12], %o2
+ ld [%sp+64+16], %o3
+ cmp %l0, SPARC_RET_STRUCT ! struct return needs an unimp 4
+ ld [%sp+64+20], %o4
+ be 8f
+ ld [%sp+64+24], %o5
+
+ ! Call foreign function
+ call %i1
+ mov %i5, %g2 ! load static chain
+
+0: call 1f ! load pc in %o7
+ sll %l0, 4, %l0
+1: add %o7, %l0, %o7 ! o7 = 0b + ret_type*16
+ jmp %o7+(2f-0b)
+ nop
+
+ ! Note that each entry is 4 insns, enforced by the E macro.
+ .align 16
+2:
+E(SPARC_RET_VOID)
+ ret
+ restore
+E(SPARC_RET_STRUCT)
+ unimp
+E(SPARC_RET_UINT8)
+ and %o0, 0xff, %o0
+ st %o0, [%i2]
+ ret
+ restore
+E(SPARC_RET_SINT8)
+ sll %o0, 24, %o0
+ b 7f
+ sra %o0, 24, %o0
+E(SPARC_RET_UINT16)
+ sll %o0, 16, %o0
+ b 7f
+ srl %o0, 16, %o0
+E(SPARC_RET_SINT16)
+ sll %o0, 16, %o0
+ b 7f
+ sra %o0, 16, %o0
+E(SPARC_RET_UINT32)
+7: st %o0, [%i2]
+ ret
+ restore
+E(SP_V8_RET_CPLX16)
+ sth %o0, [%i2+2]
+ b 9f
+ srl %o0, 16, %o0
+E(SPARC_RET_INT64)
+ st %o0, [%i2]
+ st %o1, [%i2+4]
+ ret
+ restore
+E(SPARC_RET_INT128)
+ std %o0, [%i2]
+ std %o2, [%i2+8]
+ ret
+ restore
+E(SPARC_RET_F_8)
+ st %f7, [%i2+7*4]
nop
-
- cmp %i3, FFI_TYPE_INT
- be,a done
- st %o0, [%i4] ! (delay)
-
- cmp %i3, FFI_TYPE_FLOAT
- be,a done
- st %f0, [%i4+0] ! (delay)
-
- cmp %i3, FFI_TYPE_DOUBLE
- be,a double
- st %f0, [%i4+0] ! (delay)
-
- cmp %i3, FFI_TYPE_SINT8
- be,a sint8
- sll %o0, 24, %o0 ! (delay)
-
- cmp %i3, FFI_TYPE_UINT8
- be,a uint8
- sll %o0, 24, %o0 ! (delay)
-
- cmp %i3, FFI_TYPE_SINT16
- be,a sint16
- sll %o0, 16, %o0 ! (delay)
-
- cmp %i3, FFI_TYPE_UINT16
- be,a uint16
- sll %o0, 16, %o0 ! (delay)
-
- cmp %i3, FFI_TYPE_SINT64
- be,a longlong
- st %o0, [%i4+0] ! (delay)
-done:
+ st %f6, [%i2+6*4]
+ nop
+E(SPARC_RET_F_6)
+ st %f5, [%i2+5*4]
+ nop
+ st %f4, [%i2+4*4]
+ nop
+E(SPARC_RET_F_4)
+ st %f3, [%i2+3*4]
+ nop
+ st %f2, [%i2+2*4]
+ nop
+E(SPARC_RET_F_2)
+ st %f1, [%i2+4]
+ st %f0, [%i2]
ret
- restore
-
-double:
- st %f1, [%i4+4]
+ restore
+E(SP_V8_RET_CPLX8)
+ stb %o0, [%i2+1]
+ b 0f
+ srl %o0, 8, %o0
+E(SPARC_RET_F_1)
+ st %f0, [%i2]
ret
- restore
+ restore
-sint8:
- sra %o0, 24, %o0
- st %o0, [%i4+0]
+ .align 8
+9: sth %o0, [%i2]
ret
- restore
-
-uint8:
- srl %o0, 24, %o0
- st %o0, [%i4+0]
+ restore
+ .align 8
+0: stb %o0, [%i2]
ret
- restore
+ restore
-sint16:
- sra %o0, 16, %o0
- st %o0, [%i4+0]
- ret
- restore
+ ! Struct returning functions expect and skip the unimp here.
+ ! To make it worse, conforming callees examine the unimp and
+ ! make sure the low 12 bits of the unimp match the size of
+ ! the struct being returned.
+ .align 8
+8: call 1f ! load pc in %o7
+ sll %l1, 2, %l0 ! size * 4
+1: sll %l1, 4, %l1 ! size * 16
+ add %l0, %l1, %l0 ! size * 20
+ add %o7, %l0, %o7 ! o7 = 8b + size*20
+ jmp %o7+(2f-8b)
+ mov %i5, %g2 ! load static chain
+2:
+
+/* The Sun assembler doesn't understand .rept 0x1000. */
+#define rept1 \
+ call %i1; \
+ nop; \
+ unimp (. - 2b) / 20; \
+ ret; \
+ restore
-uint16:
- srl %o0, 16, %o0
- st %o0, [%i4+0]
- ret
- restore
+#define rept16 \
+ rept1; rept1; rept1; rept1; \
+ rept1; rept1; rept1; rept1; \
+ rept1; rept1; rept1; rept1; \
+ rept1; rept1; rept1; rept1
-longlong:
- st %o1, [%i4+4]
- ret
- restore
-.LLFE1:
+#define rept256 \
+ rept16; rept16; rept16; rept16; \
+ rept16; rept16; rept16; rept16; \
+ rept16; rept16; rept16; rept16; \
+ rept16; rept16; rept16; rept16
-.ffi_call_v8_end:
- .size ffi_call_v8,.ffi_call_v8_end-ffi_call_v8
+ rept256; rept256; rept256; rept256
+ rept256; rept256; rept256; rept256
+ rept256; rept256; rept256; rept256
+ rept256; rept256; rept256; rept256
+.LUW2:
+ .size C(ffi_call_v8),. - C(ffi_call_v8)
-#undef STACKFRAME
-#define STACKFRAME 104 /* 16*4 register window +
- 1*4 struct return +
- 6*4 args backing store +
- 3*4 locals */
+
+/* 16*4 register window + 1*4 struct return + 6*4 args backing store
+ + 8*4 return storage + 1*4 alignment. */
+#define STACKFRAME (16*4 + 4 + 6*4 + 8*4 + 4)
/* ffi_closure_v8(...)
Receives the closure argument in %g2. */
- .text
- .align 8
- .globl ffi_closure_v8
-
-ffi_closure_v8:
#ifdef HAVE_AS_REGISTER_PSEUDO_OP
- .register %g2, #scratch
+ .register %g2, #scratch
#endif
-.LLFB2:
- ! Reserve frame space for all arguments in case
- ! we need to align them on a 8-byte boundary.
- ld [%g2+FFI_TRAMPOLINE_SIZE], %g1
- ld [%g1+4], %g1
- sll %g1, 3, %g1
- add %g1, STACKFRAME, %g1
- ! %g1 == STACKFRAME + 8*nargs
- neg %g1
- save %sp, %g1, %sp
-.LLCFI1:
+ .align 8
+ .globl C(ffi_go_closure_v8)
+ .type C(ffi_go_closure_v8),#function
+ FFI_HIDDEN(C(ffi_go_closure_v8))
+
+C(ffi_go_closure_v8):
+.LUW3:
+ save %sp, -STACKFRAME, %sp
+.LUW4:
+ ld [%g2+4], %o0 ! load cif
+ ld [%g2+8], %o1 ! load fun
+ b 0f
+ mov %g2, %o2 ! load user_data
+.LUW5:
+ .size C(ffi_go_closure_v8), . - C(ffi_go_closure_v8)
+
+ .align 8
+ .globl C(ffi_closure_v8)
+ .type C(ffi_closure_v8),#function
+ FFI_HIDDEN(C(ffi_closure_v8))
+
+C(ffi_closure_v8):
+.LUW6:
+ save %sp, -STACKFRAME, %sp
+.LUW7:
+ ld [%g2+FFI_TRAMPOLINE_SIZE], %o0 ! load cif
+ ld [%g2+FFI_TRAMPOLINE_SIZE+4], %o1 ! load fun
+ ld [%g2+FFI_TRAMPOLINE_SIZE+8], %o2 ! load user_data
+0:
! Store all of the potential argument registers in va_list format.
st %i0, [%fp+68+0]
st %i1, [%fp+68+4]
@@ -207,140 +281,163 @@ ffi_closure_v8:
st %i5, [%fp+68+20]
! Call ffi_closure_sparc_inner to do the bulk of the work.
- mov %g2, %o0
- add %fp, -8, %o1
- add %fp, 64, %o2
+ add %fp, -8*4, %o3
call ffi_closure_sparc_inner_v8
- add %fp, -16, %o3
-
- ! Load up the return value in the proper type.
- ! See ffi_prep_cif_machdep for the list of cases.
- cmp %o0, FFI_TYPE_VOID
- be done1
-
- cmp %o0, FFI_TYPE_INT
- be done1
- ld [%fp-8], %i0
-
- cmp %o0, FFI_TYPE_FLOAT
- be,a done1
- ld [%fp-8], %f0
-
- cmp %o0, FFI_TYPE_DOUBLE
- be,a done1
- ldd [%fp-8], %f0
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- cmp %o0, FFI_TYPE_LONGDOUBLE
- be done2
-#endif
-
- cmp %o0, FFI_TYPE_STRUCT
- be done2
-
- cmp %o0, FFI_TYPE_SINT64
- be,a done1
- ldd [%fp-8], %i0
-
- cmp %o0, FFI_TYPE_UINT64
- be,a done1
- ldd [%fp-8], %i0
-
- ld [%fp-8], %i0
-done1:
- jmp %i7+8
+ add %fp, 64, %o4
+
+0: call 1f
+ and %o0, SPARC_FLAG_RET_MASK, %o0
+1: sll %o0, 4, %o0 ! o0 = o0 * 16
+ add %o7, %o0, %o7 ! o7 = 0b + o0*16
+ jmp %o7+(2f-0b)
+ add %fp, -8*4, %i2
+
+ ! Note that each entry is 4 insns, enforced by the E macro.
+ .align 16
+2:
+E(SPARC_RET_VOID)
+ ret
restore
-done2:
- ! Skip 'unimp'.
+E(SPARC_RET_STRUCT)
+ ld [%i2], %i0
jmp %i7+12
restore
-.LLFE2:
-
-.ffi_closure_v8_end:
- .size ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8
+E(SPARC_RET_UINT8)
+ ldub [%i2+3], %i0
+ ret
+ restore
+E(SPARC_RET_SINT8)
+ ldsb [%i2+3], %i0
+ ret
+ restore
+E(SPARC_RET_UINT16)
+ lduh [%i2+2], %i0
+ ret
+ restore
+E(SPARC_RET_SINT16)
+ ldsh [%i2+2], %i0
+ ret
+ restore
+E(SPARC_RET_UINT32)
+ ld [%i2], %i0
+ ret
+ restore
+E(SP_V8_RET_CPLX16)
+ ld [%i2], %i0
+ ret
+ restore
+E(SPARC_RET_INT64)
+ ldd [%i2], %i0
+ ret
+ restore
+E(SPARC_RET_INT128)
+ ldd [%i2], %i0
+ ldd [%i2+8], %i2
+ ret
+ restore
+E(SPARC_RET_F_8)
+ ld [%i2+7*4], %f7
+ nop
+ ld [%i2+6*4], %f6
+ nop
+E(SPARC_RET_F_6)
+ ld [%i2+5*4], %f5
+ nop
+ ld [%i2+4*4], %f4
+ nop
+E(SPARC_RET_F_4)
+ ld [%i2+3*4], %f3
+ nop
+ ld [%i2+2*4], %f2
+ nop
+E(SPARC_RET_F_2)
+ ldd [%i2], %f0
+ ret
+ restore
+E(SP_V8_RET_CPLX8)
+ lduh [%i2], %i0
+ ret
+ restore
+E(SPARC_RET_F_1)
+ ld [%i2], %f0
+ ret
+ restore
-#ifdef SPARC64
-#define WS 8
-#define nword xword
-#define uanword uaxword
-#else
-#define WS 4
-#define nword long
-#define uanword uaword
-#endif
+.LUW8:
+ .size C(ffi_closure_v8), . - C(ffi_closure_v8)
#ifdef HAVE_RO_EH_FRAME
- .section ".eh_frame",#alloc
+ .section ".eh_frame",#alloc
#else
- .section ".eh_frame",#alloc,#write
+ .section ".eh_frame",#alloc,#write
#endif
-.LLframe1:
- .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
-.LLSCIE1:
- .uaword 0x0 ! CIE Identifier Tag
- .byte 0x1 ! CIE Version
- .ascii "zR\0" ! CIE Augmentation
- .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor
- .byte 0x80-WS ! sleb128 -WS; CIE Data Alignment Factor
- .byte 0xf ! CIE RA Column
- .byte 0x1 ! uleb128 0x1; Augmentation size
-#ifdef HAVE_AS_SPARC_UA_PCREL
- .byte 0x1b ! FDE Encoding (pcrel sdata4)
-#else
- .byte 0x50 ! FDE Encoding (aligned absolute)
-#endif
- .byte 0xc ! DW_CFA_def_cfa
- .byte 0xe ! uleb128 0xe
- .byte 0x0 ! uleb128 0x0
- .align WS
-.LLECIE1:
-.LLSFDE1:
- .uaword .LLEFDE1-.LLASFDE1 ! FDE Length
-.LLASFDE1:
- .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset
+
#ifdef HAVE_AS_SPARC_UA_PCREL
- .uaword %r_disp32(.LLFB1)
- .uaword .LLFE1-.LLFB1 ! FDE address range
+# define FDE_ADDR(X) %r_disp32(X)
#else
- .align WS
- .nword .LLFB1
- .uanword .LLFE1-.LLFB1 ! FDE address range
+# define FDE_ADDR(X) X
#endif
- .byte 0x0 ! uleb128 0x0; Augmentation size
- .byte 0x4 ! DW_CFA_advance_loc4
- .uaword .LLCFI0-.LLFB1
- .byte 0xd ! DW_CFA_def_cfa_register
- .byte 0x1e ! uleb128 0x1e
- .byte 0x2d ! DW_CFA_GNU_window_save
- .byte 0x9 ! DW_CFA_register
- .byte 0xf ! uleb128 0xf
- .byte 0x1f ! uleb128 0x1f
- .align WS
-.LLEFDE1:
-.LLSFDE2:
- .uaword .LLEFDE2-.LLASFDE2 ! FDE Length
-.LLASFDE2:
- .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
+
+ .align 4
+.LCIE:
+ .long .LECIE - .LSCIE ! CIE Length
+.LSCIE:
+ .long 0 ! CIE Identifier Tag
+ .byte 1 ! CIE Version
+ .ascii "zR\0" ! CIE Augmentation
+ .byte 4 ! CIE Code Alignment Factor
+ .byte 0x7c ! CIE Data Alignment Factor
+ .byte 15 ! CIE RA Column
+ .byte 1 ! Augmentation size
#ifdef HAVE_AS_SPARC_UA_PCREL
- .uaword %r_disp32(.LLFB2)
- .uaword .LLFE2-.LLFB2 ! FDE address range
+ .byte 0x1b ! FDE Encoding (pcrel sdata4)
#else
- .align WS
- .nword .LLFB2
- .uanword .LLFE2-.LLFB2 ! FDE address range
+ .byte 0x50 ! FDE Encoding (aligned absolute)
#endif
- .byte 0x0 ! uleb128 0x0; Augmentation size
- .byte 0x4 ! DW_CFA_advance_loc4
- .uaword .LLCFI1-.LLFB2
- .byte 0xd ! DW_CFA_def_cfa_register
- .byte 0x1e ! uleb128 0x1e
- .byte 0x2d ! DW_CFA_GNU_window_save
- .byte 0x9 ! DW_CFA_register
- .byte 0xf ! uleb128 0xf
- .byte 0x1f ! uleb128 0x1f
- .align WS
-.LLEFDE2:
-
+ .byte 0xc, 14, 0 ! DW_CFA_def_cfa, %o6, offset 0
+ .align 4
+.LECIE:
+
+ .long .LEFDE1 - .LSFDE1 ! FDE Length
+.LSFDE1:
+ .long .LSFDE1 - .LCIE ! FDE CIE offset
+ .long FDE_ADDR(.LUW0) ! Initial location
+ .long .LUW2 - .LUW0 ! Address range
+ .byte 0 ! Augmentation size
+ .byte 0x40+1 ! DW_CFA_advance_loc 4
+ .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7
+ .align 4
+.LEFDE1:
+
+ .long .LEFDE2 - .LSFDE2 ! FDE Length
+.LSFDE2:
+ .long .LSFDE2 - .LCIE ! FDE CIE offset
+ .long FDE_ADDR(.LUW3) ! Initial location
+ .long .LUW5 - .LUW3 ! Address range
+ .byte 0 ! Augmentation size
+ .byte 0x40+1 ! DW_CFA_advance_loc 4
+ .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7
+ .align 4
+.LEFDE2:
+
+ .long .LEFDE3 - .LSFDE3 ! FDE Length
+.LSFDE3:
+ .long .LSFDE3 - .LCIE ! FDE CIE offset
+ .long FDE_ADDR(.LUW6) ! Initial location
+ .long .LUW8 - .LUW6 ! Address range
+ .byte 0 ! Augmentation size
+ .byte 0x40+1 ! DW_CFA_advance_loc 4
+ .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7
+ .align 4
+.LEFDE3:
+
+#endif /* !SPARC64 */
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
#endif
diff --git a/src/sparc/v9.S b/src/sparc/v9.S
index bf31a2b5..55f8f432 100644
--- a/src/sparc/v9.S
+++ b/src/sparc/v9.S
@@ -27,105 +27,176 @@
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
+#include "internal.h"
#ifdef SPARC64
-/* Only compile this in for 64bit builds, because otherwise the object file
- will have inproper architecture due to used instructions. */
-#define STACKFRAME 176 /* Minimum stack framesize for SPARC 64-bit */
-#define STACK_BIAS 2047
-#define ARGS (128) /* Offset of register area in frame */
-
-.text
- .align 8
-.globl ffi_call_v9
-.globl _ffi_call_v9
-
-ffi_call_v9:
-_ffi_call_v9:
-.LLFB1:
- save %sp, -STACKFRAME, %sp
-.LLCFI0:
-
- sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
- add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of
- ! frame to set up
-
- mov %l0, %o0 ! call routine to set up frame
- call %i0
- mov %i1, %o1 ! (delay)
- brz,pt %o0, 1f
- ldx [%l0+ARGS], %o0 ! call foreign function
-
- ldd [%l0+ARGS], %f0
- ldd [%l0+ARGS+8], %f2
- ldd [%l0+ARGS+16], %f4
- ldd [%l0+ARGS+24], %f6
- ldd [%l0+ARGS+32], %f8
- ldd [%l0+ARGS+40], %f10
- ldd [%l0+ARGS+48], %f12
- ldd [%l0+ARGS+56], %f14
- ldd [%l0+ARGS+64], %f16
- ldd [%l0+ARGS+72], %f18
- ldd [%l0+ARGS+80], %f20
- ldd [%l0+ARGS+88], %f22
- ldd [%l0+ARGS+96], %f24
- ldd [%l0+ARGS+104], %f26
- ldd [%l0+ARGS+112], %f28
- ldd [%l0+ARGS+120], %f30
-
-1: ldx [%l0+ARGS+8], %o1
- ldx [%l0+ARGS+16], %o2
- ldx [%l0+ARGS+24], %o3
- ldx [%l0+ARGS+32], %o4
- ldx [%l0+ARGS+40], %o5
- call %i5
- sub %l0, STACK_BIAS, %sp ! (delay) switch to frame
-
- ! If the return value pointer is NULL, assume no return value.
- brz,pn %i4, done
- nop
+#define C2(X, Y) X ## Y
+#define C1(X, Y) C2(X, Y)
- cmp %i3, FFI_TYPE_INT
- be,a,pt %icc, done
- stx %o0, [%i4+0] ! (delay)
+#ifdef __USER_LABEL_PREFIX__
+# define C(Y) C1(__USER_LABEL_PREFIX__, Y)
+#else
+# define C(Y) Y
+#endif
+#define L(Y) C1(.L, Y)
- cmp %i3, FFI_TYPE_FLOAT
- be,a,pn %icc, done
- st %f0, [%i4+0] ! (delay)
+#if defined(__sun__) && defined(__svr4__)
+# define E(INDEX) .align 16
+#else
+# define E(INDEX) .align 16; .org 2b + INDEX * 16
+#endif
- cmp %i3, FFI_TYPE_DOUBLE
- be,a,pn %icc, done
- std %f0, [%i4+0] ! (delay)
+#define STACK_BIAS 2047
- cmp %i3, FFI_TYPE_STRUCT
- be,pn %icc, dostruct
+ .text
+ .align 8
+ .globl C(ffi_call_v9)
+ .type C(ffi_call_v9),#function
+ FFI_HIDDEN(C(ffi_call_v9))
+
+C(ffi_call_v9):
+.LUW0:
+ save %sp, %o4, %sp
+.LUW1:
+ mov %i0, %o0 ! copy cif
+ add %sp, STACK_BIAS+128+48, %o1 ! load args area
+ mov %i2, %o2 ! copy rvalue
+ call C(ffi_prep_args_v9)
+ mov %i3, %o3 ! copy avalue
+
+ andcc %o0, SPARC_FLAG_FP_ARGS, %g0 ! need fp regs?
+ add %sp, 48, %sp ! deallocate prep frame
+ be,pt %xcc, 1f
+ mov %o0, %l0 ! save flags
+
+ ldd [%sp+STACK_BIAS+128], %f0 ! load all fp arg regs
+ ldd [%sp+STACK_BIAS+128+8], %f2
+ ldd [%sp+STACK_BIAS+128+16], %f4
+ ldd [%sp+STACK_BIAS+128+24], %f6
+ ldd [%sp+STACK_BIAS+128+32], %f8
+ ldd [%sp+STACK_BIAS+128+40], %f10
+ ldd [%sp+STACK_BIAS+128+48], %f12
+ ldd [%sp+STACK_BIAS+128+56], %f14
+ ldd [%sp+STACK_BIAS+128+64], %f16
+ ldd [%sp+STACK_BIAS+128+72], %f18
+ ldd [%sp+STACK_BIAS+128+80], %f20
+ ldd [%sp+STACK_BIAS+128+88], %f22
+ ldd [%sp+STACK_BIAS+128+96], %f24
+ ldd [%sp+STACK_BIAS+128+104], %f26
+ ldd [%sp+STACK_BIAS+128+112], %f28
+ ldd [%sp+STACK_BIAS+128+120], %f30
+
+1: ldx [%sp+STACK_BIAS+128], %o0 ! load all int arg regs
+ ldx [%sp+STACK_BIAS+128+8], %o1
+ ldx [%sp+STACK_BIAS+128+16], %o2
+ ldx [%sp+STACK_BIAS+128+24], %o3
+ ldx [%sp+STACK_BIAS+128+32], %o4
+ ldx [%sp+STACK_BIAS+128+40], %o5
+ call %i1
+ mov %i5, %g5 ! load static chain
+
+0: call 1f ! load pc in %o7
+ and %l0, SPARC_FLAG_RET_MASK, %l1
+1: sll %l1, 4, %l1
+ add %o7, %l1, %o7 ! o7 = 0b + ret_type*16
+ jmp %o7+(2f-0b)
+ nop
- cmp %i3, FFI_TYPE_LONGDOUBLE
- bne,pt %icc, done
+ .align 16
+2:
+E(SPARC_RET_VOID)
+ return %i7+8
+ nop
+E(SPARC_RET_STRUCT)
+ add %sp, STACK_BIAS-64+128+48, %l2
+ sub %sp, 64, %sp
+ b 8f
+ stx %o0, [%l2]
+E(SPARC_RET_UINT8)
+ and %o0, 0xff, %i0
+ return %i7+8
+ stx %o0, [%o2]
+E(SPARC_RET_SINT8)
+ sll %o0, 24, %o0
+ sra %o0, 24, %i0
+ return %i7+8
+ stx %o0, [%o2]
+E(SPARC_RET_UINT16)
+ sll %o0, 16, %o0
+ srl %o0, 16, %i0
+ return %i7+8
+ stx %o0, [%o2]
+E(SPARC_RET_SINT16)
+ sll %o0, 16, %o0
+ sra %o0, 16, %i0
+ return %i7+8
+ stx %o0, [%o2]
+E(SPARC_RET_UINT32)
+ srl %o0, 0, %i0
+ return %i7+8
+ stx %o0, [%o2]
+E(SP_V9_RET_SINT32)
+ sra %o0, 0, %i0
+ return %i7+8
+ stx %o0, [%o2]
+E(SPARC_RET_INT64)
+ stx %o0, [%i2]
+ return %i7+8
+ nop
+E(SPARC_RET_INT128)
+ stx %o0, [%i2]
+ stx %o1, [%i2+8]
+ return %i7+8
nop
- std %f0, [%i4+0]
- std %f2, [%i4+8]
-
-done: ret
- restore
-
-dostruct:
- /* This will not work correctly for unions. */
- stx %o0, [%i4+0]
- stx %o1, [%i4+8]
- stx %o2, [%i4+16]
- stx %o3, [%i4+24]
- std %f0, [%i4+32]
- std %f2, [%i4+40]
- std %f4, [%i4+48]
- std %f6, [%i4+56]
- ret
- restore
-.LLFE1:
-
-.ffi_call_v9_end:
- .size ffi_call_v9,.ffi_call_v9_end-ffi_call_v9
+E(SPARC_RET_F_8)
+ st %f7, [%i2+7*4]
+ nop
+ st %f6, [%i2+6*4]
+ nop
+E(SPARC_RET_F_6)
+ st %f5, [%i2+5*4]
+ nop
+ st %f4, [%i2+4*4]
+ nop
+E(SPARC_RET_F_4)
+ std %f2, [%i2+2*4]
+ return %i7+8
+ std %f0, [%o2]
+E(SPARC_RET_F_2)
+ return %i7+8
+ std %f0, [%o2]
+E(SP_V9_RET_F_3)
+ st %f2, [%i2+2*4]
+ nop
+ st %f1, [%i2+1*4]
+ nop
+E(SPARC_RET_F_1)
+ return %i7+8
+ st %f0, [%o2]
+
+ ! Finish the SPARC_RET_STRUCT sequence.
+ .align 8
+8: stx %o1, [%l2+8]
+ stx %o2, [%l2+16]
+ stx %o3, [%l2+24]
+ std %f0, [%l2+32]
+ std %f2, [%l2+40]
+ std %f4, [%l2+48]
+ std %f6, [%l2+56]
+
+ ! Copy the structure into place.
+ srl %l0, SPARC_SIZEMASK_SHIFT, %o0 ! load size_mask
+ mov %i2, %o1 ! load dst
+ mov %l2, %o2 ! load src_gp
+ call C(ffi_struct_float_copy)
+ add %l2, 32, %o3 ! load src_fp
+
+ return %i7+8
+ nop
+
+.LUW2:
+ .size C(ffi_call_v9), . - C(ffi_call_v9)
#undef STACKFRAME
@@ -138,15 +209,36 @@ dostruct:
Receives the closure argument in %g1. */
- .text
.align 8
- .globl ffi_closure_v9
+ .globl C(ffi_go_closure_v9)
+ .type C(ffi_go_closure_v9),#function
+ FFI_HIDDEN(C(ffi_go_closure_v9))
-ffi_closure_v9:
-.LLFB2:
+C(ffi_go_closure_v9):
+.LUW3:
save %sp, -STACKFRAME, %sp
-.LLCFI1:
+.LUW4:
+ ldx [%g5+8], %o0
+ ldx [%g5+16], %o1
+ b 0f
+ mov %g5, %o2
+
+.LUW5:
+ .size C(ffi_go_closure_v9), . - C(ffi_go_closure_v9)
+ .align 8
+ .globl C(ffi_closure_v9)
+ .type C(ffi_closure_v9),#function
+ FFI_HIDDEN(C(ffi_closure_v9))
+
+C(ffi_closure_v9):
+.LUW6:
+ save %sp, -STACKFRAME, %sp
+.LUW7:
+ ldx [%g1+FFI_TRAMPOLINE_SIZE], %o0
+ ldx [%g1+FFI_TRAMPOLINE_SIZE+8], %o1
+ ldx [%g1+FFI_TRAMPOLINE_SIZE+16], %o2
+0:
! Store all of the potential argument registers in va_list format.
stx %i0, [FP+128+0]
stx %i1, [FP+128+8]
@@ -174,134 +266,175 @@ ffi_closure_v9:
std %f30, [FP-8]
! Call ffi_closure_sparc_inner to do the bulk of the work.
- mov %g1, %o0
- add %fp, STACK_BIAS-160, %o1
- add %fp, STACK_BIAS+128, %o2
- call ffi_closure_sparc_inner_v9
- add %fp, STACK_BIAS-128, %o3
-
- ! Load up the return value in the proper type.
- ! See ffi_prep_cif_machdep for the list of cases.
- cmp %o0, FFI_TYPE_VOID
- be,pn %icc, done1
-
- cmp %o0, FFI_TYPE_INT
- be,pn %icc, integer
-
- cmp %o0, FFI_TYPE_FLOAT
- be,a,pn %icc, done1
- ld [FP-160], %f0
-
- cmp %o0, FFI_TYPE_DOUBLE
- be,a,pn %icc, done1
- ldd [FP-160], %f0
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- cmp %o0, FFI_TYPE_LONGDOUBLE
- be,a,pn %icc, longdouble1
- ldd [FP-160], %f0
-#endif
+ add %fp, STACK_BIAS-160, %o3
+ add %fp, STACK_BIAS+128, %o4
+ call C(ffi_closure_sparc_inner_v9)
+ add %fp, STACK_BIAS-128, %o5
+
+0: call 1f ! load pc in %o7
+ and %o0, SPARC_FLAG_RET_MASK, %o0
+1: sll %o0, 4, %o0 ! o2 = i2 * 16
+ add %o7, %o0, %o7 ! o7 = 0b + i2*16
+ jmp %o7+(2f-0b)
+ nop
- ! FFI_TYPE_STRUCT
- ldx [FP-152], %i1
- ldx [FP-144], %i2
- ldx [FP-136], %i3
+ ! Note that we cannot load the data in the delay slot of
+ ! the return insn because the data is in the stack frame
+ ! that is deallocated by the return.
+ .align 16
+2:
+E(SPARC_RET_VOID)
+ return %i7+8
+ nop
+E(SPARC_RET_STRUCT)
+ ldx [FP-160], %i0
ldd [FP-160], %f0
- ldd [FP-152], %f2
- ldd [FP-144], %f4
- ldd [FP-136], %f6
-
-integer:
+ b 8f
+ ldx [FP-152], %i1
+E(SPARC_RET_UINT8)
+ ldub [FP-160+7], %i0
+ return %i7+8
+ nop
+E(SPARC_RET_SINT8)
+ ldsb [FP-160+7], %i0
+ return %i7+8
+ nop
+E(SPARC_RET_UINT16)
+ lduh [FP-160+6], %i0
+ return %i7+8
+ nop
+E(SPARC_RET_SINT16)
+ ldsh [FP-160+6], %i0
+ return %i7+8
+ nop
+E(SPARC_RET_UINT32)
+ lduw [FP-160+4], %i0
+ return %i7+8
+ nop
+E(SP_V9_RET_SINT32)
+ ldsw [FP-160+4], %i0
+ return %i7+8
+ nop
+E(SPARC_RET_INT64)
ldx [FP-160], %i0
+ return %i7+8
+ nop
+E(SPARC_RET_INT128)
+ ldx [FP-160], %i0
+ ldx [FP-160+8], %i1
+ return %i7+8
+ nop
+E(SPARC_RET_F_8)
+ ld [FP-160+7*4], %f7
+ nop
+ ld [FP-160+6*4], %f6
+ nop
+E(SPARC_RET_F_6)
+ ld [FP-160+5*4], %f5
+ nop
+ ld [FP-160+4*4], %f4
+ nop
+E(SPARC_RET_F_4)
+ ldd [FP-160], %f0
+ ldd [FP-160+8], %f2
+ return %i7+8
+ nop
+E(SPARC_RET_F_2)
+ ldd [FP-160], %f0
+ return %i7+8
+ nop
+E(SP_V9_RET_F_3)
+ ld [FP-160+2*4], %f2
+ nop
+ ld [FP-160+1*4], %f1
+ nop
+E(SPARC_RET_F_1)
+ ld [FP-160], %f0
+ return %i7+8
+ nop
-done1:
- ret
- restore
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
-longdouble1:
- ldd [FP-152], %f2
- ret
- restore
-#endif
-.LLFE2:
+ ! Finish the SPARC_RET_STRUCT sequence.
+ .align 8
+8: ldd [FP-152], %f2
+ ldx [FP-144], %i2
+ ldd [FP-144], %f4
+ ldx [FP-136], %i3
+ ldd [FP-136], %f6
+ return %i7+8
+ nop
-.ffi_closure_v9_end:
- .size ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9
+.LUW8:
+ .size C(ffi_closure_v9), . - C(ffi_closure_v9)
#ifdef HAVE_RO_EH_FRAME
- .section ".eh_frame",#alloc
-#else
- .section ".eh_frame",#alloc,#write
-#endif
-.LLframe1:
- .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
-.LLSCIE1:
- .uaword 0x0 ! CIE Identifier Tag
- .byte 0x1 ! CIE Version
- .ascii "zR\0" ! CIE Augmentation
- .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor
- .byte 0x78 ! sleb128 -8; CIE Data Alignment Factor
- .byte 0xf ! CIE RA Column
- .byte 0x1 ! uleb128 0x1; Augmentation size
-#ifdef HAVE_AS_SPARC_UA_PCREL
- .byte 0x1b ! FDE Encoding (pcrel sdata4)
+ .section ".eh_frame",#alloc
#else
- .byte 0x50 ! FDE Encoding (aligned absolute)
+ .section ".eh_frame",#alloc,#write
#endif
- .byte 0xc ! DW_CFA_def_cfa
- .byte 0xe ! uleb128 0xe
- .byte 0xff,0xf ! uleb128 0x7ff
- .align 8
-.LLECIE1:
-.LLSFDE1:
- .uaword .LLEFDE1-.LLASFDE1 ! FDE Length
-.LLASFDE1:
- .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset
+
#ifdef HAVE_AS_SPARC_UA_PCREL
- .uaword %r_disp32(.LLFB1)
- .uaword .LLFE1-.LLFB1 ! FDE address range
+# define FDE_RANGE(B, E) .long %r_disp32(B), E - B
#else
- .align 8
- .xword .LLFB1
- .uaxword .LLFE1-.LLFB1 ! FDE address range
+# define FDE_RANGE(B, E) .align 8; .xword B, E - B
#endif
- .byte 0x0 ! uleb128 0x0; Augmentation size
- .byte 0x4 ! DW_CFA_advance_loc4
- .uaword .LLCFI0-.LLFB1
- .byte 0xd ! DW_CFA_def_cfa_register
- .byte 0x1e ! uleb128 0x1e
- .byte 0x2d ! DW_CFA_GNU_window_save
- .byte 0x9 ! DW_CFA_register
- .byte 0xf ! uleb128 0xf
- .byte 0x1f ! uleb128 0x1f
+
.align 8
-.LLEFDE1:
-.LLSFDE2:
- .uaword .LLEFDE2-.LLASFDE2 ! FDE Length
-.LLASFDE2:
- .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
+.LCIE:
+ .long .LECIE - .LSCIE ! CIE Length
+.LSCIE:
+ .long 0 ! CIE Identifier Tag
+ .byte 1 ! CIE Version
+ .ascii "zR\0" ! CIE Augmentation
+ .byte 4 ! CIE Code Alignment Factor
+ .byte 0x78 ! CIE Data Alignment Factor
+ .byte 15 ! CIE RA Column
+ .byte 1 ! Augmentation size
#ifdef HAVE_AS_SPARC_UA_PCREL
- .uaword %r_disp32(.LLFB2)
- .uaword .LLFE2-.LLFB2 ! FDE address range
+ .byte 0x1b ! FDE Encoding (pcrel sdata4)
#else
- .align 8
- .xword .LLFB2
- .uaxword .LLFE2-.LLFB2 ! FDE address range
-#endif
- .byte 0x0 ! uleb128 0x0; Augmentation size
- .byte 0x4 ! DW_CFA_advance_loc4
- .uaword .LLCFI1-.LLFB2
- .byte 0xd ! DW_CFA_def_cfa_register
- .byte 0x1e ! uleb128 0x1e
- .byte 0x2d ! DW_CFA_GNU_window_save
- .byte 0x9 ! DW_CFA_register
- .byte 0xf ! uleb128 0xf
- .byte 0x1f ! uleb128 0x1f
- .align 8
-.LLEFDE2:
+ .byte 0x50 ! FDE Encoding (aligned absolute)
#endif
-
+ .byte 0xc, 14, 0xff, 0xf ! DW_CFA_def_cfa, %o6, offset 0x7ff
+ .align 8
+.LECIE:
+
+ .long .LEFDE1 - .LSFDE1 ! FDE Length
+.LSFDE1:
+ .long .LSFDE1 - .LCIE ! FDE CIE offset
+ FDE_RANGE(.LUW0, .LUW2)
+ .byte 0 ! Augmentation size
+ .byte 0x40+1 ! DW_CFA_advance_loc 4
+ .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7
+ .align 8
+.LEFDE1:
+
+ .long .LEFDE2 - .LSFDE2 ! FDE Length
+.LSFDE2:
+ .long .LSFDE2 - .LCIE ! FDE CIE offset
+ FDE_RANGE(.LUW3, .LUW5)
+ .byte 0 ! Augmentation size
+ .byte 0x40+1 ! DW_CFA_advance_loc 4
+ .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7
+ .align 8
+.LEFDE2:
+
+ .long .LEFDE3 - .LSFDE3 ! FDE Length
+.LSFDE3:
+ .long .LSFDE3 - .LCIE ! FDE CIE offset
+ FDE_RANGE(.LUW6, .LUW8)
+ .byte 0 ! Augmentation size
+ .byte 0x40+1 ! DW_CFA_advance_loc 4
+ .byte 0xd, 30 ! DW_CFA_def_cfa_register, %i6
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9, 15, 31 ! DW_CFA_register, %o7, %i7
+ .align 8
+.LEFDE3:
+
+#endif /* SPARC64 */
#ifdef __linux__
.section .note.GNU-stack,"",@progbits
#endif
diff --git a/src/types.c b/src/types.c
index 7e80aec6..9ec27f6c 100644
--- a/src/types.c
+++ b/src/types.c
@@ -38,6 +38,7 @@ struct struct_align_##name { \
char c; \
type x; \
}; \
+FFI_EXTERN \
maybe_const ffi_type ffi_type_##name = { \
sizeof(type), \
offsetof(struct struct_align_##name, x), \
@@ -52,6 +53,7 @@ struct struct_align_complex_##name { \
char c; \
_Complex type x; \
}; \
+FFI_EXTERN \
maybe_const ffi_type ffi_type_complex_##name = { \
sizeof(_Complex type), \
offsetof(struct struct_align_complex_##name, x), \
@@ -60,7 +62,7 @@ maybe_const ffi_type ffi_type_complex_##name = { \
}
/* Size and alignment are fake here. They must not be 0. */
-const ffi_type ffi_type_void = {
+FFI_EXTERN const ffi_type ffi_type_void = {
1, 1, FFI_TYPE_VOID, NULL
};
diff --git a/src/vax/ffi.c b/src/vax/ffi.c
index f4d6bbb4..e52caec8 100644
--- a/src/vax/ffi.c
+++ b/src/vax/ffi.c
@@ -108,7 +108,7 @@ ffi_prep_args (extended_cif *ecif, void *stack)
/* Align if necessary. */
if ((sizeof(int) - 1) & z)
- z = ALIGN(z, sizeof(int));
+ z = FFI_ALIGN(z, sizeof(int));
}
p_argv++;
@@ -215,7 +215,7 @@ ffi_prep_closure_elfbsd (ffi_cif *cif, void **avalue, char *stackp)
/* Align if necessary */
if ((sizeof (int) - 1) & z)
- z = ALIGN(z, sizeof (int));
+ z = FFI_ALIGN(z, sizeof (int));
p_argv++;
stackp += z;
diff --git a/src/x86/asmnames.h b/src/x86/asmnames.h
new file mode 100644
index 00000000..7551021e
--- /dev/null
+++ b/src/x86/asmnames.h
@@ -0,0 +1,30 @@
+#ifndef ASMNAMES_H
+#define ASMNAMES_H
+
+#define C2(X, Y) X ## Y
+#define C1(X, Y) C2(X, Y)
+#ifdef __USER_LABEL_PREFIX__
+# define C(X) C1(__USER_LABEL_PREFIX__, X)
+#else
+# define C(X) X
+#endif
+
+#ifdef __APPLE__
+# define L(X) C1(L, X)
+#else
+# define L(X) C1(.L, X)
+#endif
+
+#if defined(__ELF__) && defined(__PIC__)
+# define PLT(X) X@PLT
+#else
+# define PLT(X) X
+#endif
+
+#ifdef __ELF__
+# define ENDF(X) .type X,@function; .size X, . - X
+#else
+# define ENDF(X)
+#endif
+
+#endif /* ASMNAMES_H */
diff --git a/src/x86/darwin.S b/src/x86/darwin.S
deleted file mode 100644
index 8f0f0707..00000000
--- a/src/x86/darwin.S
+++ /dev/null
@@ -1,444 +0,0 @@
-/* -----------------------------------------------------------------------
- darwin.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc.
- Copyright (C) 2008 Free Software Foundation, Inc.
-
- X86 Foreign Function Interface
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- ``Software''), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS 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.
- -----------------------------------------------------------------------
- */
-
-#ifndef __x86_64__
-
-#define LIBFFI_ASM
-#include <fficonfig.h>
-#include <ffi.h>
-
-.text
-
-.globl _ffi_prep_args
-
- .align 4
-.globl _ffi_call_SYSV
-
-_ffi_call_SYSV:
-.LFB1:
- pushl %ebp
-.LCFI0:
- movl %esp,%ebp
-.LCFI1:
- subl $8,%esp
- /* Make room for all of the new args. */
- movl 16(%ebp),%ecx
- subl %ecx,%esp
-
- movl %esp,%eax
-
- /* Place all of the ffi_prep_args in position */
- subl $8,%esp
- pushl 12(%ebp)
- pushl %eax
- call *8(%ebp)
-
- /* Return stack to previous state and call the function */
- addl $16,%esp
-
- call *28(%ebp)
-
- /* Load %ecx with the return type code */
- movl 20(%ebp),%ecx
-
- /* Protect %esi. We're going to pop it in the epilogue. */
- pushl %esi
-
- /* If the return value pointer is NULL, assume no return value. */
- cmpl $0,24(%ebp)
- jne 0f
-
- /* Even if there is no space for the return value, we are
- obliged to handle floating-point values. */
- cmpl $FFI_TYPE_FLOAT,%ecx
- jne noretval
- fstp %st(0)
-
- jmp epilogue
-0:
- .align 4
- call 1f
-.Lstore_table:
- .long noretval-.Lstore_table /* FFI_TYPE_VOID */
- .long retint-.Lstore_table /* FFI_TYPE_INT */
- .long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */
- .long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */
- .long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */
- .long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */
- .long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */
- .long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */
- .long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */
- .long retint-.Lstore_table /* FFI_TYPE_UINT32 */
- .long retint-.Lstore_table /* FFI_TYPE_SINT32 */
- .long retint64-.Lstore_table /* FFI_TYPE_UINT64 */
- .long retint64-.Lstore_table /* FFI_TYPE_SINT64 */
- .long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */
- .long retint-.Lstore_table /* FFI_TYPE_POINTER */
- .long retstruct1b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_1B */
- .long retstruct2b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_2B */
-1:
- pop %esi
- add (%esi, %ecx, 4), %esi
- jmp *%esi
-
- /* Sign/zero extend as appropriate. */
-retsint8:
- movsbl %al, %eax
- jmp retint
-
-retsint16:
- movswl %ax, %eax
- jmp retint
-
-retuint8:
- movzbl %al, %eax
- jmp retint
-
-retuint16:
- movzwl %ax, %eax
- jmp retint
-
-retfloat:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- fstps (%ecx)
- jmp epilogue
-
-retdouble:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- fstpl (%ecx)
- jmp epilogue
-
-retlongdouble:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- fstpt (%ecx)
- jmp epilogue
-
-retint64:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- movl %eax,0(%ecx)
- movl %edx,4(%ecx)
- jmp epilogue
-
-retstruct1b:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- movb %al,0(%ecx)
- jmp epilogue
-
-retstruct2b:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- movw %ax,0(%ecx)
- jmp epilogue
-
-retint:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- movl %eax,0(%ecx)
-
-retstruct:
- /* Nothing to do! */
-
-noretval:
-epilogue:
- popl %esi
- movl %ebp,%esp
- popl %ebp
- ret
-
-.LFE1:
-.ffi_call_SYSV_end:
-
- .align 4
-FFI_HIDDEN (ffi_closure_SYSV)
-.globl _ffi_closure_SYSV
-
-_ffi_closure_SYSV:
-.LFB2:
- pushl %ebp
-.LCFI2:
- movl %esp, %ebp
-.LCFI3:
- subl $40, %esp
- leal -24(%ebp), %edx
- movl %edx, -12(%ebp) /* resp */
- leal 8(%ebp), %edx
- movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */
- leal -12(%ebp), %edx
- movl %edx, (%esp) /* &resp */
- movl %ebx, 8(%esp)
-.LCFI7:
- call L_ffi_closure_SYSV_inner$stub
- movl 8(%esp), %ebx
- movl -12(%ebp), %ecx
- cmpl $FFI_TYPE_INT, %eax
- je .Lcls_retint
-
- /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
- FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */
- cmpl $FFI_TYPE_UINT64, %eax
- jge 0f
- cmpl $FFI_TYPE_UINT8, %eax
- jge .Lcls_retint
-
-0: cmpl $FFI_TYPE_FLOAT, %eax
- je .Lcls_retfloat
- cmpl $FFI_TYPE_DOUBLE, %eax
- je .Lcls_retdouble
- cmpl $FFI_TYPE_LONGDOUBLE, %eax
- je .Lcls_retldouble
- cmpl $FFI_TYPE_SINT64, %eax
- je .Lcls_retllong
- cmpl $FFI_TYPE_SMALL_STRUCT_1B, %eax
- je .Lcls_retstruct1b
- cmpl $FFI_TYPE_SMALL_STRUCT_2B, %eax
- je .Lcls_retstruct2b
- cmpl $FFI_TYPE_STRUCT, %eax
- je .Lcls_retstruct
-.Lcls_epilogue:
- movl %ebp, %esp
- popl %ebp
- ret
-.Lcls_retint:
- movl (%ecx), %eax
- jmp .Lcls_epilogue
-.Lcls_retfloat:
- flds (%ecx)
- jmp .Lcls_epilogue
-.Lcls_retdouble:
- fldl (%ecx)
- jmp .Lcls_epilogue
-.Lcls_retldouble:
- fldt (%ecx)
- jmp .Lcls_epilogue
-.Lcls_retllong:
- movl (%ecx), %eax
- movl 4(%ecx), %edx
- jmp .Lcls_epilogue
-.Lcls_retstruct1b:
- movsbl (%ecx), %eax
- jmp .Lcls_epilogue
-.Lcls_retstruct2b:
- movswl (%ecx), %eax
- jmp .Lcls_epilogue
-.Lcls_retstruct:
- lea -8(%ebp),%esp
- movl %ebp, %esp
- popl %ebp
- ret $4
-.LFE2:
-
-#if !FFI_NO_RAW_API
-
-#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
-#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
-#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
-#define CIF_FLAGS_OFFSET 20
-
- .align 4
-FFI_HIDDEN (ffi_closure_raw_SYSV)
-.globl _ffi_closure_raw_SYSV
-
-_ffi_closure_raw_SYSV:
-.LFB3:
- pushl %ebp
-.LCFI4:
- movl %esp, %ebp
-.LCFI5:
- pushl %esi
-.LCFI6:
- subl $36, %esp
- movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
- movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
- movl %edx, 12(%esp) /* user_data */
- leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */
- movl %edx, 8(%esp) /* raw_args */
- leal -24(%ebp), %edx
- movl %edx, 4(%esp) /* &res */
- movl %esi, (%esp) /* cif */
- call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */
- movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */
- cmpl $FFI_TYPE_INT, %eax
- je .Lrcls_retint
-
- /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
- FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */
- cmpl $FFI_TYPE_UINT64, %eax
- jge 0f
- cmpl $FFI_TYPE_UINT8, %eax
- jge .Lrcls_retint
-0:
- cmpl $FFI_TYPE_FLOAT, %eax
- je .Lrcls_retfloat
- cmpl $FFI_TYPE_DOUBLE, %eax
- je .Lrcls_retdouble
- cmpl $FFI_TYPE_LONGDOUBLE, %eax
- je .Lrcls_retldouble
- cmpl $FFI_TYPE_SINT64, %eax
- je .Lrcls_retllong
-.Lrcls_epilogue:
- addl $36, %esp
- popl %esi
- popl %ebp
- ret
-.Lrcls_retint:
- movl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-.Lrcls_retfloat:
- flds -24(%ebp)
- jmp .Lrcls_epilogue
-.Lrcls_retdouble:
- fldl -24(%ebp)
- jmp .Lrcls_epilogue
-.Lrcls_retldouble:
- fldt -24(%ebp)
- jmp .Lrcls_epilogue
-.Lrcls_retllong:
- movl -24(%ebp), %eax
- movl -20(%ebp), %edx
- jmp .Lrcls_epilogue
-.LFE3:
-#endif
-
-.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
-L_ffi_closure_SYSV_inner$stub:
- .indirect_symbol _ffi_closure_SYSV_inner
- hlt ; hlt ; hlt ; hlt ; hlt
-
-
-.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
-EH_frame1:
- .set L$set$0,LECIE1-LSCIE1
- .long L$set$0
-LSCIE1:
- .long 0x0
- .byte 0x1
- .ascii "zR\0"
- .byte 0x1
- .byte 0x7c
- .byte 0x8
- .byte 0x1
- .byte 0x10
- .byte 0xc
- .byte 0x5
- .byte 0x4
- .byte 0x88
- .byte 0x1
- .align 2
-LECIE1:
-.globl _ffi_call_SYSV.eh
-_ffi_call_SYSV.eh:
-LSFDE1:
- .set L$set$1,LEFDE1-LASFDE1
- .long L$set$1
-LASFDE1:
- .long LASFDE1-EH_frame1
- .long .LFB1-.
- .set L$set$2,.LFE1-.LFB1
- .long L$set$2
- .byte 0x0
- .byte 0x4
- .set L$set$3,.LCFI0-.LFB1
- .long L$set$3
- .byte 0xe
- .byte 0x8
- .byte 0x84
- .byte 0x2
- .byte 0x4
- .set L$set$4,.LCFI1-.LCFI0
- .long L$set$4
- .byte 0xd
- .byte 0x4
- .align 2
-LEFDE1:
-.globl _ffi_closure_SYSV.eh
-_ffi_closure_SYSV.eh:
-LSFDE2:
- .set L$set$5,LEFDE2-LASFDE2
- .long L$set$5
-LASFDE2:
- .long LASFDE2-EH_frame1
- .long .LFB2-.
- .set L$set$6,.LFE2-.LFB2
- .long L$set$6
- .byte 0x0
- .byte 0x4
- .set L$set$7,.LCFI2-.LFB2
- .long L$set$7
- .byte 0xe
- .byte 0x8
- .byte 0x84
- .byte 0x2
- .byte 0x4
- .set L$set$8,.LCFI3-.LCFI2
- .long L$set$8
- .byte 0xd
- .byte 0x4
- .align 2
-LEFDE2:
-
-#if !FFI_NO_RAW_API
-
-.globl _ffi_closure_raw_SYSV.eh
-_ffi_closure_raw_SYSV.eh:
-LSFDE3:
- .set L$set$10,LEFDE3-LASFDE3
- .long L$set$10
-LASFDE3:
- .long LASFDE3-EH_frame1
- .long .LFB3-.
- .set L$set$11,.LFE3-.LFB3
- .long L$set$11
- .byte 0x0
- .byte 0x4
- .set L$set$12,.LCFI4-.LFB3
- .long L$set$12
- .byte 0xe
- .byte 0x8
- .byte 0x84
- .byte 0x2
- .byte 0x4
- .set L$set$13,.LCFI5-.LCFI4
- .long L$set$13
- .byte 0xd
- .byte 0x4
- .byte 0x4
- .set L$set$14,.LCFI6-.LCFI5
- .long L$set$14
- .byte 0x85
- .byte 0x3
- .align 2
-LEFDE3:
-
-#endif
-
-#endif /* ifndef __x86_64__ */
diff --git a/src/x86/darwin64.S b/src/x86/darwin64.S
deleted file mode 100644
index 2f7394ef..00000000
--- a/src/x86/darwin64.S
+++ /dev/null
@@ -1,416 +0,0 @@
-/* -----------------------------------------------------------------------
- darwin64.S - Copyright (c) 2006 Free Software Foundation, Inc.
- Copyright (c) 2008 Red Hat, Inc.
- derived from unix64.S
-
- x86-64 Foreign Function Interface for Darwin.
-
- 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.
- ----------------------------------------------------------------------- */
-
-#ifdef __x86_64__
-#define LIBFFI_ASM
-#include <fficonfig.h>
-#include <ffi.h>
-
- .file "darwin64.S"
-.text
-
-/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
- void *raddr, void (*fnaddr)(void));
-
- Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
- for this function. This has been allocated by ffi_call. We also
- deallocate some of the stack that has been alloca'd. */
-
- .align 3
- .globl _ffi_call_unix64
-
-_ffi_call_unix64:
-LUW0:
- movq (%rsp), %r10 /* Load return address. */
- leaq (%rdi, %rsi), %rax /* Find local stack base. */
- movq %rdx, (%rax) /* Save flags. */
- movq %rcx, 8(%rax) /* Save raddr. */
- movq %rbp, 16(%rax) /* Save old frame pointer. */
- movq %r10, 24(%rax) /* Relocate return address. */
- movq %rax, %rbp /* Finalize local stack frame. */
-LUW1:
- movq %rdi, %r10 /* Save a copy of the register area. */
- movq %r8, %r11 /* Save a copy of the target fn. */
- movl %r9d, %eax /* Set number of SSE registers. */
-
- /* Load up all argument registers. */
- movq (%r10), %rdi
- movq 8(%r10), %rsi
- movq 16(%r10), %rdx
- movq 24(%r10), %rcx
- movq 32(%r10), %r8
- movq 40(%r10), %r9
- testl %eax, %eax
- jnz Lload_sse
-Lret_from_load_sse:
-
- /* Deallocate the reg arg area. */
- leaq 176(%r10), %rsp
-
- /* Call the user function. */
- call *%r11
-
- /* Deallocate stack arg area; local stack frame in redzone. */
- leaq 24(%rbp), %rsp
-
- movq 0(%rbp), %rcx /* Reload flags. */
- movq 8(%rbp), %rdi /* Reload raddr. */
- movq 16(%rbp), %rbp /* Reload old frame pointer. */
-LUW2:
-
- /* The first byte of the flags contains the FFI_TYPE. */
- movzbl %cl, %r10d
- leaq Lstore_table(%rip), %r11
- movslq (%r11, %r10, 4), %r10
- addq %r11, %r10
- jmp *%r10
-
-Lstore_table:
- .long Lst_void-Lstore_table /* FFI_TYPE_VOID */
- .long Lst_sint32-Lstore_table /* FFI_TYPE_INT */
- .long Lst_float-Lstore_table /* FFI_TYPE_FLOAT */
- .long Lst_double-Lstore_table /* FFI_TYPE_DOUBLE */
- .long Lst_ldouble-Lstore_table /* FFI_TYPE_LONGDOUBLE */
- .long Lst_uint8-Lstore_table /* FFI_TYPE_UINT8 */
- .long Lst_sint8-Lstore_table /* FFI_TYPE_SINT8 */
- .long Lst_uint16-Lstore_table /* FFI_TYPE_UINT16 */
- .long Lst_sint16-Lstore_table /* FFI_TYPE_SINT16 */
- .long Lst_uint32-Lstore_table /* FFI_TYPE_UINT32 */
- .long Lst_sint32-Lstore_table /* FFI_TYPE_SINT32 */
- .long Lst_int64-Lstore_table /* FFI_TYPE_UINT64 */
- .long Lst_int64-Lstore_table /* FFI_TYPE_SINT64 */
- .long Lst_struct-Lstore_table /* FFI_TYPE_STRUCT */
- .long Lst_int64-Lstore_table /* FFI_TYPE_POINTER */
-
- .text
- .align 3
-Lst_void:
- ret
- .align 3
-Lst_uint8:
- movzbq %al, %rax
- movq %rax, (%rdi)
- ret
- .align 3
-Lst_sint8:
- movsbq %al, %rax
- movq %rax, (%rdi)
- ret
- .align 3
-Lst_uint16:
- movzwq %ax, %rax
- movq %rax, (%rdi)
- .align 3
-Lst_sint16:
- movswq %ax, %rax
- movq %rax, (%rdi)
- ret
- .align 3
-Lst_uint32:
- movl %eax, %eax
- movq %rax, (%rdi)
- .align 3
-Lst_sint32:
- cltq
- movq %rax, (%rdi)
- ret
- .align 3
-Lst_int64:
- movq %rax, (%rdi)
- ret
- .align 3
-Lst_float:
- movss %xmm0, (%rdi)
- ret
- .align 3
-Lst_double:
- movsd %xmm0, (%rdi)
- ret
-Lst_ldouble:
- fstpt (%rdi)
- ret
- .align 3
-Lst_struct:
- leaq -20(%rsp), %rsi /* Scratch area in redzone. */
-
- /* We have to locate the values now, and since we don't want to
- write too much data into the user's return value, we spill the
- value to a 16 byte scratch area first. Bits 8, 9, and 10
- control where the values are located. Only one of the three
- bits will be set; see ffi_prep_cif_machdep for the pattern. */
- movd %xmm0, %r10
- movd %xmm1, %r11
- testl $0x100, %ecx
- cmovnz %rax, %rdx
- cmovnz %r10, %rax
- testl $0x200, %ecx
- cmovnz %r10, %rdx
- testl $0x400, %ecx
- cmovnz %r10, %rax
- cmovnz %r11, %rdx
- movq %rax, (%rsi)
- movq %rdx, 8(%rsi)
-
- /* Bits 12-31 contain the true size of the structure. Copy from
- the scratch area to the true destination. */
- shrl $12, %ecx
- rep movsb
- ret
-
- /* Many times we can avoid loading any SSE registers at all.
- It's not worth an indirect jump to load the exact set of
- SSE registers needed; zero or all is a good compromise. */
- .align 3
-LUW3:
-Lload_sse:
- movdqa 48(%r10), %xmm0
- movdqa 64(%r10), %xmm1
- movdqa 80(%r10), %xmm2
- movdqa 96(%r10), %xmm3
- movdqa 112(%r10), %xmm4
- movdqa 128(%r10), %xmm5
- movdqa 144(%r10), %xmm6
- movdqa 160(%r10), %xmm7
- jmp Lret_from_load_sse
-
-LUW4:
- .align 3
- .globl _ffi_closure_unix64
-
-_ffi_closure_unix64:
-LUW5:
- /* The carry flag is set by the trampoline iff SSE registers
- are used. Don't clobber it before the branch instruction. */
- leaq -200(%rsp), %rsp
-LUW6:
- movq %rdi, (%rsp)
- movq %rsi, 8(%rsp)
- movq %rdx, 16(%rsp)
- movq %rcx, 24(%rsp)
- movq %r8, 32(%rsp)
- movq %r9, 40(%rsp)
- jc Lsave_sse
-Lret_from_save_sse:
-
- movq %r10, %rdi
- leaq 176(%rsp), %rsi
- movq %rsp, %rdx
- leaq 208(%rsp), %rcx
- call _ffi_closure_unix64_inner
-
- /* Deallocate stack frame early; return value is now in redzone. */
- addq $200, %rsp
-LUW7:
-
- /* The first byte of the return value contains the FFI_TYPE. */
- movzbl %al, %r10d
- leaq Lload_table(%rip), %r11
- movslq (%r11, %r10, 4), %r10
- addq %r11, %r10
- jmp *%r10
-
-Lload_table:
- .long Lld_void-Lload_table /* FFI_TYPE_VOID */
- .long Lld_int32-Lload_table /* FFI_TYPE_INT */
- .long Lld_float-Lload_table /* FFI_TYPE_FLOAT */
- .long Lld_double-Lload_table /* FFI_TYPE_DOUBLE */
- .long Lld_ldouble-Lload_table /* FFI_TYPE_LONGDOUBLE */
- .long Lld_int8-Lload_table /* FFI_TYPE_UINT8 */
- .long Lld_int8-Lload_table /* FFI_TYPE_SINT8 */
- .long Lld_int16-Lload_table /* FFI_TYPE_UINT16 */
- .long Lld_int16-Lload_table /* FFI_TYPE_SINT16 */
- .long Lld_int32-Lload_table /* FFI_TYPE_UINT32 */
- .long Lld_int32-Lload_table /* FFI_TYPE_SINT32 */
- .long Lld_int64-Lload_table /* FFI_TYPE_UINT64 */
- .long Lld_int64-Lload_table /* FFI_TYPE_SINT64 */
- .long Lld_struct-Lload_table /* FFI_TYPE_STRUCT */
- .long Lld_int64-Lload_table /* FFI_TYPE_POINTER */
-
- .text
- .align 3
-Lld_void:
- ret
- .align 3
-Lld_int8:
- movzbl -24(%rsp), %eax
- ret
- .align 3
-Lld_int16:
- movzwl -24(%rsp), %eax
- ret
- .align 3
-Lld_int32:
- movl -24(%rsp), %eax
- ret
- .align 3
-Lld_int64:
- movq -24(%rsp), %rax
- ret
- .align 3
-Lld_float:
- movss -24(%rsp), %xmm0
- ret
- .align 3
-Lld_double:
- movsd -24(%rsp), %xmm0
- ret
- .align 3
-Lld_ldouble:
- fldt -24(%rsp)
- ret
- .align 3
-Lld_struct:
- /* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
- %rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading
- both rdx and xmm1 with the second word. For the remaining,
- bit 8 set means xmm0 gets the second word, and bit 9 means
- that rax gets the second word. */
- movq -24(%rsp), %rcx
- movq -16(%rsp), %rdx
- movq -16(%rsp), %xmm1
- testl $0x100, %eax
- cmovnz %rdx, %rcx
- movd %rcx, %xmm0
- testl $0x200, %eax
- movq -24(%rsp), %rax
- cmovnz %rdx, %rax
- ret
-
- /* See the comment above Lload_sse; the same logic applies here. */
- .align 3
-LUW8:
-Lsave_sse:
- movdqa %xmm0, 48(%rsp)
- movdqa %xmm1, 64(%rsp)
- movdqa %xmm2, 80(%rsp)
- movdqa %xmm3, 96(%rsp)
- movdqa %xmm4, 112(%rsp)
- movdqa %xmm5, 128(%rsp)
- movdqa %xmm6, 144(%rsp)
- movdqa %xmm7, 160(%rsp)
- jmp Lret_from_save_sse
-
-LUW9:
-.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
-EH_frame1:
- .set L$set$0,LECIE1-LSCIE1 /* CIE Length */
- .long L$set$0
-LSCIE1:
- .long 0x0 /* CIE Identifier Tag */
- .byte 0x1 /* CIE Version */
- .ascii "zR\0" /* CIE Augmentation */
- .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
- .byte 0x78 /* sleb128 -8; CIE Data Alignment Factor */
- .byte 0x10 /* CIE RA Column */
- .byte 0x1 /* uleb128 0x1; Augmentation size */
- .byte 0x10 /* FDE Encoding (pcrel sdata4) */
- .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
- .byte 0x7 /* uleb128 0x7 */
- .byte 0x8 /* uleb128 0x8 */
- .byte 0x90 /* DW_CFA_offset, column 0x10 */
- .byte 0x1
- .align 3
-LECIE1:
- .globl _ffi_call_unix64.eh
-_ffi_call_unix64.eh:
-LSFDE1:
- .set L$set$1,LEFDE1-LASFDE1 /* FDE Length */
- .long L$set$1
-LASFDE1:
- .long LASFDE1-EH_frame1 /* FDE CIE offset */
- .quad LUW0-. /* FDE initial location */
- .set L$set$2,LUW4-LUW0 /* FDE address range */
- .quad L$set$2
- .byte 0x0 /* Augmentation size */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .set L$set$3,LUW1-LUW0
- .long L$set$3
-
- /* New stack frame based off rbp. This is a itty bit of unwind
- trickery in that the CFA *has* changed. There is no easy way
- to describe it correctly on entry to the function. Fortunately,
- it doesn't matter too much since at all points we can correctly
- unwind back to ffi_call. Note that the location to which we
- moved the return address is (the new) CFA-8, so from the
- perspective of the unwind info, it hasn't moved. */
- .byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */
- .byte 0x6
- .byte 0x20
- .byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */
- .byte 0x2
- .byte 0xa /* DW_CFA_remember_state */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .set L$set$4,LUW2-LUW1
- .long L$set$4
- .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
- .byte 0x7
- .byte 0x8
- .byte 0xc0+6 /* DW_CFA_restore, %rbp */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .set L$set$5,LUW3-LUW2
- .long L$set$5
- .byte 0xb /* DW_CFA_restore_state */
-
- .align 3
-LEFDE1:
- .globl _ffi_closure_unix64.eh
-_ffi_closure_unix64.eh:
-LSFDE3:
- .set L$set$6,LEFDE3-LASFDE3 /* FDE Length */
- .long L$set$6
-LASFDE3:
- .long LASFDE3-EH_frame1 /* FDE CIE offset */
- .quad LUW5-. /* FDE initial location */
- .set L$set$7,LUW9-LUW5 /* FDE address range */
- .quad L$set$7
- .byte 0x0 /* Augmentation size */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .set L$set$8,LUW6-LUW5
- .long L$set$8
- .byte 0xe /* DW_CFA_def_cfa_offset */
- .byte 208,1 /* uleb128 208 */
- .byte 0xa /* DW_CFA_remember_state */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .set L$set$9,LUW7-LUW6
- .long L$set$9
- .byte 0xe /* DW_CFA_def_cfa_offset */
- .byte 0x8
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .set L$set$10,LUW8-LUW7
- .long L$set$10
- .byte 0xb /* DW_CFA_restore_state */
-
- .align 3
-LEFDE3:
- .subsections_via_symbols
-
-#endif /* __x86_64__ */
diff --git a/src/x86/ffi.c b/src/x86/ffi.c
index 006c95d9..9a592185 100644
--- a/src/x86/ffi.c
+++ b/src/x86/ffi.c
@@ -1,5 +1,6 @@
/* -----------------------------------------------------------------------
- ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc.
+ ffi.c - Copyright (c) 2017 Anthony Green
+ Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc.
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2002 Bo Thorsen
Copyright (c) 2002 Roger Sayle
@@ -28,693 +29,502 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
-#if !defined(__x86_64__) || defined(_WIN64) || defined(__CYGWIN__)
-
-#ifdef _WIN64
-#include <windows.h>
-#endif
-
+#if defined(__i386__) || defined(_M_IX86)
#include <ffi.h>
#include <ffi_common.h>
-
+#include <stdint.h>
#include <stdlib.h>
-
-
-/* ffi_prep_args is called by the assembly routine once stack space
- has been allocated for the function's arguments */
-
-unsigned int ffi_prep_args(char *stack, extended_cif *ecif);
-unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
-{
- register unsigned int i;
- register void **p_argv;
- register char *argp;
- register ffi_type **p_arg;
-#ifndef X86_WIN64
- const int cabi = ecif->cif->abi;
- const int dir = (cabi == FFI_PASCAL || cabi == FFI_REGISTER) ? -1 : +1;
- unsigned int stack_args_count = 0;
- void *p_stack_data[3];
- char *argp2 = stack;
+#include "internal.h"
+
+/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
+ all further uses in this file will refer to the 80-bit type. */
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+# if FFI_TYPE_LONGDOUBLE != 4
+# error FFI_TYPE_LONGDOUBLE out of date
+# endif
#else
- #define dir 1
+# undef FFI_TYPE_LONGDOUBLE
+# define FFI_TYPE_LONGDOUBLE 4
#endif
- argp = stack;
-
- if ((ecif->cif->flags == FFI_TYPE_STRUCT
- || ecif->cif->flags == FFI_TYPE_MS_STRUCT)
-#ifdef X86_WIN64
- && ((ecif->cif->rtype->size & (1 | 2 | 4 | 8)) == 0)
-#endif
- )
- {
-#ifndef X86_WIN64
- /* For fastcall/thiscall/register this is first register-passed
- argument. */
- if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL || cabi == FFI_REGISTER)
- {
- p_stack_data[stack_args_count] = argp;
- ++stack_args_count;
- }
-#endif
-
- *(void **) argp = ecif->rvalue;
- argp += sizeof(void*);
- }
-
- p_arg = ecif->cif->arg_types;
- p_argv = ecif->avalue;
- if (dir < 0)
- {
- const int nargs = ecif->cif->nargs - 1;
- if (nargs > 0)
- {
- p_arg += nargs;
- p_argv += nargs;
- }
- }
-
- for (i = ecif->cif->nargs;
- i != 0;
- i--, p_arg += dir, p_argv += dir)
- {
- /* Align if necessary */
- if ((sizeof(void*) - 1) & (size_t) argp)
- argp = (char *) ALIGN(argp, sizeof(void*));
-
- size_t z = (*p_arg)->size;
-
-#ifdef X86_WIN64
- if (z > FFI_SIZEOF_ARG
- || ((*p_arg)->type == FFI_TYPE_STRUCT
- && (z & (1 | 2 | 4 | 8)) == 0)
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
-#endif
- )
- {
- z = FFI_SIZEOF_ARG;
- *(void **)argp = *p_argv;
- }
- else if ((*p_arg)->type == FFI_TYPE_FLOAT)
- {
- memcpy(argp, *p_argv, z);
- }
- else
-#endif
- if (z < FFI_SIZEOF_ARG)
- {
- z = FFI_SIZEOF_ARG;
- switch ((*p_arg)->type)
- {
- case FFI_TYPE_SINT8:
- *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT8:
- *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
- break;
-
- case FFI_TYPE_SINT16:
- *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT16:
- *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
- break;
-
- case FFI_TYPE_SINT32:
- *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
- break;
-
- case FFI_TYPE_UINT32:
- *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
- break;
-
- case FFI_TYPE_STRUCT:
- *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
- break;
-
- default:
- FFI_ASSERT(0);
- }
- }
- else
- {
- memcpy(argp, *p_argv, z);
- }
-
-#ifndef X86_WIN64
- /* For thiscall/fastcall/register convention register-passed arguments
- are the first two none-floating-point arguments with a size
- smaller or equal to sizeof (void*). */
- if ((z == FFI_SIZEOF_ARG)
- && ((cabi == FFI_REGISTER)
- || (cabi == FFI_THISCALL && stack_args_count < 1)
- || (cabi == FFI_FASTCALL && stack_args_count < 2))
- && ((*p_arg)->type != FFI_TYPE_FLOAT && (*p_arg)->type != FFI_TYPE_STRUCT)
- )
- {
- if (dir < 0 && stack_args_count > 2)
- {
- /* Iterating arguments backwards, so first register-passed argument
- will be passed last. Shift temporary values to make place. */
- p_stack_data[0] = p_stack_data[1];
- p_stack_data[1] = p_stack_data[2];
- stack_args_count = 2;
- }
-
- p_stack_data[stack_args_count] = argp;
- ++stack_args_count;
- }
+#if defined(__GNUC__) && !defined(__declspec)
+# define __declspec(x) __attribute__((x))
#endif
-#ifdef X86_WIN64
- argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+#if defined(_MSC_VER) && defined(_M_IX86)
+/* Stack is not 16-byte aligned on Windows. */
+#define STACK_ALIGN(bytes) (bytes)
#else
- argp += z;
+#define STACK_ALIGN(bytes) FFI_ALIGN (bytes, 16)
#endif
- }
-#ifndef X86_WIN64
- /* We need to move the register-passed arguments for thiscall/fastcall/register
- on top of stack, so that those can be moved to registers by call-handler. */
- if (stack_args_count > 0)
+/* Perform machine dependent cif processing. */
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ size_t bytes = 0;
+ int i, n, flags, cabi = cif->abi;
+
+ switch (cabi)
{
- if (dir < 0 && stack_args_count > 1)
- {
- /* Reverse order if iterating arguments backwards */
- ffi_arg tmp = *(ffi_arg*) p_stack_data[0];
- *(ffi_arg*) p_stack_data[0] = *(ffi_arg*) p_stack_data[stack_args_count - 1];
- *(ffi_arg*) p_stack_data[stack_args_count - 1] = tmp;
- }
-
- int i;
- for (i = 0; i < stack_args_count; i++)
- {
- if (p_stack_data[i] != argp2)
- {
- ffi_arg tmp = *(ffi_arg*) p_stack_data[i];
- memmove (argp2 + FFI_SIZEOF_ARG, argp2, (size_t) ((char*) p_stack_data[i] - (char*)argp2));
- *(ffi_arg *) argp2 = tmp;
- }
-
- argp2 += FFI_SIZEOF_ARG;
- }
+ case FFI_SYSV:
+ case FFI_STDCALL:
+ case FFI_THISCALL:
+ case FFI_FASTCALL:
+ case FFI_MS_CDECL:
+ case FFI_PASCAL:
+ case FFI_REGISTER:
+ break;
+ default:
+ return FFI_BAD_ABI;
}
- return stack_args_count;
-#endif
- return 0;
-}
-
-/* Perform machine dependent cif processing */
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
-{
- unsigned int i;
- ffi_type **ptr;
-
- /* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
+ flags = X86_RET_VOID;
+ break;
+ case FFI_TYPE_FLOAT:
+ flags = X86_RET_FLOAT;
+ break;
+ case FFI_TYPE_DOUBLE:
+ flags = X86_RET_DOUBLE;
+ break;
+ case FFI_TYPE_LONGDOUBLE:
+ flags = X86_RET_LDOUBLE;
+ break;
case FFI_TYPE_UINT8:
+ flags = X86_RET_UINT8;
+ break;
case FFI_TYPE_UINT16:
+ flags = X86_RET_UINT16;
+ break;
case FFI_TYPE_SINT8:
+ flags = X86_RET_SINT8;
+ break;
case FFI_TYPE_SINT16:
-#ifdef X86_WIN64
- case FFI_TYPE_UINT32:
+ flags = X86_RET_SINT16;
+ break;
+ case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
-#endif
- case FFI_TYPE_SINT64:
- case FFI_TYPE_FLOAT:
- case FFI_TYPE_DOUBLE:
-#ifndef X86_WIN64
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- case FFI_TYPE_LONGDOUBLE:
-#endif
-#endif
- cif->flags = (unsigned) cif->rtype->type;
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_POINTER:
+ flags = X86_RET_INT32;
break;
-
+ case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
-#ifdef X86_WIN64
- case FFI_TYPE_POINTER:
-#endif
- cif->flags = FFI_TYPE_SINT64;
+ flags = X86_RET_INT64;
break;
-
case FFI_TYPE_STRUCT:
#ifndef X86
+ /* ??? This should be a different ABI rather than an ifdef. */
if (cif->rtype->size == 1)
- {
- cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
- }
+ flags = X86_RET_STRUCT_1B;
else if (cif->rtype->size == 2)
- {
- cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
- }
+ flags = X86_RET_STRUCT_2B;
else if (cif->rtype->size == 4)
- {
-#ifdef X86_WIN64
- cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
-#else
- cif->flags = FFI_TYPE_INT; /* same as int type */
-#endif
- }
+ flags = X86_RET_INT32;
else if (cif->rtype->size == 8)
- {
- cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
- }
+ flags = X86_RET_INT64;
else
#endif
- {
-#ifdef X86_WIN32
- if (cif->abi == FFI_MS_CDECL)
- cif->flags = FFI_TYPE_MS_STRUCT;
- else
-#endif
- cif->flags = FFI_TYPE_STRUCT;
- /* allocate space for return value pointer */
- cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
- }
+ {
+ do_struct:
+ switch (cabi)
+ {
+ case FFI_THISCALL:
+ case FFI_FASTCALL:
+ case FFI_STDCALL:
+ case FFI_MS_CDECL:
+ flags = X86_RET_STRUCTARG;
+ break;
+ default:
+ flags = X86_RET_STRUCTPOP;
+ break;
+ }
+ /* Allocate space for return value pointer. */
+ bytes += FFI_ALIGN (sizeof(void*), FFI_SIZEOF_ARG);
+ }
break;
-
- default:
-#ifdef X86_WIN64
- cif->flags = FFI_TYPE_SINT64;
- break;
- case FFI_TYPE_INT:
- cif->flags = FFI_TYPE_SINT32;
-#else
- cif->flags = FFI_TYPE_INT;
-#endif
+ case FFI_TYPE_COMPLEX:
+ switch (cif->rtype->elements[0]->type)
+ {
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ goto do_struct;
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ flags = X86_RET_INT64;
+ break;
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ flags = X86_RET_INT32;
+ break;
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ flags = X86_RET_STRUCT_2B;
+ break;
+ default:
+ return FFI_BAD_TYPEDEF;
+ }
break;
+ default:
+ return FFI_BAD_TYPEDEF;
}
+ cif->flags = flags;
- for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+ for (i = 0, n = cif->nargs; i < n; i++)
{
- if (((*ptr)->alignment - 1) & cif->bytes)
- cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
- cif->bytes += (unsigned)ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
- }
+ ffi_type *t = cif->arg_types[i];
-#ifdef X86_WIN64
- /* ensure space for storing four registers */
- cif->bytes += 4 * FFI_SIZEOF_ARG;
-#endif
-
-#ifndef X86_WIN32
-#ifndef X86_WIN64
- if (cif->abi == FFI_SYSV || cif->abi == FFI_UNIX64)
-#endif
- cif->bytes = (cif->bytes + 15) & ~0xF;
-#endif
+ bytes = FFI_ALIGN (bytes, t->alignment);
+ bytes += FFI_ALIGN (t->size, FFI_SIZEOF_ARG);
+ }
+ cif->bytes = bytes;
return FFI_OK;
}
-#ifdef X86_WIN64
-extern int
-ffi_call_win64(unsigned int (*)(char *, extended_cif *), extended_cif *,
- unsigned, unsigned, unsigned *, void (*fn)(void));
-#else
-extern void
-ffi_call_win32(unsigned int (*)(char *, extended_cif *), extended_cif *,
- unsigned, unsigned, unsigned, unsigned *, void (*fn)(void));
-extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
- unsigned, unsigned, unsigned *, void (*fn)(void));
-#endif
-
-void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+static ffi_arg
+extend_basic_type(void *arg, int type)
{
- extended_cif ecif;
-
- 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 */
-
-#ifdef X86_WIN64
- if (rvalue == NULL
- && cif->flags == FFI_TYPE_STRUCT
- && ((cif->rtype->size & (1 | 2 | 4 | 8)) == 0))
+ switch (type)
{
- ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
- }
-#else
- if (rvalue == NULL
- && (cif->flags == FFI_TYPE_STRUCT
- || cif->flags == FFI_TYPE_MS_STRUCT))
- {
- ecif.rvalue = alloca(cif->rtype->size);
- }
-#endif
- else
- ecif.rvalue = rvalue;
-
-
- switch (cif->abi)
- {
-#ifdef X86_WIN64
- case FFI_WIN64:
- ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
- cif->flags, ecif.rvalue, fn);
- break;
-#else
-#ifndef X86_WIN32
- case FFI_SYSV:
- ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
- fn);
- break;
-#else
- case FFI_SYSV:
- case FFI_MS_CDECL:
-#endif
- case FFI_STDCALL:
- case FFI_THISCALL:
- case FFI_FASTCALL:
- case FFI_PASCAL:
- case FFI_REGISTER:
- ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
- ecif.rvalue, fn);
- break;
-#endif
+ case FFI_TYPE_SINT8:
+ return *(SINT8 *)arg;
+ case FFI_TYPE_UINT8:
+ return *(UINT8 *)arg;
+ case FFI_TYPE_SINT16:
+ return *(SINT16 *)arg;
+ case FFI_TYPE_UINT16:
+ return *(UINT16 *)arg;
+
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_FLOAT:
+ return *(UINT32 *)arg;
+
default:
- FFI_ASSERT(0);
- break;
+ abort();
}
}
-
-/** private members **/
-
-/* The following __attribute__((regparm(1))) decorations will have no effect
- on MSVC or SUNPRO_C -- standard conventions apply. */
-static unsigned int ffi_prep_incoming_args (char *stack, void **ret,
- void** args, ffi_cif* cif);
-void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
- __attribute__ ((regparm(1)));
-unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
- __attribute__ ((regparm(1)));
-unsigned int FFI_HIDDEN ffi_closure_WIN32_inner (ffi_closure *, void **, void *)
- __attribute__ ((regparm(1)));
-void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
- __attribute__ ((regparm(1)));
-#ifdef X86_WIN32
-void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *)
- __attribute__ ((regparm(1)));
-#endif
-#ifndef X86_WIN64
-void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *);
-void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *);
-void FFI_HIDDEN ffi_closure_FASTCALL (ffi_closure *);
-void FFI_HIDDEN ffi_closure_REGISTER (ffi_closure *);
+struct call_frame
+{
+ void *ebp; /* 0 */
+ void *retaddr; /* 4 */
+ void (*fn)(void); /* 8 */
+ int flags; /* 12 */
+ void *rvalue; /* 16 */
+ unsigned regs[3]; /* 20-28 */
+};
+
+struct abi_params
+{
+ int dir; /* parameter growth direction */
+ int static_chain; /* the static chain register used by gcc */
+ int nregs; /* number of register parameters */
+ int regs[3];
+};
+
+static const struct abi_params abi_params[FFI_LAST_ABI] = {
+ [FFI_SYSV] = { 1, R_ECX, 0 },
+ [FFI_THISCALL] = { 1, R_EAX, 1, { R_ECX } },
+ [FFI_FASTCALL] = { 1, R_EAX, 2, { R_ECX, R_EDX } },
+ [FFI_STDCALL] = { 1, R_ECX, 0 },
+ [FFI_PASCAL] = { -1, R_ECX, 0 },
+ /* ??? No defined static chain; gcc does not support REGISTER. */
+ [FFI_REGISTER] = { -1, R_ECX, 3, { R_EAX, R_EDX, R_ECX } },
+ [FFI_MS_CDECL] = { 1, R_ECX, 0 }
+};
+
+#ifdef HAVE_FASTCALL
+ #ifdef _MSC_VER
+ #define FFI_DECLARE_FASTCALL __fastcall
+ #else
+ #define FFI_DECLARE_FASTCALL __declspec(fastcall)
+ #endif
#else
-void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
+ #define FFI_DECLARE_FASTCALL
#endif
-/* This function is jumped to by the trampoline */
-
-#ifdef X86_WIN64
-void * FFI_HIDDEN
-ffi_closure_win64_inner (ffi_closure *closure, void *args) {
- ffi_cif *cif;
- void **arg_area;
- void *result;
- void *resp = &result;
-
- cif = closure->cif;
- arg_area = (void**) alloca (cif->nargs * sizeof (void*));
-
- /* this call will initialize ARG_AREA, such that each
- * element in that array points to the corresponding
- * value on the stack; and if the function returns
- * a structure, it will change RESP to point to the
- * structure return address. */
-
- ffi_prep_incoming_args(args, &resp, arg_area, cif);
-
- (closure->fun) (cif, resp, arg_area, closure->user_data);
-
- /* The result is returned in rax. This does the right thing for
- result types except for floats; we have to 'mov xmm0, rax' in the
- caller to correct this.
- TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
- */
- return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
-}
+extern void FFI_DECLARE_FASTCALL ffi_call_i386(struct call_frame *, char *) FFI_HIDDEN;
-#else
-unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
-ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
+static void
+ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
{
- /* our various things... */
- ffi_cif *cif;
- void **arg_area;
+ size_t rsize, bytes;
+ struct call_frame *frame;
+ char *stack, *argp;
+ ffi_type **arg_types;
+ int flags, cabi, i, n, dir, narg_reg;
+ const struct abi_params *pabi;
+
+ flags = cif->flags;
+ cabi = cif->abi;
+ pabi = &abi_params[cabi];
+ dir = pabi->dir;
+
+ rsize = 0;
+ if (rvalue == NULL)
+ {
+ switch (flags)
+ {
+ case X86_RET_FLOAT:
+ case X86_RET_DOUBLE:
+ case X86_RET_LDOUBLE:
+ case X86_RET_STRUCTPOP:
+ case X86_RET_STRUCTARG:
+ /* The float cases need to pop the 387 stack.
+ The struct cases need to pass a valid pointer to the callee. */
+ rsize = cif->rtype->size;
+ break;
+ default:
+ /* We can pretend that the callee returns nothing. */
+ flags = X86_RET_VOID;
+ break;
+ }
+ }
- cif = closure->cif;
- arg_area = (void**) alloca (cif->nargs * sizeof (void*));
+ bytes = STACK_ALIGN (cif->bytes);
+ stack = alloca(bytes + sizeof(*frame) + rsize);
+ argp = (dir < 0 ? stack + bytes : stack);
+ frame = (struct call_frame *)(stack + bytes);
+ if (rsize)
+ rvalue = frame + 1;
- /* this call will initialize ARG_AREA, such that each
- * element in that array points to the corresponding
- * value on the stack; and if the function returns
- * a structure, it will change RESP to point to the
- * structure return address. */
+ frame->fn = fn;
+ frame->flags = flags;
+ frame->rvalue = rvalue;
+ frame->regs[pabi->static_chain] = (unsigned)closure;
- ffi_prep_incoming_args(args, respp, arg_area, cif);
+ narg_reg = 0;
+ switch (flags)
+ {
+ case X86_RET_STRUCTARG:
+ /* The pointer is passed as the first argument. */
+ if (pabi->nregs > 0)
+ {
+ frame->regs[pabi->regs[0]] = (unsigned)rvalue;
+ narg_reg = 1;
+ break;
+ }
+ /* fallthru */
+ case X86_RET_STRUCTPOP:
+ *(void **)argp = rvalue;
+ argp += sizeof(void *);
+ break;
+ }
- (closure->fun) (cif, *respp, arg_area, closure->user_data);
+ arg_types = cif->arg_types;
+ for (i = 0, n = cif->nargs; i < n; i++)
+ {
+ ffi_type *ty = arg_types[i];
+ void *valp = avalue[i];
+ size_t z = ty->size;
+ int t = ty->type;
- return cif->flags;
+ if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT)
+ {
+ ffi_arg val = extend_basic_type (valp, t);
+
+ if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs)
+ frame->regs[pabi->regs[narg_reg++]] = val;
+ else if (dir < 0)
+ {
+ argp -= 4;
+ *(ffi_arg *)argp = val;
+ }
+ else
+ {
+ *(ffi_arg *)argp = val;
+ argp += 4;
+ }
+ }
+ else
+ {
+ size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
+ size_t align = FFI_SIZEOF_ARG;
+
+ /* Issue 434: For thiscall and fastcall, if the paramter passed
+ as 64-bit integer or struct, all following integer paramters
+ will be passed on stack. */
+ if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
+ && (t == FFI_TYPE_SINT64
+ || t == FFI_TYPE_UINT64
+ || t == FFI_TYPE_STRUCT))
+ narg_reg = 2;
+
+ /* Alignment rules for arguments are quite complex. Vectors and
+ structures with 16 byte alignment get it. Note that long double
+ on Darwin does have 16 byte alignment, and does not get this
+ alignment if passed directly; a structure with a long double
+ inside, however, would get 16 byte alignment. Since libffi does
+ not support vectors, we need non concern ourselves with other
+ cases. */
+ if (t == FFI_TYPE_STRUCT && ty->alignment >= 16)
+ align = 16;
+
+ if (dir < 0)
+ {
+ /* ??? These reverse argument ABIs are probably too old
+ to have cared about alignment. Someone should check. */
+ argp -= za;
+ memcpy (argp, valp, z);
+ }
+ else
+ {
+ argp = (char *)FFI_ALIGN (argp, align);
+ memcpy (argp, valp, z);
+ argp += za;
+ }
+ }
+ }
+ FFI_ASSERT (dir > 0 || argp == stack);
+
+ ffi_call_i386 (frame, stack);
}
-unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
-ffi_closure_WIN32_inner (ffi_closure *closure, void **respp, void *args)
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
- /* our various things... */
- ffi_cif *cif;
- void **arg_area;
- unsigned int ret;
-
- cif = closure->cif;
- arg_area = (void**) alloca (cif->nargs * sizeof (void*));
-
- /* this call will initialize ARG_AREA, such that each
- * element in that array points to the corresponding
- * value on the stack; and if the function returns
- * a structure, it will change RESP to point to the
- * structure return address. */
-
- ret = ffi_prep_incoming_args(args, respp, arg_area, cif);
-
- (closure->fun) (cif, *respp, arg_area, closure->user_data);
-
- return ret;
+ ffi_call_int (cif, fn, rvalue, avalue, NULL);
}
-#endif /* !X86_WIN64 */
-static unsigned int
-ffi_prep_incoming_args(char *stack, void **rvalue, void **avalue,
- ffi_cif *cif)
+void
+ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
{
- register unsigned int i;
- register void **p_argv;
- register char *argp;
- register ffi_type **p_arg;
-#ifndef X86_WIN64
- const int cabi = cif->abi;
- const int dir = (cabi == FFI_PASCAL || cabi == FFI_REGISTER) ? -1 : +1;
- const unsigned int max_stack_count = (cabi == FFI_THISCALL) ? 1
- : (cabi == FFI_FASTCALL) ? 2
- : (cabi == FFI_REGISTER) ? 3
- : 0;
- unsigned int passed_regs = 0;
- void *p_stack_data[3] = { stack - 1 };
-#else
- #define dir 1
-#endif
+ ffi_call_int (cif, fn, rvalue, avalue, closure);
+}
- argp = stack;
-#ifndef X86_WIN64
- argp += max_stack_count * FFI_SIZEOF_ARG;
-#endif
+/** private members **/
- if ((cif->flags == FFI_TYPE_STRUCT
- || cif->flags == FFI_TYPE_MS_STRUCT)
-#ifdef X86_WIN64
- && ((cif->rtype->size & (1 | 2 | 4 | 8)) == 0)
-#endif
- )
- {
-#ifndef X86_WIN64
- if (passed_regs < max_stack_count)
- {
- *rvalue = *(void**) (stack + (passed_regs*FFI_SIZEOF_ARG));
- ++passed_regs;
- }
- else
-#endif
- {
- *rvalue = *(void **) argp;
- argp += sizeof(void *);
- }
- }
+void FFI_HIDDEN ffi_closure_i386(void);
+void FFI_HIDDEN ffi_closure_STDCALL(void);
+void FFI_HIDDEN ffi_closure_REGISTER(void);
-#ifndef X86_WIN64
- /* Do register arguments first */
- for (i = 0, p_arg = cif->arg_types;
- i < cif->nargs && passed_regs < max_stack_count;
- i++, p_arg++)
+struct closure_frame
+{
+ unsigned rettemp[4]; /* 0 */
+ unsigned regs[3]; /* 16-24 */
+ ffi_cif *cif; /* 28 */
+ void (*fun)(ffi_cif*,void*,void**,void*); /* 32 */
+ void *user_data; /* 36 */
+};
+
+int FFI_HIDDEN FFI_DECLARE_FASTCALL
+ffi_closure_inner (struct closure_frame *frame, char *stack)
+{
+ ffi_cif *cif = frame->cif;
+ int cabi, i, n, flags, dir, narg_reg;
+ const struct abi_params *pabi;
+ ffi_type **arg_types;
+ char *argp;
+ void *rvalue;
+ void **avalue;
+
+ cabi = cif->abi;
+ flags = cif->flags;
+ narg_reg = 0;
+ rvalue = frame->rettemp;
+ pabi = &abi_params[cabi];
+ dir = pabi->dir;
+ argp = (dir < 0 ? stack + STACK_ALIGN (cif->bytes) : stack);
+
+ switch (flags)
{
- if ((*p_arg)->type == FFI_TYPE_FLOAT
- || (*p_arg)->type == FFI_TYPE_STRUCT)
- continue;
-
- size_t sz = (*p_arg)->size;
- if(sz == 0 || sz > FFI_SIZEOF_ARG)
- continue;
-
- p_stack_data[passed_regs] = avalue + i;
- avalue[i] = stack + (passed_regs*FFI_SIZEOF_ARG);
- ++passed_regs;
+ case X86_RET_STRUCTARG:
+ if (pabi->nregs > 0)
+ {
+ rvalue = (void *)frame->regs[pabi->regs[0]];
+ narg_reg = 1;
+ frame->rettemp[0] = (unsigned)rvalue;
+ break;
+ }
+ /* fallthru */
+ case X86_RET_STRUCTPOP:
+ rvalue = *(void **)argp;
+ argp += sizeof(void *);
+ frame->rettemp[0] = (unsigned)rvalue;
+ break;
}
-#endif
- p_arg = cif->arg_types;
- p_argv = avalue;
- if (dir < 0)
- {
- const int nargs = cif->nargs - 1;
- if (nargs > 0)
- {
- p_arg += nargs;
- p_argv += nargs;
- }
- }
+ n = cif->nargs;
+ avalue = alloca(sizeof(void *) * n);
- for (i = cif->nargs;
- i != 0;
- i--, p_arg += dir, p_argv += dir)
+ arg_types = cif->arg_types;
+ for (i = 0; i < n; ++i)
{
- /* Align if necessary */
- if ((sizeof(void*) - 1) & (size_t) argp)
- argp = (char *) ALIGN(argp, sizeof(void*));
-
- size_t z = (*p_arg)->size;
-
-#ifdef X86_WIN64
- if (z > FFI_SIZEOF_ARG
- || ((*p_arg)->type == FFI_TYPE_STRUCT
- && (z & (1 | 2 | 4 | 8)) == 0)
-#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
- || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
-#endif
- )
- {
- z = FFI_SIZEOF_ARG;
- *p_argv = *(void **)argp;
- }
+ ffi_type *ty = arg_types[i];
+ size_t z = ty->size;
+ int t = ty->type;
+ void *valp;
+
+ if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT)
+ {
+ if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs)
+ valp = &frame->regs[pabi->regs[narg_reg++]];
+ else if (dir < 0)
+ {
+ argp -= 4;
+ valp = argp;
+ }
+ else
+ {
+ valp = argp;
+ argp += 4;
+ }
+ }
else
-#else
- if (passed_regs > 0
- && z <= FFI_SIZEOF_ARG
- && (p_argv == p_stack_data[0]
- || p_argv == p_stack_data[1]
- || p_argv == p_stack_data[2]))
- {
- /* Already assigned a register value */
- continue;
- }
- else
-#endif
- {
- /* because we're little endian, this is what it turns into. */
- *p_argv = (void*) argp;
- }
-
-#ifdef X86_WIN64
- argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
-#else
- argp += z;
-#endif
+ {
+ size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
+ size_t align = FFI_SIZEOF_ARG;
+
+ /* See the comment in ffi_call_int. */
+ if (t == FFI_TYPE_STRUCT && ty->alignment >= 16)
+ align = 16;
+
+ /* Issue 434: For thiscall and fastcall, if the paramter passed
+ as 64-bit integer or struct, all following integer paramters
+ will be passed on stack. */
+ if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
+ && (t == FFI_TYPE_SINT64
+ || t == FFI_TYPE_UINT64
+ || t == FFI_TYPE_STRUCT))
+ narg_reg = 2;
+
+ if (dir < 0)
+ {
+ /* ??? These reverse argument ABIs are probably too old
+ to have cared about alignment. Someone should check. */
+ argp -= za;
+ valp = argp;
+ }
+ else
+ {
+ argp = (char *)FFI_ALIGN (argp, align);
+ valp = argp;
+ argp += za;
+ }
+ }
+
+ avalue[i] = valp;
}
- return (size_t)argp - (size_t)stack;
-}
+ frame->fun (cif, rvalue, avalue, frame->user_data);
-#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
-{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
- void* __fun = (void*)(FUN); \
- void* __ctx = (void*)(CTX); \
- *(unsigned char*) &__tramp[0] = 0x41; \
- *(unsigned char*) &__tramp[1] = 0xbb; \
- *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
- *(unsigned char*) &__tramp[6] = 0x48; \
- *(unsigned char*) &__tramp[7] = 0xb8; \
- *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
- *(unsigned char *) &__tramp[16] = 0x49; \
- *(unsigned char *) &__tramp[17] = 0xba; \
- *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
- *(unsigned char *) &__tramp[26] = 0x41; \
- *(unsigned char *) &__tramp[27] = 0xff; \
- *(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \
- }
-
-/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
-
-#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
-{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
- unsigned int __fun = (unsigned int)(FUN); \
- unsigned int __ctx = (unsigned int)(CTX); \
- unsigned int __dis = __fun - (__ctx + 10); \
- *(unsigned char*) &__tramp[0] = 0xb8; \
- *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
- *(unsigned char*) &__tramp[5] = 0xe9; \
- *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
- }
-
-#define FFI_INIT_TRAMPOLINE_RAW_THISCALL(TRAMP,FUN,CTX,SIZE) \
-{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
- unsigned int __fun = (unsigned int)(FUN); \
- unsigned int __ctx = (unsigned int)(CTX); \
- unsigned int __dis = __fun - (__ctx + 49); \
- unsigned short __size = (unsigned short)(SIZE); \
- *(unsigned int *) &__tramp[0] = 0x8324048b; /* mov (%esp), %eax */ \
- *(unsigned int *) &__tramp[4] = 0x4c890cec; /* sub $12, %esp */ \
- *(unsigned int *) &__tramp[8] = 0x04890424; /* mov %ecx, 4(%esp) */ \
- *(unsigned char*) &__tramp[12] = 0x24; /* mov %eax, (%esp) */ \
- *(unsigned char*) &__tramp[13] = 0xb8; \
- *(unsigned int *) &__tramp[14] = __size; /* mov __size, %eax */ \
- *(unsigned int *) &__tramp[18] = 0x08244c8d; /* lea 8(%esp), %ecx */ \
- *(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \
- *(unsigned short*) &__tramp[26] = 0x0b74; /* jz 1f */ \
- *(unsigned int *) &__tramp[28] = 0x8908518b; /* 2b: mov 8(%ecx), %edx */ \
- *(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \
- *(unsigned char*) &__tramp[36] = 0x48; /* dec %eax */ \
- *(unsigned short*) &__tramp[37] = 0xf575; /* jnz 2b ; 1f: */ \
- *(unsigned char*) &__tramp[39] = 0xb8; \
- *(unsigned int*) &__tramp[40] = __ctx; /* movl __ctx, %eax */ \
- *(unsigned char *) &__tramp[44] = 0xe8; \
- *(unsigned int*) &__tramp[45] = __dis; /* call __fun */ \
- *(unsigned char*) &__tramp[49] = 0xc2; /* ret */ \
- *(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \
- }
-
-#define FFI_INIT_TRAMPOLINE_WIN32(TRAMP,FUN,CTX) \
-{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
- unsigned int __fun = (unsigned int)(FUN); \
- unsigned int __ctx = (unsigned int)(CTX); \
- unsigned int __dis = __fun - (__ctx + 10); \
- *(unsigned char*) &__tramp[0] = 0x68; \
- *(unsigned int*) &__tramp[1] = __ctx; /* push __ctx */ \
- *(unsigned char*) &__tramp[5] = 0xe9; \
- *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
- }
-
-/* the cif must already be prep'ed */
+ if (cabi == FFI_STDCALL)
+ return flags + (cif->bytes << X86_RET_POP_SHIFT);
+ else
+ return flags;
+}
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
@@ -723,65 +533,77 @@ ffi_prep_closure_loc (ffi_closure* closure,
void *user_data,
void *codeloc)
{
-#ifdef X86_WIN64
-#define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
-#define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
- if (cif->abi == FFI_WIN64)
- {
- int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
- FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
- &ffi_closure_win64,
- codeloc, mask);
- /* make sure we can execute here */
- }
-#else
- if (cif->abi == FFI_SYSV)
- {
- FFI_INIT_TRAMPOLINE (&closure->tramp[0],
- &ffi_closure_SYSV,
- (void*)codeloc);
- }
- else if (cif->abi == FFI_REGISTER)
- {
- FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
- &ffi_closure_REGISTER,
- (void*)codeloc);
- }
- else if (cif->abi == FFI_FASTCALL)
- {
- FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
- &ffi_closure_FASTCALL,
- (void*)codeloc);
- }
- else if (cif->abi == FFI_THISCALL)
- {
- FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
- &ffi_closure_THISCALL,
- (void*)codeloc);
- }
- else if (cif->abi == FFI_STDCALL || cif->abi == FFI_PASCAL)
- {
- FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
- &ffi_closure_STDCALL,
- (void*)codeloc);
- }
-#ifdef X86_WIN32
- else if (cif->abi == FFI_MS_CDECL)
+ char *tramp = closure->tramp;
+ void (*dest)(void);
+ int op = 0xb8; /* movl imm, %eax */
+
+ switch (cif->abi)
{
- FFI_INIT_TRAMPOLINE (&closure->tramp[0],
- &ffi_closure_SYSV,
- (void*)codeloc);
+ case FFI_SYSV:
+ case FFI_THISCALL:
+ case FFI_FASTCALL:
+ case FFI_MS_CDECL:
+ dest = ffi_closure_i386;
+ break;
+ case FFI_STDCALL:
+ case FFI_PASCAL:
+ dest = ffi_closure_STDCALL;
+ break;
+ case FFI_REGISTER:
+ dest = ffi_closure_REGISTER;
+ op = 0x68; /* pushl imm */
+ break;
+ default:
+ return FFI_BAD_ABI;
}
-#endif /* X86_WIN32 */
-#endif /* !X86_WIN64 */
- else
+
+ /* movl or pushl immediate. */
+ tramp[0] = op;
+ *(void **)(tramp + 1) = codeloc;
+
+ /* jmp dest */
+ tramp[5] = 0xe9;
+ *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10);
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ return FFI_OK;
+}
+
+void FFI_HIDDEN ffi_go_closure_EAX(void);
+void FFI_HIDDEN ffi_go_closure_ECX(void);
+void FFI_HIDDEN ffi_go_closure_STDCALL(void);
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*))
+{
+ void (*dest)(void);
+
+ switch (cif->abi)
{
+ case FFI_SYSV:
+ case FFI_MS_CDECL:
+ dest = ffi_go_closure_ECX;
+ break;
+ case FFI_THISCALL:
+ case FFI_FASTCALL:
+ dest = ffi_go_closure_EAX;
+ break;
+ case FFI_STDCALL:
+ case FFI_PASCAL:
+ dest = ffi_go_closure_STDCALL;
+ break;
+ case FFI_REGISTER:
+ default:
return FFI_BAD_ABI;
}
-
- closure->cif = cif;
- closure->user_data = user_data;
- closure->fun = fun;
+
+ closure->tramp = dest;
+ closure->cif = cif;
+ closure->fun = fun;
return FFI_OK;
}
@@ -790,142 +612,150 @@ ffi_prep_closure_loc (ffi_closure* closure,
#if !FFI_NO_RAW_API
+void FFI_HIDDEN ffi_closure_raw_SYSV(void);
+void FFI_HIDDEN ffi_closure_raw_THISCALL(void);
+
ffi_status
-ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
- ffi_cif* cif,
+ffi_prep_raw_closure_loc (ffi_raw_closure *closure,
+ ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc)
{
+ char *tramp = closure->tramp;
+ void (*dest)(void);
int i;
- if (cif->abi != FFI_SYSV
-#ifdef X86_WIN32
- && cif->abi != FFI_THISCALL
-#endif
- )
- return FFI_BAD_ABI;
-
- /* we currently don't support certain kinds of arguments for raw
+ /* We currently don't support certain kinds of arguments for raw
closures. This should be implemented by a separate assembly
language routine, since it would require argument processing,
something we don't do now for performance. */
-
for (i = cif->nargs-1; i >= 0; i--)
+ switch (cif->arg_types[i]->type)
+ {
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_LONGDOUBLE:
+ return FFI_BAD_TYPEDEF;
+ }
+
+ switch (cif->abi)
{
- FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
- FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
- }
-
-#ifdef X86_WIN32
- if (cif->abi == FFI_SYSV)
- {
-#endif
- FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
- codeloc);
-#ifdef X86_WIN32
- }
- else if (cif->abi == FFI_THISCALL)
- {
- FFI_INIT_TRAMPOLINE_RAW_THISCALL (&closure->tramp[0], &ffi_closure_raw_THISCALL, codeloc, cif->bytes);
+ case FFI_THISCALL:
+ dest = ffi_closure_raw_THISCALL;
+ break;
+ case FFI_SYSV:
+ dest = ffi_closure_raw_SYSV;
+ break;
+ default:
+ return FFI_BAD_ABI;
}
-#endif
- closure->cif = cif;
+
+ /* movl imm, %eax. */
+ tramp[0] = 0xb8;
+ *(void **)(tramp + 1) = codeloc;
+
+ /* jmp dest */
+ tramp[5] = 0xe9;
+ *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10);
+
+ closure->cif = cif;
+ closure->fun = fun;
closure->user_data = user_data;
- closure->fun = fun;
return FFI_OK;
}
-static unsigned int
-ffi_prep_args_raw(char *stack, extended_cif *ecif)
+void
+ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
{
- const ffi_cif *cif = ecif->cif;
- unsigned int i, passed_regs = 0;
-
-#ifndef X86_WIN64
- const unsigned int abi = cif->abi;
- const unsigned int max_regs = (abi == FFI_THISCALL) ? 1
- : (abi == FFI_FASTCALL) ? 2
- : (abi == FFI_REGISTER) ? 3
- : 0;
-
- if (cif->flags == FFI_TYPE_STRUCT)
- ++passed_regs;
-
- for (i = 0; i < cif->nargs && passed_regs <= max_regs; i++)
+ size_t rsize, bytes;
+ struct call_frame *frame;
+ char *stack, *argp;
+ ffi_type **arg_types;
+ int flags, cabi, i, n, narg_reg;
+ const struct abi_params *pabi;
+
+ flags = cif->flags;
+ cabi = cif->abi;
+ pabi = &abi_params[cabi];
+
+ rsize = 0;
+ if (rvalue == NULL)
{
- if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
- || cif->arg_types[i]->type == FFI_TYPE_STRUCT)
- continue;
-
- size_t sz = cif->arg_types[i]->size;
- if (sz == 0 || sz > FFI_SIZEOF_ARG)
- continue;
-
- ++passed_regs;
+ switch (flags)
+ {
+ case X86_RET_FLOAT:
+ case X86_RET_DOUBLE:
+ case X86_RET_LDOUBLE:
+ case X86_RET_STRUCTPOP:
+ case X86_RET_STRUCTARG:
+ /* The float cases need to pop the 387 stack.
+ The struct cases need to pass a valid pointer to the callee. */
+ rsize = cif->rtype->size;
+ break;
+ default:
+ /* We can pretend that the callee returns nothing. */
+ flags = X86_RET_VOID;
+ break;
+ }
}
-#endif
- memcpy (stack, ecif->avalue, cif->bytes);
- return passed_regs;
-}
+ bytes = STACK_ALIGN (cif->bytes);
+ argp = stack =
+ (void *)((uintptr_t)alloca(bytes + sizeof(*frame) + rsize + 15) & ~16);
+ frame = (struct call_frame *)(stack + bytes);
+ if (rsize)
+ rvalue = frame + 1;
-/* we borrow this routine from libffi (it must be changed, though, to
- * actually call the function passed in the first argument. as of
- * libffi-1.20, this is not the case.)
- */
+ frame->fn = fn;
+ frame->flags = flags;
+ frame->rvalue = rvalue;
-void
-ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
-{
- extended_cif ecif;
- void **avalue = (void **)fake_avalue;
-
- 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
- && (cif->flags == FFI_TYPE_STRUCT
- || cif->flags == FFI_TYPE_MS_STRUCT))
+ narg_reg = 0;
+ switch (flags)
{
- ecif.rvalue = alloca(cif->rtype->size);
- }
- else
- ecif.rvalue = rvalue;
-
-
- switch (cif->abi)
- {
-#ifndef X86_WIN32
- case FFI_SYSV:
- ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
- ecif.rvalue, fn);
- break;
-#else
- case FFI_SYSV:
- case FFI_MS_CDECL:
-#endif
-#ifndef X86_WIN64
- case FFI_STDCALL:
- case FFI_THISCALL:
- case FFI_FASTCALL:
- case FFI_PASCAL:
- case FFI_REGISTER:
- ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags,
- ecif.rvalue, fn);
- break;
-#endif
- default:
- FFI_ASSERT(0);
+ case X86_RET_STRUCTARG:
+ /* The pointer is passed as the first argument. */
+ if (pabi->nregs > 0)
+ {
+ frame->regs[pabi->regs[0]] = (unsigned)rvalue;
+ narg_reg = 1;
+ break;
+ }
+ /* fallthru */
+ case X86_RET_STRUCTPOP:
+ *(void **)argp = rvalue;
+ argp += sizeof(void *);
+ bytes -= sizeof(void *);
break;
}
-}
-
-#endif
-#endif /* !__x86_64__ || X86_WIN64 */
+ arg_types = cif->arg_types;
+ for (i = 0, n = cif->nargs; narg_reg < pabi->nregs && i < n; i++)
+ {
+ ffi_type *ty = arg_types[i];
+ size_t z = ty->size;
+ int t = ty->type;
+
+ if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT && t != FFI_TYPE_FLOAT)
+ {
+ ffi_arg val = extend_basic_type (avalue, t);
+ frame->regs[pabi->regs[narg_reg++]] = val;
+ z = FFI_SIZEOF_ARG;
+ }
+ else
+ {
+ memcpy (argp, avalue, z);
+ z = FFI_ALIGN (z, FFI_SIZEOF_ARG);
+ argp += z;
+ }
+ avalue += z;
+ bytes -= z;
+ }
+ if (i < n)
+ memcpy (argp, avalue, bytes);
+ ffi_call_i386 (frame, stack);
+}
+#endif /* !FFI_NO_RAW_API */
+#endif /* __i386__ */
diff --git a/src/x86/ffi64.c b/src/x86/ffi64.c
index 5a5e0438..dec331c9 100644
--- a/src/x86/ffi64.c
+++ b/src/x86/ffi64.c
@@ -1,6 +1,6 @@
/* -----------------------------------------------------------------------
- ffi64.c - Copyright (c) 2013 The Written Word, Inc.
- Copyright (c) 2011 Anthony Green
+ ffi64.c - Copyright (c) 2011, 2018 Anthony Green
+ Copyright (c) 2013 The Written Word, Inc.
Copyright (c) 2008, 2010 Red Hat, Inc.
Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de>
@@ -32,6 +32,8 @@
#include <stdlib.h>
#include <stdarg.h>
+#include <stdint.h>
+#include "internal64.h"
#ifdef __x86_64__
@@ -62,10 +64,12 @@ struct register_args
/* Registers for argument passing. */
UINT64 gpr[MAX_GPR_REGS];
union big_int_union sse[MAX_SSE_REGS];
+ UINT64 rax; /* ssecount */
+ UINT64 r10; /* static chain */
};
extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
- void *raddr, void (*fnaddr)(void), unsigned ssecount);
+ void *raddr, void (*fnaddr)(void)) FFI_HIDDEN;
/* All reference to register classes here is identical to the code in
gcc/config/i386/i386.c. Do *not* change one without the other. */
@@ -167,6 +171,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_POINTER:
+ do_integer:
{
size_t size = byte_offset + type->size;
@@ -188,7 +193,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
}
else if (size <= 16)
{
- classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
+ classes[0] = classes[1] = X86_64_INTEGER_CLASS;
return 2;
}
else
@@ -214,7 +219,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
const size_t UNITS_PER_WORD = 8;
size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
ffi_type **ptr;
- int i;
+ unsigned int i;
enum x86_64_reg_class subclasses[MAX_CLASSES];
/* If the struct is larger than 32 bytes, pass it on the stack. */
@@ -228,6 +233,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
signalize memory class, so handle it as special case. */
if (!words)
{
+ case FFI_TYPE_VOID:
classes[0] = X86_64_NO_CLASS;
return 1;
}
@@ -237,7 +243,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
{
size_t num;
- byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
+ byte_offset = FFI_ALIGN (byte_offset, (*ptr)->alignment);
num = classify_argument (*ptr, subclasses, byte_offset % 8);
if (num == 0)
@@ -276,7 +282,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
/* The X86_64_SSEUP_CLASS should be always preceded by
X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */
- if (classes[i] == X86_64_SSEUP_CLASS
+ if (i > 1 && classes[i] == X86_64_SSEUP_CLASS
&& classes[i - 1] != X86_64_SSE_CLASS
&& classes[i - 1] != X86_64_SSEUP_CLASS)
{
@@ -287,7 +293,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
/* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
everything should be passed in memory. */
- if (classes[i] == X86_64_X87UP_CLASS
+ if (i > 1 && classes[i] == X86_64_X87UP_CLASS
&& (classes[i - 1] != X86_64_X87_CLASS))
{
/* The first one should never be X86_64_X87UP_CLASS. */
@@ -297,11 +303,42 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
}
return words;
}
-
- default:
- FFI_ASSERT(0);
+ case FFI_TYPE_COMPLEX:
+ {
+ ffi_type *inner = type->elements[0];
+ switch (inner->type)
+ {
+ case FFI_TYPE_INT:
+ 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:
+ goto do_integer;
+
+ case FFI_TYPE_FLOAT:
+ classes[0] = X86_64_SSE_CLASS;
+ if (byte_offset % 8)
+ {
+ classes[1] = X86_64_SSESF_CLASS;
+ return 2;
+ }
+ return 1;
+ case FFI_TYPE_DOUBLE:
+ classes[0] = classes[1] = X86_64_SSEDF_CLASS;
+ return 2;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ classes[0] = X86_64_COMPLEX_X87_CLASS;
+ return 1;
+#endif
+ }
+ }
}
- return 0; /* Never reached. */
+ abort();
}
/* Examine the argument and return set number of register required in each
@@ -313,7 +350,8 @@ examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
_Bool in_return, int *pngpr, int *pnsse)
{
size_t n;
- int i, ngpr, nsse;
+ unsigned int i;
+ int ngpr, nsse;
n = classify_argument (type, classes, 0);
if (n == 0)
@@ -351,18 +389,74 @@ examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
/* Perform machine dependent cif processing. */
-ffi_status
+#ifndef __ILP32__
+extern ffi_status
+ffi_prep_cif_machdep_efi64(ffi_cif *cif);
+#endif
+
+ffi_status FFI_HIDDEN
ffi_prep_cif_machdep (ffi_cif *cif)
{
- int gprcount, ssecount, i, avn, ngpr, nsse, flags;
+ int gprcount, ssecount, i, avn, ngpr, nsse;
+ unsigned flags;
enum x86_64_reg_class classes[MAX_CLASSES];
- size_t bytes, n;
+ size_t bytes, n, rtype_size;
+ ffi_type *rtype;
+
+#ifndef __ILP32__
+ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+ return ffi_prep_cif_machdep_efi64(cif);
+#endif
+ if (cif->abi != FFI_UNIX64)
+ return FFI_BAD_ABI;
gprcount = ssecount = 0;
- flags = cif->rtype->type;
- if (flags != FFI_TYPE_VOID)
+ rtype = cif->rtype;
+ rtype_size = rtype->size;
+ switch (rtype->type)
{
+ case FFI_TYPE_VOID:
+ flags = UNIX64_RET_VOID;
+ break;
+ case FFI_TYPE_UINT8:
+ flags = UNIX64_RET_UINT8;
+ break;
+ case FFI_TYPE_SINT8:
+ flags = UNIX64_RET_SINT8;
+ break;
+ case FFI_TYPE_UINT16:
+ flags = UNIX64_RET_UINT16;
+ break;
+ case FFI_TYPE_SINT16:
+ flags = UNIX64_RET_SINT16;
+ break;
+ case FFI_TYPE_UINT32:
+ flags = UNIX64_RET_UINT32;
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ flags = UNIX64_RET_SINT32;
+ break;
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ flags = UNIX64_RET_INT64;
+ break;
+ case FFI_TYPE_POINTER:
+ flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
+ break;
+ case FFI_TYPE_FLOAT:
+ flags = UNIX64_RET_XMM32;
+ break;
+ case FFI_TYPE_DOUBLE:
+ flags = UNIX64_RET_XMM64;
+ break;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ flags = UNIX64_RET_X87;
+ break;
+#endif
+ case FFI_TYPE_STRUCT:
n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
if (n == 0)
{
@@ -370,22 +464,62 @@ ffi_prep_cif_machdep (ffi_cif *cif)
memory is the first argument. Allocate a register for it. */
gprcount++;
/* We don't have to do anything in asm for the return. */
- flags = FFI_TYPE_VOID;
+ flags = UNIX64_RET_VOID | UNIX64_FLAG_RET_IN_MEM;
}
- else if (flags == FFI_TYPE_STRUCT)
+ else
{
- /* Mark which registers the result appears in. */
_Bool sse0 = SSE_CLASS_P (classes[0]);
- _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
- if (sse0 && !sse1)
- flags |= 1 << 8;
- else if (!sse0 && sse1)
- flags |= 1 << 9;
- else if (sse0 && sse1)
- flags |= 1 << 10;
- /* Mark the true size of the structure. */
- flags |= cif->rtype->size << 12;
+
+ if (rtype_size == 4 && sse0)
+ flags = UNIX64_RET_XMM32;
+ else if (rtype_size == 8)
+ flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64;
+ else
+ {
+ _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
+ if (sse0 && sse1)
+ flags = UNIX64_RET_ST_XMM0_XMM1;
+ else if (sse0)
+ flags = UNIX64_RET_ST_XMM0_RAX;
+ else if (sse1)
+ flags = UNIX64_RET_ST_RAX_XMM0;
+ else
+ flags = UNIX64_RET_ST_RAX_RDX;
+ flags |= rtype_size << UNIX64_SIZE_SHIFT;
+ }
}
+ break;
+ case FFI_TYPE_COMPLEX:
+ switch (rtype->elements[0]->type)
+ {
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ flags = UNIX64_RET_ST_RAX_RDX | ((unsigned) rtype_size << UNIX64_SIZE_SHIFT);
+ break;
+ case FFI_TYPE_FLOAT:
+ flags = UNIX64_RET_XMM64;
+ break;
+ case FFI_TYPE_DOUBLE:
+ flags = UNIX64_RET_ST_XMM0_XMM1 | (16 << UNIX64_SIZE_SHIFT);
+ break;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ flags = UNIX64_RET_X87_2;
+ break;
+#endif
+ default:
+ return FFI_BAD_TYPEDEF;
+ }
+ break;
+ default:
+ return FFI_BAD_TYPEDEF;
}
/* Go over all arguments and determine the way they should be passed.
@@ -402,7 +536,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
if (align < 8)
align = 8;
- bytes = ALIGN (bytes, align);
+ bytes = FFI_ALIGN (bytes, align);
bytes += cif->arg_types[i]->size;
}
else
@@ -412,44 +546,50 @@ ffi_prep_cif_machdep (ffi_cif *cif)
}
}
if (ssecount)
- flags |= 1 << 11;
+ flags |= UNIX64_FLAG_XMM_ARGS;
+
cif->flags = flags;
- cif->bytes = (unsigned)ALIGN (bytes, 8);
+ cif->bytes = (unsigned) FFI_ALIGN (bytes, 8);
return FFI_OK;
}
-void
-ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+static void
+ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
{
enum x86_64_reg_class classes[MAX_CLASSES];
char *stack, *argp;
ffi_type **arg_types;
- int gprcount, ssecount, ngpr, nsse, i, avn;
- _Bool ret_in_memory;
+ int gprcount, ssecount, ngpr, nsse, i, avn, flags;
struct register_args *reg_args;
/* Can't call 32-bit mode from 64-bit mode. */
FFI_ASSERT (cif->abi == FFI_UNIX64);
/* If the return value is a struct and we don't have a return value
- address then we need to make one. Note the setting of flags to
- VOID above in ffi_prep_cif_machdep. */
- ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
- && (cif->flags & 0xff) == FFI_TYPE_VOID);
- if (rvalue == NULL && ret_in_memory)
- rvalue = alloca (cif->rtype->size);
+ address then we need to make one. Otherwise we can ignore it. */
+ flags = cif->flags;
+ if (rvalue == NULL)
+ {
+ if (flags & UNIX64_FLAG_RET_IN_MEM)
+ rvalue = alloca (cif->rtype->size);
+ else
+ flags = UNIX64_RET_VOID;
+ }
/* Allocate the space for the arguments, plus 4 words of temp space. */
stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
reg_args = (struct register_args *) stack;
argp = stack + sizeof (struct register_args);
+ reg_args->r10 = (uintptr_t) closure;
+
gprcount = ssecount = 0;
/* If the return value is passed in memory, add the pointer as the
first integer argument. */
- if (ret_in_memory)
+ if (flags & UNIX64_FLAG_RET_IN_MEM)
reg_args->gpr[gprcount++] = (unsigned long) rvalue;
avn = cif->nargs;
@@ -471,7 +611,7 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
align = 8;
/* Pass this argument in memory. */
- argp = (void *) ALIGN (argp, align);
+ argp = (void *) FFI_ALIGN (argp, align);
memcpy (argp, avalue[i], size);
argp += size;
}
@@ -479,12 +619,15 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
/* The argument is passed entirely in registers. */
char *a = (char *) avalue[i];
- int j;
+ unsigned int j;
for (j = 0; j < n; j++, a += 8, size -= 8)
{
switch (classes[j])
{
+ case X86_64_NO_CLASS:
+ case X86_64_SSEUP_CLASS:
+ break;
case X86_64_INTEGER_CLASS:
case X86_64_INTEGERSI_CLASS:
/* Sign-extend integer arguments passed in general
@@ -494,26 +637,26 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
switch (arg_types[i]->type)
{
case FFI_TYPE_SINT8:
- *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
+ reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
break;
case FFI_TYPE_SINT16:
- *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
+ reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
break;
case FFI_TYPE_SINT32:
- *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
+ reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
break;
default:
reg_args->gpr[gprcount] = 0;
- memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8);
+ memcpy (&reg_args->gpr[gprcount], a, size);
}
gprcount++;
break;
case X86_64_SSE_CLASS:
case X86_64_SSEDF_CLASS:
- reg_args->sse[ssecount++].i64 = *(UINT64 *) a;
+ memcpy (&reg_args->sse[ssecount++].i64, a, sizeof(UINT64));
break;
case X86_64_SSESF_CLASS:
- reg_args->sse[ssecount++].i32 = *(UINT32 *) a;
+ memcpy (&reg_args->sse[ssecount++].i32, a, sizeof(UINT32));
break;
default:
abort();
@@ -521,13 +664,62 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
}
}
+ reg_args->rax = ssecount;
ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
- cif->flags, rvalue, fn, ssecount);
+ flags, rvalue, fn);
+}
+
+#ifndef __ILP32__
+extern void
+ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);
+#endif
+
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+#ifndef __ILP32__
+ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+ {
+ ffi_call_efi64(cif, fn, rvalue, avalue);
+ return;
+ }
+#endif
+ ffi_call_int (cif, fn, rvalue, avalue, NULL);
+}
+
+#ifndef __ILP32__
+extern void
+ffi_call_go_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure);
+#endif
+
+void
+ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+#ifndef __ILP32__
+ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+ {
+ ffi_call_go_efi64(cif, fn, rvalue, avalue, closure);
+ return;
+ }
+#endif
+ ffi_call_int (cif, fn, rvalue, avalue, closure);
}
-extern void ffi_closure_unix64(void);
+extern void ffi_closure_unix64(void) FFI_HIDDEN;
+extern void ffi_closure_unix64_sse(void) FFI_HIDDEN;
+
+#ifndef __ILP32__
+extern ffi_status
+ffi_prep_closure_loc_efi64(ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ void *codeloc);
+#endif
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
@@ -536,29 +728,31 @@ ffi_prep_closure_loc (ffi_closure* closure,
void *user_data,
void *codeloc)
{
- volatile unsigned short *tramp;
-
- /* Sanity check on the cif ABI. */
- {
- int abi = cif->abi;
- if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)))
- return FFI_BAD_ABI;
- }
-
- tramp = (volatile unsigned short *) &closure->tramp[0];
+ static const unsigned char trampoline[16] = {
+ /* leaq -0x7(%rip),%r10 # 0x0 */
+ 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
+ /* jmpq *0x3(%rip) # 0x10 */
+ 0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
+ /* nopl (%rax) */
+ 0x0f, 0x1f, 0x00
+ };
+ void (*dest)(void);
+ char *tramp = closure->tramp;
- tramp[0] = 0xbb49; /* mov <code>, %r11 */
- *((unsigned long long * volatile) &tramp[1])
- = (unsigned long) ffi_closure_unix64;
- tramp[5] = 0xba49; /* mov <data>, %r10 */
- *((unsigned long long * volatile) &tramp[6])
- = (unsigned long) codeloc;
+#ifndef __ILP32__
+ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+ return ffi_prep_closure_loc_efi64(closure, cif, fun, user_data, codeloc);
+#endif
+ if (cif->abi != FFI_UNIX64)
+ return FFI_BAD_ABI;
- /* Set the carry bit iff the function uses any sse registers.
- This is clc or stc, together with the first byte of the jmp. */
- tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8;
+ if (cif->flags & UNIX64_FLAG_XMM_ARGS)
+ dest = ffi_closure_unix64_sse;
+ else
+ dest = ffi_closure_unix64;
- tramp[11] = 0xe3ff; /* jmp *%r11 */
+ memcpy (tramp, trampoline, sizeof(trampoline));
+ *(UINT64 *)(tramp + 16) = (uintptr_t)dest;
closure->cif = cif;
closure->fun = fun;
@@ -567,49 +761,36 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}
-int
-ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
- struct register_args *reg_args, char *argp)
+int FFI_HIDDEN
+ffi_closure_unix64_inner(ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ void *rvalue,
+ struct register_args *reg_args,
+ char *argp)
{
- ffi_cif *cif;
void **avalue;
ffi_type **arg_types;
long i, avn;
int gprcount, ssecount, ngpr, nsse;
- int ret;
+ int flags;
- cif = closure->cif;
- avalue = alloca(cif->nargs * sizeof(void *));
+ avn = cif->nargs;
+ flags = cif->flags;
+ avalue = alloca(avn * sizeof(void *));
gprcount = ssecount = 0;
- ret = cif->rtype->type;
- if (ret != FFI_TYPE_VOID)
+ if (flags & UNIX64_FLAG_RET_IN_MEM)
{
- enum x86_64_reg_class classes[MAX_CLASSES];
- size_t n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
- if (n == 0)
- {
- /* The return value goes in memory. Arrange for the closure
- return value to go directly back to the original caller. */
- rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++];
- /* We don't have to do anything in asm for the return. */
- ret = FFI_TYPE_VOID;
- }
- else if (ret == FFI_TYPE_STRUCT && n == 2)
- {
- /* Mark which register the second word of the structure goes in. */
- _Bool sse0 = SSE_CLASS_P (classes[0]);
- _Bool sse1 = SSE_CLASS_P (classes[1]);
- if (!sse0 && sse1)
- ret |= 1 << 8;
- else if (sse0 && !sse1)
- ret |= 1 << 9;
- }
+ /* On return, %rax will contain the address that was passed
+ by the caller in %rdi. */
+ void *r = (void *)(uintptr_t)reg_args->gpr[gprcount++];
+ *(void **)rvalue = r;
+ rvalue = r;
+ flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
}
- avn = cif->nargs;
arg_types = cif->arg_types;
-
for (i = 0; i < avn; ++i)
{
enum x86_64_reg_class classes[MAX_CLASSES];
@@ -627,7 +808,7 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
align = 8;
/* Pass this argument in memory. */
- argp = (void *) ALIGN (argp, align);
+ argp = (void *) FFI_ALIGN (argp, align);
avalue[i] = argp;
argp += arg_types[i]->size;
}
@@ -653,7 +834,7 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
else
{
char *a = alloca (16);
- int j;
+ unsigned int j;
avalue[i] = a;
for (j = 0; j < n; j++, a += 8)
@@ -667,10 +848,39 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
}
/* Invoke the closure. */
- closure->fun (cif, rvalue, avalue, closure->user_data);
+ fun (cif, rvalue, avalue, user_data);
/* Tell assembly how to perform return type promotions. */
- return ret;
+ return flags;
+}
+
+extern void ffi_go_closure_unix64(void) FFI_HIDDEN;
+extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN;
+
+#ifndef __ILP32__
+extern ffi_status
+ffi_prep_go_closure_efi64(ffi_go_closure* closure, ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*));
+#endif
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*))
+{
+#ifndef __ILP32__
+ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
+ return ffi_prep_go_closure_efi64(closure, cif, fun);
+#endif
+ if (cif->abi != FFI_UNIX64)
+ return FFI_BAD_ABI;
+
+ closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS
+ ? ffi_go_closure_unix64_sse
+ : ffi_go_closure_unix64);
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
}
#endif /* __x86_64__ */
diff --git a/src/x86/ffitarget.h b/src/x86/ffitarget.h
index a236677c..85ccedfe 100644
--- a/src/x86/ffitarget.h
+++ b/src/x86/ffitarget.h
@@ -1,5 +1,5 @@
/* -----------------------------------------------------------------*-C-*-
- ffitarget.h - Copyright (c) 2012, 2014 Anthony Green
+ ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green
Copyright (c) 1996-2003, 2010 Red Hat, Inc.
Copyright (C) 2008 Free Software Foundation, Inc.
@@ -50,7 +50,9 @@
#endif
#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
+#ifndef _MSC_VER
#define FFI_TARGET_HAS_COMPLEX_TYPE
+#endif
/* ---- Generic type definitions ----------------------------------------- */
@@ -76,44 +78,48 @@ typedef signed long ffi_sarg;
#endif
typedef enum ffi_abi {
+#if defined(X86_WIN64)
FFI_FIRST_ABI = 0,
-
- /* ---- Intel x86 Win32 ---------- */
-#ifdef X86_WIN32
- FFI_SYSV,
- FFI_STDCALL,
- FFI_THISCALL,
- FFI_FASTCALL,
- FFI_MS_CDECL,
- FFI_PASCAL,
- FFI_REGISTER,
+ FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */
+ FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */
FFI_LAST_ABI,
-#ifdef _MSC_VER
- FFI_DEFAULT_ABI = FFI_MS_CDECL
-#else
- FFI_DEFAULT_ABI = FFI_SYSV
-#endif
+#ifdef __GNUC__
+ FFI_DEFAULT_ABI = FFI_GNUW64
+#else
+ FFI_DEFAULT_ABI = FFI_WIN64
+#endif
-#elif defined(X86_WIN64)
+#elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
+ FFI_FIRST_ABI = 1,
+ FFI_UNIX64,
FFI_WIN64,
+ FFI_EFI64 = FFI_WIN64,
+ FFI_GNUW64,
FFI_LAST_ABI,
- FFI_DEFAULT_ABI = FFI_WIN64
+ FFI_DEFAULT_ABI = FFI_UNIX64
+#elif defined(X86_WIN32)
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV = 1,
+ FFI_STDCALL = 2,
+ FFI_THISCALL = 3,
+ FFI_FASTCALL = 4,
+ FFI_MS_CDECL = 5,
+ FFI_PASCAL = 6,
+ FFI_REGISTER = 7,
+ FFI_LAST_ABI,
+ FFI_DEFAULT_ABI = FFI_MS_CDECL
#else
- /* ---- Intel x86 and AMD x86-64 - */
- FFI_SYSV,
- FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */
- FFI_THISCALL,
- FFI_FASTCALL,
- FFI_STDCALL,
- FFI_PASCAL,
- FFI_REGISTER,
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV = 1,
+ FFI_THISCALL = 3,
+ FFI_FASTCALL = 4,
+ FFI_STDCALL = 5,
+ FFI_PASCAL = 6,
+ FFI_REGISTER = 7,
+ FFI_MS_CDECL = 8,
FFI_LAST_ABI,
-#if defined(__i386__) || defined(__i386)
FFI_DEFAULT_ABI = FFI_SYSV
-#else
- FFI_DEFAULT_ABI = FFI_UNIX64
-#endif
#endif
} ffi_abi;
#endif
@@ -121,29 +127,20 @@ typedef enum ffi_abi {
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
+#define FFI_GO_CLOSURES 1
+
#define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1)
#define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2)
#define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
#define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4)
-#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
-#define FFI_TRAMPOLINE_SIZE 24
-#define FFI_NATIVE_RAW_API 0
+#if defined (X86_64) || defined(X86_WIN64) \
+ || (defined (__x86_64__) && defined (X86_DARWIN))
+# define FFI_TRAMPOLINE_SIZE 24
+# define FFI_NATIVE_RAW_API 0
#else
-#ifdef X86_WIN32
-#define FFI_TRAMPOLINE_SIZE 52
-#else
-#ifdef X86_WIN64
-#define FFI_TRAMPOLINE_SIZE 29
-#define FFI_NATIVE_RAW_API 0
-#define FFI_NO_RAW_API 1
-#else
-#define FFI_TRAMPOLINE_SIZE 10
-#endif
-#endif
-#ifndef X86_WIN64
-#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
-#endif
+# define FFI_TRAMPOLINE_SIZE 12
+# define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
#endif
#endif
diff --git a/src/x86/ffiw64.c b/src/x86/ffiw64.c
new file mode 100644
index 00000000..b68f69cc
--- /dev/null
+++ b/src/x86/ffiw64.c
@@ -0,0 +1,311 @@
+/* -----------------------------------------------------------------------
+ ffiw64.c - Copyright (c) 2018 Anthony Green
+ Copyright (c) 2014 Red Hat, Inc.
+
+ x86 win64 Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS 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.
+ ----------------------------------------------------------------------- */
+
+#if defined(__x86_64__) || defined(_M_AMD64)
+#include <ffi.h>
+#include <ffi_common.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifdef X86_WIN64
+#define EFI64(name) name
+#else
+#define EFI64(name) FFI_HIDDEN name##_efi64
+#endif
+
+struct win64_call_frame
+{
+ UINT64 rbp; /* 0 */
+ UINT64 retaddr; /* 8 */
+ UINT64 fn; /* 16 */
+ UINT64 flags; /* 24 */
+ UINT64 rvalue; /* 32 */
+};
+
+extern void ffi_call_win64 (void *stack, struct win64_call_frame *,
+ void *closure) FFI_HIDDEN;
+
+ffi_status FFI_HIDDEN
+EFI64(ffi_prep_cif_machdep)(ffi_cif *cif)
+{
+ int flags, n;
+
+ switch (cif->abi)
+ {
+ case FFI_WIN64:
+ case FFI_GNUW64:
+ break;
+ default:
+ return FFI_BAD_ABI;
+ }
+
+ flags = cif->rtype->type;
+ switch (flags)
+ {
+ default:
+ break;
+ case FFI_TYPE_LONGDOUBLE:
+ /* GCC returns long double values by reference, like a struct */
+ if (cif->abi == FFI_GNUW64)
+ flags = FFI_TYPE_STRUCT;
+ break;
+ case FFI_TYPE_COMPLEX:
+ flags = FFI_TYPE_STRUCT;
+ /* FALLTHRU */
+ case FFI_TYPE_STRUCT:
+ switch (cif->rtype->size)
+ {
+ case 8:
+ flags = FFI_TYPE_UINT64;
+ break;
+ case 4:
+ flags = FFI_TYPE_SMALL_STRUCT_4B;
+ break;
+ case 2:
+ flags = FFI_TYPE_SMALL_STRUCT_2B;
+ break;
+ case 1:
+ flags = FFI_TYPE_SMALL_STRUCT_1B;
+ break;
+ }
+ break;
+ }
+ cif->flags = flags;
+
+ /* Each argument either fits in a register, an 8 byte slot, or is
+ passed by reference with the pointer in the 8 byte slot. */
+ n = cif->nargs;
+ n += (flags == FFI_TYPE_STRUCT);
+ if (n < 4)
+ n = 4;
+ cif->bytes = n * 8;
+
+ return FFI_OK;
+}
+
+static void
+ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ int i, j, n, flags;
+ UINT64 *stack;
+ size_t rsize;
+ struct win64_call_frame *frame;
+
+ FFI_ASSERT(cif->abi == FFI_GNUW64 || cif->abi == FFI_WIN64);
+
+ flags = cif->flags;
+ rsize = 0;
+
+ /* If we have no return value for a structure, we need to create one.
+ Otherwise we can ignore the return type entirely. */
+ if (rvalue == NULL)
+ {
+ if (flags == FFI_TYPE_STRUCT)
+ rsize = cif->rtype->size;
+ else
+ flags = FFI_TYPE_VOID;
+ }
+
+ stack = alloca(cif->bytes + sizeof(struct win64_call_frame) + rsize);
+ frame = (struct win64_call_frame *)((char *)stack + cif->bytes);
+ if (rsize)
+ rvalue = frame + 1;
+
+ frame->fn = (uintptr_t)fn;
+ frame->flags = flags;
+ frame->rvalue = (uintptr_t)rvalue;
+
+ j = 0;
+ if (flags == FFI_TYPE_STRUCT)
+ {
+ stack[0] = (uintptr_t)rvalue;
+ j = 1;
+ }
+
+ for (i = 0, n = cif->nargs; i < n; ++i, ++j)
+ {
+ switch (cif->arg_types[i]->size)
+ {
+ case 8:
+ stack[j] = *(UINT64 *)avalue[i];
+ break;
+ case 4:
+ stack[j] = *(UINT32 *)avalue[i];
+ break;
+ case 2:
+ stack[j] = *(UINT16 *)avalue[i];
+ break;
+ case 1:
+ stack[j] = *(UINT8 *)avalue[i];
+ break;
+ default:
+ stack[j] = (uintptr_t)avalue[i];
+ break;
+ }
+ }
+
+ ffi_call_win64 (stack, frame, closure);
+}
+
+void
+EFI64(ffi_call)(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ ffi_call_int (cif, fn, rvalue, avalue, NULL);
+}
+
+void
+EFI64(ffi_call_go)(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int (cif, fn, rvalue, avalue, closure);
+}
+
+
+extern void ffi_closure_win64(void) FFI_HIDDEN;
+extern void ffi_go_closure_win64(void) FFI_HIDDEN;
+
+ffi_status
+EFI64(ffi_prep_closure_loc)(ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ void *codeloc)
+{
+ static const unsigned char trampoline[16] = {
+ /* leaq -0x7(%rip),%r10 # 0x0 */
+ 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
+ /* jmpq *0x3(%rip) # 0x10 */
+ 0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
+ /* nopl (%rax) */
+ 0x0f, 0x1f, 0x00
+ };
+ char *tramp = closure->tramp;
+
+ switch (cif->abi)
+ {
+ case FFI_WIN64:
+ case FFI_GNUW64:
+ break;
+ default:
+ return FFI_BAD_ABI;
+ }
+
+ memcpy (tramp, trampoline, sizeof(trampoline));
+ *(UINT64 *)(tramp + 16) = (uintptr_t)ffi_closure_win64;
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ return FFI_OK;
+}
+
+ffi_status
+EFI64(ffi_prep_go_closure)(ffi_go_closure* closure, ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*))
+{
+ switch (cif->abi)
+ {
+ case FFI_WIN64:
+ case FFI_GNUW64:
+ break;
+ default:
+ return FFI_BAD_ABI;
+ }
+
+ closure->tramp = ffi_go_closure_win64;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+struct win64_closure_frame
+{
+ UINT64 rvalue[2];
+ UINT64 fargs[4];
+ UINT64 retaddr;
+ UINT64 args[];
+};
+
+/* Force the inner function to use the MS ABI. When compiling on win64
+ this is a nop. When compiling on unix, this simplifies the assembly,
+ and places the burden of saving the extra call-saved registers on
+ the compiler. */
+int FFI_HIDDEN __attribute__((ms_abi))
+ffi_closure_win64_inner(ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ struct win64_closure_frame *frame)
+{
+ void **avalue;
+ void *rvalue;
+ int i, n, nreg, flags;
+
+ avalue = alloca(cif->nargs * sizeof(void *));
+ rvalue = frame->rvalue;
+ nreg = 0;
+
+ /* When returning a structure, the address is in the first argument.
+ We must also be prepared to return the same address in eax, so
+ install that address in the frame and pretend we return a pointer. */
+ flags = cif->flags;
+ if (flags == FFI_TYPE_STRUCT)
+ {
+ rvalue = (void *)(uintptr_t)frame->args[0];
+ frame->rvalue[0] = frame->args[0];
+ nreg = 1;
+ }
+
+ for (i = 0, n = cif->nargs; i < n; ++i, ++nreg)
+ {
+ size_t size = cif->arg_types[i]->size;
+ size_t type = cif->arg_types[i]->type;
+ void *a;
+
+ if (type == FFI_TYPE_DOUBLE || type == FFI_TYPE_FLOAT)
+ {
+ if (nreg < 4)
+ a = &frame->fargs[nreg];
+ else
+ a = &frame->args[nreg];
+ }
+ else if (size == 1 || size == 2 || size == 4 || size == 8)
+ a = &frame->args[nreg];
+ else
+ a = (void *)(uintptr_t)frame->args[nreg];
+
+ avalue[i] = a;
+ }
+
+ /* Invoke the closure. */
+ fun (cif, rvalue, avalue, user_data);
+ return flags;
+}
+
+#endif /* __x86_64__ */
diff --git a/src/x86/internal.h b/src/x86/internal.h
new file mode 100644
index 00000000..09771ba8
--- /dev/null
+++ b/src/x86/internal.h
@@ -0,0 +1,29 @@
+#define X86_RET_FLOAT 0
+#define X86_RET_DOUBLE 1
+#define X86_RET_LDOUBLE 2
+#define X86_RET_SINT8 3
+#define X86_RET_SINT16 4
+#define X86_RET_UINT8 5
+#define X86_RET_UINT16 6
+#define X86_RET_INT64 7
+#define X86_RET_INT32 8
+#define X86_RET_VOID 9
+#define X86_RET_STRUCTPOP 10
+#define X86_RET_STRUCTARG 11
+#define X86_RET_STRUCT_1B 12
+#define X86_RET_STRUCT_2B 13
+#define X86_RET_UNUSED14 14
+#define X86_RET_UNUSED15 15
+
+#define X86_RET_TYPE_MASK 15
+#define X86_RET_POP_SHIFT 4
+
+#define R_EAX 0
+#define R_EDX 1
+#define R_ECX 2
+
+#ifdef __PCC__
+# define HAVE_FASTCALL 0
+#else
+# define HAVE_FASTCALL 1
+#endif
diff --git a/src/x86/internal64.h b/src/x86/internal64.h
new file mode 100644
index 00000000..512e9552
--- /dev/null
+++ b/src/x86/internal64.h
@@ -0,0 +1,22 @@
+#define UNIX64_RET_VOID 0
+#define UNIX64_RET_UINT8 1
+#define UNIX64_RET_UINT16 2
+#define UNIX64_RET_UINT32 3
+#define UNIX64_RET_SINT8 4
+#define UNIX64_RET_SINT16 5
+#define UNIX64_RET_SINT32 6
+#define UNIX64_RET_INT64 7
+#define UNIX64_RET_XMM32 8
+#define UNIX64_RET_XMM64 9
+#define UNIX64_RET_X87 10
+#define UNIX64_RET_X87_2 11
+#define UNIX64_RET_ST_XMM0_RAX 12
+#define UNIX64_RET_ST_RAX_XMM0 13
+#define UNIX64_RET_ST_XMM0_XMM1 14
+#define UNIX64_RET_ST_RAX_RDX 15
+
+#define UNIX64_RET_LAST 15
+
+#define UNIX64_FLAG_RET_IN_MEM (1 << 10)
+#define UNIX64_FLAG_XMM_ARGS (1 << 11)
+#define UNIX64_SIZE_SHIFT 12
diff --git a/src/x86/sysv.S b/src/x86/sysv.S
index 3bd5477e..7c9598c9 100644
--- a/src/x86/sysv.S
+++ b/src/x86/sysv.S
@@ -1,6 +1,7 @@
/* -----------------------------------------------------------------------
- sysv.S - Copyright (c) 2013 The Written Word, Inc.
- - Copyright (c) 1996,1998,2001-2003,2005,2008,2010 Red Hat, Inc.
+ sysv.S - Copyright (c) 2017 Anthony Green
+ - Copyright (c) 2013 The Written Word, Inc.
+ - Copyright (c) 1996,1998,2001-2003,2005,2008,2010 Red Hat, Inc.
X86 Foreign Function Interface
@@ -25,458 +26,1103 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
-#ifndef __x86_64__
+#ifdef __i386__
+#ifndef _MSC_VER
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
+#include "internal.h"
-.text
-
-.globl ffi_prep_args
-
- .align 4
-.globl ffi_call_SYSV
- .type ffi_call_SYSV,@function
-
-ffi_call_SYSV:
-.LFB1:
- pushl %ebp
-.LCFI0:
- movl %esp,%ebp
-.LCFI1:
- /* Make room for all of the new args. */
- movl 16(%ebp),%ecx
- subl %ecx,%esp
-
- /* Align the stack pointer to 16-bytes */
- andl $0xfffffff0, %esp
-
- movl %esp,%eax
-
- /* Place all of the ffi_prep_args in position */
- pushl 12(%ebp)
- pushl %eax
- call *8(%ebp)
-
- /* Return stack to previous state and call the function */
- addl $8,%esp
-
- call *28(%ebp)
-
- /* Load %ecx with the return type code */
- movl 20(%ebp),%ecx
-
- /* Protect %esi. We're going to pop it in the epilogue. */
- pushl %esi
-
- /* If the return value pointer is NULL, assume no return value. */
- cmpl $0,24(%ebp)
- jne 0f
-
- /* Even if there is no space for the return value, we are
- obliged to handle floating-point values. */
- cmpl $FFI_TYPE_FLOAT,%ecx
- jne noretval
- fstp %st(0)
-
- jmp epilogue
-
-0:
- call 1f
-
-.Lstore_table:
- .long noretval-.Lstore_table /* FFI_TYPE_VOID */
- .long retint-.Lstore_table /* FFI_TYPE_INT */
- .long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */
- .long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */
- .long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */
- .long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */
- .long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */
- .long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */
- .long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */
- .long retint-.Lstore_table /* FFI_TYPE_UINT32 */
- .long retint-.Lstore_table /* FFI_TYPE_SINT32 */
- .long retint64-.Lstore_table /* FFI_TYPE_UINT64 */
- .long retint64-.Lstore_table /* FFI_TYPE_SINT64 */
- .long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */
- .long retint-.Lstore_table /* FFI_TYPE_POINTER */
-
-1:
- pop %esi
- add (%esi, %ecx, 4), %esi
- jmp *%esi
-
- /* Sign/zero extend as appropriate. */
-retsint8:
- movsbl %al, %eax
- jmp retint
+#define C2(X, Y) X ## Y
+#define C1(X, Y) C2(X, Y)
+#ifdef __USER_LABEL_PREFIX__
+# define C(X) C1(__USER_LABEL_PREFIX__, X)
+#else
+# define C(X) X
+#endif
-retsint16:
- movswl %ax, %eax
- jmp retint
+#ifdef X86_DARWIN
+# define L(X) C1(L, X)
+#else
+# define L(X) C1(.L, X)
+#endif
-retuint8:
- movzbl %al, %eax
- jmp retint
+#ifdef __ELF__
+# define ENDF(X) .type X,@function; .size X, . - X
+#else
+# define ENDF(X)
+#endif
-retuint16:
- movzwl %ax, %eax
- jmp retint
-
-retfloat:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- fstps (%ecx)
- jmp epilogue
-
-retdouble:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- fstpl (%ecx)
- jmp epilogue
-
-retlongdouble:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- fstpt (%ecx)
- jmp epilogue
-
-retint64:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- movl %eax,0(%ecx)
- movl %edx,4(%ecx)
- jmp epilogue
-
-retint:
- /* Load %ecx with the pointer to storage for the return value */
- movl 24(%ebp),%ecx
- movl %eax,0(%ecx)
-
-retstruct:
- /* Nothing to do! */
-
-noretval:
-epilogue:
- popl %esi
- movl %ebp,%esp
- popl %ebp
- ret
-.LFE1:
-.ffi_call_SYSV_end:
- .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
-
- .align 4
-FFI_HIDDEN (ffi_closure_SYSV)
-.globl ffi_closure_SYSV
- .type ffi_closure_SYSV, @function
-
-ffi_closure_SYSV:
-.LFB2:
- pushl %ebp
-.LCFI2:
- movl %esp, %ebp
-.LCFI3:
- subl $40, %esp
- leal -24(%ebp), %edx
- movl %edx, -12(%ebp) /* resp */
- leal 8(%ebp), %edx
-#ifdef __SUNPRO_C
- /* The SUNPRO compiler doesn't support GCC's regparm function
- attribute, so we have to pass all three arguments to
- ffi_closure_SYSV_inner on the stack. */
- movl %edx, 8(%esp) /* args = __builtin_dwarf_cfa () */
- leal -12(%ebp), %edx
- movl %edx, 4(%esp) /* &resp */
- movl %eax, (%esp) /* closure */
+/* Handle win32 fastcall name mangling. */
+#ifdef X86_WIN32
+# define ffi_call_i386 @ffi_call_i386@8
+# define ffi_closure_inner @ffi_closure_inner@8
#else
- movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */
- leal -12(%ebp), %edx
- movl %edx, (%esp) /* &resp */
+# define ffi_call_i386 C(ffi_call_i386)
+# define ffi_closure_inner C(ffi_closure_inner)
#endif
-#if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__
- call ffi_closure_SYSV_inner
+
+/* This macro allows the safe creation of jump tables without an
+ actual table. The entry points into the table are all 8 bytes.
+ The use of ORG asserts that we're at the correct location. */
+/* ??? The clang assembler doesn't handle .org with symbolic expressions. */
+#if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
+# define E(BASE, X) .balign 8
#else
- movl %ebx, 8(%esp)
-.LCFI7:
- call 1f
-1: popl %ebx
- addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
- call ffi_closure_SYSV_inner@PLT
- movl 8(%esp), %ebx
+# define E(BASE, X) .balign 8; .org BASE + X * 8
#endif
- movl -12(%ebp), %ecx
- cmpl $FFI_TYPE_INT, %eax
- je .Lcls_retint
-
- /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
- FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */
- cmpl $FFI_TYPE_UINT64, %eax
- jge 0f
- cmpl $FFI_TYPE_UINT8, %eax
- jge .Lcls_retint
-
-0: cmpl $FFI_TYPE_FLOAT, %eax
- je .Lcls_retfloat
- cmpl $FFI_TYPE_DOUBLE, %eax
- je .Lcls_retdouble
- cmpl $FFI_TYPE_LONGDOUBLE, %eax
- je .Lcls_retldouble
- cmpl $FFI_TYPE_SINT64, %eax
- je .Lcls_retllong
- cmpl $FFI_TYPE_STRUCT, %eax
- je .Lcls_retstruct
-.Lcls_epilogue:
- movl %ebp, %esp
- popl %ebp
- ret
-.Lcls_retint:
- movl (%ecx), %eax
- jmp .Lcls_epilogue
-.Lcls_retfloat:
- flds (%ecx)
- jmp .Lcls_epilogue
-.Lcls_retdouble:
- fldl (%ecx)
- jmp .Lcls_epilogue
-.Lcls_retldouble:
- fldt (%ecx)
- jmp .Lcls_epilogue
-.Lcls_retllong:
- movl (%ecx), %eax
- movl 4(%ecx), %edx
- jmp .Lcls_epilogue
-.Lcls_retstruct:
- movl %ebp, %esp
- popl %ebp
- ret $4
-.LFE2:
- .size ffi_closure_SYSV, .-ffi_closure_SYSV
-#if !FFI_NO_RAW_API
+ .text
+ .balign 16
+ .globl ffi_call_i386
+ FFI_HIDDEN(ffi_call_i386)
+
+/* This is declared as
-/* Precalculate for e.g. the Solaris 10/x86 assembler. */
-#if FFI_TRAMPOLINE_SIZE == 10
-#define RAW_CLOSURE_CIF_OFFSET 12
-#define RAW_CLOSURE_FUN_OFFSET 16
-#define RAW_CLOSURE_USER_DATA_OFFSET 20
-#elif FFI_TRAMPOLINE_SIZE == 24
-#define RAW_CLOSURE_CIF_OFFSET 24
-#define RAW_CLOSURE_FUN_OFFSET 28
-#define RAW_CLOSURE_USER_DATA_OFFSET 32
+ void ffi_call_i386(struct call_frame *frame, char *argp)
+ __attribute__((fastcall));
+
+ Thus the arguments are present in
+
+ ecx: frame
+ edx: argp
+*/
+
+ffi_call_i386:
+L(UW0):
+ # cfi_startproc
+#if !HAVE_FASTCALL
+ movl 4(%esp), %ecx
+ movl 8(%esp), %edx
+#endif
+ movl (%esp), %eax /* move the return address */
+ movl %ebp, (%ecx) /* store %ebp into local frame */
+ movl %eax, 4(%ecx) /* store retaddr into local frame */
+
+ /* New stack frame based off ebp. This is a itty bit of unwind
+ trickery in that the CFA *has* changed. There is no easy way
+ to describe it correctly on entry to the function. Fortunately,
+ it doesn't matter too much since at all points we can correctly
+ unwind back to ffi_call. Note that the location to which we
+ moved the return address is (the new) CFA-4, so from the
+ perspective of the unwind info, it hasn't moved. */
+ movl %ecx, %ebp
+L(UW1):
+ # cfi_def_cfa(%ebp, 8)
+ # cfi_rel_offset(%ebp, 0)
+
+ movl %edx, %esp /* set outgoing argument stack */
+ movl 20+R_EAX*4(%ebp), %eax /* set register arguments */
+ movl 20+R_EDX*4(%ebp), %edx
+ movl 20+R_ECX*4(%ebp), %ecx
+
+ call *8(%ebp)
+
+ movl 12(%ebp), %ecx /* load return type code */
+ movl %ebx, 8(%ebp) /* preserve %ebx */
+L(UW2):
+ # cfi_rel_offset(%ebx, 8)
+
+ andl $X86_RET_TYPE_MASK, %ecx
+#ifdef __PIC__
+ call C(__x86.get_pc_thunk.bx)
+L(pc1):
+ leal L(store_table)-L(pc1)(%ebx, %ecx, 8), %ebx
#else
-#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
-#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
-#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
+ leal L(store_table)(,%ecx, 8), %ebx
#endif
-#define CIF_FLAGS_OFFSET 20
-
- .align 4
-FFI_HIDDEN (ffi_closure_raw_SYSV)
-.globl ffi_closure_raw_SYSV
- .type ffi_closure_raw_SYSV, @function
-
-ffi_closure_raw_SYSV:
-.LFB3:
- pushl %ebp
-.LCFI4:
- movl %esp, %ebp
-.LCFI5:
- pushl %esi
-.LCFI6:
- subl $36, %esp
- movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
- movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
- movl %edx, 12(%esp) /* user_data */
- leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */
- movl %edx, 8(%esp) /* raw_args */
- leal -24(%ebp), %edx
- movl %edx, 4(%esp) /* &res */
- movl %esi, (%esp) /* cif */
- call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */
- movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */
- cmpl $FFI_TYPE_INT, %eax
- je .Lrcls_retint
-
- /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16,
- FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */
- cmpl $FFI_TYPE_UINT64, %eax
- jge 0f
- cmpl $FFI_TYPE_UINT8, %eax
- jge .Lrcls_retint
-0:
- cmpl $FFI_TYPE_FLOAT, %eax
- je .Lrcls_retfloat
- cmpl $FFI_TYPE_DOUBLE, %eax
- je .Lrcls_retdouble
- cmpl $FFI_TYPE_LONGDOUBLE, %eax
- je .Lrcls_retldouble
- cmpl $FFI_TYPE_SINT64, %eax
- je .Lrcls_retllong
-.Lrcls_epilogue:
- addl $36, %esp
- popl %esi
+ movl 16(%ebp), %ecx /* load result address */
+ jmp *%ebx
+
+ .balign 8
+L(store_table):
+E(L(store_table), X86_RET_FLOAT)
+ fstps (%ecx)
+ jmp L(e1)
+E(L(store_table), X86_RET_DOUBLE)
+ fstpl (%ecx)
+ jmp L(e1)
+E(L(store_table), X86_RET_LDOUBLE)
+ fstpt (%ecx)
+ jmp L(e1)
+E(L(store_table), X86_RET_SINT8)
+ movsbl %al, %eax
+ mov %eax, (%ecx)
+ jmp L(e1)
+E(L(store_table), X86_RET_SINT16)
+ movswl %ax, %eax
+ mov %eax, (%ecx)
+ jmp L(e1)
+E(L(store_table), X86_RET_UINT8)
+ movzbl %al, %eax
+ mov %eax, (%ecx)
+ jmp L(e1)
+E(L(store_table), X86_RET_UINT16)
+ movzwl %ax, %eax
+ mov %eax, (%ecx)
+ jmp L(e1)
+E(L(store_table), X86_RET_INT64)
+ movl %edx, 4(%ecx)
+ /* fallthru */
+E(L(store_table), X86_RET_INT32)
+ movl %eax, (%ecx)
+ /* fallthru */
+E(L(store_table), X86_RET_VOID)
+L(e1):
+ movl 8(%ebp), %ebx
+ movl %ebp, %esp
popl %ebp
+L(UW3):
+ # cfi_remember_state
+ # cfi_def_cfa(%esp, 4)
+ # cfi_restore(%ebx)
+ # cfi_restore(%ebp)
ret
-.Lrcls_retint:
- movl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-.Lrcls_retfloat:
- flds -24(%ebp)
- jmp .Lrcls_epilogue
-.Lrcls_retdouble:
- fldl -24(%ebp)
- jmp .Lrcls_epilogue
-.Lrcls_retldouble:
- fldt -24(%ebp)
- jmp .Lrcls_epilogue
-.Lrcls_retllong:
- movl -24(%ebp), %eax
- movl -20(%ebp), %edx
- jmp .Lrcls_epilogue
-.LFE3:
- .size ffi_closure_raw_SYSV, .-ffi_closure_raw_SYSV
+L(UW4):
+ # cfi_restore_state
+
+E(L(store_table), X86_RET_STRUCTPOP)
+ jmp L(e1)
+E(L(store_table), X86_RET_STRUCTARG)
+ jmp L(e1)
+E(L(store_table), X86_RET_STRUCT_1B)
+ movb %al, (%ecx)
+ jmp L(e1)
+E(L(store_table), X86_RET_STRUCT_2B)
+ movw %ax, (%ecx)
+ jmp L(e1)
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(store_table), X86_RET_UNUSED14)
+ ud2
+E(L(store_table), X86_RET_UNUSED15)
+ ud2
+
+L(UW5):
+ # cfi_endproc
+ENDF(ffi_call_i386)
+
+/* The inner helper is declared as
+
+ void ffi_closure_inner(struct closure_frame *frame, char *argp)
+ __attribute_((fastcall))
+
+ Thus the arguments are placed in
+
+ ecx: frame
+ edx: argp
+*/
+
+/* Macros to help setting up the closure_data structure. */
+
+#if HAVE_FASTCALL
+# define closure_FS (40 + 4)
+# define closure_CF 0
+#else
+# define closure_FS (8 + 40 + 12)
+# define closure_CF 8
#endif
-#if defined __GNUC__
-/* Only emit dwarf unwind info when building with GNU toolchain. */
+#define FFI_CLOSURE_SAVE_REGS \
+ movl %eax, closure_CF+16+R_EAX*4(%esp); \
+ movl %edx, closure_CF+16+R_EDX*4(%esp); \
+ movl %ecx, closure_CF+16+R_ECX*4(%esp)
-#if defined __PIC__
-# if defined __sun__ && defined __svr4__
-/* 32-bit Solaris 2/x86 uses datarel encoding for PIC. GNU ld before 2.22
- doesn't correctly sort .eh_frame_hdr with mixed encodings, so match this. */
-# define FDE_ENCODING 0x30 /* datarel */
-# define FDE_ENCODE(X) X@GOTOFF
-# else
-# define FDE_ENCODING 0x1b /* pcrel sdata4 */
-# if defined HAVE_AS_X86_PCREL
-# define FDE_ENCODE(X) X-.
-# else
-# define FDE_ENCODE(X) X@rel
-# endif
-# endif
+#define FFI_CLOSURE_COPY_TRAMP_DATA \
+ movl FFI_TRAMPOLINE_SIZE(%eax), %edx; /* copy cif */ \
+ movl FFI_TRAMPOLINE_SIZE+4(%eax), %ecx; /* copy fun */ \
+ movl FFI_TRAMPOLINE_SIZE+8(%eax), %eax; /* copy user_data */ \
+ movl %edx, closure_CF+28(%esp); \
+ movl %ecx, closure_CF+32(%esp); \
+ movl %eax, closure_CF+36(%esp)
+
+#if HAVE_FASTCALL
+# define FFI_CLOSURE_PREP_CALL \
+ movl %esp, %ecx; /* load closure_data */ \
+ leal closure_FS+4(%esp), %edx; /* load incoming stack */
#else
-# define FDE_ENCODING 0 /* absolute */
-# define FDE_ENCODE(X) X
+# define FFI_CLOSURE_PREP_CALL \
+ leal closure_CF(%esp), %ecx; /* load closure_data */ \
+ leal closure_FS+4(%esp), %edx; /* load incoming stack */ \
+ movl %ecx, (%esp); \
+ movl %edx, 4(%esp)
#endif
- .section .eh_frame,EH_FRAME_FLAGS,@progbits
-.Lframe1:
- .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */
-.LSCIE1:
- .long 0x0 /* CIE Identifier Tag */
- .byte 0x1 /* CIE Version */
-#ifdef HAVE_AS_ASCII_PSEUDO_OP
+#define FFI_CLOSURE_CALL_INNER(UWN) \
+ call ffi_closure_inner
+
+#define FFI_CLOSURE_MASK_AND_JUMP(N, UW) \
+ andl $X86_RET_TYPE_MASK, %eax; \
+ leal L(C1(load_table,N))(, %eax, 8), %edx; \
+ movl closure_CF(%esp), %eax; /* optimiztic load */ \
+ jmp *%edx
+
#ifdef __PIC__
- .ascii "zR\0" /* CIE Augmentation */
+# if defined X86_DARWIN || defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+# undef FFI_CLOSURE_MASK_AND_JUMP
+# define FFI_CLOSURE_MASK_AND_JUMP(N, UW) \
+ andl $X86_RET_TYPE_MASK, %eax; \
+ call C(__x86.get_pc_thunk.dx); \
+L(C1(pc,N)): \
+ leal L(C1(load_table,N))-L(C1(pc,N))(%edx, %eax, 8), %edx; \
+ movl closure_CF(%esp), %eax; /* optimiztic load */ \
+ jmp *%edx
+# else
+# define FFI_CLOSURE_CALL_INNER_SAVE_EBX
+# undef FFI_CLOSURE_CALL_INNER
+# define FFI_CLOSURE_CALL_INNER(UWN) \
+ movl %ebx, 40(%esp); /* save ebx */ \
+L(C1(UW,UWN)): \
+ /* cfi_rel_offset(%ebx, 40); */ \
+ call C(__x86.get_pc_thunk.bx); /* load got register */ \
+ addl $C(_GLOBAL_OFFSET_TABLE_), %ebx; \
+ call ffi_closure_inner@PLT
+# undef FFI_CLOSURE_MASK_AND_JUMP
+# define FFI_CLOSURE_MASK_AND_JUMP(N, UWN) \
+ andl $X86_RET_TYPE_MASK, %eax; \
+ leal L(C1(load_table,N))@GOTOFF(%ebx, %eax, 8), %edx; \
+ movl 40(%esp), %ebx; /* restore ebx */ \
+L(C1(UW,UWN)): \
+ /* cfi_restore(%ebx); */ \
+ movl closure_CF(%esp), %eax; /* optimiztic load */ \
+ jmp *%edx
+# endif /* DARWIN || HIDDEN */
+#endif /* __PIC__ */
+
+ .balign 16
+ .globl C(ffi_go_closure_EAX)
+ FFI_HIDDEN(C(ffi_go_closure_EAX))
+C(ffi_go_closure_EAX):
+L(UW6):
+ # cfi_startproc
+ subl $closure_FS, %esp
+L(UW7):
+ # cfi_def_cfa_offset(closure_FS + 4)
+ FFI_CLOSURE_SAVE_REGS
+ movl 4(%eax), %edx /* copy cif */
+ movl 8(%eax), %ecx /* copy fun */
+ movl %edx, closure_CF+28(%esp)
+ movl %ecx, closure_CF+32(%esp)
+ movl %eax, closure_CF+36(%esp) /* closure is user_data */
+ jmp L(do_closure_i386)
+L(UW8):
+ # cfi_endproc
+ENDF(C(ffi_go_closure_EAX))
+
+ .balign 16
+ .globl C(ffi_go_closure_ECX)
+ FFI_HIDDEN(C(ffi_go_closure_ECX))
+C(ffi_go_closure_ECX):
+L(UW9):
+ # cfi_startproc
+ subl $closure_FS, %esp
+L(UW10):
+ # cfi_def_cfa_offset(closure_FS + 4)
+ FFI_CLOSURE_SAVE_REGS
+ movl 4(%ecx), %edx /* copy cif */
+ movl 8(%ecx), %eax /* copy fun */
+ movl %edx, closure_CF+28(%esp)
+ movl %eax, closure_CF+32(%esp)
+ movl %ecx, closure_CF+36(%esp) /* closure is user_data */
+ jmp L(do_closure_i386)
+L(UW11):
+ # cfi_endproc
+ENDF(C(ffi_go_closure_ECX))
+
+/* The closure entry points are reached from the ffi_closure trampoline.
+ On entry, %eax contains the address of the ffi_closure. */
+
+ .balign 16
+ .globl C(ffi_closure_i386)
+ FFI_HIDDEN(C(ffi_closure_i386))
+
+C(ffi_closure_i386):
+L(UW12):
+ # cfi_startproc
+ subl $closure_FS, %esp
+L(UW13):
+ # cfi_def_cfa_offset(closure_FS + 4)
+
+ FFI_CLOSURE_SAVE_REGS
+ FFI_CLOSURE_COPY_TRAMP_DATA
+
+ /* Entry point from preceeding Go closures. */
+L(do_closure_i386):
+
+ FFI_CLOSURE_PREP_CALL
+ FFI_CLOSURE_CALL_INNER(14)
+ FFI_CLOSURE_MASK_AND_JUMP(2, 15)
+
+ .balign 8
+L(load_table2):
+E(L(load_table2), X86_RET_FLOAT)
+ flds closure_CF(%esp)
+ jmp L(e2)
+E(L(load_table2), X86_RET_DOUBLE)
+ fldl closure_CF(%esp)
+ jmp L(e2)
+E(L(load_table2), X86_RET_LDOUBLE)
+ fldt closure_CF(%esp)
+ jmp L(e2)
+E(L(load_table2), X86_RET_SINT8)
+ movsbl %al, %eax
+ jmp L(e2)
+E(L(load_table2), X86_RET_SINT16)
+ movswl %ax, %eax
+ jmp L(e2)
+E(L(load_table2), X86_RET_UINT8)
+ movzbl %al, %eax
+ jmp L(e2)
+E(L(load_table2), X86_RET_UINT16)
+ movzwl %ax, %eax
+ jmp L(e2)
+E(L(load_table2), X86_RET_INT64)
+ movl closure_CF+4(%esp), %edx
+ jmp L(e2)
+E(L(load_table2), X86_RET_INT32)
+ nop
+ /* fallthru */
+E(L(load_table2), X86_RET_VOID)
+L(e2):
+ addl $closure_FS, %esp
+L(UW16):
+ # cfi_adjust_cfa_offset(-closure_FS)
+ ret
+L(UW17):
+ # cfi_adjust_cfa_offset(closure_FS)
+E(L(load_table2), X86_RET_STRUCTPOP)
+ addl $closure_FS, %esp
+L(UW18):
+ # cfi_adjust_cfa_offset(-closure_FS)
+ ret $4
+L(UW19):
+ # cfi_adjust_cfa_offset(closure_FS)
+E(L(load_table2), X86_RET_STRUCTARG)
+ jmp L(e2)
+E(L(load_table2), X86_RET_STRUCT_1B)
+ movzbl %al, %eax
+ jmp L(e2)
+E(L(load_table2), X86_RET_STRUCT_2B)
+ movzwl %ax, %eax
+ jmp L(e2)
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(load_table2), X86_RET_UNUSED14)
+ ud2
+E(L(load_table2), X86_RET_UNUSED15)
+ ud2
+
+L(UW20):
+ # cfi_endproc
+ENDF(C(ffi_closure_i386))
+
+ .balign 16
+ .globl C(ffi_go_closure_STDCALL)
+ FFI_HIDDEN(C(ffi_go_closure_STDCALL))
+C(ffi_go_closure_STDCALL):
+L(UW21):
+ # cfi_startproc
+ subl $closure_FS, %esp
+L(UW22):
+ # cfi_def_cfa_offset(closure_FS + 4)
+ FFI_CLOSURE_SAVE_REGS
+ movl 4(%ecx), %edx /* copy cif */
+ movl 8(%ecx), %eax /* copy fun */
+ movl %edx, closure_CF+28(%esp)
+ movl %eax, closure_CF+32(%esp)
+ movl %ecx, closure_CF+36(%esp) /* closure is user_data */
+ jmp L(do_closure_STDCALL)
+L(UW23):
+ # cfi_endproc
+ENDF(C(ffi_go_closure_STDCALL))
+
+/* For REGISTER, we have no available parameter registers, and so we
+ enter here having pushed the closure onto the stack. */
+
+ .balign 16
+ .globl C(ffi_closure_REGISTER)
+ FFI_HIDDEN(C(ffi_closure_REGISTER))
+C(ffi_closure_REGISTER):
+L(UW24):
+ # cfi_startproc
+ # cfi_def_cfa(%esp, 8)
+ # cfi_offset(%eip, -8)
+ subl $closure_FS-4, %esp
+L(UW25):
+ # cfi_def_cfa_offset(closure_FS + 4)
+ FFI_CLOSURE_SAVE_REGS
+ movl closure_FS-4(%esp), %ecx /* load retaddr */
+ movl closure_FS(%esp), %eax /* load closure */
+ movl %ecx, closure_FS(%esp) /* move retaddr */
+ jmp L(do_closure_REGISTER)
+L(UW26):
+ # cfi_endproc
+ENDF(C(ffi_closure_REGISTER))
+
+/* For STDCALL (and others), we need to pop N bytes of arguments off
+ the stack following the closure. The amount needing to be popped
+ is returned to us from ffi_closure_inner. */
+
+ .balign 16
+ .globl C(ffi_closure_STDCALL)
+ FFI_HIDDEN(C(ffi_closure_STDCALL))
+C(ffi_closure_STDCALL):
+L(UW27):
+ # cfi_startproc
+ subl $closure_FS, %esp
+L(UW28):
+ # cfi_def_cfa_offset(closure_FS + 4)
+
+ FFI_CLOSURE_SAVE_REGS
+
+ /* Entry point from ffi_closure_REGISTER. */
+L(do_closure_REGISTER):
+
+ FFI_CLOSURE_COPY_TRAMP_DATA
+
+ /* Entry point from preceeding Go closure. */
+L(do_closure_STDCALL):
+
+ FFI_CLOSURE_PREP_CALL
+ FFI_CLOSURE_CALL_INNER(29)
+
+ movl %eax, %ecx
+ shrl $X86_RET_POP_SHIFT, %ecx /* isolate pop count */
+ leal closure_FS(%esp, %ecx), %ecx /* compute popped esp */
+ movl closure_FS(%esp), %edx /* move return address */
+ movl %edx, (%ecx)
+
+ /* From this point on, the value of %esp upon return is %ecx+4,
+ and we've copied the return address to %ecx to make return easy.
+ There's no point in representing this in the unwind info, as
+ there is always a window between the mov and the ret which
+ will be wrong from one point of view or another. */
+
+ FFI_CLOSURE_MASK_AND_JUMP(3, 30)
+
+ .balign 8
+L(load_table3):
+E(L(load_table3), X86_RET_FLOAT)
+ flds closure_CF(%esp)
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_DOUBLE)
+ fldl closure_CF(%esp)
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_LDOUBLE)
+ fldt closure_CF(%esp)
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_SINT8)
+ movsbl %al, %eax
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_SINT16)
+ movswl %ax, %eax
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_UINT8)
+ movzbl %al, %eax
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_UINT16)
+ movzwl %ax, %eax
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_INT64)
+ movl closure_CF+4(%esp), %edx
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_INT32)
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_VOID)
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_STRUCTPOP)
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_STRUCTARG)
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_STRUCT_1B)
+ movzbl %al, %eax
+ movl %ecx, %esp
+ ret
+E(L(load_table3), X86_RET_STRUCT_2B)
+ movzwl %ax, %eax
+ movl %ecx, %esp
+ ret
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(load_table3), X86_RET_UNUSED14)
+ ud2
+E(L(load_table3), X86_RET_UNUSED15)
+ ud2
+
+L(UW31):
+ # cfi_endproc
+ENDF(C(ffi_closure_STDCALL))
+
+#if !FFI_NO_RAW_API
+
+#define raw_closure_S_FS (16+16+12)
+
+ .balign 16
+ .globl C(ffi_closure_raw_SYSV)
+ FFI_HIDDEN(C(ffi_closure_raw_SYSV))
+C(ffi_closure_raw_SYSV):
+L(UW32):
+ # cfi_startproc
+ subl $raw_closure_S_FS, %esp
+L(UW33):
+ # cfi_def_cfa_offset(raw_closure_S_FS + 4)
+ movl %ebx, raw_closure_S_FS-4(%esp)
+L(UW34):
+ # cfi_rel_offset(%ebx, raw_closure_S_FS-4)
+
+ movl FFI_TRAMPOLINE_SIZE+8(%eax), %edx /* load cl->user_data */
+ movl %edx, 12(%esp)
+ leal raw_closure_S_FS+4(%esp), %edx /* load raw_args */
+ movl %edx, 8(%esp)
+ leal 16(%esp), %edx /* load &res */
+ movl %edx, 4(%esp)
+ movl FFI_TRAMPOLINE_SIZE(%eax), %ebx /* load cl->cif */
+ movl %ebx, (%esp)
+ call *FFI_TRAMPOLINE_SIZE+4(%eax) /* call cl->fun */
+
+ movl 20(%ebx), %eax /* load cif->flags */
+ andl $X86_RET_TYPE_MASK, %eax
+#ifdef __PIC__
+ call C(__x86.get_pc_thunk.bx)
+L(pc4):
+ leal L(load_table4)-L(pc4)(%ebx, %eax, 8), %ecx
#else
- .ascii "\0" /* CIE Augmentation */
+ leal L(load_table4)(,%eax, 8), %ecx
#endif
-#elif defined HAVE_AS_STRING_PSEUDO_OP
+ movl raw_closure_S_FS-4(%esp), %ebx
+L(UW35):
+ # cfi_restore(%ebx)
+ movl 16(%esp), %eax /* Optimistic load */
+ jmp *%ecx
+
+ .balign 8
+L(load_table4):
+E(L(load_table4), X86_RET_FLOAT)
+ flds 16(%esp)
+ jmp L(e4)
+E(L(load_table4), X86_RET_DOUBLE)
+ fldl 16(%esp)
+ jmp L(e4)
+E(L(load_table4), X86_RET_LDOUBLE)
+ fldt 16(%esp)
+ jmp L(e4)
+E(L(load_table4), X86_RET_SINT8)
+ movsbl %al, %eax
+ jmp L(e4)
+E(L(load_table4), X86_RET_SINT16)
+ movswl %ax, %eax
+ jmp L(e4)
+E(L(load_table4), X86_RET_UINT8)
+ movzbl %al, %eax
+ jmp L(e4)
+E(L(load_table4), X86_RET_UINT16)
+ movzwl %ax, %eax
+ jmp L(e4)
+E(L(load_table4), X86_RET_INT64)
+ movl 16+4(%esp), %edx
+ jmp L(e4)
+E(L(load_table4), X86_RET_INT32)
+ nop
+ /* fallthru */
+E(L(load_table4), X86_RET_VOID)
+L(e4):
+ addl $raw_closure_S_FS, %esp
+L(UW36):
+ # cfi_adjust_cfa_offset(-raw_closure_S_FS)
+ ret
+L(UW37):
+ # cfi_adjust_cfa_offset(raw_closure_S_FS)
+E(L(load_table4), X86_RET_STRUCTPOP)
+ addl $raw_closure_S_FS, %esp
+L(UW38):
+ # cfi_adjust_cfa_offset(-raw_closure_S_FS)
+ ret $4
+L(UW39):
+ # cfi_adjust_cfa_offset(raw_closure_S_FS)
+E(L(load_table4), X86_RET_STRUCTARG)
+ jmp L(e4)
+E(L(load_table4), X86_RET_STRUCT_1B)
+ movzbl %al, %eax
+ jmp L(e4)
+E(L(load_table4), X86_RET_STRUCT_2B)
+ movzwl %ax, %eax
+ jmp L(e4)
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(load_table4), X86_RET_UNUSED14)
+ ud2
+E(L(load_table4), X86_RET_UNUSED15)
+ ud2
+
+L(UW40):
+ # cfi_endproc
+ENDF(C(ffi_closure_raw_SYSV))
+
+#define raw_closure_T_FS (16+16+8)
+
+ .balign 16
+ .globl C(ffi_closure_raw_THISCALL)
+ FFI_HIDDEN(C(ffi_closure_raw_THISCALL))
+C(ffi_closure_raw_THISCALL):
+L(UW41):
+ # cfi_startproc
+ /* Rearrange the stack such that %ecx is the first argument.
+ This means moving the return address. */
+ popl %edx
+L(UW42):
+ # cfi_def_cfa_offset(0)
+ # cfi_register(%eip, %edx)
+ pushl %ecx
+L(UW43):
+ # cfi_adjust_cfa_offset(4)
+ pushl %edx
+L(UW44):
+ # cfi_adjust_cfa_offset(4)
+ # cfi_rel_offset(%eip, 0)
+ subl $raw_closure_T_FS, %esp
+L(UW45):
+ # cfi_adjust_cfa_offset(raw_closure_T_FS)
+ movl %ebx, raw_closure_T_FS-4(%esp)
+L(UW46):
+ # cfi_rel_offset(%ebx, raw_closure_T_FS-4)
+
+ movl FFI_TRAMPOLINE_SIZE+8(%eax), %edx /* load cl->user_data */
+ movl %edx, 12(%esp)
+ leal raw_closure_T_FS+4(%esp), %edx /* load raw_args */
+ movl %edx, 8(%esp)
+ leal 16(%esp), %edx /* load &res */
+ movl %edx, 4(%esp)
+ movl FFI_TRAMPOLINE_SIZE(%eax), %ebx /* load cl->cif */
+ movl %ebx, (%esp)
+ call *FFI_TRAMPOLINE_SIZE+4(%eax) /* call cl->fun */
+
+ movl 20(%ebx), %eax /* load cif->flags */
+ andl $X86_RET_TYPE_MASK, %eax
#ifdef __PIC__
- .string "zR" /* CIE Augmentation */
+ call C(__x86.get_pc_thunk.bx)
+L(pc5):
+ leal L(load_table5)-L(pc5)(%ebx, %eax, 8), %ecx
#else
- .string "" /* CIE Augmentation */
+ leal L(load_table5)(,%eax, 8), %ecx
#endif
+ movl raw_closure_T_FS-4(%esp), %ebx
+L(UW47):
+ # cfi_restore(%ebx)
+ movl 16(%esp), %eax /* Optimistic load */
+ jmp *%ecx
+
+ .balign 8
+L(load_table5):
+E(L(load_table5), X86_RET_FLOAT)
+ flds 16(%esp)
+ jmp L(e5)
+E(L(load_table5), X86_RET_DOUBLE)
+ fldl 16(%esp)
+ jmp L(e5)
+E(L(load_table5), X86_RET_LDOUBLE)
+ fldt 16(%esp)
+ jmp L(e5)
+E(L(load_table5), X86_RET_SINT8)
+ movsbl %al, %eax
+ jmp L(e5)
+E(L(load_table5), X86_RET_SINT16)
+ movswl %ax, %eax
+ jmp L(e5)
+E(L(load_table5), X86_RET_UINT8)
+ movzbl %al, %eax
+ jmp L(e5)
+E(L(load_table5), X86_RET_UINT16)
+ movzwl %ax, %eax
+ jmp L(e5)
+E(L(load_table5), X86_RET_INT64)
+ movl 16+4(%esp), %edx
+ jmp L(e5)
+E(L(load_table5), X86_RET_INT32)
+ nop
+ /* fallthru */
+E(L(load_table5), X86_RET_VOID)
+L(e5):
+ addl $raw_closure_T_FS, %esp
+L(UW48):
+ # cfi_adjust_cfa_offset(-raw_closure_T_FS)
+ /* Remove the extra %ecx argument we pushed. */
+ ret $4
+L(UW49):
+ # cfi_adjust_cfa_offset(raw_closure_T_FS)
+E(L(load_table5), X86_RET_STRUCTPOP)
+ addl $raw_closure_T_FS, %esp
+L(UW50):
+ # cfi_adjust_cfa_offset(-raw_closure_T_FS)
+ ret $8
+L(UW51):
+ # cfi_adjust_cfa_offset(raw_closure_T_FS)
+E(L(load_table5), X86_RET_STRUCTARG)
+ jmp L(e5)
+E(L(load_table5), X86_RET_STRUCT_1B)
+ movzbl %al, %eax
+ jmp L(e5)
+E(L(load_table5), X86_RET_STRUCT_2B)
+ movzwl %ax, %eax
+ jmp L(e5)
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(load_table5), X86_RET_UNUSED14)
+ ud2
+E(L(load_table5), X86_RET_UNUSED15)
+ ud2
+
+L(UW52):
+ # cfi_endproc
+ENDF(C(ffi_closure_raw_THISCALL))
+
+#endif /* !FFI_NO_RAW_API */
+
+#ifdef X86_DARWIN
+# define COMDAT(X) \
+ .section __TEXT,__text,coalesced,pure_instructions; \
+ .weak_definition X; \
+ FFI_HIDDEN(X)
+#elif defined __ELF__ && !(defined(__sun__) && defined(__svr4__))
+# define COMDAT(X) \
+ .section .text.X,"axG",@progbits,X,comdat; \
+ .globl X; \
+ FFI_HIDDEN(X)
#else
-#error missing .ascii/.string
+# define COMDAT(X)
#endif
- .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
- .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
- .byte 0x8 /* CIE RA Column */
-#ifdef __PIC__
- .byte 0x1 /* .uleb128 0x1; Augmentation size */
- .byte FDE_ENCODING
+
+#if defined(__PIC__)
+ COMDAT(C(__x86.get_pc_thunk.bx))
+C(__x86.get_pc_thunk.bx):
+ movl (%esp), %ebx
+ ret
+ENDF(C(__x86.get_pc_thunk.bx))
+# if defined X86_DARWIN || defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+ COMDAT(C(__x86.get_pc_thunk.dx))
+C(__x86.get_pc_thunk.dx):
+ movl (%esp), %edx
+ ret
+ENDF(C(__x86.get_pc_thunk.dx))
+#endif /* DARWIN || HIDDEN */
+#endif /* __PIC__ */
+
+/* Sadly, OSX cctools-as doesn't understand .cfi directives at all. */
+
+#ifdef __APPLE__
+.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
+EHFrame0:
+#elif defined(X86_WIN32)
+.section .eh_frame,"r"
+#elif defined(HAVE_AS_X86_64_UNWIND_SECTION_TYPE)
+.section .eh_frame,EH_FRAME_FLAGS,@unwind
+#else
+.section .eh_frame,EH_FRAME_FLAGS,@progbits
#endif
- .byte 0xc /* DW_CFA_def_cfa */
- .byte 0x4 /* .uleb128 0x4 */
- .byte 0x4 /* .uleb128 0x4 */
- .byte 0x88 /* DW_CFA_offset, column 0x8 */
- .byte 0x1 /* .uleb128 0x1 */
- .align 4
-.LECIE1:
-.LSFDE1:
- .long .LEFDE1-.LASFDE1 /* FDE Length */
-.LASFDE1:
- .long .LASFDE1-.Lframe1 /* FDE CIE offset */
- .long FDE_ENCODE(.LFB1) /* FDE initial location */
- .long .LFE1-.LFB1 /* FDE address range */
-#ifdef __PIC__
- .byte 0x0 /* .uleb128 0x0; Augmentation size */
+
+#ifdef HAVE_AS_X86_PCREL
+# define PCREL(X) X - .
+#else
+# define PCREL(X) X@rel
#endif
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI0-.LFB1
- .byte 0xe /* DW_CFA_def_cfa_offset */
- .byte 0x8 /* .uleb128 0x8 */
- .byte 0x85 /* DW_CFA_offset, column 0x5 */
- .byte 0x2 /* .uleb128 0x2 */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI1-.LCFI0
- .byte 0xd /* DW_CFA_def_cfa_register */
- .byte 0x5 /* .uleb128 0x5 */
- .align 4
-.LEFDE1:
-.LSFDE2:
- .long .LEFDE2-.LASFDE2 /* FDE Length */
-.LASFDE2:
- .long .LASFDE2-.Lframe1 /* FDE CIE offset */
- .long FDE_ENCODE(.LFB2) /* FDE initial location */
- .long .LFE2-.LFB2 /* FDE address range */
-#ifdef __PIC__
- .byte 0x0 /* .uleb128 0x0; Augmentation size */
+
+/* Simplify advancing between labels. Assume DW_CFA_advance_loc1 fits. */
+#define ADV(N, P) .byte 2, L(N)-L(P)
+
+ .balign 4
+L(CIE):
+ .set L(set0),L(ECIE)-L(SCIE)
+ .long L(set0) /* CIE Length */
+L(SCIE):
+ .long 0 /* CIE Identifier Tag */
+ .byte 1 /* CIE Version */
+ .ascii "zR\0" /* CIE Augmentation */
+ .byte 1 /* CIE Code Alignment Factor */
+ .byte 0x7c /* CIE Data Alignment Factor */
+ .byte 0x8 /* CIE RA Column */
+ .byte 1 /* Augmentation size */
+ .byte 0x1b /* FDE Encoding (pcrel sdata4) */
+ .byte 0xc, 4, 4 /* DW_CFA_def_cfa, %esp offset 4 */
+ .byte 0x80+8, 1 /* DW_CFA_offset, %eip offset 1*-4 */
+ .balign 4
+L(ECIE):
+
+ .set L(set1),L(EFDE1)-L(SFDE1)
+ .long L(set1) /* FDE Length */
+L(SFDE1):
+ .long L(SFDE1)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW0)) /* Initial location */
+ .long L(UW5)-L(UW0) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW1, UW0)
+ .byte 0xc, 5, 8 /* DW_CFA_def_cfa, %ebp 8 */
+ .byte 0x80+5, 2 /* DW_CFA_offset, %ebp 2*-4 */
+ ADV(UW2, UW1)
+ .byte 0x80+3, 0 /* DW_CFA_offset, %ebx 0*-4 */
+ ADV(UW3, UW2)
+ .byte 0xa /* DW_CFA_remember_state */
+ .byte 0xc, 4, 4 /* DW_CFA_def_cfa, %esp 4 */
+ .byte 0xc0+3 /* DW_CFA_restore, %ebx */
+ .byte 0xc0+5 /* DW_CFA_restore, %ebp */
+ ADV(UW4, UW3)
+ .byte 0xb /* DW_CFA_restore_state */
+ .balign 4
+L(EFDE1):
+
+ .set L(set2),L(EFDE2)-L(SFDE2)
+ .long L(set2) /* FDE Length */
+L(SFDE2):
+ .long L(SFDE2)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW6)) /* Initial location */
+ .long L(UW8)-L(UW6) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW7, UW6)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE2):
+
+ .set L(set3),L(EFDE3)-L(SFDE3)
+ .long L(set3) /* FDE Length */
+L(SFDE3):
+ .long L(SFDE3)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW9)) /* Initial location */
+ .long L(UW11)-L(UW9) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW10, UW9)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE3):
+
+ .set L(set4),L(EFDE4)-L(SFDE4)
+ .long L(set4) /* FDE Length */
+L(SFDE4):
+ .long L(SFDE4)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW12)) /* Initial location */
+ .long L(UW20)-L(UW12) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW13, UW12)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+#ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX
+ ADV(UW14, UW13)
+ .byte 0x80+3, (40-(closure_FS+4))/-4 /* DW_CFA_offset %ebx */
+ ADV(UW15, UW14)
+ .byte 0xc0+3 /* DW_CFA_restore %ebx */
+ ADV(UW16, UW15)
+#else
+ ADV(UW16, UW13)
#endif
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI2-.LFB2
- .byte 0xe /* DW_CFA_def_cfa_offset */
- .byte 0x8 /* .uleb128 0x8 */
- .byte 0x85 /* DW_CFA_offset, column 0x5 */
- .byte 0x2 /* .uleb128 0x2 */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI3-.LCFI2
- .byte 0xd /* DW_CFA_def_cfa_register */
- .byte 0x5 /* .uleb128 0x5 */
-#if !defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE && defined __PIC__
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI7-.LCFI3
- .byte 0x83 /* DW_CFA_offset, column 0x3 */
- .byte 0xa /* .uleb128 0xa */
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW17, UW16)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ ADV(UW18, UW17)
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW19, UW18)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE4):
+
+ .set L(set5),L(EFDE5)-L(SFDE5)
+ .long L(set5) /* FDE Length */
+L(SFDE5):
+ .long L(SFDE5)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW21)) /* Initial location */
+ .long L(UW23)-L(UW21) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW22, UW21)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE5):
+
+ .set L(set6),L(EFDE6)-L(SFDE6)
+ .long L(set6) /* FDE Length */
+L(SFDE6):
+ .long L(SFDE6)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW24)) /* Initial location */
+ .long L(UW26)-L(UW24) /* Address range */
+ .byte 0 /* Augmentation size */
+ .byte 0xe, 8 /* DW_CFA_def_cfa_offset */
+ .byte 0x80+8, 2 /* DW_CFA_offset %eip, 2*-4 */
+ ADV(UW25, UW24)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE6):
+
+ .set L(set7),L(EFDE7)-L(SFDE7)
+ .long L(set7) /* FDE Length */
+L(SFDE7):
+ .long L(SFDE7)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW27)) /* Initial location */
+ .long L(UW31)-L(UW27) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW28, UW27)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+#ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX
+ ADV(UW29, UW28)
+ .byte 0x80+3, (40-(closure_FS+4))/-4 /* DW_CFA_offset %ebx */
+ ADV(UW30, UW29)
+ .byte 0xc0+3 /* DW_CFA_restore %ebx */
#endif
- .align 4
-.LEFDE2:
+ .balign 4
+L(EFDE7):
#if !FFI_NO_RAW_API
+ .set L(set8),L(EFDE8)-L(SFDE8)
+ .long L(set8) /* FDE Length */
+L(SFDE8):
+ .long L(SFDE8)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW32)) /* Initial location */
+ .long L(UW40)-L(UW32) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW33, UW32)
+ .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */
+ ADV(UW34, UW33)
+ .byte 0x80+3, 2 /* DW_CFA_offset %ebx 2*-4 */
+ ADV(UW35, UW34)
+ .byte 0xc0+3 /* DW_CFA_restore %ebx */
+ ADV(UW36, UW35)
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW37, UW36)
+ .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */
+ ADV(UW38, UW37)
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW39, UW38)
+ .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE8):
-.LSFDE3:
- .long .LEFDE3-.LASFDE3 /* FDE Length */
-.LASFDE3:
- .long .LASFDE3-.Lframe1 /* FDE CIE offset */
- .long FDE_ENCODE(.LFB3) /* FDE initial location */
- .long .LFE3-.LFB3 /* FDE address range */
-#ifdef __PIC__
- .byte 0x0 /* .uleb128 0x0; Augmentation size */
-#endif
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI4-.LFB3
- .byte 0xe /* DW_CFA_def_cfa_offset */
- .byte 0x8 /* .uleb128 0x8 */
- .byte 0x85 /* DW_CFA_offset, column 0x5 */
- .byte 0x2 /* .uleb128 0x2 */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI5-.LCFI4
- .byte 0xd /* DW_CFA_def_cfa_register */
- .byte 0x5 /* .uleb128 0x5 */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI6-.LCFI5
- .byte 0x86 /* DW_CFA_offset, column 0x6 */
- .byte 0x3 /* .uleb128 0x3 */
- .align 4
-.LEFDE3:
+ .set L(set9),L(EFDE9)-L(SFDE9)
+ .long L(set9) /* FDE Length */
+L(SFDE9):
+ .long L(SFDE9)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW41)) /* Initial location */
+ .long L(UW52)-L(UW41) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW42, UW41)
+ .byte 0xe, 0 /* DW_CFA_def_cfa_offset */
+ .byte 0x9, 8, 2 /* DW_CFA_register %eip, %edx */
+ ADV(UW43, UW42)
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW44, UW43)
+ .byte 0xe, 8 /* DW_CFA_def_cfa_offset */
+ .byte 0x80+8, 2 /* DW_CFA_offset %eip 2*-4 */
+ ADV(UW45, UW44)
+ .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */
+ ADV(UW46, UW45)
+ .byte 0x80+3, 3 /* DW_CFA_offset %ebx 3*-4 */
+ ADV(UW47, UW46)
+ .byte 0xc0+3 /* DW_CFA_restore %ebx */
+ ADV(UW48, UW47)
+ .byte 0xe, 8 /* DW_CFA_def_cfa_offset */
+ ADV(UW49, UW48)
+ .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */
+ ADV(UW50, UW49)
+ .byte 0xe, 8 /* DW_CFA_def_cfa_offset */
+ ADV(UW51, UW50)
+ .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE9):
+#endif /* !FFI_NO_RAW_API */
+#ifdef _WIN32
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+@feat.00 = 1
#endif
-#endif
-#endif /* ifndef __x86_64__ */
+#ifdef __APPLE__
+ .subsections_via_symbols
+ .section __LD,__compact_unwind,regular,debug
+
+ /* compact unwind for ffi_call_i386 */
+ .long C(ffi_call_i386)
+ .set L1,L(UW5)-L(UW0)
+ .long L1
+ .long 0x04000000 /* use dwarf unwind info */
+ .long 0
+ .long 0
+
+ /* compact unwind for ffi_go_closure_EAX */
+ .long C(ffi_go_closure_EAX)
+ .set L2,L(UW8)-L(UW6)
+ .long L2
+ .long 0x04000000 /* use dwarf unwind info */
+ .long 0
+ .long 0
+
+ /* compact unwind for ffi_go_closure_ECX */
+ .long C(ffi_go_closure_ECX)
+ .set L3,L(UW11)-L(UW9)
+ .long L3
+ .long 0x04000000 /* use dwarf unwind info */
+ .long 0
+ .long 0
+
+ /* compact unwind for ffi_closure_i386 */
+ .long C(ffi_closure_i386)
+ .set L4,L(UW20)-L(UW12)
+ .long L4
+ .long 0x04000000 /* use dwarf unwind info */
+ .long 0
+ .long 0
+
+ /* compact unwind for ffi_go_closure_STDCALL */
+ .long C(ffi_go_closure_STDCALL)
+ .set L5,L(UW23)-L(UW21)
+ .long L5
+ .long 0x04000000 /* use dwarf unwind info */
+ .long 0
+ .long 0
+
+ /* compact unwind for ffi_closure_REGISTER */
+ .long C(ffi_closure_REGISTER)
+ .set L6,L(UW26)-L(UW24)
+ .long L6
+ .long 0x04000000 /* use dwarf unwind info */
+ .long 0
+ .long 0
+
+ /* compact unwind for ffi_closure_STDCALL */
+ .long C(ffi_closure_STDCALL)
+ .set L7,L(UW31)-L(UW27)
+ .long L7
+ .long 0x04000000 /* use dwarf unwind info */
+ .long 0
+ .long 0
+
+ /* compact unwind for ffi_closure_raw_SYSV */
+ .long C(ffi_closure_raw_SYSV)
+ .set L8,L(UW40)-L(UW32)
+ .long L8
+ .long 0x04000000 /* use dwarf unwind info */
+ .long 0
+ .long 0
+
+ /* compact unwind for ffi_closure_raw_THISCALL */
+ .long C(ffi_closure_raw_THISCALL)
+ .set L9,L(UW52)-L(UW41)
+ .long L9
+ .long 0x04000000 /* use dwarf unwind info */
+ .long 0
+ .long 0
+#endif /* __APPLE__ */
+
+#endif /* ifndef _MSC_VER */
+#endif /* ifdef __i386__ */
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
diff --git a/src/x86/sysv_intel.S b/src/x86/sysv_intel.S
new file mode 100644
index 00000000..3cafd71c
--- /dev/null
+++ b/src/x86/sysv_intel.S
@@ -0,0 +1,995 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 2017 Anthony Green
+ - Copyright (c) 2013 The Written Word, Inc.
+ - Copyright (c) 1996,1998,2001-2003,2005,2008,2010 Red Hat, Inc.
+
+ X86 Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS 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.
+ ----------------------------------------------------------------------- */
+
+#ifndef __x86_64__
+#ifdef _MSC_VER
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+#include <ffi_cfi.h>
+#include "internal.h"
+
+#define C2(X, Y) X ## Y
+#define C1(X, Y) C2(X, Y)
+#define L(X) C1(L, X)
+# define ENDF(X) X ENDP
+
+/* This macro allows the safe creation of jump tables without an
+ actual table. The entry points into the table are all 8 bytes.
+ The use of ORG asserts that we're at the correct location. */
+/* ??? The clang assembler doesn't handle .org with symbolic expressions. */
+#if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
+# define E(BASE, X) ALIGN 8
+#else
+# define E(BASE, X) ALIGN 8; ORG BASE + X * 8
+#endif
+
+ .686P
+ .MODEL FLAT
+
+EXTRN @ffi_closure_inner@8:PROC
+_TEXT SEGMENT
+
+/* This is declared as
+
+ void ffi_call_i386(struct call_frame *frame, char *argp)
+ __attribute__((fastcall));
+
+ Thus the arguments are present in
+
+ ecx: frame
+ edx: argp
+*/
+
+ALIGN 16
+PUBLIC @ffi_call_i386@8
+@ffi_call_i386@8 PROC
+L(UW0):
+ cfi_startproc
+ #if !HAVE_FASTCALL
+ mov ecx, [esp+4]
+ mov edx, [esp+8]
+ #endif
+ mov eax, [esp] /* move the return address */
+ mov [ecx], ebp /* store ebp into local frame */
+ mov [ecx+4], eax /* store retaddr into local frame */
+
+ /* New stack frame based off ebp. This is a itty bit of unwind
+ trickery in that the CFA *has* changed. There is no easy way
+ to describe it correctly on entry to the function. Fortunately,
+ it doesn't matter too much since at all points we can correctly
+ unwind back to ffi_call. Note that the location to which we
+ moved the return address is (the new) CFA-4, so from the
+ perspective of the unwind info, it hasn't moved. */
+ mov ebp, ecx
+L(UW1):
+ // cfi_def_cfa(%ebp, 8)
+ // cfi_rel_offset(%ebp, 0)
+
+ mov esp, edx /* set outgoing argument stack */
+ mov eax, [20+R_EAX*4+ebp] /* set register arguments */
+ mov edx, [20+R_EDX*4+ebp]
+ mov ecx, [20+R_ECX*4+ebp]
+
+ call dword ptr [ebp+8]
+
+ mov ecx, [12+ebp] /* load return type code */
+ mov [ebp+8], ebx /* preserve %ebx */
+L(UW2):
+ // cfi_rel_offset(%ebx, 8)
+
+ and ecx, X86_RET_TYPE_MASK
+ lea ebx, [L(store_table) + ecx * 8]
+ mov ecx, [ebp+16] /* load result address */
+ jmp ebx
+
+ ALIGN 8
+L(store_table):
+E(L(store_table), X86_RET_FLOAT)
+ fstp DWORD PTR [ecx]
+ jmp L(e1)
+E(L(store_table), X86_RET_DOUBLE)
+ fstp QWORD PTR [ecx]
+ jmp L(e1)
+E(L(store_table), X86_RET_LDOUBLE)
+ fstp QWORD PTR [ecx]
+ jmp L(e1)
+E(L(store_table), X86_RET_SINT8)
+ movsx eax, al
+ mov [ecx], eax
+ jmp L(e1)
+E(L(store_table), X86_RET_SINT16)
+ movsx eax, ax
+ mov [ecx], eax
+ jmp L(e1)
+E(L(store_table), X86_RET_UINT8)
+ movzx eax, al
+ mov [ecx], eax
+ jmp L(e1)
+E(L(store_table), X86_RET_UINT16)
+ movzx eax, ax
+ mov [ecx], eax
+ jmp L(e1)
+E(L(store_table), X86_RET_INT64)
+ mov [ecx+4], edx
+ /* fallthru */
+E(L(store_table), X86_RET_int 32)
+ mov [ecx], eax
+ /* fallthru */
+E(L(store_table), X86_RET_VOID)
+L(e1):
+ mov ebx, [ebp+8]
+ mov esp, ebp
+ pop ebp
+L(UW3):
+ // cfi_remember_state
+ // cfi_def_cfa(%esp, 4)
+ // cfi_restore(%ebx)
+ // cfi_restore(%ebp)
+ ret
+L(UW4):
+ // cfi_restore_state
+
+E(L(store_table), X86_RET_STRUCTPOP)
+ jmp L(e1)
+E(L(store_table), X86_RET_STRUCTARG)
+ jmp L(e1)
+E(L(store_table), X86_RET_STRUCT_1B)
+ mov [ecx], al
+ jmp L(e1)
+E(L(store_table), X86_RET_STRUCT_2B)
+ mov [ecx], ax
+ jmp L(e1)
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(store_table), X86_RET_UNUSED14)
+ int 3
+E(L(store_table), X86_RET_UNUSED15)
+ int 3
+
+L(UW5):
+ // cfi_endproc
+ENDF(@ffi_call_i386@8)
+
+/* The inner helper is declared as
+
+ void ffi_closure_inner(struct closure_frame *frame, char *argp)
+ __attribute_((fastcall))
+
+ Thus the arguments are placed in
+
+ ecx: frame
+ edx: argp
+*/
+
+/* Macros to help setting up the closure_data structure. */
+
+#if HAVE_FASTCALL
+# define closure_FS (40 + 4)
+# define closure_CF 0
+#else
+# define closure_FS (8 + 40 + 12)
+# define closure_CF 8
+#endif
+
+FFI_CLOSURE_SAVE_REGS MACRO
+ mov [esp + closure_CF+16+R_EAX*4], eax
+ mov [esp + closure_CF+16+R_EDX*4], edx
+ mov [esp + closure_CF+16+R_ECX*4], ecx
+ENDM
+
+FFI_CLOSURE_COPY_TRAMP_DATA MACRO
+ mov edx, [eax+FFI_TRAMPOLINE_SIZE] /* copy cif */
+ mov ecx, [eax+FFI_TRAMPOLINE_SIZE+4] /* copy fun */
+ mov eax, [eax+FFI_TRAMPOLINE_SIZE+8]; /* copy user_data */
+ mov [esp+closure_CF+28], edx
+ mov [esp+closure_CF+32], ecx
+ mov [esp+closure_CF+36], eax
+ENDM
+
+#if HAVE_FASTCALL
+FFI_CLOSURE_PREP_CALL MACRO
+ mov ecx, esp /* load closure_data */
+ lea edx, [esp+closure_FS+4] /* load incoming stack */
+ENDM
+#else
+FFI_CLOSURE_PREP_CALL MACRO
+ lea ecx, [esp+closure_CF] /* load closure_data */
+ lea edx, [esp+closure_FS+4] /* load incoming stack */
+ mov [esp], ecx
+ mov [esp+4], edx
+ENDM
+#endif
+
+FFI_CLOSURE_CALL_INNER MACRO UWN
+ call @ffi_closure_inner@8
+ENDM
+
+FFI_CLOSURE_MASK_AND_JUMP MACRO LABEL
+ and eax, X86_RET_TYPE_MASK
+ lea edx, [LABEL+eax*8]
+ mov eax, [esp+closure_CF] /* optimiztic load */
+ jmp edx
+ENDM
+
+ALIGN 16
+PUBLIC ffi_go_closure_EAX
+ffi_go_closure_EAX PROC C
+L(UW6):
+ // cfi_startproc
+ sub esp, closure_FS
+L(UW7):
+ // cfi_def_cfa_offset(closure_FS + 4)
+ FFI_CLOSURE_SAVE_REGS
+ mov edx, [eax+4] /* copy cif */
+ mov ecx, [eax +8] /* copy fun */
+ mov [esp+closure_CF+28], edx
+ mov [esp+closure_CF+32], ecx
+ mov [esp+closure_CF+36], eax /* closure is user_data */
+ jmp L(do_closure_i386)
+L(UW8):
+ // cfi_endproc
+ENDF(ffi_go_closure_EAX)
+
+ALIGN 16
+PUBLIC ffi_go_closure_ECX
+ffi_go_closure_ECX PROC C
+L(UW9):
+ // cfi_startproc
+ sub esp, closure_FS
+L(UW10):
+ // cfi_def_cfa_offset(closure_FS + 4)
+ FFI_CLOSURE_SAVE_REGS
+ mov edx, [ecx+4] /* copy cif */
+ mov eax, [ecx+8] /* copy fun */
+ mov [esp+closure_CF+28], edx
+ mov [esp+closure_CF+32], eax
+ mov [esp+closure_CF+36], ecx /* closure is user_data */
+ jmp L(do_closure_i386)
+L(UW11):
+ // cfi_endproc
+ENDF(ffi_go_closure_ECX)
+
+/* The closure entry points are reached from the ffi_closure trampoline.
+ On entry, %eax contains the address of the ffi_closure. */
+
+ALIGN 16
+PUBLIC ffi_closure_i386
+ffi_closure_i386 PROC C
+L(UW12):
+ // cfi_startproc
+ sub esp, closure_FS
+L(UW13):
+ // cfi_def_cfa_offset(closure_FS + 4)
+
+ FFI_CLOSURE_SAVE_REGS
+ FFI_CLOSURE_COPY_TRAMP_DATA
+
+ /* Entry point from preceeding Go closures. */
+L(do_closure_i386)::
+
+ FFI_CLOSURE_PREP_CALL
+ FFI_CLOSURE_CALL_INNER(14)
+ FFI_CLOSURE_MASK_AND_JUMP L(C1(load_table,2))
+
+ ALIGN 8
+L(load_table2):
+E(L(load_table2), X86_RET_FLOAT)
+ fld dword ptr [esp+closure_CF]
+ jmp L(e2)
+E(L(load_table2), X86_RET_DOUBLE)
+ fld qword ptr [esp+closure_CF]
+ jmp L(e2)
+E(L(load_table2), X86_RET_LDOUBLE)
+ fld qword ptr [esp+closure_CF]
+ jmp L(e2)
+E(L(load_table2), X86_RET_SINT8)
+ movsx eax, al
+ jmp L(e2)
+E(L(load_table2), X86_RET_SINT16)
+ movsx eax, ax
+ jmp L(e2)
+E(L(load_table2), X86_RET_UINT8)
+ movzx eax, al
+ jmp L(e2)
+E(L(load_table2), X86_RET_UINT16)
+ movzx eax, ax
+ jmp L(e2)
+E(L(load_table2), X86_RET_INT64)
+ mov edx, [esp+closure_CF+4]
+ jmp L(e2)
+E(L(load_table2), X86_RET_INT32)
+ nop
+ /* fallthru */
+E(L(load_table2), X86_RET_VOID)
+L(e2):
+ add esp, closure_FS
+L(UW16):
+ // cfi_adjust_cfa_offset(-closure_FS)
+ ret
+L(UW17):
+ // cfi_adjust_cfa_offset(closure_FS)
+E(L(load_table2), X86_RET_STRUCTPOP)
+ add esp, closure_FS
+L(UW18):
+ // cfi_adjust_cfa_offset(-closure_FS)
+ ret 4
+L(UW19):
+ // cfi_adjust_cfa_offset(closure_FS)
+E(L(load_table2), X86_RET_STRUCTARG)
+ jmp L(e2)
+E(L(load_table2), X86_RET_STRUCT_1B)
+ movzx eax, al
+ jmp L(e2)
+E(L(load_table2), X86_RET_STRUCT_2B)
+ movzx eax, ax
+ jmp L(e2)
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(load_table2), X86_RET_UNUSED14)
+ int 3
+E(L(load_table2), X86_RET_UNUSED15)
+ int 3
+
+L(UW20):
+ // cfi_endproc
+ENDF(ffi_closure_i386)
+
+ALIGN 16
+PUBLIC ffi_go_closure_STDCALL
+ffi_go_closure_STDCALL PROC C
+L(UW21):
+ // cfi_startproc
+ sub esp, closure_FS
+L(UW22):
+ // cfi_def_cfa_offset(closure_FS + 4)
+ FFI_CLOSURE_SAVE_REGS
+ mov edx, [ecx+4] /* copy cif */
+ mov eax, [ecx+8] /* copy fun */
+ mov [esp+closure_CF+28], edx
+ mov [esp+closure_CF+32], eax
+ mov [esp+closure_CF+36], ecx /* closure is user_data */
+ jmp L(do_closure_STDCALL)
+L(UW23):
+ // cfi_endproc
+ENDF(ffi_go_closure_STDCALL)
+
+/* For REGISTER, we have no available parameter registers, and so we
+ enter here having pushed the closure onto the stack. */
+
+ALIGN 16
+PUBLIC ffi_closure_REGISTER
+ffi_closure_REGISTER PROC C
+L(UW24):
+ // cfi_startproc
+ // cfi_def_cfa(%esp, 8)
+ // cfi_offset(%eip, -8)
+ sub esp, closure_FS-4
+L(UW25):
+ // cfi_def_cfa_offset(closure_FS + 4)
+ FFI_CLOSURE_SAVE_REGS
+ mov ecx, [esp+closure_FS-4] /* load retaddr */
+ mov eax, [esp+closure_FS] /* load closure */
+ mov [esp+closure_FS], ecx /* move retaddr */
+ jmp L(do_closure_REGISTER)
+L(UW26):
+ // cfi_endproc
+ENDF(ffi_closure_REGISTER)
+
+/* For STDCALL (and others), we need to pop N bytes of arguments off
+ the stack following the closure. The amount needing to be popped
+ is returned to us from ffi_closure_inner. */
+
+ALIGN 16
+PUBLIC ffi_closure_STDCALL
+ffi_closure_STDCALL PROC C
+L(UW27):
+ // cfi_startproc
+ sub esp, closure_FS
+L(UW28):
+ // cfi_def_cfa_offset(closure_FS + 4)
+
+ FFI_CLOSURE_SAVE_REGS
+
+ /* Entry point from ffi_closure_REGISTER. */
+L(do_closure_REGISTER)::
+
+ FFI_CLOSURE_COPY_TRAMP_DATA
+
+ /* Entry point from preceeding Go closure. */
+L(do_closure_STDCALL)::
+
+ FFI_CLOSURE_PREP_CALL
+ FFI_CLOSURE_CALL_INNER(29)
+
+ mov ecx, eax
+ shr ecx, X86_RET_POP_SHIFT /* isolate pop count */
+ lea ecx, [esp+closure_FS+ecx] /* compute popped esp */
+ mov edx, [esp+closure_FS] /* move return address */
+ mov [ecx], edx
+
+ /* From this point on, the value of %esp upon return is %ecx+4,
+ and we've copied the return address to %ecx to make return easy.
+ There's no point in representing this in the unwind info, as
+ there is always a window between the mov and the ret which
+ will be wrong from one point of view or another. */
+
+ FFI_CLOSURE_MASK_AND_JUMP L(C1(load_table,3))
+
+ ALIGN 8
+L(load_table3):
+E(L(load_table3), X86_RET_FLOAT)
+ fld DWORD PTR [esp+closure_CF]
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_DOUBLE)
+ fld QWORD PTR [esp+closure_CF]
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_LDOUBLE)
+ fld QWORD PTR [esp+closure_CF]
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_SINT8)
+ movsx eax, al
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_SINT16)
+ movsx eax, ax
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_UINT8)
+ movzx eax, al
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_UINT16)
+ movzx eax, ax
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_INT64)
+ mov edx, [esp+closure_CF+4]
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_int 32)
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_VOID)
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_STRUCTPOP)
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_STRUCTARG)
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_STRUCT_1B)
+ movzx eax, al
+ mov esp, ecx
+ ret
+E(L(load_table3), X86_RET_STRUCT_2B)
+ movzx eax, ax
+ mov esp, ecx
+ ret
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(load_table3), X86_RET_UNUSED14)
+ int 3
+E(L(load_table3), X86_RET_UNUSED15)
+ int 3
+
+L(UW31):
+ // cfi_endproc
+ENDF(ffi_closure_STDCALL)
+
+#if !FFI_NO_RAW_API
+
+#define raw_closure_S_FS (16+16+12)
+
+ALIGN 16
+PUBLIC ffi_closure_raw_SYSV
+ffi_closure_raw_SYSV PROC C
+L(UW32):
+ // cfi_startproc
+ sub esp, raw_closure_S_FS
+L(UW33):
+ // cfi_def_cfa_offset(raw_closure_S_FS + 4)
+ mov [esp+raw_closure_S_FS-4], ebx
+L(UW34):
+ // cfi_rel_offset(%ebx, raw_closure_S_FS-4)
+
+ mov edx, [eax+FFI_TRAMPOLINE_SIZE+8] /* load cl->user_data */
+ mov [esp+12], edx
+ lea edx, [esp+raw_closure_S_FS+4] /* load raw_args */
+ mov [esp+8], edx
+ lea edx, [esp+16] /* load &res */
+ mov [esp+4], edx
+ mov ebx, [eax+FFI_TRAMPOLINE_SIZE] /* load cl->cif */
+ mov [esp], ebx
+ call DWORD PTR [eax+FFI_TRAMPOLINE_SIZE+4] /* call cl->fun */
+
+ mov eax, [ebx+20] /* load cif->flags */
+ and eax, X86_RET_TYPE_MASK
+// #ifdef __PIC__
+// call __x86.get_pc_thunk.bx
+// L(pc4):
+// lea ecx, L(load_table4)-L(pc4)(%ebx, %eax, 8), %ecx
+// #else
+ lea ecx, [L(load_table4)+eax+8]
+// #endif
+ mov ebx, [esp+raw_closure_S_FS-4]
+L(UW35):
+ // cfi_restore(%ebx)
+ mov eax, [esp+16] /* Optimistic load */
+ jmp dword ptr [ecx]
+
+ ALIGN 8
+L(load_table4):
+E(L(load_table4), X86_RET_FLOAT)
+ fld DWORD PTR [esp +16]
+ jmp L(e4)
+E(L(load_table4), X86_RET_DOUBLE)
+ fld QWORD PTR [esp +16]
+ jmp L(e4)
+E(L(load_table4), X86_RET_LDOUBLE)
+ fld QWORD PTR [esp +16]
+ jmp L(e4)
+E(L(load_table4), X86_RET_SINT8)
+ movsx eax, al
+ jmp L(e4)
+E(L(load_table4), X86_RET_SINT16)
+ movsx eax, ax
+ jmp L(e4)
+E(L(load_table4), X86_RET_UINT8)
+ movzx eax, al
+ jmp L(e4)
+E(L(load_table4), X86_RET_UINT16)
+ movzx eax, ax
+ jmp L(e4)
+E(L(load_table4), X86_RET_INT64)
+ mov edx, [esp+16+4]
+ jmp L(e4)
+E(L(load_table4), X86_RET_int 32)
+ nop
+ /* fallthru */
+E(L(load_table4), X86_RET_VOID)
+L(e4):
+ add esp, raw_closure_S_FS
+L(UW36):
+ // cfi_adjust_cfa_offset(-raw_closure_S_FS)
+ ret
+L(UW37):
+ // cfi_adjust_cfa_offset(raw_closure_S_FS)
+E(L(load_table4), X86_RET_STRUCTPOP)
+ add esp, raw_closure_S_FS
+L(UW38):
+ // cfi_adjust_cfa_offset(-raw_closure_S_FS)
+ ret 4
+L(UW39):
+ // cfi_adjust_cfa_offset(raw_closure_S_FS)
+E(L(load_table4), X86_RET_STRUCTARG)
+ jmp L(e4)
+E(L(load_table4), X86_RET_STRUCT_1B)
+ movzx eax, al
+ jmp L(e4)
+E(L(load_table4), X86_RET_STRUCT_2B)
+ movzx eax, ax
+ jmp L(e4)
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(load_table4), X86_RET_UNUSED14)
+ int 3
+E(L(load_table4), X86_RET_UNUSED15)
+ int 3
+
+L(UW40):
+ // cfi_endproc
+ENDF(ffi_closure_raw_SYSV)
+
+#define raw_closure_T_FS (16+16+8)
+
+ALIGN 16
+PUBLIC ffi_closure_raw_THISCALL
+ffi_closure_raw_THISCALL PROC C
+L(UW41):
+ // cfi_startproc
+ /* Rearrange the stack such that %ecx is the first argument.
+ This means moving the return address. */
+ pop edx
+L(UW42):
+ // cfi_def_cfa_offset(0)
+ // cfi_register(%eip, %edx)
+ push ecx
+L(UW43):
+ // cfi_adjust_cfa_offset(4)
+ push edx
+L(UW44):
+ // cfi_adjust_cfa_offset(4)
+ // cfi_rel_offset(%eip, 0)
+ sub esp, raw_closure_T_FS
+L(UW45):
+ // cfi_adjust_cfa_offset(raw_closure_T_FS)
+ mov [esp+raw_closure_T_FS-4], ebx
+L(UW46):
+ // cfi_rel_offset(%ebx, raw_closure_T_FS-4)
+
+ mov edx, [eax+FFI_TRAMPOLINE_SIZE+8] /* load cl->user_data */
+ mov [esp+12], edx
+ lea edx, [esp+raw_closure_T_FS+4] /* load raw_args */
+ mov [esp+8], edx
+ lea edx, [esp+16] /* load &res */
+ mov [esp+4], edx
+ mov ebx, [eax+FFI_TRAMPOLINE_SIZE] /* load cl->cif */
+ mov [esp], ebx
+ call DWORD PTR [eax+FFI_TRAMPOLINE_SIZE+4] /* call cl->fun */
+
+ mov eax, [ebx+20] /* load cif->flags */
+ and eax, X86_RET_TYPE_MASK
+// #ifdef __PIC__
+// call __x86.get_pc_thunk.bx
+// L(pc5):
+// leal L(load_table5)-L(pc5)(%ebx, %eax, 8), %ecx
+// #else
+ lea ecx, [L(load_table5)+eax*8]
+//#endif
+ mov ebx, [esp+raw_closure_T_FS-4]
+L(UW47):
+ // cfi_restore(%ebx)
+ mov eax, [esp+16] /* Optimistic load */
+ jmp DWORD PTR [ecx]
+
+ AlIGN 4
+L(load_table5):
+E(L(load_table5), X86_RET_FLOAT)
+ fld DWORD PTR [esp +16]
+ jmp L(e5)
+E(L(load_table5), X86_RET_DOUBLE)
+ fld QWORD PTR [esp +16]
+ jmp L(e5)
+E(L(load_table5), X86_RET_LDOUBLE)
+ fld QWORD PTR [esp+16]
+ jmp L(e5)
+E(L(load_table5), X86_RET_SINT8)
+ movsx eax, al
+ jmp L(e5)
+E(L(load_table5), X86_RET_SINT16)
+ movsx eax, ax
+ jmp L(e5)
+E(L(load_table5), X86_RET_UINT8)
+ movzx eax, al
+ jmp L(e5)
+E(L(load_table5), X86_RET_UINT16)
+ movzx eax, ax
+ jmp L(e5)
+E(L(load_table5), X86_RET_INT64)
+ mov edx, [esp+16+4]
+ jmp L(e5)
+E(L(load_table5), X86_RET_int 32)
+ nop
+ /* fallthru */
+E(L(load_table5), X86_RET_VOID)
+L(e5):
+ add esp, raw_closure_T_FS
+L(UW48):
+ // cfi_adjust_cfa_offset(-raw_closure_T_FS)
+ /* Remove the extra %ecx argument we pushed. */
+ ret 4
+L(UW49):
+ // cfi_adjust_cfa_offset(raw_closure_T_FS)
+E(L(load_table5), X86_RET_STRUCTPOP)
+ add esp, raw_closure_T_FS
+L(UW50):
+ // cfi_adjust_cfa_offset(-raw_closure_T_FS)
+ ret 8
+L(UW51):
+ // cfi_adjust_cfa_offset(raw_closure_T_FS)
+E(L(load_table5), X86_RET_STRUCTARG)
+ jmp L(e5)
+E(L(load_table5), X86_RET_STRUCT_1B)
+ movzx eax, al
+ jmp L(e5)
+E(L(load_table5), X86_RET_STRUCT_2B)
+ movzx eax, ax
+ jmp L(e5)
+
+ /* Fill out the table so that bad values are predictable. */
+E(L(load_table5), X86_RET_UNUSED14)
+ int 3
+E(L(load_table5), X86_RET_UNUSED15)
+ int 3
+
+L(UW52):
+ // cfi_endproc
+ENDF(ffi_closure_raw_THISCALL)
+
+#endif /* !FFI_NO_RAW_API */
+
+#ifdef X86_DARWIN
+# define COMDAT(X) \
+ .section __TEXT,__text,coalesced,pure_instructions; \
+ .weak_definition X; \
+ FFI_HIDDEN(X)
+#elif defined __ELF__ && !(defined(__sun__) && defined(__svr4__))
+# define COMDAT(X) \
+ .section .text.X,"axG",@progbits,X,comdat; \
+ PUBLIC X; \
+ FFI_HIDDEN(X)
+#else
+# define COMDAT(X)
+#endif
+
+// #if defined(__PIC__)
+// COMDAT(C(__x86.get_pc_thunk.bx))
+// C(__x86.get_pc_thunk.bx):
+// movl (%esp), %ebx
+// ret
+// ENDF(C(__x86.get_pc_thunk.bx))
+// # if defined X86_DARWIN || defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+// COMDAT(C(__x86.get_pc_thunk.dx))
+// C(__x86.get_pc_thunk.dx):
+// movl (%esp), %edx
+// ret
+// ENDF(C(__x86.get_pc_thunk.dx))
+// #endif /* DARWIN || HIDDEN */
+// #endif /* __PIC__ */
+
+#if 0
+/* Sadly, OSX cctools-as doesn't understand .cfi directives at all. */
+
+#ifdef __APPLE__
+.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
+EHFrame0:
+#elif defined(X86_WIN32)
+.section .eh_frame,"r"
+#elif defined(HAVE_AS_X86_64_UNWIND_SECTION_TYPE)
+.section .eh_frame,EH_FRAME_FLAGS,@unwind
+#else
+.section .eh_frame,EH_FRAME_FLAGS,@progbits
+#endif
+
+#ifdef HAVE_AS_X86_PCREL
+# define PCREL(X) X - .
+#else
+# define PCREL(X) X@rel
+#endif
+
+/* Simplify advancing between labels. Assume DW_CFA_advance_loc1 fits. */
+#define ADV(N, P) .byte 2, L(N)-L(P)
+
+ .balign 4
+L(CIE):
+ .set L(set0),L(ECIE)-L(SCIE)
+ .long L(set0) /* CIE Length */
+L(SCIE):
+ .long 0 /* CIE Identifier Tag */
+ .byte 1 /* CIE Version */
+ .ascii "zR\0" /* CIE Augmentation */
+ .byte 1 /* CIE Code Alignment Factor */
+ .byte 0x7c /* CIE Data Alignment Factor */
+ .byte 0x8 /* CIE RA Column */
+ .byte 1 /* Augmentation size */
+ .byte 0x1b /* FDE Encoding (pcrel sdata4) */
+ .byte 0xc, 4, 4 /* DW_CFA_def_cfa, %esp offset 4 */
+ .byte 0x80+8, 1 /* DW_CFA_offset, %eip offset 1*-4 */
+ .balign 4
+L(ECIE):
+
+ .set L(set1),L(EFDE1)-L(SFDE1)
+ .long L(set1) /* FDE Length */
+L(SFDE1):
+ .long L(SFDE1)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW0)) /* Initial location */
+ .long L(UW5)-L(UW0) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW1, UW0)
+ .byte 0xc, 5, 8 /* DW_CFA_def_cfa, %ebp 8 */
+ .byte 0x80+5, 2 /* DW_CFA_offset, %ebp 2*-4 */
+ ADV(UW2, UW1)
+ .byte 0x80+3, 0 /* DW_CFA_offset, %ebx 0*-4 */
+ ADV(UW3, UW2)
+ .byte 0xa /* DW_CFA_remember_state */
+ .byte 0xc, 4, 4 /* DW_CFA_def_cfa, %esp 4 */
+ .byte 0xc0+3 /* DW_CFA_restore, %ebx */
+ .byte 0xc0+5 /* DW_CFA_restore, %ebp */
+ ADV(UW4, UW3)
+ .byte 0xb /* DW_CFA_restore_state */
+ .balign 4
+L(EFDE1):
+
+ .set L(set2),L(EFDE2)-L(SFDE2)
+ .long L(set2) /* FDE Length */
+L(SFDE2):
+ .long L(SFDE2)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW6)) /* Initial location */
+ .long L(UW8)-L(UW6) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW7, UW6)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE2):
+
+ .set L(set3),L(EFDE3)-L(SFDE3)
+ .long L(set3) /* FDE Length */
+L(SFDE3):
+ .long L(SFDE3)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW9)) /* Initial location */
+ .long L(UW11)-L(UW9) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW10, UW9)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE3):
+
+ .set L(set4),L(EFDE4)-L(SFDE4)
+ .long L(set4) /* FDE Length */
+L(SFDE4):
+ .long L(SFDE4)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW12)) /* Initial location */
+ .long L(UW20)-L(UW12) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW13, UW12)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+#ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX
+ ADV(UW14, UW13)
+ .byte 0x80+3, (40-(closure_FS+4))/-4 /* DW_CFA_offset %ebx */
+ ADV(UW15, UW14)
+ .byte 0xc0+3 /* DW_CFA_restore %ebx */
+ ADV(UW16, UW15)
+#else
+ ADV(UW16, UW13)
+#endif
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW17, UW16)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ ADV(UW18, UW17)
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW19, UW18)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE4):
+
+ .set L(set5),L(EFDE5)-L(SFDE5)
+ .long L(set5) /* FDE Length */
+L(SFDE5):
+ .long L(SFDE5)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW21)) /* Initial location */
+ .long L(UW23)-L(UW21) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW22, UW21)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE5):
+
+ .set L(set6),L(EFDE6)-L(SFDE6)
+ .long L(set6) /* FDE Length */
+L(SFDE6):
+ .long L(SFDE6)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW24)) /* Initial location */
+ .long L(UW26)-L(UW24) /* Address range */
+ .byte 0 /* Augmentation size */
+ .byte 0xe, 8 /* DW_CFA_def_cfa_offset */
+ .byte 0x80+8, 2 /* DW_CFA_offset %eip, 2*-4 */
+ ADV(UW25, UW24)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE6):
+
+ .set L(set7),L(EFDE7)-L(SFDE7)
+ .long L(set7) /* FDE Length */
+L(SFDE7):
+ .long L(SFDE7)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW27)) /* Initial location */
+ .long L(UW31)-L(UW27) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW28, UW27)
+ .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */
+#ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX
+ ADV(UW29, UW28)
+ .byte 0x80+3, (40-(closure_FS+4))/-4 /* DW_CFA_offset %ebx */
+ ADV(UW30, UW29)
+ .byte 0xc0+3 /* DW_CFA_restore %ebx */
+#endif
+ .balign 4
+L(EFDE7):
+
+#if !FFI_NO_RAW_API
+ .set L(set8),L(EFDE8)-L(SFDE8)
+ .long L(set8) /* FDE Length */
+L(SFDE8):
+ .long L(SFDE8)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW32)) /* Initial location */
+ .long L(UW40)-L(UW32) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW33, UW32)
+ .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */
+ ADV(UW34, UW33)
+ .byte 0x80+3, 2 /* DW_CFA_offset %ebx 2*-4 */
+ ADV(UW35, UW34)
+ .byte 0xc0+3 /* DW_CFA_restore %ebx */
+ ADV(UW36, UW35)
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW37, UW36)
+ .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */
+ ADV(UW38, UW37)
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW39, UW38)
+ .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE8):
+
+ .set L(set9),L(EFDE9)-L(SFDE9)
+ .long L(set9) /* FDE Length */
+L(SFDE9):
+ .long L(SFDE9)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW41)) /* Initial location */
+ .long L(UW52)-L(UW41) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW42, UW41)
+ .byte 0xe, 0 /* DW_CFA_def_cfa_offset */
+ .byte 0x9, 8, 2 /* DW_CFA_register %eip, %edx */
+ ADV(UW43, UW42)
+ .byte 0xe, 4 /* DW_CFA_def_cfa_offset */
+ ADV(UW44, UW43)
+ .byte 0xe, 8 /* DW_CFA_def_cfa_offset */
+ .byte 0x80+8, 2 /* DW_CFA_offset %eip 2*-4 */
+ ADV(UW45, UW44)
+ .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */
+ ADV(UW46, UW45)
+ .byte 0x80+3, 3 /* DW_CFA_offset %ebx 3*-4 */
+ ADV(UW47, UW46)
+ .byte 0xc0+3 /* DW_CFA_restore %ebx */
+ ADV(UW48, UW47)
+ .byte 0xe, 8 /* DW_CFA_def_cfa_offset */
+ ADV(UW49, UW48)
+ .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */
+ ADV(UW50, UW49)
+ .byte 0xe, 8 /* DW_CFA_def_cfa_offset */
+ ADV(UW51, UW50)
+ .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */
+ .balign 4
+L(EFDE9):
+#endif /* !FFI_NO_RAW_API */
+
+#ifdef _WIN32
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ PUBLIC @feat.00
+@feat.00 = 1
+#endif
+
+#endif /* ifndef _MSC_VER */
+#endif /* ifndef __x86_64__ */
+
+#if defined __ELF__ && defined __linux__
+ .section .note.GNU-stack,"",@progbits
+#endif
+#endif
+
+END \ No newline at end of file
diff --git a/src/x86/unix64.S b/src/x86/unix64.S
index dcd6bc71..41563f5c 100644
--- a/src/x86/unix64.S
+++ b/src/x86/unix64.S
@@ -30,8 +30,20 @@
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
+#include "internal64.h"
+#include "asmnames.h"
-.text
+ .text
+
+/* This macro allows the safe creation of jump tables without an
+ actual table. The entry points into the table are all 8 bytes.
+ The use of ORG asserts that we're at the correct location. */
+/* ??? The clang assembler doesn't handle .org with symbolic expressions. */
+#if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
+# define E(BASE, X) .balign 8
+#else
+# define E(BASE, X) .balign 8; .org BASE + X * 8
+#endif
/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
void *raddr, void (*fnaddr)(void));
@@ -40,12 +52,12 @@
for this function. This has been allocated by ffi_call. We also
deallocate some of the stack that has been alloca'd. */
- .align 2
- .globl ffi_call_unix64
- .type ffi_call_unix64,@function
+ .balign 8
+ .globl C(ffi_call_unix64)
+ FFI_HIDDEN(C(ffi_call_unix64))
-ffi_call_unix64:
-.LUW0:
+C(ffi_call_unix64):
+L(UW0):
movq (%rsp), %r10 /* Load return address. */
leaq (%rdi, %rsi), %rax /* Find local stack base. */
movq %rdx, (%rax) /* Save flags. */
@@ -53,24 +65,37 @@ ffi_call_unix64:
movq %rbp, 16(%rax) /* Save old frame pointer. */
movq %r10, 24(%rax) /* Relocate return address. */
movq %rax, %rbp /* Finalize local stack frame. */
-.LUW1:
+
+ /* New stack frame based off rbp. This is a itty bit of unwind
+ trickery in that the CFA *has* changed. There is no easy way
+ to describe it correctly on entry to the function. Fortunately,
+ it doesn't matter too much since at all points we can correctly
+ unwind back to ffi_call. Note that the location to which we
+ moved the return address is (the new) CFA-8, so from the
+ perspective of the unwind info, it hasn't moved. */
+L(UW1):
+ /* cfi_def_cfa(%rbp, 32) */
+ /* cfi_rel_offset(%rbp, 16) */
+
movq %rdi, %r10 /* Save a copy of the register area. */
movq %r8, %r11 /* Save a copy of the target fn. */
movl %r9d, %eax /* Set number of SSE registers. */
/* Load up all argument registers. */
movq (%r10), %rdi
- movq 8(%r10), %rsi
- movq 16(%r10), %rdx
- movq 24(%r10), %rcx
- movq 32(%r10), %r8
- movq 40(%r10), %r9
+ movq 0x08(%r10), %rsi
+ movq 0x10(%r10), %rdx
+ movq 0x18(%r10), %rcx
+ movq 0x20(%r10), %r8
+ movq 0x28(%r10), %r9
+ movl 0xb0(%r10), %eax
testl %eax, %eax
- jnz .Lload_sse
-.Lret_from_load_sse:
+ jnz L(load_sse)
+L(ret_from_load_sse):
- /* Deallocate the reg arg area. */
- leaq 176(%r10), %rsp
+ /* Deallocate the reg arg area, except for r10, then load via pop. */
+ leaq 0xb8(%r10), %rsp
+ popq %r10
/* Call the user function. */
call *%r11
@@ -81,352 +106,461 @@ ffi_call_unix64:
movq 0(%rbp), %rcx /* Reload flags. */
movq 8(%rbp), %rdi /* Reload raddr. */
movq 16(%rbp), %rbp /* Reload old frame pointer. */
-.LUW2:
+L(UW2):
+ /* cfi_remember_state */
+ /* cfi_def_cfa(%rsp, 8) */
+ /* cfi_restore(%rbp) */
/* The first byte of the flags contains the FFI_TYPE. */
+ cmpb $UNIX64_RET_LAST, %cl
movzbl %cl, %r10d
- leaq .Lstore_table(%rip), %r11
- movslq (%r11, %r10, 4), %r10
- addq %r11, %r10
+ leaq L(store_table)(%rip), %r11
+ ja L(sa)
+ leaq (%r11, %r10, 8), %r10
+
+ /* Prep for the structure cases: scratch area in redzone. */
+ leaq -20(%rsp), %rsi
jmp *%r10
-.Lstore_table:
- .long .Lst_void-.Lstore_table /* FFI_TYPE_VOID */
- .long .Lst_sint32-.Lstore_table /* FFI_TYPE_INT */
- .long .Lst_float-.Lstore_table /* FFI_TYPE_FLOAT */
- .long .Lst_double-.Lstore_table /* FFI_TYPE_DOUBLE */
- .long .Lst_ldouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */
- .long .Lst_uint8-.Lstore_table /* FFI_TYPE_UINT8 */
- .long .Lst_sint8-.Lstore_table /* FFI_TYPE_SINT8 */
- .long .Lst_uint16-.Lstore_table /* FFI_TYPE_UINT16 */
- .long .Lst_sint16-.Lstore_table /* FFI_TYPE_SINT16 */
- .long .Lst_uint32-.Lstore_table /* FFI_TYPE_UINT32 */
- .long .Lst_sint32-.Lstore_table /* FFI_TYPE_SINT32 */
- .long .Lst_int64-.Lstore_table /* FFI_TYPE_UINT64 */
- .long .Lst_int64-.Lstore_table /* FFI_TYPE_SINT64 */
- .long .Lst_struct-.Lstore_table /* FFI_TYPE_STRUCT */
- .long .Lst_int64-.Lstore_table /* FFI_TYPE_POINTER */
-
- .align 2
-.Lst_void:
+ .balign 8
+L(store_table):
+E(L(store_table), UNIX64_RET_VOID)
ret
- .align 2
-
-.Lst_uint8:
- movzbq %al, %rax
+E(L(store_table), UNIX64_RET_UINT8)
+ movzbl %al, %eax
movq %rax, (%rdi)
ret
- .align 2
-.Lst_sint8:
- movsbq %al, %rax
+E(L(store_table), UNIX64_RET_UINT16)
+ movzwl %ax, %eax
movq %rax, (%rdi)
ret
- .align 2
-.Lst_uint16:
- movzwq %ax, %rax
+E(L(store_table), UNIX64_RET_UINT32)
+ movl %eax, %eax
movq %rax, (%rdi)
- .align 2
-.Lst_sint16:
- movswq %ax, %rax
+ ret
+E(L(store_table), UNIX64_RET_SINT8)
+ movsbq %al, %rax
movq %rax, (%rdi)
ret
- .align 2
-.Lst_uint32:
- movl %eax, %eax
+E(L(store_table), UNIX64_RET_SINT16)
+ movswq %ax, %rax
movq %rax, (%rdi)
- .align 2
-.Lst_sint32:
+ ret
+E(L(store_table), UNIX64_RET_SINT32)
cltq
movq %rax, (%rdi)
ret
- .align 2
-.Lst_int64:
+E(L(store_table), UNIX64_RET_INT64)
movq %rax, (%rdi)
ret
-
- .align 2
-.Lst_float:
- movss %xmm0, (%rdi)
+E(L(store_table), UNIX64_RET_XMM32)
+ movd %xmm0, (%rdi)
ret
- .align 2
-.Lst_double:
- movsd %xmm0, (%rdi)
+E(L(store_table), UNIX64_RET_XMM64)
+ movq %xmm0, (%rdi)
ret
-.Lst_ldouble:
+E(L(store_table), UNIX64_RET_X87)
fstpt (%rdi)
ret
-
- .align 2
-.Lst_struct:
- leaq -20(%rsp), %rsi /* Scratch area in redzone. */
-
- /* We have to locate the values now, and since we don't want to
- write too much data into the user's return value, we spill the
- value to a 16 byte scratch area first. Bits 8, 9, and 10
- control where the values are located. Only one of the three
- bits will be set; see ffi_prep_cif_machdep for the pattern. */
- movd %xmm0, %r10
- movd %xmm1, %r11
- testl $0x100, %ecx
- cmovnz %rax, %rdx
- cmovnz %r10, %rax
- testl $0x200, %ecx
- cmovnz %r10, %rdx
- testl $0x400, %ecx
- cmovnz %r10, %rax
- cmovnz %r11, %rdx
- movq %rax, (%rsi)
+E(L(store_table), UNIX64_RET_X87_2)
+ fstpt (%rdi)
+ fstpt 16(%rdi)
+ ret
+E(L(store_table), UNIX64_RET_ST_XMM0_RAX)
+ movq %rax, 8(%rsi)
+ jmp L(s3)
+E(L(store_table), UNIX64_RET_ST_RAX_XMM0)
+ movq %xmm0, 8(%rsi)
+ jmp L(s2)
+E(L(store_table), UNIX64_RET_ST_XMM0_XMM1)
+ movq %xmm1, 8(%rsi)
+ jmp L(s3)
+E(L(store_table), UNIX64_RET_ST_RAX_RDX)
movq %rdx, 8(%rsi)
-
- /* Bits 12-31 contain the true size of the structure. Copy from
- the scratch area to the true destination. */
- shrl $12, %ecx
+L(s2):
+ movq %rax, (%rsi)
+ shrl $UNIX64_SIZE_SHIFT, %ecx
rep movsb
ret
+ .balign 8
+L(s3):
+ movq %xmm0, (%rsi)
+ shrl $UNIX64_SIZE_SHIFT, %ecx
+ rep movsb
+ ret
+
+L(sa): call PLT(C(abort))
/* Many times we can avoid loading any SSE registers at all.
It's not worth an indirect jump to load the exact set of
SSE registers needed; zero or all is a good compromise. */
- .align 2
-.LUW3:
-.Lload_sse:
- movdqa 48(%r10), %xmm0
- movdqa 64(%r10), %xmm1
- movdqa 80(%r10), %xmm2
- movdqa 96(%r10), %xmm3
- movdqa 112(%r10), %xmm4
- movdqa 128(%r10), %xmm5
- movdqa 144(%r10), %xmm6
- movdqa 160(%r10), %xmm7
- jmp .Lret_from_load_sse
-
-.LUW4:
- .size ffi_call_unix64,.-ffi_call_unix64
-
- .align 2
- .globl ffi_closure_unix64
- .type ffi_closure_unix64,@function
-
-ffi_closure_unix64:
-.LUW5:
- /* The carry flag is set by the trampoline iff SSE registers
- are used. Don't clobber it before the branch instruction. */
- leaq -200(%rsp), %rsp
-.LUW6:
- movq %rdi, (%rsp)
- movq %rsi, 8(%rsp)
- movq %rdx, 16(%rsp)
- movq %rcx, 24(%rsp)
- movq %r8, 32(%rsp)
- movq %r9, 40(%rsp)
- jc .Lsave_sse
-.Lret_from_save_sse:
-
- movq %r10, %rdi
- leaq 176(%rsp), %rsi
- movq %rsp, %rdx
- leaq 208(%rsp), %rcx
- call ffi_closure_unix64_inner@PLT
+ .balign 2
+L(UW3):
+ /* cfi_restore_state */
+L(load_sse):
+ movdqa 0x30(%r10), %xmm0
+ movdqa 0x40(%r10), %xmm1
+ movdqa 0x50(%r10), %xmm2
+ movdqa 0x60(%r10), %xmm3
+ movdqa 0x70(%r10), %xmm4
+ movdqa 0x80(%r10), %xmm5
+ movdqa 0x90(%r10), %xmm6
+ movdqa 0xa0(%r10), %xmm7
+ jmp L(ret_from_load_sse)
+
+L(UW4):
+ENDF(C(ffi_call_unix64))
+
+/* 6 general registers, 8 vector registers,
+ 32 bytes of rvalue, 8 bytes of alignment. */
+#define ffi_closure_OFS_G 0
+#define ffi_closure_OFS_V (6*8)
+#define ffi_closure_OFS_RVALUE (ffi_closure_OFS_V + 8*16)
+#define ffi_closure_FS (ffi_closure_OFS_RVALUE + 32 + 8)
+
+/* The location of rvalue within the red zone after deallocating the frame. */
+#define ffi_closure_RED_RVALUE (ffi_closure_OFS_RVALUE - ffi_closure_FS)
+
+ .balign 2
+ .globl C(ffi_closure_unix64_sse)
+ FFI_HIDDEN(C(ffi_closure_unix64_sse))
+
+C(ffi_closure_unix64_sse):
+L(UW5):
+ subq $ffi_closure_FS, %rsp
+L(UW6):
+ /* cfi_adjust_cfa_offset(ffi_closure_FS) */
+
+ movdqa %xmm0, ffi_closure_OFS_V+0x00(%rsp)
+ movdqa %xmm1, ffi_closure_OFS_V+0x10(%rsp)
+ movdqa %xmm2, ffi_closure_OFS_V+0x20(%rsp)
+ movdqa %xmm3, ffi_closure_OFS_V+0x30(%rsp)
+ movdqa %xmm4, ffi_closure_OFS_V+0x40(%rsp)
+ movdqa %xmm5, ffi_closure_OFS_V+0x50(%rsp)
+ movdqa %xmm6, ffi_closure_OFS_V+0x60(%rsp)
+ movdqa %xmm7, ffi_closure_OFS_V+0x70(%rsp)
+ jmp L(sse_entry1)
+
+L(UW7):
+ENDF(C(ffi_closure_unix64_sse))
+
+ .balign 2
+ .globl C(ffi_closure_unix64)
+ FFI_HIDDEN(C(ffi_closure_unix64))
+
+C(ffi_closure_unix64):
+L(UW8):
+ subq $ffi_closure_FS, %rsp
+L(UW9):
+ /* cfi_adjust_cfa_offset(ffi_closure_FS) */
+L(sse_entry1):
+ movq %rdi, ffi_closure_OFS_G+0x00(%rsp)
+ movq %rsi, ffi_closure_OFS_G+0x08(%rsp)
+ movq %rdx, ffi_closure_OFS_G+0x10(%rsp)
+ movq %rcx, ffi_closure_OFS_G+0x18(%rsp)
+ movq %r8, ffi_closure_OFS_G+0x20(%rsp)
+ movq %r9, ffi_closure_OFS_G+0x28(%rsp)
+
+#ifdef __ILP32__
+ movl FFI_TRAMPOLINE_SIZE(%r10), %edi /* Load cif */
+ movl FFI_TRAMPOLINE_SIZE+4(%r10), %esi /* Load fun */
+ movl FFI_TRAMPOLINE_SIZE+8(%r10), %edx /* Load user_data */
+#else
+ movq FFI_TRAMPOLINE_SIZE(%r10), %rdi /* Load cif */
+ movq FFI_TRAMPOLINE_SIZE+8(%r10), %rsi /* Load fun */
+ movq FFI_TRAMPOLINE_SIZE+16(%r10), %rdx /* Load user_data */
+#endif
+L(do_closure):
+ leaq ffi_closure_OFS_RVALUE(%rsp), %rcx /* Load rvalue */
+ movq %rsp, %r8 /* Load reg_args */
+ leaq ffi_closure_FS+8(%rsp), %r9 /* Load argp */
+ call PLT(C(ffi_closure_unix64_inner))
/* Deallocate stack frame early; return value is now in redzone. */
- addq $200, %rsp
-.LUW7:
+ addq $ffi_closure_FS, %rsp
+L(UW10):
+ /* cfi_adjust_cfa_offset(-ffi_closure_FS) */
/* The first byte of the return value contains the FFI_TYPE. */
+ cmpb $UNIX64_RET_LAST, %al
movzbl %al, %r10d
- leaq .Lload_table(%rip), %r11
- movslq (%r11, %r10, 4), %r10
- addq %r11, %r10
+ leaq L(load_table)(%rip), %r11
+ ja L(la)
+ leaq (%r11, %r10, 8), %r10
+ leaq ffi_closure_RED_RVALUE(%rsp), %rsi
jmp *%r10
-.Lload_table:
- .long .Lld_void-.Lload_table /* FFI_TYPE_VOID */
- .long .Lld_int32-.Lload_table /* FFI_TYPE_INT */
- .long .Lld_float-.Lload_table /* FFI_TYPE_FLOAT */
- .long .Lld_double-.Lload_table /* FFI_TYPE_DOUBLE */
- .long .Lld_ldouble-.Lload_table /* FFI_TYPE_LONGDOUBLE */
- .long .Lld_int8-.Lload_table /* FFI_TYPE_UINT8 */
- .long .Lld_int8-.Lload_table /* FFI_TYPE_SINT8 */
- .long .Lld_int16-.Lload_table /* FFI_TYPE_UINT16 */
- .long .Lld_int16-.Lload_table /* FFI_TYPE_SINT16 */
- .long .Lld_int32-.Lload_table /* FFI_TYPE_UINT32 */
- .long .Lld_int32-.Lload_table /* FFI_TYPE_SINT32 */
- .long .Lld_int64-.Lload_table /* FFI_TYPE_UINT64 */
- .long .Lld_int64-.Lload_table /* FFI_TYPE_SINT64 */
- .long .Lld_struct-.Lload_table /* FFI_TYPE_STRUCT */
- .long .Lld_int64-.Lload_table /* FFI_TYPE_POINTER */
-
- .align 2
-.Lld_void:
+ .balign 8
+L(load_table):
+E(L(load_table), UNIX64_RET_VOID)
ret
-
- .align 2
-.Lld_int8:
- movzbl -24(%rsp), %eax
+E(L(load_table), UNIX64_RET_UINT8)
+ movzbl (%rsi), %eax
ret
- .align 2
-.Lld_int16:
- movzwl -24(%rsp), %eax
+E(L(load_table), UNIX64_RET_UINT16)
+ movzwl (%rsi), %eax
ret
- .align 2
-.Lld_int32:
- movl -24(%rsp), %eax
+E(L(load_table), UNIX64_RET_UINT32)
+ movl (%rsi), %eax
ret
- .align 2
-.Lld_int64:
- movq -24(%rsp), %rax
+E(L(load_table), UNIX64_RET_SINT8)
+ movsbl (%rsi), %eax
ret
-
- .align 2
-.Lld_float:
- movss -24(%rsp), %xmm0
+E(L(load_table), UNIX64_RET_SINT16)
+ movswl (%rsi), %eax
ret
- .align 2
-.Lld_double:
- movsd -24(%rsp), %xmm0
+E(L(load_table), UNIX64_RET_SINT32)
+ movl (%rsi), %eax
ret
- .align 2
-.Lld_ldouble:
- fldt -24(%rsp)
+E(L(load_table), UNIX64_RET_INT64)
+ movq (%rsi), %rax
ret
-
- .align 2
-.Lld_struct:
- /* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
- %rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading
- both rdx and xmm1 with the second word. For the remaining,
- bit 8 set means xmm0 gets the second word, and bit 9 means
- that rax gets the second word. */
- movq -24(%rsp), %rcx
- movq -16(%rsp), %rdx
- movq -16(%rsp), %xmm1
- testl $0x100, %eax
- cmovnz %rdx, %rcx
- movd %rcx, %xmm0
- testl $0x200, %eax
- movq -24(%rsp), %rax
- cmovnz %rdx, %rax
+E(L(load_table), UNIX64_RET_XMM32)
+ movd (%rsi), %xmm0
+ ret
+E(L(load_table), UNIX64_RET_XMM64)
+ movq (%rsi), %xmm0
+ ret
+E(L(load_table), UNIX64_RET_X87)
+ fldt (%rsi)
+ ret
+E(L(load_table), UNIX64_RET_X87_2)
+ fldt 16(%rsi)
+ fldt (%rsi)
+ ret
+E(L(load_table), UNIX64_RET_ST_XMM0_RAX)
+ movq 8(%rsi), %rax
+ jmp L(l3)
+E(L(load_table), UNIX64_RET_ST_RAX_XMM0)
+ movq 8(%rsi), %xmm0
+ jmp L(l2)
+E(L(load_table), UNIX64_RET_ST_XMM0_XMM1)
+ movq 8(%rsi), %xmm1
+ jmp L(l3)
+E(L(load_table), UNIX64_RET_ST_RAX_RDX)
+ movq 8(%rsi), %rdx
+L(l2):
+ movq (%rsi), %rax
+ ret
+ .balign 8
+L(l3):
+ movq (%rsi), %xmm0
ret
- /* See the comment above .Lload_sse; the same logic applies here. */
- .align 2
-.LUW8:
-.Lsave_sse:
- movdqa %xmm0, 48(%rsp)
- movdqa %xmm1, 64(%rsp)
- movdqa %xmm2, 80(%rsp)
- movdqa %xmm3, 96(%rsp)
- movdqa %xmm4, 112(%rsp)
- movdqa %xmm5, 128(%rsp)
- movdqa %xmm6, 144(%rsp)
- movdqa %xmm7, 160(%rsp)
- jmp .Lret_from_save_sse
-
-.LUW9:
- .size ffi_closure_unix64,.-ffi_closure_unix64
-
-#ifdef __GNUC__
-/* Only emit DWARF unwind info when building with the GNU toolchain. */
-
-#ifdef HAVE_AS_X86_64_UNWIND_SECTION_TYPE
- .section .eh_frame,"a",@unwind
-#else
- .section .eh_frame,"a",@progbits
-#endif
-.Lframe1:
- .long .LECIE1-.LSCIE1 /* CIE Length */
-.LSCIE1:
- .long 0 /* CIE Identifier Tag */
- .byte 1 /* CIE Version */
- .ascii "zR\0" /* CIE Augmentation */
- .uleb128 1 /* CIE Code Alignment Factor */
- .sleb128 -8 /* CIE Data Alignment Factor */
- .byte 0x10 /* CIE RA Column */
- .uleb128 1 /* Augmentation size */
- .byte 0x1b /* FDE Encoding (pcrel sdata4) */
- .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
- .uleb128 7
- .uleb128 8
- .byte 0x80+16 /* DW_CFA_offset, %rip offset 1*-8 */
- .uleb128 1
- .align 8
-.LECIE1:
-.LSFDE1:
- .long .LEFDE1-.LASFDE1 /* FDE Length */
-.LASFDE1:
- .long .LASFDE1-.Lframe1 /* FDE CIE offset */
-#if HAVE_AS_X86_PCREL
- .long .LUW0-. /* FDE initial location */
+L(la): call PLT(C(abort))
+
+L(UW11):
+ENDF(C(ffi_closure_unix64))
+
+ .balign 2
+ .globl C(ffi_go_closure_unix64_sse)
+ FFI_HIDDEN(C(ffi_go_closure_unix64_sse))
+
+C(ffi_go_closure_unix64_sse):
+L(UW12):
+ subq $ffi_closure_FS, %rsp
+L(UW13):
+ /* cfi_adjust_cfa_offset(ffi_closure_FS) */
+
+ movdqa %xmm0, ffi_closure_OFS_V+0x00(%rsp)
+ movdqa %xmm1, ffi_closure_OFS_V+0x10(%rsp)
+ movdqa %xmm2, ffi_closure_OFS_V+0x20(%rsp)
+ movdqa %xmm3, ffi_closure_OFS_V+0x30(%rsp)
+ movdqa %xmm4, ffi_closure_OFS_V+0x40(%rsp)
+ movdqa %xmm5, ffi_closure_OFS_V+0x50(%rsp)
+ movdqa %xmm6, ffi_closure_OFS_V+0x60(%rsp)
+ movdqa %xmm7, ffi_closure_OFS_V+0x70(%rsp)
+ jmp L(sse_entry2)
+
+L(UW14):
+ENDF(C(ffi_go_closure_unix64_sse))
+
+ .balign 2
+ .globl C(ffi_go_closure_unix64)
+ FFI_HIDDEN(C(ffi_go_closure_unix64))
+
+C(ffi_go_closure_unix64):
+L(UW15):
+ subq $ffi_closure_FS, %rsp
+L(UW16):
+ /* cfi_adjust_cfa_offset(ffi_closure_FS) */
+L(sse_entry2):
+ movq %rdi, ffi_closure_OFS_G+0x00(%rsp)
+ movq %rsi, ffi_closure_OFS_G+0x08(%rsp)
+ movq %rdx, ffi_closure_OFS_G+0x10(%rsp)
+ movq %rcx, ffi_closure_OFS_G+0x18(%rsp)
+ movq %r8, ffi_closure_OFS_G+0x20(%rsp)
+ movq %r9, ffi_closure_OFS_G+0x28(%rsp)
+
+#ifdef __ILP32__
+ movl 4(%r10), %edi /* Load cif */
+ movl 8(%r10), %esi /* Load fun */
+ movl %r10d, %edx /* Load closure (user_data) */
#else
- .long .LUW0@rel
+ movq 8(%r10), %rdi /* Load cif */
+ movq 16(%r10), %rsi /* Load fun */
+ movq %r10, %rdx /* Load closure (user_data) */
#endif
- .long .LUW4-.LUW0 /* FDE address range */
- .uleb128 0x0 /* Augmentation size */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LUW1-.LUW0
+ jmp L(do_closure)
- /* New stack frame based off rbp. This is a itty bit of unwind
- trickery in that the CFA *has* changed. There is no easy way
- to describe it correctly on entry to the function. Fortunately,
- it doesn't matter too much since at all points we can correctly
- unwind back to ffi_call. Note that the location to which we
- moved the return address is (the new) CFA-8, so from the
- perspective of the unwind info, it hasn't moved. */
- .byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */
- .uleb128 6
- .uleb128 32
- .byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */
- .uleb128 2
- .byte 0xa /* DW_CFA_remember_state */
+L(UW17):
+ENDF(C(ffi_go_closure_unix64))
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LUW2-.LUW1
- .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
- .uleb128 7
- .uleb128 8
- .byte 0xc0+6 /* DW_CFA_restore, %rbp */
+/* Sadly, OSX cctools-as doesn't understand .cfi directives at all. */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LUW3-.LUW2
- .byte 0xb /* DW_CFA_restore_state */
-
- .align 8
-.LEFDE1:
-.LSFDE3:
- .long .LEFDE3-.LASFDE3 /* FDE Length */
-.LASFDE3:
- .long .LASFDE3-.Lframe1 /* FDE CIE offset */
-#if HAVE_AS_X86_PCREL
- .long .LUW5-. /* FDE initial location */
+#ifdef __APPLE__
+.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
+EHFrame0:
+#elif defined(HAVE_AS_X86_64_UNWIND_SECTION_TYPE)
+.section .eh_frame,"a",@unwind
#else
- .long .LUW5@rel
+.section .eh_frame,"a",@progbits
#endif
- .long .LUW9-.LUW5 /* FDE address range */
- .uleb128 0x0 /* Augmentation size */
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LUW6-.LUW5
- .byte 0xe /* DW_CFA_def_cfa_offset */
- .uleb128 208
- .byte 0xa /* DW_CFA_remember_state */
+#ifdef HAVE_AS_X86_PCREL
+# define PCREL(X) X - .
+#else
+# define PCREL(X) X@rel
+#endif
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LUW7-.LUW6
- .byte 0xe /* DW_CFA_def_cfa_offset */
- .uleb128 8
+/* Simplify advancing between labels. Assume DW_CFA_advance_loc1 fits. */
+#define ADV(N, P) .byte 2, L(N)-L(P)
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LUW8-.LUW7
+ .balign 8
+L(CIE):
+ .set L(set0),L(ECIE)-L(SCIE)
+ .long L(set0) /* CIE Length */
+L(SCIE):
+ .long 0 /* CIE Identifier Tag */
+ .byte 1 /* CIE Version */
+ .ascii "zR\0" /* CIE Augmentation */
+ .byte 1 /* CIE Code Alignment Factor */
+ .byte 0x78 /* CIE Data Alignment Factor */
+ .byte 0x10 /* CIE RA Column */
+ .byte 1 /* Augmentation size */
+ .byte 0x1b /* FDE Encoding (pcrel sdata4) */
+ .byte 0xc, 7, 8 /* DW_CFA_def_cfa, %rsp offset 8 */
+ .byte 0x80+16, 1 /* DW_CFA_offset, %rip offset 1*-8 */
+ .balign 8
+L(ECIE):
+
+ .set L(set1),L(EFDE1)-L(SFDE1)
+ .long L(set1) /* FDE Length */
+L(SFDE1):
+ .long L(SFDE1)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW0)) /* Initial location */
+ .long L(UW4)-L(UW0) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW1, UW0)
+ .byte 0xc, 6, 32 /* DW_CFA_def_cfa, %rbp 32 */
+ .byte 0x80+6, 2 /* DW_CFA_offset, %rbp 2*-8 */
+ ADV(UW2, UW1)
+ .byte 0xa /* DW_CFA_remember_state */
+ .byte 0xc, 7, 8 /* DW_CFA_def_cfa, %rsp 8 */
+ .byte 0xc0+6 /* DW_CFA_restore, %rbp */
+ ADV(UW3, UW2)
.byte 0xb /* DW_CFA_restore_state */
+ .balign 8
+L(EFDE1):
+
+ .set L(set2),L(EFDE2)-L(SFDE2)
+ .long L(set2) /* FDE Length */
+L(SFDE2):
+ .long L(SFDE2)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW5)) /* Initial location */
+ .long L(UW7)-L(UW5) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW6, UW5)
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */
+ .balign 8
+L(EFDE2):
+
+ .set L(set3),L(EFDE3)-L(SFDE3)
+ .long L(set3) /* FDE Length */
+L(SFDE3):
+ .long L(SFDE3)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW8)) /* Initial location */
+ .long L(UW11)-L(UW8) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW9, UW8)
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */
+ ADV(UW10, UW9)
+ .byte 0xe, 8 /* DW_CFA_def_cfa_offset 8 */
+L(EFDE3):
+
+ .set L(set4),L(EFDE4)-L(SFDE4)
+ .long L(set4) /* FDE Length */
+L(SFDE4):
+ .long L(SFDE4)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW12)) /* Initial location */
+ .long L(UW14)-L(UW12) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW13, UW12)
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */
+ .balign 8
+L(EFDE4):
+
+ .set L(set5),L(EFDE5)-L(SFDE5)
+ .long L(set5) /* FDE Length */
+L(SFDE5):
+ .long L(SFDE5)-L(CIE) /* FDE CIE offset */
+ .long PCREL(L(UW15)) /* Initial location */
+ .long L(UW17)-L(UW15) /* Address range */
+ .byte 0 /* Augmentation size */
+ ADV(UW16, UW15)
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */
+ .balign 8
+L(EFDE5):
+#ifdef __APPLE__
+ .subsections_via_symbols
+ .section __LD,__compact_unwind,regular,debug
+
+ /* compact unwind for ffi_call_unix64 */
+ .quad C(ffi_call_unix64)
+ .set L1,L(UW4)-L(UW0)
+ .long L1
+ .long 0x04000000 /* use dwarf unwind info */
+ .quad 0
+ .quad 0
+
+ /* compact unwind for ffi_closure_unix64_sse */
+ .quad C(ffi_closure_unix64_sse)
+ .set L2,L(UW7)-L(UW5)
+ .long L2
+ .long 0x04000000 /* use dwarf unwind info */
+ .quad 0
+ .quad 0
+
+ /* compact unwind for ffi_closure_unix64 */
+ .quad C(ffi_closure_unix64)
+ .set L3,L(UW11)-L(UW8)
+ .long L3
+ .long 0x04000000 /* use dwarf unwind info */
+ .quad 0
+ .quad 0
+
+ /* compact unwind for ffi_go_closure_unix64_sse */
+ .quad C(ffi_go_closure_unix64_sse)
+ .set L4,L(UW14)-L(UW12)
+ .long L4
+ .long 0x04000000 /* use dwarf unwind info */
+ .quad 0
+ .quad 0
+
+ /* compact unwind for ffi_go_closure_unix64 */
+ .quad C(ffi_go_closure_unix64)
+ .set L5,L(UW17)-L(UW15)
+ .long L5
+ .long 0x04000000 /* use dwarf unwind info */
+ .quad 0
+ .quad 0
+#endif
- .align 8
-.LEFDE3:
-
-#endif /* __GNUC__ */
-
#endif /* __x86_64__ */
-
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
#endif
diff --git a/src/x86/win32.S b/src/x86/win32.S
deleted file mode 100644
index 3680bf53..00000000
--- a/src/x86/win32.S
+++ /dev/null
@@ -1,1351 +0,0 @@
-/* -----------------------------------------------------------------------
- win32.S - Copyright (c) 2014 Anthony Green
- Copyright (c) 1996, 1998, 2001, 2002, 2009 Red Hat, Inc.
- Copyright (c) 2001 John Beniton
- Copyright (c) 2002 Ranjit Mathew
- Copyright (c) 2009 Daniel Witte
-
-
- X86 Foreign Function Interface
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- ``Software''), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS 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 <fficonfig.h>
-#include <ffi.h>
-
-#define CIF_BYTES_OFFSET 16
-#define CIF_FLAGS_OFFSET 20
-
-#ifdef _MSC_VER
-
-#define CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) AND NOT 3)
-
-.386
-.MODEL FLAT, C
-
-EXTRN ffi_closure_SYSV_inner:NEAR
-EXTRN ffi_closure_WIN32_inner:NEAR
-
-_TEXT SEGMENT
-
-ffi_call_win32 PROC NEAR,
- ffi_prep_args : NEAR PTR DWORD,
- ecif : NEAR PTR DWORD,
- cif_abi : DWORD,
- cif_bytes : DWORD,
- cif_flags : DWORD,
- rvalue : NEAR PTR DWORD,
- fn : NEAR PTR DWORD
-
- ;; Make room for all of the new args.
- mov ecx, cif_bytes
- sub esp, ecx
-
- mov eax, esp
-
- ;; Call ffi_prep_args
- push ecif
- push eax
- call ffi_prep_args
- add esp, 8
-
- ;; Prepare registers
- ;; EAX stores the number of register arguments
- cmp eax, 0
- je fun
- cmp eax, 3
- jl prepr_two_cmp
-
- mov ecx, esp
- add esp, 12
- mov eax, DWORD PTR [ecx+8]
- jmp prepr_two
-prepr_two_cmp:
- cmp eax, 2
- jl prepr_one_prep
- mov ecx, esp
- add esp, 8
-prepr_two:
- mov edx, DWORD PTR [ecx+4]
- jmp prepr_one
-prepr_one_prep:
- mov ecx, esp
- add esp, 4
-prepr_one:
- mov ecx, DWORD PTR [ecx]
- cmp cif_abi, 7 ;; FFI_REGISTER
- jne fun
-
- xchg ecx, eax
-
-fun:
- ;; Call function
- call fn
-
- ;; Load ecx with the return type code
- mov ecx, cif_flags
-
- ;; If the return value pointer is NULL, assume no return value.
- cmp rvalue, 0
- jne ca_jumptable
-
- ;; Even if there is no space for the return value, we are
- ;; obliged to handle floating-point values.
- cmp ecx, FFI_TYPE_FLOAT
- jne ca_epilogue
- fstp st(0)
-
- jmp ca_epilogue
-
-ca_jumptable:
- jmp [ca_jumpdata + 4 * ecx]
-ca_jumpdata:
- ;; Do not insert anything here between label and jump table.
- dd offset ca_epilogue ;; FFI_TYPE_VOID
- dd offset ca_retint ;; FFI_TYPE_INT
- dd offset ca_retfloat ;; FFI_TYPE_FLOAT
- dd offset ca_retdouble ;; FFI_TYPE_DOUBLE
- dd offset ca_retlongdouble ;; FFI_TYPE_LONGDOUBLE
- dd offset ca_retuint8 ;; FFI_TYPE_UINT8
- dd offset ca_retsint8 ;; FFI_TYPE_SINT8
- dd offset ca_retuint16 ;; FFI_TYPE_UINT16
- dd offset ca_retsint16 ;; FFI_TYPE_SINT16
- dd offset ca_retint ;; FFI_TYPE_UINT32
- dd offset ca_retint ;; FFI_TYPE_SINT32
- dd offset ca_retint64 ;; FFI_TYPE_UINT64
- dd offset ca_retint64 ;; FFI_TYPE_SINT64
- dd offset ca_epilogue ;; FFI_TYPE_STRUCT
- dd offset ca_retint ;; FFI_TYPE_POINTER
- dd offset ca_retstruct1b ;; FFI_TYPE_SMALL_STRUCT_1B
- dd offset ca_retstruct2b ;; FFI_TYPE_SMALL_STRUCT_2B
- dd offset ca_retint ;; FFI_TYPE_SMALL_STRUCT_4B
- dd offset ca_epilogue ;; FFI_TYPE_MS_STRUCT
-
- /* Sign/zero extend as appropriate. */
-ca_retuint8:
- movzx eax, al
- jmp ca_retint
-
-ca_retsint8:
- movsx eax, al
- jmp ca_retint
-
-ca_retuint16:
- movzx eax, ax
- jmp ca_retint
-
-ca_retsint16:
- movsx eax, ax
- jmp ca_retint
-
-ca_retint:
- ;; Load %ecx with the pointer to storage for the return value
- mov ecx, rvalue
- mov [ecx + 0], eax
- jmp ca_epilogue
-
-ca_retint64:
- ;; Load %ecx with the pointer to storage for the return value
- mov ecx, rvalue
- mov [ecx + 0], eax
- mov [ecx + 4], edx
- jmp ca_epilogue
-
-ca_retfloat:
- ;; Load %ecx with the pointer to storage for the return value
- mov ecx, rvalue
- fstp DWORD PTR [ecx]
- jmp ca_epilogue
-
-ca_retdouble:
- ;; Load %ecx with the pointer to storage for the return value
- mov ecx, rvalue
- fstp QWORD PTR [ecx]
- jmp ca_epilogue
-
-ca_retlongdouble:
- ;; Load %ecx with the pointer to storage for the return value
- mov ecx, rvalue
- fstp TBYTE PTR [ecx]
- jmp ca_epilogue
-
-ca_retstruct1b:
- ;; Load %ecx with the pointer to storage for the return value
- mov ecx, rvalue
- mov [ecx + 0], al
- jmp ca_epilogue
-
-ca_retstruct2b:
- ;; Load %ecx with the pointer to storage for the return value
- mov ecx, rvalue
- mov [ecx + 0], ax
- jmp ca_epilogue
-
-ca_epilogue:
- ;; Epilogue code is autogenerated.
- ret
-ffi_call_win32 ENDP
-
-ffi_closure_THISCALL PROC NEAR
- ;; Insert the register argument on the stack as the first argument
- xchg DWORD PTR [esp+4], ecx
- xchg DWORD PTR [esp], ecx
- push ecx
- jmp ffi_closure_STDCALL
-ffi_closure_THISCALL ENDP
-
-ffi_closure_FASTCALL PROC NEAR
- ;; Insert the 2 register arguments on the stack as the first argument
- xchg DWORD PTR [esp+4], edx
- xchg DWORD PTR [esp], ecx
- push edx
- push ecx
- jmp ffi_closure_STDCALL
-ffi_closure_FASTCALL ENDP
-
-ffi_closure_REGISTER PROC NEAR
- ;; Insert the 3 register arguments on the stack as the first argument
- push eax
- xchg DWORD PTR [esp+8], ecx
- xchg DWORD PTR [esp+4], edx
- push ecx
- push edx
- jmp ffi_closure_STDCALL
-ffi_closure_REGISTER ENDP
-
-ffi_closure_SYSV PROC NEAR FORCEFRAME
- ;; the ffi_closure ctx is passed in eax by the trampoline.
-
- sub esp, 40
- lea edx, [ebp - 24]
- mov [ebp - 12], edx ;; resp
- lea edx, [ebp + 8]
-stub::
- mov [esp + 8], edx ;; args
- lea edx, [ebp - 12]
- mov [esp + 4], edx ;; &resp
- mov [esp], eax ;; closure
- call ffi_closure_SYSV_inner
- mov ecx, [ebp - 12]
-
-cs_jumptable:
- jmp [cs_jumpdata + 4 * eax]
-cs_jumpdata:
- ;; Do not insert anything here between the label and jump table.
- dd offset cs_epilogue ;; FFI_TYPE_VOID
- dd offset cs_retint ;; FFI_TYPE_INT
- dd offset cs_retfloat ;; FFI_TYPE_FLOAT
- dd offset cs_retdouble ;; FFI_TYPE_DOUBLE
- dd offset cs_retlongdouble ;; FFI_TYPE_LONGDOUBLE
- dd offset cs_retuint8 ;; FFI_TYPE_UINT8
- dd offset cs_retsint8 ;; FFI_TYPE_SINT8
- dd offset cs_retuint16 ;; FFI_TYPE_UINT16
- dd offset cs_retsint16 ;; FFI_TYPE_SINT16
- dd offset cs_retint ;; FFI_TYPE_UINT32
- dd offset cs_retint ;; FFI_TYPE_SINT32
- dd offset cs_retint64 ;; FFI_TYPE_UINT64
- dd offset cs_retint64 ;; FFI_TYPE_SINT64
- dd offset cs_retstruct ;; FFI_TYPE_STRUCT
- dd offset cs_retint ;; FFI_TYPE_POINTER
- dd offset cs_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
- dd offset cs_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
- dd offset cs_retint ;; FFI_TYPE_SMALL_STRUCT_4B
- dd offset cs_retmsstruct ;; FFI_TYPE_MS_STRUCT
-
-cs_retuint8:
- movzx eax, BYTE PTR [ecx]
- jmp cs_epilogue
-
-cs_retsint8:
- movsx eax, BYTE PTR [ecx]
- jmp cs_epilogue
-
-cs_retuint16:
- movzx eax, WORD PTR [ecx]
- jmp cs_epilogue
-
-cs_retsint16:
- movsx eax, WORD PTR [ecx]
- jmp cs_epilogue
-
-cs_retint:
- mov eax, [ecx]
- jmp cs_epilogue
-
-cs_retint64:
- mov eax, [ecx + 0]
- mov edx, [ecx + 4]
- jmp cs_epilogue
-
-cs_retfloat:
- fld DWORD PTR [ecx]
- jmp cs_epilogue
-
-cs_retdouble:
- fld QWORD PTR [ecx]
- jmp cs_epilogue
-
-cs_retlongdouble:
- fld TBYTE PTR [ecx]
- jmp cs_epilogue
-
-cs_retstruct:
- ;; Caller expects us to pop struct return value pointer hidden arg.
- ;; Epilogue code is autogenerated.
- ret 4
-
-cs_retmsstruct:
- ;; Caller expects us to return a pointer to the real return value.
- mov eax, ecx
- ;; Caller doesn't expects us to pop struct return value pointer hidden arg.
- jmp cs_epilogue
-
-cs_epilogue:
- ;; Epilogue code is autogenerated.
- ret
-ffi_closure_SYSV ENDP
-
-#if !FFI_NO_RAW_API
-
-#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) AND NOT 3)
-#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
-#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
-
-ffi_closure_raw_THISCALL PROC NEAR USES esi FORCEFRAME
- sub esp, 36
- mov esi, [eax + RAW_CLOSURE_CIF_OFFSET] ;; closure->cif
- mov edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET] ;; closure->user_data
- mov [esp + 12], edx
- lea edx, [ebp + 12]
- jmp stubraw
-ffi_closure_raw_THISCALL ENDP
-
-ffi_closure_raw_SYSV PROC NEAR USES esi FORCEFRAME
- ;; the ffi_closure ctx is passed in eax by the trampoline.
-
- sub esp, 40
- mov esi, [eax + RAW_CLOSURE_CIF_OFFSET] ;; closure->cif
- mov edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET] ;; closure->user_data
- mov [esp + 12], edx ;; user_data
- lea edx, [ebp + 8]
-stubraw::
- mov [esp + 8], edx ;; raw_args
- lea edx, [ebp - 24]
- mov [esp + 4], edx ;; &res
- mov [esp], esi ;; cif
- call DWORD PTR [eax + RAW_CLOSURE_FUN_OFFSET] ;; closure->fun
- mov eax, [esi + CIF_FLAGS_OFFSET] ;; cif->flags
- lea ecx, [ebp - 24]
-
-cr_jumptable:
- jmp [cr_jumpdata + 4 * eax]
-cr_jumpdata:
- ;; Do not insert anything here between the label and jump table.
- dd offset cr_epilogue ;; FFI_TYPE_VOID
- dd offset cr_retint ;; FFI_TYPE_INT
- dd offset cr_retfloat ;; FFI_TYPE_FLOAT
- dd offset cr_retdouble ;; FFI_TYPE_DOUBLE
- dd offset cr_retlongdouble ;; FFI_TYPE_LONGDOUBLE
- dd offset cr_retuint8 ;; FFI_TYPE_UINT8
- dd offset cr_retsint8 ;; FFI_TYPE_SINT8
- dd offset cr_retuint16 ;; FFI_TYPE_UINT16
- dd offset cr_retsint16 ;; FFI_TYPE_SINT16
- dd offset cr_retint ;; FFI_TYPE_UINT32
- dd offset cr_retint ;; FFI_TYPE_SINT32
- dd offset cr_retint64 ;; FFI_TYPE_UINT64
- dd offset cr_retint64 ;; FFI_TYPE_SINT64
- dd offset cr_epilogue ;; FFI_TYPE_STRUCT
- dd offset cr_retint ;; FFI_TYPE_POINTER
- dd offset cr_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
- dd offset cr_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
- dd offset cr_retint ;; FFI_TYPE_SMALL_STRUCT_4B
- dd offset cr_epilogue ;; FFI_TYPE_MS_STRUCT
-
-cr_retuint8:
- movzx eax, BYTE PTR [ecx]
- jmp cr_epilogue
-
-cr_retsint8:
- movsx eax, BYTE PTR [ecx]
- jmp cr_epilogue
-
-cr_retuint16:
- movzx eax, WORD PTR [ecx]
- jmp cr_epilogue
-
-cr_retsint16:
- movsx eax, WORD PTR [ecx]
- jmp cr_epilogue
-
-cr_retint:
- mov eax, [ecx]
- jmp cr_epilogue
-
-cr_retint64:
- mov eax, [ecx + 0]
- mov edx, [ecx + 4]
- jmp cr_epilogue
-
-cr_retfloat:
- fld DWORD PTR [ecx]
- jmp cr_epilogue
-
-cr_retdouble:
- fld QWORD PTR [ecx]
- jmp cr_epilogue
-
-cr_retlongdouble:
- fld TBYTE PTR [ecx]
- jmp cr_epilogue
-
-cr_epilogue:
- ;; Epilogue code is autogenerated.
- ret
-ffi_closure_raw_SYSV ENDP
-
-#endif /* !FFI_NO_RAW_API */
-
-ffi_closure_STDCALL PROC NEAR FORCEFRAME
- mov eax, [esp] ;; the ffi_closure ctx passed by the trampoline.
-
- sub esp, 40
- lea edx, [ebp - 24]
- mov [ebp - 12], edx ;; resp
- lea edx, [ebp + 12] ;; account for stub return address on stack
- mov [esp + 8], edx ;; args
- lea edx, [ebp - 12]
- mov [esp + 4], edx ;; &resp
- mov [esp], eax ;; closure
- call ffi_closure_WIN32_inner
- mov ecx, [ebp - 12]
-
- xchg [ebp + 4], eax ;;xchg size of stack parameters and ffi_closure ctx
- mov eax, DWORD PTR [eax + CLOSURE_CIF_OFFSET]
- mov eax, DWORD PTR [eax + CIF_FLAGS_OFFSET]
-
-cd_jumptable:
- jmp [cd_jumpdata + 4 * eax]
-cd_jumpdata:
- ;; Do not insert anything here between the label and jump table.
- dd offset cd_epilogue ;; FFI_TYPE_VOID
- dd offset cd_retint ;; FFI_TYPE_INT
- dd offset cd_retfloat ;; FFI_TYPE_FLOAT
- dd offset cd_retdouble ;; FFI_TYPE_DOUBLE
- dd offset cd_retlongdouble ;; FFI_TYPE_LONGDOUBLE
- dd offset cd_retuint8 ;; FFI_TYPE_UINT8
- dd offset cd_retsint8 ;; FFI_TYPE_SINT8
- dd offset cd_retuint16 ;; FFI_TYPE_UINT16
- dd offset cd_retsint16 ;; FFI_TYPE_SINT16
- dd offset cd_retint ;; FFI_TYPE_UINT32
- dd offset cd_retint ;; FFI_TYPE_SINT32
- dd offset cd_retint64 ;; FFI_TYPE_UINT64
- dd offset cd_retint64 ;; FFI_TYPE_SINT64
- dd offset cd_epilogue ;; FFI_TYPE_STRUCT
- dd offset cd_retint ;; FFI_TYPE_POINTER
- dd offset cd_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
- dd offset cd_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
- dd offset cd_retint ;; FFI_TYPE_SMALL_STRUCT_4B
-
-cd_retuint8:
- movzx eax, BYTE PTR [ecx]
- jmp cd_epilogue
-
-cd_retsint8:
- movsx eax, BYTE PTR [ecx]
- jmp cd_epilogue
-
-cd_retuint16:
- movzx eax, WORD PTR [ecx]
- jmp cd_epilogue
-
-cd_retsint16:
- movsx eax, WORD PTR [ecx]
- jmp cd_epilogue
-
-cd_retint:
- mov eax, [ecx]
- jmp cd_epilogue
-
-cd_retint64:
- mov eax, [ecx + 0]
- mov edx, [ecx + 4]
- jmp cd_epilogue
-
-cd_retfloat:
- fld DWORD PTR [ecx]
- jmp cd_epilogue
-
-cd_retdouble:
- fld QWORD PTR [ecx]
- jmp cd_epilogue
-
-cd_retlongdouble:
- fld TBYTE PTR [ecx]
- jmp cd_epilogue
-
-cd_epilogue:
- mov esp, ebp
- pop ebp
- mov ecx, [esp + 4] ;; Return address
- add esp, [esp] ;; Parameters stack size
- add esp, 8
- jmp ecx
-ffi_closure_STDCALL ENDP
-
-_TEXT ENDS
-END
-
-#else
-
-#define CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
-
-#if defined(SYMBOL_UNDERSCORE)
-#define USCORE_SYMBOL(x) _##x
-#else
-#define USCORE_SYMBOL(x) x
-#endif
- .text
-
- # This assumes we are using gas.
- .balign 16
-FFI_HIDDEN(ffi_call_win32)
- .globl USCORE_SYMBOL(ffi_call_win32)
-#if defined(X86_WIN32) && !defined(__OS2__)
- .def _ffi_call_win32; .scl 2; .type 32; .endef
-#endif
-USCORE_SYMBOL(ffi_call_win32):
-.LFB1:
- pushl %ebp
-.LCFI0:
- movl %esp,%ebp
-.LCFI1:
- # Make room for all of the new args.
- movl 20(%ebp),%ecx
- subl %ecx,%esp
-
- movl %esp,%eax
-
- # Call ffi_prep_args
- pushl 12(%ebp)
- pushl %eax
- call *8(%ebp)
- addl $8,%esp
-
- # Prepare registers
- # EAX stores the number of register arguments
- cmpl $0, %eax
- je .fun
- cmpl $3, %eax
- jl .prepr_two_cmp
-
- movl %esp, %ecx
- addl $12, %esp
- movl 8(%ecx), %eax
- jmp .prepr_two
-.prepr_two_cmp:
- cmpl $2, %eax
- jl .prepr_one_prep
- movl %esp, %ecx
- addl $8, %esp
-.prepr_two:
- movl 4(%ecx), %edx
- jmp .prepr_one
-.prepr_one_prep:
- movl %esp, %ecx
- addl $4, %esp
-.prepr_one:
- movl (%ecx), %ecx
- cmpl $7, 16(%ebp) # FFI_REGISTER
- jne .fun
-
- xchgl %eax, %ecx
-
-.fun:
- # FIXME: Align the stack to a 128-bit boundary to avoid
- # potential performance hits.
-
- # Call function
- call *32(%ebp)
-
- # stdcall functions pop arguments off the stack themselves
-
- # Load %ecx with the return type code
- movl 24(%ebp),%ecx
-
- # If the return value pointer is NULL, assume no return value.
- cmpl $0,28(%ebp)
- jne 0f
-
- # Even if there is no space for the return value, we are
- # obliged to handle floating-point values.
- cmpl $FFI_TYPE_FLOAT,%ecx
- jne .Lnoretval
- fstp %st(0)
-
- jmp .Lepilogue
-
-0:
- call 1f
- # Do not insert anything here between the call and the jump table.
-.Lstore_table:
- .long .Lnoretval-.Lstore_table /* FFI_TYPE_VOID */
- .long .Lretint-.Lstore_table /* FFI_TYPE_INT */
- .long .Lretfloat-.Lstore_table /* FFI_TYPE_FLOAT */
- .long .Lretdouble-.Lstore_table /* FFI_TYPE_DOUBLE */
- .long .Lretlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */
- .long .Lretuint8-.Lstore_table /* FFI_TYPE_UINT8 */
- .long .Lretsint8-.Lstore_table /* FFI_TYPE_SINT8 */
- .long .Lretuint16-.Lstore_table /* FFI_TYPE_UINT16 */
- .long .Lretsint16-.Lstore_table /* FFI_TYPE_SINT16 */
- .long .Lretint-.Lstore_table /* FFI_TYPE_UINT32 */
- .long .Lretint-.Lstore_table /* FFI_TYPE_SINT32 */
- .long .Lretint64-.Lstore_table /* FFI_TYPE_UINT64 */
- .long .Lretint64-.Lstore_table /* FFI_TYPE_SINT64 */
- .long .Lretstruct-.Lstore_table /* FFI_TYPE_STRUCT */
- .long .Lretint-.Lstore_table /* FFI_TYPE_POINTER */
- .long .Lretstruct1b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_1B */
- .long .Lretstruct2b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_2B */
- .long .Lretstruct4b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_4B */
- .long .Lretstruct-.Lstore_table /* FFI_TYPE_MS_STRUCT */
-1:
- shl $2, %ecx
- add (%esp),%ecx
- mov (%ecx),%ecx
- add (%esp),%ecx
- add $4, %esp
- jmp *%ecx
-
- /* Sign/zero extend as appropriate. */
-.Lretsint8:
- movsbl %al, %eax
- jmp .Lretint
-
-.Lretsint16:
- movswl %ax, %eax
- jmp .Lretint
-
-.Lretuint8:
- movzbl %al, %eax
- jmp .Lretint
-
-.Lretuint16:
- movzwl %ax, %eax
- jmp .Lretint
-
-.Lretint:
- # Load %ecx with the pointer to storage for the return value
- movl 28(%ebp),%ecx
- movl %eax,0(%ecx)
- jmp .Lepilogue
-
-.Lretfloat:
- # Load %ecx with the pointer to storage for the return value
- movl 28(%ebp),%ecx
- fstps (%ecx)
- jmp .Lepilogue
-
-.Lretdouble:
- # Load %ecx with the pointer to storage for the return value
- movl 28(%ebp),%ecx
- fstpl (%ecx)
- jmp .Lepilogue
-
-.Lretlongdouble:
- # Load %ecx with the pointer to storage for the return value
- movl 28(%ebp),%ecx
- fstpt (%ecx)
- jmp .Lepilogue
-
-.Lretint64:
- # Load %ecx with the pointer to storage for the return value
- movl 28(%ebp),%ecx
- movl %eax,0(%ecx)
- movl %edx,4(%ecx)
- jmp .Lepilogue
-
-.Lretstruct1b:
- # Load %ecx with the pointer to storage for the return value
- movl 28(%ebp),%ecx
- movb %al,0(%ecx)
- jmp .Lepilogue
-
-.Lretstruct2b:
- # Load %ecx with the pointer to storage for the return value
- movl 28(%ebp),%ecx
- movw %ax,0(%ecx)
- jmp .Lepilogue
-
-.Lretstruct4b:
- # Load %ecx with the pointer to storage for the return value
- movl 28(%ebp),%ecx
- movl %eax,0(%ecx)
- jmp .Lepilogue
-
-.Lretstruct:
- # Nothing to do!
-
-.Lnoretval:
-.Lepilogue:
- movl %ebp,%esp
- popl %ebp
- ret
-.ffi_call_win32_end:
- .balign 16
-FFI_HIDDEN(ffi_closure_THISCALL)
- .globl USCORE_SYMBOL(ffi_closure_THISCALL)
-#if defined(X86_WIN32) && !defined(__OS2__)
- .def _ffi_closure_THISCALL; .scl 2; .type 32; .endef
-#endif
-USCORE_SYMBOL(ffi_closure_THISCALL):
- /* Insert the register argument on the stack as the first argument */
- xchg %ecx, 4(%esp)
- xchg %ecx, (%esp)
- push %ecx
- jmp .ffi_closure_STDCALL_internal
-
- .balign 16
-FFI_HIDDEN(ffi_closure_FASTCALL)
- .globl USCORE_SYMBOL(ffi_closure_FASTCALL)
-#if defined(X86_WIN32) && !defined(__OS2__)
- .def _ffi_closure_FASTCALL; .scl 2; .type 32; .endef
-#endif
-USCORE_SYMBOL(ffi_closure_FASTCALL):
- /* Insert the 2 register arguments on the stack as the first two arguments */
- xchg %edx, 4(%esp)
- xchg %ecx, (%esp)
- push %edx
- push %ecx
- jmp .ffi_closure_STDCALL_internal
-FFI_HIDDEN(ffi_closure_REGISTER)
- .globl USCORE_SYMBOL(ffi_closure_REGISTER)
-#if defined(X86_WIN32) && !defined(__OS2__)
- .def _ffi_closure_REGISTER; .scl 2; .type 32; .endef
-#endif
-USCORE_SYMBOL(ffi_closure_REGISTER):
- /* Insert the 3 register arguments on the stack as the first two arguments */
- push %eax
- xchg %ecx, 8(%esp)
- xchg %edx, 4(%esp)
- push %ecx
- push %edx
- jmp .ffi_closure_STDCALL_internal
-
-.LFE1:
- # This assumes we are using gas.
- .balign 16
-FFI_HIDDEN(ffi_closure_SYSV)
-#if defined(X86_WIN32)
- .globl USCORE_SYMBOL(ffi_closure_SYSV)
-#if defined(X86_WIN32) && !defined(__OS2__)
- .def _ffi_closure_SYSV; .scl 2; .type 32; .endef
-#endif
-USCORE_SYMBOL(ffi_closure_SYSV):
-#endif
-.LFB3:
- pushl %ebp
-.LCFI4:
- movl %esp, %ebp
-.LCFI5:
- subl $40, %esp
- leal -24(%ebp), %edx
- movl %edx, -12(%ebp) /* resp */
- leal 8(%ebp), %edx
- movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */
- leal -12(%ebp), %edx
- movl %edx, (%esp) /* &resp */
-#if defined(HAVE_HIDDEN_VISIBILITY_ATTRIBUTE) || !defined(__PIC__)
- call USCORE_SYMBOL(ffi_closure_SYSV_inner)
-#elif defined(X86_DARWIN)
- calll L_ffi_closure_SYSV_inner$stub
-#else
- movl %ebx, 8(%esp)
- call 1f
-1: popl %ebx
- addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
- call ffi_closure_SYSV_inner@PLT
- movl 8(%esp), %ebx
-#endif
- movl -12(%ebp), %ecx
-
-0:
- call 1f
- # Do not insert anything here between the call and the jump table.
-.Lcls_store_table:
- .long .Lcls_noretval-.Lcls_store_table /* FFI_TYPE_VOID */
- .long .Lcls_retint-.Lcls_store_table /* FFI_TYPE_INT */
- .long .Lcls_retfloat-.Lcls_store_table /* FFI_TYPE_FLOAT */
- .long .Lcls_retdouble-.Lcls_store_table /* FFI_TYPE_DOUBLE */
- .long .Lcls_retldouble-.Lcls_store_table /* FFI_TYPE_LONGDOUBLE */
- .long .Lcls_retuint8-.Lcls_store_table /* FFI_TYPE_UINT8 */
- .long .Lcls_retsint8-.Lcls_store_table /* FFI_TYPE_SINT8 */
- .long .Lcls_retuint16-.Lcls_store_table /* FFI_TYPE_UINT16 */
- .long .Lcls_retsint16-.Lcls_store_table /* FFI_TYPE_SINT16 */
- .long .Lcls_retint-.Lcls_store_table /* FFI_TYPE_UINT32 */
- .long .Lcls_retint-.Lcls_store_table /* FFI_TYPE_SINT32 */
- .long .Lcls_retllong-.Lcls_store_table /* FFI_TYPE_UINT64 */
- .long .Lcls_retllong-.Lcls_store_table /* FFI_TYPE_SINT64 */
- .long .Lcls_retstruct-.Lcls_store_table /* FFI_TYPE_STRUCT */
- .long .Lcls_retint-.Lcls_store_table /* FFI_TYPE_POINTER */
- .long .Lcls_retstruct1-.Lcls_store_table /* FFI_TYPE_SMALL_STRUCT_1B */
- .long .Lcls_retstruct2-.Lcls_store_table /* FFI_TYPE_SMALL_STRUCT_2B */
- .long .Lcls_retstruct4-.Lcls_store_table /* FFI_TYPE_SMALL_STRUCT_4B */
- .long .Lcls_retmsstruct-.Lcls_store_table /* FFI_TYPE_MS_STRUCT */
-
-1:
- shl $2, %eax
- add (%esp),%eax
- mov (%eax),%eax
- add (%esp),%eax
- add $4, %esp
- jmp *%eax
-
- /* Sign/zero extend as appropriate. */
-.Lcls_retsint8:
- movsbl (%ecx), %eax
- jmp .Lcls_epilogue
-
-.Lcls_retsint16:
- movswl (%ecx), %eax
- jmp .Lcls_epilogue
-
-.Lcls_retuint8:
- movzbl (%ecx), %eax
- jmp .Lcls_epilogue
-
-.Lcls_retuint16:
- movzwl (%ecx), %eax
- jmp .Lcls_epilogue
-
-.Lcls_retint:
- movl (%ecx), %eax
- jmp .Lcls_epilogue
-
-.Lcls_retfloat:
- flds (%ecx)
- jmp .Lcls_epilogue
-
-.Lcls_retdouble:
- fldl (%ecx)
- jmp .Lcls_epilogue
-
-.Lcls_retldouble:
- fldt (%ecx)
- jmp .Lcls_epilogue
-
-.Lcls_retllong:
- movl (%ecx), %eax
- movl 4(%ecx), %edx
- jmp .Lcls_epilogue
-
-.Lcls_retstruct1:
- movsbl (%ecx), %eax
- jmp .Lcls_epilogue
-
-.Lcls_retstruct2:
- movswl (%ecx), %eax
- jmp .Lcls_epilogue
-
-.Lcls_retstruct4:
- movl (%ecx), %eax
- jmp .Lcls_epilogue
-
-.Lcls_retstruct:
- # Caller expects us to pop struct return value pointer hidden arg.
- movl %ebp, %esp
- popl %ebp
- ret $0x4
-
-.Lcls_retmsstruct:
- # Caller expects us to return a pointer to the real return value.
- mov %ecx, %eax
- # Caller doesn't expects us to pop struct return value pointer hidden arg.
- jmp .Lcls_epilogue
-
-.Lcls_noretval:
-.Lcls_epilogue:
- movl %ebp, %esp
- popl %ebp
- ret
-.ffi_closure_SYSV_end:
-.LFE3:
-
-#if !FFI_NO_RAW_API
-
-#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
-#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
-#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
-
-#ifdef X86_WIN32
- .balign 16
-FFI_HIDDEN(ffi_closure_raw_THISCALL)
- .globl USCORE_SYMBOL(ffi_closure_raw_THISCALL)
-#if defined(X86_WIN32) && !defined(__OS2__)
- .def _ffi_closure_raw_THISCALL; .scl 2; .type 32; .endef
-#endif
-USCORE_SYMBOL(ffi_closure_raw_THISCALL):
- pushl %ebp
- movl %esp, %ebp
- pushl %esi
- subl $36, %esp
- movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
- movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
- movl %edx, 12(%esp) /* user_data */
- leal 12(%ebp), %edx /* __builtin_dwarf_cfa () */
- jmp .stubraw
-#endif /* X86_WIN32 */
-
- # This assumes we are using gas.
- .balign 16
-#if defined(X86_WIN32)
- .globl USCORE_SYMBOL(ffi_closure_raw_SYSV)
-#if defined(X86_WIN32) && !defined(__OS2__)
- .def _ffi_closure_raw_SYSV; .scl 2; .type 32; .endef
-#endif
-USCORE_SYMBOL(ffi_closure_raw_SYSV):
-#endif /* defined(X86_WIN32) */
-.LFB4:
- pushl %ebp
-.LCFI6:
- movl %esp, %ebp
-.LCFI7:
- pushl %esi
-.LCFI8:
- subl $36, %esp
- movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
- movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
- movl %edx, 12(%esp) /* user_data */
- leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */
-.stubraw:
- movl %edx, 8(%esp) /* raw_args */
- leal -24(%ebp), %edx
- movl %edx, 4(%esp) /* &res */
- movl %esi, (%esp) /* cif */
- call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */
- movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */
-0:
- call 1f
- # Do not insert anything here between the call and the jump table.
-.Lrcls_store_table:
- .long .Lrcls_noretval-.Lrcls_store_table /* FFI_TYPE_VOID */
- .long .Lrcls_retint-.Lrcls_store_table /* FFI_TYPE_INT */
- .long .Lrcls_retfloat-.Lrcls_store_table /* FFI_TYPE_FLOAT */
- .long .Lrcls_retdouble-.Lrcls_store_table /* FFI_TYPE_DOUBLE */
- .long .Lrcls_retldouble-.Lrcls_store_table /* FFI_TYPE_LONGDOUBLE */
- .long .Lrcls_retuint8-.Lrcls_store_table /* FFI_TYPE_UINT8 */
- .long .Lrcls_retsint8-.Lrcls_store_table /* FFI_TYPE_SINT8 */
- .long .Lrcls_retuint16-.Lrcls_store_table /* FFI_TYPE_UINT16 */
- .long .Lrcls_retsint16-.Lrcls_store_table /* FFI_TYPE_SINT16 */
- .long .Lrcls_retint-.Lrcls_store_table /* FFI_TYPE_UINT32 */
- .long .Lrcls_retint-.Lrcls_store_table /* FFI_TYPE_SINT32 */
- .long .Lrcls_retllong-.Lrcls_store_table /* FFI_TYPE_UINT64 */
- .long .Lrcls_retllong-.Lrcls_store_table /* FFI_TYPE_SINT64 */
- .long .Lrcls_retstruct-.Lrcls_store_table /* FFI_TYPE_STRUCT */
- .long .Lrcls_retint-.Lrcls_store_table /* FFI_TYPE_POINTER */
- .long .Lrcls_retstruct1-.Lrcls_store_table /* FFI_TYPE_SMALL_STRUCT_1B */
- .long .Lrcls_retstruct2-.Lrcls_store_table /* FFI_TYPE_SMALL_STRUCT_2B */
- .long .Lrcls_retstruct4-.Lrcls_store_table /* FFI_TYPE_SMALL_STRUCT_4B */
- .long .Lrcls_retstruct-.Lrcls_store_table /* FFI_TYPE_MS_STRUCT */
-1:
- shl $2, %eax
- add (%esp),%eax
- mov (%eax),%eax
- add (%esp),%eax
- add $4, %esp
- jmp *%eax
-
- /* Sign/zero extend as appropriate. */
-.Lrcls_retsint8:
- movsbl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-
-.Lrcls_retsint16:
- movswl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-
-.Lrcls_retuint8:
- movzbl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-
-.Lrcls_retuint16:
- movzwl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-
-.Lrcls_retint:
- movl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-
-.Lrcls_retfloat:
- flds -24(%ebp)
- jmp .Lrcls_epilogue
-
-.Lrcls_retdouble:
- fldl -24(%ebp)
- jmp .Lrcls_epilogue
-
-.Lrcls_retldouble:
- fldt -24(%ebp)
- jmp .Lrcls_epilogue
-
-.Lrcls_retllong:
- movl -24(%ebp), %eax
- movl -20(%ebp), %edx
- jmp .Lrcls_epilogue
-
-.Lrcls_retstruct1:
- movsbl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-
-.Lrcls_retstruct2:
- movswl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-
-.Lrcls_retstruct4:
- movl -24(%ebp), %eax
- jmp .Lrcls_epilogue
-
-.Lrcls_retstruct:
- # Nothing to do!
-
-.Lrcls_noretval:
-.Lrcls_epilogue:
- addl $36, %esp
- popl %esi
- popl %ebp
- ret
-.ffi_closure_raw_SYSV_end:
-.LFE4:
-
-#endif /* !FFI_NO_RAW_API */
-
- # This assumes we are using gas.
- .balign 16
-FFI_HIDDEN(ffi_closure_STDCALL)
- .globl USCORE_SYMBOL(ffi_closure_STDCALL)
-#if defined(X86_WIN32) && !defined(__OS2__)
- .def _ffi_closure_STDCALL; .scl 2; .type 32; .endef
-#endif
-USCORE_SYMBOL(ffi_closure_STDCALL):
-.ffi_closure_STDCALL_internal:
- /* ffi_closure ctx is at top of the stack */
- movl (%esp), %eax
-.LFB5:
- pushl %ebp
-.LCFI9:
- movl %esp, %ebp
-.LCFI10:
- subl $40, %esp
- leal -24(%ebp), %edx
- movl %edx, -12(%ebp) /* resp */
- leal 12(%ebp), %edx /* account for stub return address on stack */
- movl %edx, 4(%esp) /* args */
- leal -12(%ebp), %edx
- movl %edx, (%esp) /* &resp */
-#if defined(HAVE_HIDDEN_VISIBILITY_ATTRIBUTE) || !defined(__PIC__)
- call USCORE_SYMBOL(ffi_closure_WIN32_inner)
-#elif defined(X86_DARWIN)
- calll L_ffi_closure_WIN32_inner$stub
-#else
- movl %ebx, 8(%esp)
- call 1f
-1: popl %ebx
- addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
- call ffi_closure_WIN32_inner@PLT
- movl 8(%esp), %ebx
-#endif
- movl -12(%ebp), %ecx
-0:
- xchgl 4(%ebp), %eax /* xchg size of stack parameters and ffi_closure ctx */
- movl CLOSURE_CIF_OFFSET(%eax), %eax
- movl CIF_FLAGS_OFFSET(%eax), %eax
-
- call 1f
- # Do not insert anything here between the call and the jump table.
-.Lscls_store_table:
- .long .Lscls_noretval-.Lscls_store_table /* FFI_TYPE_VOID */
- .long .Lscls_retint-.Lscls_store_table /* FFI_TYPE_INT */
- .long .Lscls_retfloat-.Lscls_store_table /* FFI_TYPE_FLOAT */
- .long .Lscls_retdouble-.Lscls_store_table /* FFI_TYPE_DOUBLE */
- .long .Lscls_retldouble-.Lscls_store_table /* FFI_TYPE_LONGDOUBLE */
- .long .Lscls_retuint8-.Lscls_store_table /* FFI_TYPE_UINT8 */
- .long .Lscls_retsint8-.Lscls_store_table /* FFI_TYPE_SINT8 */
- .long .Lscls_retuint16-.Lscls_store_table /* FFI_TYPE_UINT16 */
- .long .Lscls_retsint16-.Lscls_store_table /* FFI_TYPE_SINT16 */
- .long .Lscls_retint-.Lscls_store_table /* FFI_TYPE_UINT32 */
- .long .Lscls_retint-.Lscls_store_table /* FFI_TYPE_SINT32 */
- .long .Lscls_retllong-.Lscls_store_table /* FFI_TYPE_UINT64 */
- .long .Lscls_retllong-.Lscls_store_table /* FFI_TYPE_SINT64 */
- .long .Lscls_retstruct-.Lscls_store_table /* FFI_TYPE_STRUCT */
- .long .Lscls_retint-.Lscls_store_table /* FFI_TYPE_POINTER */
- .long .Lscls_retstruct1-.Lscls_store_table /* FFI_TYPE_SMALL_STRUCT_1B */
- .long .Lscls_retstruct2-.Lscls_store_table /* FFI_TYPE_SMALL_STRUCT_2B */
- .long .Lscls_retstruct4-.Lscls_store_table /* FFI_TYPE_SMALL_STRUCT_4B */
-1:
- shl $2, %eax
- add (%esp),%eax
- mov (%eax),%eax
- add (%esp),%eax
- add $4, %esp
- jmp *%eax
-
- /* Sign/zero extend as appropriate. */
-.Lscls_retsint8:
- movsbl (%ecx), %eax
- jmp .Lscls_epilogue
-
-.Lscls_retsint16:
- movswl (%ecx), %eax
- jmp .Lscls_epilogue
-
-.Lscls_retuint8:
- movzbl (%ecx), %eax
- jmp .Lscls_epilogue
-
-.Lscls_retuint16:
- movzwl (%ecx), %eax
- jmp .Lscls_epilogue
-
-.Lscls_retint:
- movl (%ecx), %eax
- jmp .Lscls_epilogue
-
-.Lscls_retfloat:
- flds (%ecx)
- jmp .Lscls_epilogue
-
-.Lscls_retdouble:
- fldl (%ecx)
- jmp .Lscls_epilogue
-
-.Lscls_retldouble:
- fldt (%ecx)
- jmp .Lscls_epilogue
-
-.Lscls_retllong:
- movl (%ecx), %eax
- movl 4(%ecx), %edx
- jmp .Lscls_epilogue
-
-.Lscls_retstruct1:
- movsbl (%ecx), %eax
- jmp .Lscls_epilogue
-
-.Lscls_retstruct2:
- movswl (%ecx), %eax
- jmp .Lscls_epilogue
-
-.Lscls_retstruct4:
- movl (%ecx), %eax
- jmp .Lscls_epilogue
-
-.Lscls_retstruct:
- # Nothing to do!
-
-.Lscls_noretval:
-.Lscls_epilogue:
- movl %ebp, %esp
- popl %ebp
- movl 4(%esp), %ecx /* Return address */
- addl (%esp), %esp /* Parameters stack size */
- addl $8, %esp
- jmp *%ecx
-.ffi_closure_STDCALL_end:
-.LFE5:
-
-#if defined(X86_DARWIN)
-.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
-L_ffi_closure_SYSV_inner$stub:
- .indirect_symbol _ffi_closure_SYSV_inner
- hlt ; hlt ; hlt ; hlt ; hlt
-L_ffi_closure_WIN32_inner$stub:
- .indirect_symbol _ffi_closure_WIN32_inner
- hlt ; hlt ; hlt ; hlt ; hlt
-#endif
-
-#if defined(X86_WIN32) && !defined(__OS2__)
- .section .eh_frame,"w"
-#endif
-.Lframe1:
-.LSCIE1:
- .long .LECIE1-.LASCIE1 /* Length of Common Information Entry */
-.LASCIE1:
- .long 0x0 /* CIE Identifier Tag */
- .byte 0x1 /* CIE Version */
-#ifdef __PIC__
- .ascii "zR\0" /* CIE Augmentation */
-#else
- .ascii "\0" /* CIE Augmentation */
-#endif
- .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
- .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
- .byte 0x8 /* CIE RA Column */
-#ifdef __PIC__
- .byte 0x1 /* .uleb128 0x1; Augmentation size */
- .byte 0x1b /* FDE Encoding (pcrel sdata4) */
-#endif
- .byte 0xc /* DW_CFA_def_cfa CFA = r4 + 4 = 4(%esp) */
- .byte 0x4 /* .uleb128 0x4 */
- .byte 0x4 /* .uleb128 0x4 */
- .byte 0x88 /* DW_CFA_offset, column 0x8 %eip at CFA + 1 * -4 */
- .byte 0x1 /* .uleb128 0x1 */
- .align 4
-.LECIE1:
-
-.LSFDE1:
- .long .LEFDE1-.LASFDE1 /* FDE Length */
-.LASFDE1:
- .long .LASFDE1-.Lframe1 /* FDE CIE offset */
-#if defined __PIC__ && defined HAVE_AS_X86_PCREL
- .long .LFB1-. /* FDE initial location */
-#else
- .long .LFB1
-#endif
- .long .LFE1-.LFB1 /* FDE address range */
-#ifdef __PIC__
- .byte 0x0 /* .uleb128 0x0; Augmentation size */
-#endif
- /* DW_CFA_xxx CFI instructions go here. */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI0-.LFB1
- .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
- .byte 0x8 /* .uleb128 0x8 */
- .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
- .byte 0x2 /* .uleb128 0x2 */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI1-.LCFI0
- .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
- .byte 0x5 /* .uleb128 0x5 */
-
- /* End of DW_CFA_xxx CFI instructions. */
- .align 4
-.LEFDE1:
-
-.LSFDE3:
- .long .LEFDE3-.LASFDE3 /* FDE Length */
-.LASFDE3:
- .long .LASFDE3-.Lframe1 /* FDE CIE offset */
-#if defined __PIC__ && defined HAVE_AS_X86_PCREL
- .long .LFB3-. /* FDE initial location */
-#else
- .long .LFB3
-#endif
- .long .LFE3-.LFB3 /* FDE address range */
-#ifdef __PIC__
- .byte 0x0 /* .uleb128 0x0; Augmentation size */
-#endif
- /* DW_CFA_xxx CFI instructions go here. */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI4-.LFB3
- .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
- .byte 0x8 /* .uleb128 0x8 */
- .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
- .byte 0x2 /* .uleb128 0x2 */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI5-.LCFI4
- .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
- .byte 0x5 /* .uleb128 0x5 */
-
- /* End of DW_CFA_xxx CFI instructions. */
- .align 4
-.LEFDE3:
-
-#if !FFI_NO_RAW_API
-
-.LSFDE4:
- .long .LEFDE4-.LASFDE4 /* FDE Length */
-.LASFDE4:
- .long .LASFDE4-.Lframe1 /* FDE CIE offset */
-#if defined __PIC__ && defined HAVE_AS_X86_PCREL
- .long .LFB4-. /* FDE initial location */
-#else
- .long .LFB4
-#endif
- .long .LFE4-.LFB4 /* FDE address range */
-#ifdef __PIC__
- .byte 0x0 /* .uleb128 0x0; Augmentation size */
-#endif
- /* DW_CFA_xxx CFI instructions go here. */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI6-.LFB4
- .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
- .byte 0x8 /* .uleb128 0x8 */
- .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
- .byte 0x2 /* .uleb128 0x2 */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI7-.LCFI6
- .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
- .byte 0x5 /* .uleb128 0x5 */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI8-.LCFI7
- .byte 0x86 /* DW_CFA_offset, column 0x6 %esi at CFA + 3 * -4 */
- .byte 0x3 /* .uleb128 0x3 */
-
- /* End of DW_CFA_xxx CFI instructions. */
- .align 4
-.LEFDE4:
-
-#endif /* !FFI_NO_RAW_API */
-
-.LSFDE5:
- .long .LEFDE5-.LASFDE5 /* FDE Length */
-.LASFDE5:
- .long .LASFDE5-.Lframe1 /* FDE CIE offset */
-#if defined __PIC__ && defined HAVE_AS_X86_PCREL
- .long .LFB5-. /* FDE initial location */
-#else
- .long .LFB5
-#endif
- .long .LFE5-.LFB5 /* FDE address range */
-#ifdef __PIC__
- .byte 0x0 /* .uleb128 0x0; Augmentation size */
-#endif
- /* DW_CFA_xxx CFI instructions go here. */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI9-.LFB5
- .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
- .byte 0x8 /* .uleb128 0x8 */
- .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
- .byte 0x2 /* .uleb128 0x2 */
-
- .byte 0x4 /* DW_CFA_advance_loc4 */
- .long .LCFI10-.LCFI9
- .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
- .byte 0x5 /* .uleb128 0x5 */
-
- /* End of DW_CFA_xxx CFI instructions. */
- .align 4
-.LEFDE5:
-
-#endif /* !_MSC_VER */
-
-#if defined __ELF__ && defined __linux__
- .section .note.GNU-stack,"",@progbits
-#endif
diff --git a/src/x86/win64.S b/src/x86/win64.S
index 687f97c4..2c334c82 100644
--- a/src/x86/win64.S
+++ b/src/x86/win64.S
@@ -1,520 +1,237 @@
+#ifdef __x86_64__
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
+#include <ffi_cfi.h>
+#include "asmnames.h"
-/* Constants for ffi_call_win64 */
-#define STACK 0
-#define PREP_ARGS_FN 32
-#define ECIF 40
-#define CIF_BYTES 48
-#define CIF_FLAGS 56
-#define RVALUE 64
-#define FN 72
-
-/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *),
- extended_cif *ecif, unsigned bytes, unsigned flags,
- unsigned *rvalue, void (*fn)());
- */
-
-#ifdef _MSC_VER
-PUBLIC ffi_call_win64
-
-EXTRN __chkstk:NEAR
-EXTRN ffi_closure_win64_inner:NEAR
-
-_TEXT SEGMENT
-
-;;; ffi_closure_win64 will be called with these registers set:
-;;; rax points to 'closure'
-;;; r11 contains a bit mask that specifies which of the
-;;; first four parameters are float or double
-;;;
-;;; It must move the parameters passed in registers to their stack location,
-;;; call ffi_closure_win64_inner for the actual work, then return the result.
-;;;
-ffi_closure_win64 PROC FRAME
- ;; copy register arguments onto stack
- test r11, 1
- jne first_is_float
- mov QWORD PTR [rsp+8], rcx
- jmp second
-first_is_float:
- movlpd QWORD PTR [rsp+8], xmm0
-
-second:
- test r11, 2
- jne second_is_float
- mov QWORD PTR [rsp+16], rdx
- jmp third
-second_is_float:
- movlpd QWORD PTR [rsp+16], xmm1
-
-third:
- test r11, 4
- jne third_is_float
- mov QWORD PTR [rsp+24], r8
- jmp fourth
-third_is_float:
- movlpd QWORD PTR [rsp+24], xmm2
-
-fourth:
- test r11, 8
- jne fourth_is_float
- mov QWORD PTR [rsp+32], r9
- jmp done
-fourth_is_float:
- movlpd QWORD PTR [rsp+32], xmm3
-
-done:
- .ALLOCSTACK 40
- sub rsp, 40
- .ENDPROLOG
- mov rcx, rax ; context is first parameter
- mov rdx, rsp ; stack is second parameter
- add rdx, 48 ; point to start of arguments
- mov rax, ffi_closure_win64_inner
- call rax ; call the real closure function
- add rsp, 40
- movd xmm0, rax ; If the closure returned a float,
- ; ffi_closure_win64_inner wrote it to rax
- ret 0
-ffi_closure_win64 ENDP
-
-ffi_call_win64 PROC FRAME
- ;; copy registers onto stack
- mov QWORD PTR [rsp+32], r9
- mov QWORD PTR [rsp+24], r8
- mov QWORD PTR [rsp+16], rdx
- mov QWORD PTR [rsp+8], rcx
- .PUSHREG rbp
- push rbp
- .ALLOCSTACK 48
- sub rsp, 48 ; 00000030H
- .SETFRAME rbp, 32
- lea rbp, QWORD PTR [rsp+32]
- .ENDPROLOG
-
- mov eax, DWORD PTR CIF_BYTES[rbp]
- add rax, 15
- and rax, -16
- call __chkstk
- sub rsp, rax
- lea rax, QWORD PTR [rsp+32]
- mov QWORD PTR STACK[rbp], rax
-
- mov rdx, QWORD PTR ECIF[rbp]
- mov rcx, QWORD PTR STACK[rbp]
- call QWORD PTR PREP_ARGS_FN[rbp]
-
- mov rsp, QWORD PTR STACK[rbp]
-
- movlpd xmm3, QWORD PTR [rsp+24]
- movd r9, xmm3
-
- movlpd xmm2, QWORD PTR [rsp+16]
- movd r8, xmm2
-
- movlpd xmm1, QWORD PTR [rsp+8]
- movd rdx, xmm1
-
- movlpd xmm0, QWORD PTR [rsp]
- movd rcx, xmm0
-
- call QWORD PTR FN[rbp]
-ret_struct4b$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B
- jne ret_struct2b$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- mov DWORD PTR [rcx], eax
- jmp ret_void$
-
-ret_struct2b$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B
- jne ret_struct1b$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- mov WORD PTR [rcx], ax
- jmp ret_void$
-
-ret_struct1b$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B
- jne ret_uint8$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- mov BYTE PTR [rcx], al
- jmp ret_void$
-
-ret_uint8$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8
- jne ret_sint8$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- movzx rax, al
- mov QWORD PTR [rcx], rax
- jmp ret_void$
-
-ret_sint8$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8
- jne ret_uint16$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- movsx rax, al
- mov QWORD PTR [rcx], rax
- jmp ret_void$
-
-ret_uint16$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16
- jne ret_sint16$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- movzx rax, ax
- mov QWORD PTR [rcx], rax
- jmp SHORT ret_void$
-
-ret_sint16$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16
- jne ret_uint32$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- movsx rax, ax
- mov QWORD PTR [rcx], rax
- jmp SHORT ret_void$
-
-ret_uint32$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32
- jne ret_sint32$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- mov eax, eax
- mov QWORD PTR [rcx], rax
- jmp SHORT ret_void$
-
-ret_sint32$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32
- jne ret_float$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- cdqe
- mov QWORD PTR [rcx], rax
- jmp SHORT ret_void$
-
-ret_float$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT
- jne SHORT ret_double$
-
- mov rax, QWORD PTR RVALUE[rbp]
- movss DWORD PTR [rax], xmm0
- jmp SHORT ret_void$
-
-ret_double$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE
- jne SHORT ret_uint64$
-
- mov rax, QWORD PTR RVALUE[rbp]
- movlpd QWORD PTR [rax], xmm0
- jmp SHORT ret_void$
-
-ret_uint64$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT64
- jne SHORT ret_sint64$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- mov QWORD PTR [rcx], rax
- jmp SHORT ret_void$
-
-ret_sint64$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64
- jne SHORT ret_pointer$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- mov QWORD PTR [rcx], rax
- jmp SHORT ret_void$
-
-ret_pointer$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_POINTER
- jne SHORT ret_int$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- mov QWORD PTR [rcx], rax
- jmp SHORT ret_void$
-
-ret_int$:
- cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_INT
- jne SHORT ret_void$
-
- mov rcx, QWORD PTR RVALUE[rbp]
- cdqe
- mov QWORD PTR [rcx], rax
- jmp SHORT ret_void$
-
-ret_void$:
- xor rax, rax
-
- lea rsp, QWORD PTR [rbp+16]
- pop rbp
- ret 0
-ffi_call_win64 ENDP
-_TEXT ENDS
-END
+#if defined(HAVE_AS_CFI_PSEUDO_OP)
+ .cfi_sections .debug_frame
+#endif
+#ifdef X86_WIN64
+#define SEH(...) __VA_ARGS__
+#define arg0 %rcx
+#define arg1 %rdx
+#define arg2 %r8
+#define arg3 %r9
#else
+#define SEH(...)
+#define arg0 %rdi
+#define arg1 %rsi
+#define arg2 %rdx
+#define arg3 %rcx
+#endif
-#ifdef SYMBOL_UNDERSCORE
-#define SYMBOL_NAME(name) _##name
+/* This macro allows the safe creation of jump tables without an
+ actual table. The entry points into the table are all 8 bytes.
+ The use of ORG asserts that we're at the correct location. */
+/* ??? The clang assembler doesn't handle .org with symbolic expressions. */
+#if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
+# define E(BASE, X) .balign 8
#else
-#define SYMBOL_NAME(name) name
+# define E(BASE, X) .balign 8; .org BASE + X * 8
#endif
-.text
-
-.extern SYMBOL_NAME(ffi_closure_win64_inner)
-
-# ffi_closure_win64 will be called with these registers set:
-# rax points to 'closure'
-# r11 contains a bit mask that specifies which of the
-# first four parameters are float or double
-#
-# It must move the parameters passed in registers to their stack location,
-# call ffi_closure_win64_inner for the actual work, then return the result.
-#
- .balign 16
- .globl SYMBOL_NAME(ffi_closure_win64)
- .seh_proc SYMBOL_NAME(ffi_closure_win64)
-SYMBOL_NAME(ffi_closure_win64):
- # copy register arguments onto stack
- test $1,%r11
- jne .Lfirst_is_float
- mov %rcx, 8(%rsp)
- jmp .Lsecond
-.Lfirst_is_float:
- movlpd %xmm0, 8(%rsp)
-
-.Lsecond:
- test $2, %r11
- jne .Lsecond_is_float
- mov %rdx, 16(%rsp)
- jmp .Lthird
-.Lsecond_is_float:
- movlpd %xmm1, 16(%rsp)
-
-.Lthird:
- test $4, %r11
- jne .Lthird_is_float
- mov %r8,24(%rsp)
- jmp .Lfourth
-.Lthird_is_float:
- movlpd %xmm2, 24(%rsp)
-
-.Lfourth:
- test $8, %r11
- jne .Lfourth_is_float
- mov %r9, 32(%rsp)
- jmp .Ldone
-.Lfourth_is_float:
- movlpd %xmm3, 32(%rsp)
-
-.Ldone:
- .seh_stackalloc 40
- sub $40, %rsp
- .seh_endprologue
- mov %rax, %rcx # context is first parameter
- mov %rsp, %rdx # stack is second parameter
- add $48, %rdx # point to start of arguments
- leaq SYMBOL_NAME(ffi_closure_win64_inner)(%rip), %rax
- callq *%rax # call the real closure function
- add $40, %rsp
- movq %rax, %xmm0 # If the closure returned a float,
- # ffi_closure_win64_inner wrote it to rax
- retq
- .seh_endproc
-
- .balign 16
- .globl SYMBOL_NAME(ffi_call_win64)
- .seh_proc SYMBOL_NAME(ffi_call_win64)
-SYMBOL_NAME(ffi_call_win64):
- # copy registers onto stack
- mov %r9,32(%rsp)
- mov %r8,24(%rsp)
- mov %rdx,16(%rsp)
- mov %rcx,8(%rsp)
- .seh_pushreg rbp
- push %rbp
- .seh_stackalloc 48
- sub $48,%rsp
- .seh_setframe rbp, 32
- lea 32(%rsp),%rbp
- .seh_endprologue
-
- mov CIF_BYTES(%rbp),%eax
- add $15, %rax
- and $-16, %rax
- cmpq $0x1000, %rax
- jb Lch_done
-Lch_probe:
- subq $0x1000,%rsp
- orl $0x0, (%rsp)
- subq $0x1000,%rax
- cmpq $0x1000,%rax
- ja Lch_probe
-Lch_done:
- subq %rax, %rsp
- orl $0x0, (%rsp)
- lea 32(%rsp), %rax
- mov %rax, STACK(%rbp)
-
- mov ECIF(%rbp), %rdx
- mov STACK(%rbp), %rcx
- callq *PREP_ARGS_FN(%rbp)
-
- mov STACK(%rbp), %rsp
-
- movlpd 24(%rsp), %xmm3
- movd %xmm3, %r9
-
- movlpd 16(%rsp), %xmm2
- movd %xmm2, %r8
-
- movlpd 8(%rsp), %xmm1
- movd %xmm1, %rdx
-
- movlpd (%rsp), %xmm0
- movd %xmm0, %rcx
-
- callq *FN(%rbp)
-.Lret_struct4b:
- cmpl $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp)
- jne .Lret_struct2b
-
- mov RVALUE(%rbp), %rcx
- mov %eax, (%rcx)
- jmp .Lret_void
-
-.Lret_struct2b:
- cmpl $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp)
- jne .Lret_struct1b
-
- mov RVALUE(%rbp), %rcx
- mov %ax, (%rcx)
- jmp .Lret_void
-
-.Lret_struct1b:
- cmpl $FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp)
- jne .Lret_uint8
-
- mov RVALUE(%rbp), %rcx
- mov %al, (%rcx)
- jmp .Lret_void
-
-.Lret_uint8:
- cmpl $FFI_TYPE_UINT8, CIF_FLAGS(%rbp)
- jne .Lret_sint8
-
- mov RVALUE(%rbp), %rcx
- movzbq %al, %rax
- movq %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_sint8:
- cmpl $FFI_TYPE_SINT8, CIF_FLAGS(%rbp)
- jne .Lret_uint16
-
- mov RVALUE(%rbp), %rcx
- movsbq %al, %rax
- movq %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_uint16:
- cmpl $FFI_TYPE_UINT16, CIF_FLAGS(%rbp)
- jne .Lret_sint16
-
- mov RVALUE(%rbp), %rcx
- movzwq %ax, %rax
- movq %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_sint16:
- cmpl $FFI_TYPE_SINT16, CIF_FLAGS(%rbp)
- jne .Lret_uint32
-
- mov RVALUE(%rbp), %rcx
- movswq %ax, %rax
- movq %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_uint32:
- cmpl $FFI_TYPE_UINT32, CIF_FLAGS(%rbp)
- jne .Lret_sint32
-
- mov RVALUE(%rbp), %rcx
- movl %eax, %eax
- movq %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_sint32:
- cmpl $FFI_TYPE_SINT32, CIF_FLAGS(%rbp)
- jne .Lret_float
-
- mov RVALUE(%rbp), %rcx
- cltq
- movq %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_float:
- cmpl $FFI_TYPE_FLOAT, CIF_FLAGS(%rbp)
- jne .Lret_double
-
- mov RVALUE(%rbp), %rax
- movss %xmm0, (%rax)
- jmp .Lret_void
-
-.Lret_double:
- cmpl $FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp)
- jne .Lret_uint64
-
- mov RVALUE(%rbp), %rax
- movlpd %xmm0, (%rax)
- jmp .Lret_void
-
-.Lret_uint64:
- cmpl $FFI_TYPE_UINT64, CIF_FLAGS(%rbp)
- jne .Lret_sint64
-
- mov RVALUE(%rbp), %rcx
- mov %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_sint64:
- cmpl $FFI_TYPE_SINT64, CIF_FLAGS(%rbp)
- jne .Lret_pointer
-
- mov RVALUE(%rbp), %rcx
- mov %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_pointer:
- cmpl $FFI_TYPE_POINTER, CIF_FLAGS(%rbp)
- jne .Lret_int
-
- mov RVALUE(%rbp), %rcx
- mov %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_int:
- cmpl $FFI_TYPE_INT, CIF_FLAGS(%rbp)
- jne .Lret_void
-
- mov RVALUE(%rbp), %rcx
- cltq
- movq %rax, (%rcx)
- jmp .Lret_void
-
-.Lret_void:
- xor %rax, %rax
-
- lea 16(%rbp), %rsp
- pop %rbp
- retq
- .seh_endproc
-#endif /* !_MSC_VER */
-
+ .text
+
+/* ffi_call_win64 (void *stack, struct win64_call_frame *frame, void *r10)
+
+ Bit o trickiness here -- FRAME is the base of the stack frame
+ for this function. This has been allocated by ffi_call. We also
+ deallocate some of the stack that has been alloca'd. */
+
+ .align 8
+ .globl C(ffi_call_win64)
+ FFI_HIDDEN(C(ffi_call_win64))
+
+ SEH(.seh_proc ffi_call_win64)
+C(ffi_call_win64):
+ cfi_startproc
+ /* Set up the local stack frame and install it in rbp/rsp. */
+ movq (%rsp), %rax
+ movq %rbp, (arg1)
+ movq %rax, 8(arg1)
+ movq arg1, %rbp
+ cfi_def_cfa(%rbp, 16)
+ cfi_rel_offset(%rbp, 0)
+ SEH(.seh_pushreg %rbp)
+ SEH(.seh_setframe %rbp, 0)
+ SEH(.seh_endprologue)
+ movq arg0, %rsp
+
+ movq arg2, %r10
+
+ /* Load all slots into both general and xmm registers. */
+ movq (%rsp), %rcx
+ movsd (%rsp), %xmm0
+ movq 8(%rsp), %rdx
+ movsd 8(%rsp), %xmm1
+ movq 16(%rsp), %r8
+ movsd 16(%rsp), %xmm2
+ movq 24(%rsp), %r9
+ movsd 24(%rsp), %xmm3
+
+ call *16(%rbp)
+
+ movl 24(%rbp), %ecx
+ movq 32(%rbp), %r8
+ leaq 0f(%rip), %r10
+ cmpl $FFI_TYPE_SMALL_STRUCT_4B, %ecx
+ leaq (%r10, %rcx, 8), %r10
+ ja 99f
+ jmp *%r10
+
+/* Below, we're space constrained most of the time. Thus we eschew the
+ modern "mov, pop, ret" sequence (5 bytes) for "leave, ret" (2 bytes). */
+.macro epilogue
+ leaveq
+ cfi_remember_state
+ cfi_def_cfa(%rsp, 8)
+ cfi_restore(%rbp)
+ ret
+ cfi_restore_state
+.endm
+
+ .align 8
+0:
+E(0b, FFI_TYPE_VOID)
+ epilogue
+E(0b, FFI_TYPE_INT)
+ movslq %eax, %rax
+ movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_FLOAT)
+ movss %xmm0, (%r8)
+ epilogue
+E(0b, FFI_TYPE_DOUBLE)
+ movsd %xmm0, (%r8)
+ epilogue
+E(0b, FFI_TYPE_LONGDOUBLE)
+ call PLT(C(abort))
+E(0b, FFI_TYPE_UINT8)
+ movzbl %al, %eax
+ movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SINT8)
+ movsbq %al, %rax
+ jmp 98f
+E(0b, FFI_TYPE_UINT16)
+ movzwl %ax, %eax
+ movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SINT16)
+ movswq %ax, %rax
+ jmp 98f
+E(0b, FFI_TYPE_UINT32)
+ movl %eax, %eax
+ movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SINT32)
+ movslq %eax, %rax
+ movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_UINT64)
+98: movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SINT64)
+ movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_STRUCT)
+ epilogue
+E(0b, FFI_TYPE_POINTER)
+ movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_COMPLEX)
+ call PLT(C(abort))
+E(0b, FFI_TYPE_SMALL_STRUCT_1B)
+ movb %al, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SMALL_STRUCT_2B)
+ movw %ax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SMALL_STRUCT_4B)
+ movl %eax, (%r8)
+ epilogue
+
+ .align 8
+99: call PLT(C(abort))
+
+ epilogue
+
+ cfi_endproc
+ SEH(.seh_endproc)
+
+
+/* 32 bytes of outgoing register stack space, 8 bytes of alignment,
+ 16 bytes of result, 32 bytes of xmm registers. */
+#define ffi_clo_FS (32+8+16+32)
+#define ffi_clo_OFF_R (32+8)
+#define ffi_clo_OFF_X (32+8+16)
+
+ .align 8
+ .globl C(ffi_go_closure_win64)
+ FFI_HIDDEN(C(ffi_go_closure_win64))
+
+ SEH(.seh_proc ffi_go_closure_win64)
+C(ffi_go_closure_win64):
+ cfi_startproc
+ /* Save all integer arguments into the incoming reg stack space. */
+ movq %rcx, 8(%rsp)
+ movq %rdx, 16(%rsp)
+ movq %r8, 24(%rsp)
+ movq %r9, 32(%rsp)
+
+ movq 8(%r10), %rcx /* load cif */
+ movq 16(%r10), %rdx /* load fun */
+ movq %r10, %r8 /* closure is user_data */
+ jmp 0f
+ cfi_endproc
+ SEH(.seh_endproc)
+
+ .align 8
+ .globl C(ffi_closure_win64)
+ FFI_HIDDEN(C(ffi_closure_win64))
+
+ SEH(.seh_proc ffi_closure_win64)
+C(ffi_closure_win64):
+ cfi_startproc
+ /* Save all integer arguments into the incoming reg stack space. */
+ movq %rcx, 8(%rsp)
+ movq %rdx, 16(%rsp)
+ movq %r8, 24(%rsp)
+ movq %r9, 32(%rsp)
+
+ movq FFI_TRAMPOLINE_SIZE(%r10), %rcx /* load cif */
+ movq FFI_TRAMPOLINE_SIZE+8(%r10), %rdx /* load fun */
+ movq FFI_TRAMPOLINE_SIZE+16(%r10), %r8 /* load user_data */
+0:
+ subq $ffi_clo_FS, %rsp
+ cfi_adjust_cfa_offset(ffi_clo_FS)
+ SEH(.seh_stackalloc ffi_clo_FS)
+ SEH(.seh_endprologue)
+
+ /* Save all sse arguments into the stack frame. */
+ movsd %xmm0, ffi_clo_OFF_X(%rsp)
+ movsd %xmm1, ffi_clo_OFF_X+8(%rsp)
+ movsd %xmm2, ffi_clo_OFF_X+16(%rsp)
+ movsd %xmm3, ffi_clo_OFF_X+24(%rsp)
+
+ leaq ffi_clo_OFF_R(%rsp), %r9
+ call PLT(C(ffi_closure_win64_inner))
+
+ /* Load the result into both possible result registers. */
+ movq ffi_clo_OFF_R(%rsp), %rax
+ movsd ffi_clo_OFF_R(%rsp), %xmm0
+
+ addq $ffi_clo_FS, %rsp
+ cfi_adjust_cfa_offset(-ffi_clo_FS)
+ ret
+
+ cfi_endproc
+ SEH(.seh_endproc)
+#endif /* __x86_64__ */
+
+#if defined __ELF__ && defined __linux__
+ .section .note.GNU-stack,"",@progbits
+#endif
diff --git a/src/x86/win64_intel.S b/src/x86/win64_intel.S
new file mode 100644
index 00000000..7df78b30
--- /dev/null
+++ b/src/x86/win64_intel.S
@@ -0,0 +1,237 @@
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+#include <ffi_cfi.h>
+#include "asmnames.h"
+
+#if defined(HAVE_AS_CFI_PSEUDO_OP)
+ .cfi_sections .debug_frame
+#endif
+
+#ifdef X86_WIN64
+#define SEH(...) __VA_ARGS__
+#define arg0 rcx
+#define arg1 rdx
+#define arg2 r8
+#define arg3 r9
+#else
+#define SEH(...)
+#define arg0 rdi
+#define arg1 rsi
+#define arg2 rdx
+#define arg3 rcx
+#endif
+
+/* This macro allows the safe creation of jump tables without an
+ actual table. The entry points into the table are all 8 bytes.
+ The use of ORG asserts that we're at the correct location. */
+/* ??? The clang assembler doesn't handle .org with symbolic expressions. */
+#if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
+# define E(BASE, X) ALIGN 8
+#else
+# define E(BASE, X) ALIGN 8; ORG BASE + X * 8
+#endif
+
+ .CODE
+ extern PLT(C(abort)):near
+ extern C(ffi_closure_win64_inner):near
+
+/* ffi_call_win64 (void *stack, struct win64_call_frame *frame, void *r10)
+
+ Bit o trickiness here -- FRAME is the base of the stack frame
+ for this function. This has been allocated by ffi_call. We also
+ deallocate some of the stack that has been alloca'd. */
+
+ ALIGN 8
+ PUBLIC C(ffi_call_win64)
+
+ ; SEH(.safesh ffi_call_win64)
+C(ffi_call_win64) proc SEH(frame)
+ cfi_startproc
+ /* Set up the local stack frame and install it in rbp/rsp. */
+ mov RAX, [RSP] ; movq (%rsp), %rax
+ mov [arg1], RBP ; movq %rbp, (arg1)
+ mov [arg1 + 8], RAX; movq %rax, 8(arg1)
+ mov RBP, arg1; movq arg1, %rbp
+ cfi_def_cfa(rbp, 16)
+ cfi_rel_offset(rbp, 0)
+ SEH(.pushreg rbp)
+ SEH(.setframe rbp, 0)
+ SEH(.endprolog)
+ mov RSP, arg0 ; movq arg0, %rsp
+
+ mov R10, arg2 ; movq arg2, %r10
+
+ /* Load all slots into both general and xmm registers. */
+ mov RCX, [RSP] ; movq (%rsp), %rcx
+ movsd XMM0, qword ptr [RSP] ; movsd (%rsp), %xmm0
+ mov RDX, [RSP + 8] ;movq 8(%rsp), %rdx
+ movsd XMM1, qword ptr [RSP + 8]; movsd 8(%rsp), %xmm1
+ mov R8, [RSP + 16] ; movq 16(%rsp), %r8
+ movsd XMM2, qword ptr [RSP + 16] ; movsd 16(%rsp), %xmm2
+ mov R9, [RSP + 24] ; movq 24(%rsp), %r9
+ movsd XMM3, qword ptr [RSP + 24] ;movsd 24(%rsp), %xmm3
+
+ CALL qword ptr [RBP + 16] ; call *16(%rbp)
+
+ mov ECX, [RBP + 24] ; movl 24(%rbp), %ecx
+ mov R8, [RBP + 32] ; movq 32(%rbp), %r8
+ LEA R10, ffi_call_win64_tab ; leaq 0f(%rip), %r10
+ CMP ECX, FFI_TYPE_SMALL_STRUCT_4B ; cmpl $FFI_TYPE_SMALL_STRUCT_4B, %ecx
+ LEA R10, [R10 + RCX*8] ; leaq (%r10, %rcx, 8), %r10
+ JA L99 ; ja 99f
+ JMP R10 ; jmp *%r10
+
+/* Below, we're space constrained most of the time. Thus we eschew the
+ modern "mov, pop, ret" sequence (5 bytes) for "leave, ret" (2 bytes). */
+epilogue macro
+ LEAVE
+ cfi_remember_state
+ cfi_def_cfa(rsp, 8)
+ cfi_restore(rbp)
+ RET
+ cfi_restore_state
+endm
+
+ ALIGN 8
+ffi_call_win64_tab LABEL NEAR
+E(0b, FFI_TYPE_VOID)
+ epilogue
+E(0b, FFI_TYPE_INT)
+ movsxd rax, eax ; movslq %eax, %rax
+ mov qword ptr [r8], rax; movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_FLOAT)
+ movss dword ptr [r8], xmm0 ; movss %xmm0, (%r8)
+ epilogue
+E(0b, FFI_TYPE_DOUBLE)
+ movsd qword ptr[r8], xmm0; movsd %xmm0, (%r8)
+ epilogue
+E(0b, FFI_TYPE_LONGDOUBLE)
+ call PLT(C(abort))
+E(0b, FFI_TYPE_UINT8)
+ movzx eax, al ;movzbl %al, %eax
+ mov qword ptr[r8], rax; movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SINT8)
+ movsx rax, al ; movsbq %al, %rax
+ jmp L98
+E(0b, FFI_TYPE_UINT16)
+ movzx eax, ax ; movzwl %ax, %eax
+ mov qword ptr[r8], rax; movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SINT16)
+ movsx rax, ax; movswq %ax, %rax
+ jmp L98
+E(0b, FFI_TYPE_UINT32)
+ mov eax, eax; movl %eax, %eax
+ mov qword ptr[r8], rax ; movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SINT32)
+ movsxd rax, eax; movslq %eax, %rax
+ mov qword ptr [r8], rax; movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_UINT64)
+L98 LABEL near
+ mov qword ptr [r8], rax ; movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SINT64)
+ mov qword ptr [r8], rax;movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_STRUCT)
+ epilogue
+E(0b, FFI_TYPE_POINTER)
+ mov qword ptr [r8], rax ;movq %rax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_COMPLEX)
+ call PLT(C(abort))
+E(0b, FFI_TYPE_SMALL_STRUCT_1B)
+ mov byte ptr [r8], al ; movb %al, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SMALL_STRUCT_2B)
+ mov word ptr [r8], ax ; movw %ax, (%r8)
+ epilogue
+E(0b, FFI_TYPE_SMALL_STRUCT_4B)
+ mov dword ptr [r8], eax ; movl %eax, (%r8)
+ epilogue
+
+ align 8
+L99 LABEL near
+ call PLT(C(abort))
+
+ epilogue
+
+ cfi_endproc
+ C(ffi_call_win64) endp
+
+
+/* 32 bytes of outgoing register stack space, 8 bytes of alignment,
+ 16 bytes of result, 32 bytes of xmm registers. */
+#define ffi_clo_FS (32+8+16+32)
+#define ffi_clo_OFF_R (32+8)
+#define ffi_clo_OFF_X (32+8+16)
+
+ align 8
+ PUBLIC C(ffi_go_closure_win64)
+
+C(ffi_go_closure_win64) proc
+ cfi_startproc
+ /* Save all integer arguments into the incoming reg stack space. */
+ mov qword ptr [rsp + 8], rcx; movq %rcx, 8(%rsp)
+ mov qword ptr [rsp + 16], rdx; movq %rdx, 16(%rsp)
+ mov qword ptr [rsp + 24], r8; movq %r8, 24(%rsp)
+ mov qword ptr [rsp + 32], r9 ;movq %r9, 32(%rsp)
+
+ mov rcx, qword ptr [r10 + 8]; movq 8(%r10), %rcx /* load cif */
+ mov rdx, qword ptr [r10 + 16]; movq 16(%r10), %rdx /* load fun */
+ mov r8, r10 ; movq %r10, %r8 /* closure is user_data */
+ jmp ffi_closure_win64_2
+ cfi_endproc
+ C(ffi_go_closure_win64) endp
+
+ align 8
+
+PUBLIC C(ffi_closure_win64)
+C(ffi_closure_win64) PROC FRAME
+ cfi_startproc
+ /* Save all integer arguments into the incoming reg stack space. */
+ mov qword ptr [rsp + 8], rcx; movq %rcx, 8(%rsp)
+ mov qword ptr [rsp + 16], rdx; movq %rdx, 16(%rsp)
+ mov qword ptr [rsp + 24], r8; movq %r8, 24(%rsp)
+ mov qword ptr [rsp + 32], r9; movq %r9, 32(%rsp)
+
+ mov rcx, qword ptr [FFI_TRAMPOLINE_SIZE + r10] ;movq FFI_TRAMPOLINE_SIZE(%r10), %rcx /* load cif */
+ mov rdx, qword ptr [FFI_TRAMPOLINE_SIZE + 8 + r10] ; movq FFI_TRAMPOLINE_SIZE+8(%r10), %rdx /* load fun */
+ mov r8, qword ptr [FFI_TRAMPOLINE_SIZE+16+r10] ;movq FFI_TRAMPOLINE_SIZE+16(%r10), %r8 /* load user_data */
+ffi_closure_win64_2 LABEL near
+ sub rsp, ffi_clo_FS ;subq $ffi_clo_FS, %rsp
+ cfi_adjust_cfa_offset(ffi_clo_FS)
+ SEH(.allocstack ffi_clo_FS)
+ SEH(.endprolog)
+
+ /* Save all sse arguments into the stack frame. */
+ movsd qword ptr [ffi_clo_OFF_X + rsp], xmm0 ; movsd %xmm0, ffi_clo_OFF_X(%rsp)
+ movsd qword ptr [ffi_clo_OFF_X+8+rsp], xmm1 ; movsd %xmm1, ffi_clo_OFF_X+8(%rsp)
+ movsd qword ptr [ffi_clo_OFF_X+16+rsp], xmm2 ; movsd %xmm2, ffi_clo_OFF_X+16(%rsp)
+ movsd qword ptr [ffi_clo_OFF_X+24+rsp], xmm3 ; movsd %xmm3, ffi_clo_OFF_X+24(%rsp)
+
+ lea r9, [ffi_clo_OFF_R + rsp] ; leaq ffi_clo_OFF_R(%rsp), %r9
+ call C(ffi_closure_win64_inner)
+
+ /* Load the result into both possible result registers. */
+
+ mov rax, qword ptr [ffi_clo_OFF_R + rsp] ;movq ffi_clo_OFF_R(%rsp), %rax
+ movsd xmm0, qword ptr [rsp + ffi_clo_OFF_R] ;movsd ffi_clo_OFF_R(%rsp), %xmm0
+
+ add rsp, ffi_clo_FS ;addq $ffi_clo_FS, %rsp
+ cfi_adjust_cfa_offset(-ffi_clo_FS)
+ ret
+
+ cfi_endproc
+ C(ffi_closure_win64) endp
+
+#if defined __ELF__ && defined __linux__
+ .section .note.GNU-stack,"",@progbits
+#endif
+_text ends
+end \ No newline at end of file
diff --git a/src/xtensa/ffi.c b/src/xtensa/ffi.c
index fd94dafb..9a0575ff 100644
--- a/src/xtensa/ffi.c
+++ b/src/xtensa/ffi.c
@@ -89,7 +89,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
/* Round the stack up to a full 4 register frame, just in case
(we use this size in movsp). This way, it's also a multiple of
8 bytes for 64-bit arguments. */
- cif->bytes = ALIGN(cif->bytes, 16);
+ cif->bytes = FFI_ALIGN(cif->bytes, 16);
return FFI_OK;
}
@@ -205,7 +205,7 @@ void ffi_call(ffi_cif* cif, void(*fn)(void), void *rvalue, void **avalue)
if (flags == FFI_TYPE_STRUCT && (rsize <= 16 || rvalue == NULL))
{
- alloc = alloca(ALIGN(rsize, 4));
+ alloc = alloca(FFI_ALIGN(rsize, 4));
ecif.rvalue = alloc;
}
else
diff --git a/src/xtensa/sysv.S b/src/xtensa/sysv.S
index 64e6a091..e9421796 100644
--- a/src/xtensa/sysv.S
+++ b/src/xtensa/sysv.S
@@ -169,8 +169,13 @@ ENTRY(ffi_cacheflush)
entry a1, 16
-1: dhwbi a2, 0
+1:
+#if XCHAL_DCACHE_SIZE
+ dhwbi a2, 0
+#endif
+#if XCHAL_ICACHE_SIZE
ihi a2, 0
+#endif
addi a2, a2, 4
blt a2, a3, 1b
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index da10465d..bcfea577 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -6,80 +6,117 @@ EXTRA_DEJAGNU_SITE_CONFIG=../local.exp
CLEANFILES = *.exe core* *.log *.sum
-EXTRA_DIST = config/default.exp libffi.call/cls_19byte.c \
-libffi.call/cls_align_longdouble_split.c \
-libffi.call/closure_loc_fn0.c libffi.call/cls_schar.c \
-libffi.call/closure_fn1.c \
-libffi.call/return_ul.c libffi.call/cls_align_double.c \
-libffi.call/return_fl2.c libffi.call/cls_1_1byte.c \
-libffi.call/cls_64byte.c libffi.call/nested_struct7.c \
-libffi.call/cls_align_sint32.c libffi.call/nested_struct2.c \
-libffi.call/ffitest.h libffi.call/nested_struct4.c \
-libffi.call/cls_multi_ushort.c libffi.call/struct3.c \
-libffi.call/cls_3byte1.c libffi.call/cls_16byte.c \
-libffi.call/struct8.c libffi.call/nested_struct8.c \
-libffi.call/cls_multi_sshort.c libffi.call/cls_3byte2.c \
-libffi.call/cls_pointer.c \
-libffi.call/err_bad_typedef.c libffi.call/cls_4_1byte.c \
-libffi.call/cls_9byte2.c libffi.call/cls_multi_schar.c \
-libffi.call/stret_medium2.c libffi.call/cls_5_1_byte.c \
-libffi.call/call.exp libffi.call/cls_double.c \
-libffi.call/cls_align_sint16.c libffi.call/cls_uint.c \
-libffi.call/return_ll1.c libffi.call/nested_struct3.c \
-libffi.call/cls_20byte1.c libffi.call/closure_fn4.c \
-libffi.call/cls_uchar.c libffi.call/struct2.c libffi.call/cls_7byte.c \
-libffi.call/strlen.c libffi.call/many.c libffi.call/testclosure.c \
-libffi.call/return_fl.c libffi.call/struct5.c \
-libffi.call/cls_12byte.c libffi.call/cls_multi_sshortchar.c \
-libffi.call/cls_align_longdouble_split2.c libffi.call/return_dbl2.c \
-libffi.call/return_fl3.c libffi.call/stret_medium.c \
-libffi.call/nested_struct6.c libffi.call/closure_fn3.c \
-libffi.call/float3.c libffi.call/many2.c \
-libffi.call/closure_simple.c libffi.call/cls_align_uint16.c \
-libffi.call/cls_9byte1.c libffi.call/closure_fn6.c \
-libffi.call/cls_double_va.c libffi.call/cls_align_pointer.c \
-libffi.call/cls_align_longdouble.c libffi.call/closure_fn2.c \
-libffi.call/cls_sshort.c \
-libffi.call/nested_struct.c libffi.call/cls_20byte.c \
-libffi.call/cls_longdouble.c libffi.call/cls_multi_uchar.c \
-libffi.call/return_uc.c \
-libffi.call/cls_18byte.c libffi.call/cls_8byte.c \
-libffi.call/promotion.c \
-libffi.call/return_dbl.c libffi.call/cls_24byte.c \
-libffi.call/struct4.c libffi.call/cls_6byte.c \
-libffi.call/cls_align_uint32.c libffi.call/float.c \
-libffi.call/float1.c libffi.call/float_va.c libffi.call/negint.c \
-libffi.call/return_dbl1.c libffi.call/cls_3_1byte.c \
-libffi.call/cls_align_float.c libffi.call/return_fl1.c \
-libffi.call/nested_struct10.c libffi.call/nested_struct5.c \
-libffi.call/cls_align_sint64.c \
-libffi.call/stret_large2.c libffi.call/return_sl.c \
-libffi.call/closure_fn0.c libffi.call/cls_5byte.c \
-libffi.call/cls_2byte.c libffi.call/float2.c \
-libffi.call/cls_dbls_struct.c libffi.call/cls_sint.c \
-libffi.call/stret_large.c libffi.call/cls_ulonglong.c \
-libffi.call/cls_ushort.c libffi.call/nested_struct1.c \
-libffi.call/err_bad_abi.c libffi.call/cls_longdouble_va.c \
-libffi.call/cls_float.c libffi.call/cls_pointer_stack.c \
-libffi.call/pyobjc-tc.c libffi.call/cls_multi_ushortchar.c \
-libffi.call/struct1.c libffi.call/nested_struct9.c \
-libffi.call/huge_struct.c libffi.call/problem1.c \
-libffi.call/float4.c \
-libffi.call/return_ldl.c \
-libffi.call/closure_fn5.c \
-libffi.call/struct6.c libffi.call/return_ll.c libffi.call/struct9.c \
-libffi.call/return_sc.c libffi.call/struct7.c \
-libffi.call/cls_align_uint64.c libffi.call/cls_4byte.c \
-libffi.call/cls_6_1_byte.c \
-libffi.call/cls_7_1_byte.c libffi.call/unwindtest.cc \
-libffi.call/unwindtest_ffi_call.cc \
-lib/wrapper.exp lib/target-libpath.exp \
-lib/libffi.exp libffi.call/cls_struct_va1.c \
-libffi.call/cls_uchar_va.c libffi.call/cls_uint_va.c \
-libffi.call/cls_ulong_va.c libffi.call/cls_ushort_va.c \
-libffi.call/nested_struct11.c libffi.call/uninitialized.c \
-libffi.call/va_1.c libffi.call/va_struct1.c libffi.call/va_struct2.c \
-libffi.call/va_struct3.c \
-libffi.call/strlen2.c \
-libffi.call/strlen3.c \
-libffi.call/strlen4.c
+EXTRA_DIST = lib/target-libpath.exp lib/libffi.exp lib/wrapper.exp \
+libffi.call/strlen4.c libffi.call/struct10.c libffi.call/many_mixed.c \
+libffi.call/float.c libffi.call/struct5.c libffi.call/return_fl3.c \
+libffi.call/return_fl1.c libffi.call/call.exp libffi.call/pyobjc-tc.c \
+libffi.call/float_va.c libffi.call/struct8.c libffi.call/pr1172638.c \
+libffi.call/return_sc.c libffi.call/va_struct1.c \
+libffi.call/align_stdcall.c libffi.call/struct9.c libffi.call/va_1.c \
+libffi.call/va_struct2.c libffi.call/return_fl2.c \
+libffi.call/align_mixed.c libffi.call/ffitest.h libffi.call/struct4.c \
+libffi.call/return_ldl.c libffi.call/float3.c libffi.call/return_sl.c \
+libffi.call/return_dbl1.c libffi.call/err_bad_typedef.c \
+libffi.call/return_ll1.c libffi.call/return_dbl2.c \
+libffi.call/negint.c libffi.closures/nested_struct3.c \
+libffi.call/struct2.c libffi.call/struct3.c libffi.call/return_fl.c \
+libffi.call/offsets.c libffi.call/struct7.c libffi.call/va_struct3.c \
+libffi.call/float1.c libffi.call/uninitialized.c libffi.call/many2.c \
+libffi.call/struct6.c libffi.call/strlen2.c libffi.call/float2.c \
+libffi.call/return_ul.c libffi.call/struct1.c libffi.call/strlen3.c \
+libffi.call/return_dbl.c libffi.call/float4.c libffi.call/many.c \
+libffi.call/strlen.c libffi.call/return_uc.c libffi.call/many_double.c \
+libffi.call/return_ll.c libffi.call/promotion.c \
+libffi.complex/complex_defs_longdouble.inc \
+libffi.complex/cls_align_complex_float.c \
+libffi.complex/cls_complex_va_float.c \
+libffi.complex/cls_complex_struct_float.c \
+libffi.complex/return_complex2_longdouble.c \
+libffi.complex/cls_complex_float.c \
+libffi.complex/return_complex_longdouble.c \
+libffi.complex/return_complex2_float.c libffi.complex/cls_complex.inc \
+libffi.complex/cls_complex_va_longdouble.c \
+libffi.complex/return_complex_double.c \
+libffi.complex/return_complex.inc libffi.complex/many_complex.inc \
+libffi.complex/complex_float.c libffi.complex/cls_align_complex.inc \
+libffi.complex/return_complex2_double.c \
+libffi.complex/many_complex_float.c libffi.complex/ffitest.h \
+libffi.complex/return_complex1_double.c \
+libffi.complex/cls_complex_struct_longdouble.c \
+libffi.complex/complex_defs_double.inc \
+libffi.complex/cls_complex_va_double.c \
+libffi.complex/many_complex_double.c \
+libffi.complex/return_complex2.inc \
+libffi.complex/return_complex1_float.c \
+libffi.complex/complex_longdouble.c \
+libffi.complex/complex_defs_float.inc \
+libffi.complex/cls_complex_double.c \
+libffi.complex/cls_align_complex_double.c \
+libffi.complex/cls_align_complex_longdouble.c \
+libffi.complex/complex_double.c libffi.complex/cls_complex_va.inc \
+libffi.complex/many_complex_longdouble.c libffi.complex/complex.inc \
+libffi.complex/return_complex1_longdouble.c \
+libffi.complex/complex_int.c libffi.complex/cls_complex_longdouble.c \
+libffi.complex/cls_complex_struct_double.c \
+libffi.complex/return_complex1.inc libffi.complex/complex.exp \
+libffi.complex/cls_complex_struct.inc \
+libffi.complex/return_complex_float.c libffi.go/closure1.c \
+libffi.go/aa-direct.c libffi.go/ffitest.h libffi.go/go.exp \
+libffi.go/static-chain.h libffi.bhaible/bhaible.exp \
+libffi.bhaible/test-call.c libffi.bhaible/alignof.h \
+libffi.bhaible/testcases.c libffi.bhaible/test-callback.c \
+libffi.bhaible/Makefile libffi.bhaible/README config/default.exp \
+libffi.closures/cls_multi_sshort.c \
+libffi.closures/cls_align_longdouble_split2.c \
+libffi.closures/cls_1_1byte.c libffi.closures/cls_uint_va.c \
+libffi.closures/cls_3_1byte.c libffi.closures/cls_many_mixed_args.c \
+libffi.closures/cls_20byte1.c libffi.closures/cls_pointer_stack.c \
+libffi.closures/cls_align_float.c libffi.closures/cls_5_1_byte.c \
+libffi.closures/cls_9byte1.c libffi.closures/cls_align_uint32.c \
+libffi.closures/stret_medium.c libffi.closures/cls_3byte1.c \
+libffi.closures/cls_align_uint64.c libffi.closures/cls_longdouble_va.c \
+libffi.closures/cls_align_pointer.c libffi.closures/cls_19byte.c \
+libffi.closures/cls_ushort.c libffi.closures/cls_align_sint32.c \
+libffi.closures/cls_ulonglong.c libffi.closures/cls_struct_va1.c \
+libffi.closures/cls_9byte2.c libffi.closures/closure_fn5.c \
+libffi.closures/cls_5byte.c libffi.closures/cls_3float.c \
+libffi.closures/closure.exp libffi.closures/cls_schar.c \
+libffi.closures/closure_fn4.c libffi.closures/cls_uchar_va.c \
+libffi.closures/closure_fn0.c libffi.closures/huge_struct.c \
+libffi.closures/cls_ushort_va.c \
+libffi.closures/cls_64byte.c libffi.closures/cls_longdouble.c \
+libffi.closures/cls_ulong_va.c libffi.closures/cls_6_1_byte.c \
+libffi.closures/cls_align_uint16.c libffi.closures/closure_fn2.c \
+libffi.closures/unwindtest_ffi_call.cc \
+libffi.closures/cls_multi_ushortchar.c libffi.closures/cls_8byte.c \
+libffi.closures/ffitest.h libffi.closures/nested_struct8.c \
+libffi.closures/cls_pointer.c libffi.closures/nested_struct2.c \
+libffi.closures/nested_struct.c libffi.closures/cls_multi_schar.c \
+libffi.closures/cls_align_longdouble_split.c \
+libffi.closures/cls_uchar.c libffi.closures/nested_struct9.c \
+libffi.closures/cls_float.c libffi.closures/stret_medium2.c \
+libffi.closures/closure_loc_fn0.c libffi.closures/cls_6byte.c \
+libffi.closures/closure_simple.c libffi.closures/cls_align_double.c \
+libffi.closures/cls_multi_uchar.c libffi.closures/cls_4_1byte.c \
+libffi.closures/closure_fn3.c libffi.closures/cls_align_sint64.c \
+libffi.closures/nested_struct1.c libffi.closures/unwindtest.cc \
+libffi.closures/nested_struct5.c libffi.closures/cls_multi_ushort.c \
+libffi.closures/nested_struct11.c \
+libffi.closures/cls_multi_sshortchar.c \
+libffi.closures/cls_align_longdouble.c \
+libffi.closures/cls_dbls_struct.c \
+libffi.closures/cls_many_mixed_float_double.c \
+libffi.closures/stret_large.c libffi.closures/stret_large2.c \
+libffi.closures/cls_align_sint16.c libffi.closures/cls_2byte.c \
+libffi.closures/nested_struct4.c libffi.closures/problem1.c \
+libffi.closures/testclosure.c libffi.closures/nested_struct6.c \
+libffi.closures/cls_4byte.c libffi.closures/cls_24byte.c \
+libffi.closures/nested_struct10.c libffi.closures/cls_uint.c \
+libffi.closures/cls_12byte.c libffi.closures/cls_sint.c \
+libffi.closures/cls_7_1_byte.c libffi.closures/cls_sshort.c \
+libffi.closures/cls_16byte.c libffi.closures/nested_struct7.c \
+libffi.closures/cls_double_va.c libffi.closures/cls_3byte2.c \
+libffi.closures/cls_double.c libffi.closures/cls_7byte.c \
+libffi.closures/closure_fn6.c libffi.closures/closure_fn1.c \
+libffi.closures/cls_20byte.c libffi.closures/cls_18byte.c \
+libffi.closures/err_bad_abi.c
diff --git a/testsuite/lib/libffi.exp b/testsuite/lib/libffi.exp
index 5051d317..c02adf95 100644
--- a/testsuite/lib/libffi.exp
+++ b/testsuite/lib/libffi.exp
@@ -1,4 +1,4 @@
-# Copyright (C) 2003, 2005, 2008, 2009, 2010, 2011, 2014 Free Software Foundation, Inc.
+# Copyright (C) 2003, 2005, 2008, 2009, 2010, 2011, 2014, 2019 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -24,6 +24,178 @@ load_lib libgloss.exp
load_gcc_lib target-libpath.exp
load_gcc_lib wrapper.exp
+# Return 1 if the target matches the effective target 'arg', 0 otherwise.
+# This can be used with any check_* proc that takes no argument and
+# returns only 1 or 0. It could be used with check_* procs that take
+# arguments with keywords that pass particular arguments.
+
+proc is-effective-target { arg } {
+ global et_index
+ set selected 0
+ if { ![info exists et_index] } {
+ # Initialize the effective target index that is used in some
+ # check_effective_target_* procs.
+ set et_index 0
+ }
+ if { [info procs check_effective_target_${arg}] != [list] } {
+ set selected [check_effective_target_${arg}]
+ } else {
+ error "unknown effective target keyword `$arg'"
+ }
+ verbose "is-effective-target: $arg $selected" 2
+ return $selected
+}
+
+proc is-effective-target-keyword { arg } {
+ if { [info procs check_effective_target_${arg}] != [list] } {
+ return 1
+ } else {
+ return 0
+ }
+}
+
+# Intercept the call to the DejaGnu version of dg-process-target to
+# support use of an effective-target keyword in place of a list of
+# target triplets to xfail or skip a test.
+#
+# The argument to dg-process-target is the keyword "target" or "xfail"
+# followed by a selector:
+# target-triplet-1 ...
+# effective-target-keyword
+# selector-expression
+#
+# For a target list the result is "S" if the target is selected, "N" otherwise.
+# For an xfail list the result is "F" if the target is affected, "P" otherwise.
+
+# In contexts that allow either "target" or "xfail" the argument can be
+# target selector1 xfail selector2
+# which returns "N" if selector1 is not selected, otherwise the result of
+# "xfail selector2".
+#
+# A selector expression appears within curly braces and uses a single logical
+# operator: !, &&, or ||. An operand is another selector expression, an
+# effective-target keyword, or a list of target triplets within quotes or
+# curly braces.
+
+if { [info procs saved-dg-process-target] == [list] } {
+ rename dg-process-target saved-dg-process-target
+
+ # Evaluate an operand within a selector expression.
+ proc selector_opd { op } {
+ set selector "target"
+ lappend selector $op
+ set answer [ expr { [dg-process-target $selector] == "S" } ]
+ verbose "selector_opd: `$op' $answer" 2
+ return $answer
+ }
+
+ # Evaluate a target triplet list within a selector expression.
+ # Unlike other operands, this needs to be expanded from a list to
+ # the same string as "target".
+ proc selector_list { op } {
+ set selector "target [join $op]"
+ set answer [ expr { [dg-process-target $selector] == "S" } ]
+ verbose "selector_list: `$op' $answer" 2
+ return $answer
+ }
+
+ # Evaluate a selector expression.
+ proc selector_expression { exp } {
+ if { [llength $exp] == 2 } {
+ if [string match "!" [lindex $exp 0]] {
+ set op1 [lindex $exp 1]
+ set answer [expr { ! [selector_opd $op1] }]
+ } else {
+ # Assume it's a list of target triplets.
+ set answer [selector_list $exp]
+ }
+ } elseif { [llength $exp] == 3 } {
+ set op1 [lindex $exp 0]
+ set opr [lindex $exp 1]
+ set op2 [lindex $exp 2]
+ if [string match "&&" $opr] {
+ set answer [expr { [selector_opd $op1] && [selector_opd $op2] }]
+ } elseif [string match "||" $opr] {
+ set answer [expr { [selector_opd $op1] || [selector_opd $op2] }]
+ } else {
+ # Assume it's a list of target triplets.
+ set answer [selector_list $exp]
+ }
+ } else {
+ # Assume it's a list of target triplets.
+ set answer [selector_list $exp]
+ }
+
+ verbose "selector_expression: `$exp' $answer" 2
+ return $answer
+ }
+
+ # Evaluate "target selector" or "xfail selector".
+
+ proc dg-process-target-1 { args } {
+ verbose "dg-process-target-1: `$args'" 2
+
+ # Extract the 'what' keyword from the argument list.
+ set selector [string trim [lindex $args 0]]
+ if [regexp "^xfail " $selector] {
+ set what "xfail"
+ } elseif [regexp "^target " $selector] {
+ set what "target"
+ } else {
+ error "syntax error in target selector \"$selector\""
+ }
+
+ # Extract the rest of the list, which might be a keyword.
+ regsub "^${what}" $selector "" rest
+ set rest [string trim $rest]
+
+ if [is-effective-target-keyword $rest] {
+ # The selector is an effective target keyword.
+ if [is-effective-target $rest] {
+ return [expr { $what == "xfail" ? "F" : "S" }]
+ } else {
+ return [expr { $what == "xfail" ? "P" : "N" }]
+ }
+ }
+
+ if [string match "{*}" $rest] {
+ if [selector_expression [lindex $rest 0]] {
+ return [expr { $what == "xfail" ? "F" : "S" }]
+ } else {
+ return [expr { $what == "xfail" ? "P" : "N" }]
+ }
+ }
+
+ # The selector is not an effective-target keyword, so process
+ # the list of target triplets.
+ return [saved-dg-process-target $selector]
+ }
+
+ # Intercept calls to the DejaGnu function. In addition to
+ # processing "target selector" or "xfail selector", handle
+ # "target selector1 xfail selector2".
+
+ proc dg-process-target { args } {
+ verbose "replacement dg-process-target: `$args'" 2
+
+ set selector [string trim [lindex $args 0]]
+
+ # If the argument list contains both 'target' and 'xfail',
+ # process 'target' and, if that succeeds, process 'xfail'.
+ if [regexp "^target .* xfail .*" $selector] {
+ set xfail_index [string first "xfail" $selector]
+ set xfail_selector [string range $selector $xfail_index end]
+ set target_selector [string range $selector 0 [expr $xfail_index-1]]
+ set target_selector [string trim $target_selector]
+ if { [dg-process-target-1 $target_selector] == "N" } {
+ return "N"
+ }
+ return [dg-process-target-1 $xfail_selector]
+
+ }
+ return [dg-process-target-1 $selector]
+ }
+}
# Define libffi callbacks for dg.exp.
@@ -89,6 +261,12 @@ proc libffi-dg-test { prog do_what extra_tool_flags } {
return [libffi-dg-test-1 target_compile $prog $do_what $extra_tool_flags]
}
+proc libffi-dg-prune { target_triplet text } {
+ # We get this with some qemu emulated systems (eg. ppc64le-linux-gnu)
+ regsub -all "(^|\n)\[^\n\]*unable to perform all requested operations" $text "" text
+ return $text
+}
+
proc libffi-init { args } {
global gluefile wrap_flags;
global srcdir
@@ -100,46 +278,42 @@ proc libffi-init { args } {
global libffi_link_flags
global tool_root_dir
global ld_library_path
+ global compiler_vendor
- global using_gcc
+ if ![info exists blddirffi] {
+ set blddirffi [pwd]/..
+ }
- set blddirffi [pwd]/..
verbose "libffi $blddirffi"
- # Are we building with GCC?
- set tmp [grep ../config.status "GCC='yes'"]
- if { [string match $tmp "GCC='yes'"] } {
-
- set using_gcc "yes"
+ # Which compiler are we building with?
+ set tmp [grep "$blddirffi/config.log" "^ax_cv_c_compiler_vendor.*$"]
+ regexp -- {^[^=]*=(.*)$} $tmp nil compiler_vendor
- set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a]
- if {$gccdir != ""} {
- set gccdir [file dirname $gccdir]
- }
- verbose "gccdir $gccdir"
-
- set ld_library_path "."
- append ld_library_path ":${gccdir}"
-
- set compiler "${gccdir}/xgcc"
- if { [is_remote host] == 0 && [which $compiler] != 0 } {
- foreach i "[exec $compiler --print-multi-lib]" {
- set mldir ""
- regexp -- "\[a-z0-9=_/\.-\]*;" $i mldir
- set mldir [string trimright $mldir "\;@"]
- if { "$mldir" == "." } {
- continue
- }
- if { [llength [glob -nocomplain ${gccdir}/${mldir}/libgcc_s*.so.*]] >= 1 } {
- append ld_library_path ":${gccdir}/${mldir}"
+ if { [string match $compiler_vendor "gnu"] } {
+ set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a]
+ if {$gccdir != ""} {
+ set gccdir [file dirname $gccdir]
+ }
+ verbose "gccdir $gccdir"
+
+ set ld_library_path "."
+ append ld_library_path ":${gccdir}"
+
+ set compiler "${gccdir}/xgcc"
+ if { [is_remote host] == 0 && [which $compiler] != 0 } {
+ foreach i "[exec $compiler --print-multi-lib]" {
+ set mldir ""
+ regexp -- "\[a-z0-9=_/\.-\]*;" $i mldir
+ set mldir [string trimright $mldir "\;@"]
+ if { "$mldir" == "." } {
+ continue
+ }
+ if { [llength [glob -nocomplain ${gccdir}/${mldir}/libgcc_s*.so.*]] >= 1 } {
+ append ld_library_path ":${gccdir}/${mldir}"
+ }
}
- }
- }
-
- } else {
-
- set using_gcc "no"
-
+ }
}
# add the library path for libffi.
@@ -179,7 +353,7 @@ proc libffi_target_compile { source dest type options } {
global libffi_link_flags
global libffi_include
global target_triplet
-
+ global compiler_vendor
if { [target_info needs_status_wrapper]!="" && [info exists gluefile] } {
lappend options "libs=${gluefile}"
@@ -189,7 +363,7 @@ proc libffi_target_compile { source dest type options } {
# TOOL_OPTIONS must come first, so that it doesn't override testcase
# specific options.
if [info exists TOOL_OPTIONS] {
- lappend options [concat "additional_flags=$TOOL_OPTIONS" $options];
+ lappend options "additional_flags=$TOOL_OPTIONS"
}
# search for ffi_mips.h in srcdir, too
@@ -222,14 +396,38 @@ proc libffi_target_compile { source dest type options } {
lappend options "libs= -lpthread"
}
+ # this may be required for g++, but just confused clang.
if { [string match "*.cc" $source] } {
- lappend options "c++"
+ lappend options "c++"
+ }
+
+ if { [string match "arc*-*-linux*" $target_triplet] } {
+ lappend options "libs= -lpthread"
}
verbose "options: $options"
return [target_compile $source $dest $type $options]
}
+# TEST should be a preprocessor condition. Returns true if it holds.
+proc libffi_feature_test { test } {
+ set src "ffitest[pid].c"
+
+ set f [open $src "w"]
+ puts $f "#include <ffi.h>"
+ puts $f $test
+ puts $f "/* OK */"
+ puts $f "#else"
+ puts $f "# error Failed $test"
+ puts $f "#endif"
+ close $f
+
+ set lines [libffi_target_compile $src /dev/null assembly ""]
+ file delete $src
+
+ return [string match "" $lines]
+}
+
# Utility routines.
#
@@ -278,25 +476,54 @@ proc libffi-dg-runtest { testcases default-extra-flags } {
}
proc run-many-tests { testcases extra_flags } {
- global using_gcc
- if { [string match $using_gcc "yes"] } {
+ global compiler_vendor
+ global env
+ switch $compiler_vendor {
+ "clang" {
+ set common "-W -Wall"
+ if [info exists env(LIBFFI_TEST_OPTIMIZATION)] {
+ set optimizations [ list $env(LIBFFI_TEST_OPTIMIZATION) ]
+ } else {
+ set optimizations { "-O0" "-O2" }
+ }
+ }
+ "gnu" {
set common "-W -Wall -Wno-psabi"
- set optimizations { "-O0" "-O2" "-O3" "-Os" "-O2 -fomit-frame-pointer" }
- } else {
+ if [info exists env(LIBFFI_TEST_OPTIMIZATION)] {
+ set optimizations [ list $env(LIBFFI_TEST_OPTIMIZATION) ]
+ } else {
+ set optimizations { "-O0" "-O2" }
+ }
+ }
+ default {
# Assume we are using the vendor compiler.
set common ""
- set optimizations { "" }
+ if [info exists env(LIBFFI_TEST_OPTIMIZATION)] {
+ set optimizations [ list $env(LIBFFI_TEST_OPTIMIZATION) ]
+ } else {
+ set optimizations { "" }
+ }
+ }
}
+ info exists env(LD_LIBRARY_PATH)
+
set targetabis { "" }
- if [string match $using_gcc "yes"] {
- if [istarget "i?86-*-*"] {
+ if [string match $compiler_vendor "gnu"] {
+ if [libffi_feature_test "#ifdef __i386__"] {
set targetabis {
""
"-DABI_NUM=FFI_STDCALL -DABI_ATTR=__STDCALL__"
"-DABI_NUM=FFI_THISCALL -DABI_ATTR=__THISCALL__"
"-DABI_NUM=FFI_FASTCALL -DABI_ATTR=__FASTCALL__"
}
+ } elseif { [istarget "x86_64-*-*"] \
+ && [libffi_feature_test "#if !defined __ILP32__ \
+ && !defined __i386__"] } {
+ set targetabis {
+ ""
+ "-DABI_NUM=FFI_GNUW64 -DABI_ATTR=__MSABI__"
+ }
}
}
diff --git a/testsuite/libffi.bhaible/Makefile b/testsuite/libffi.bhaible/Makefile
new file mode 100644
index 00000000..3322de94
--- /dev/null
+++ b/testsuite/libffi.bhaible/Makefile
@@ -0,0 +1,28 @@
+CC = gcc
+CFLAGS = -O2 -Wall
+prefix =
+includedir = $(prefix)/include
+libdir = $(prefix)/lib
+CPPFLAGS = -I$(includedir)
+LDFLAGS = -L$(libdir) -Wl,-rpath,$(libdir)
+
+all: check-call check-callback
+
+test-call: test-call.c testcases.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o test-call test-call.c -lffi
+
+test-callback: test-callback.c testcases.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o test-callback test-callback.c -lffi
+
+check-call: test-call
+ ./test-call > test-call.out
+ LC_ALL=C uniq -u < test-call.out > failed-call
+ test '!' -s failed-call
+
+check-callback: test-callback
+ ./test-callback > test-callback.out
+ LC_ALL=C uniq -u < test-callback.out > failed-callback
+ test '!' -s failed-callback
+
+clean:
+ rm -f test-call test-callback test-call.out test-callback.out failed-call failed-callback
diff --git a/testsuite/libffi.bhaible/README b/testsuite/libffi.bhaible/README
new file mode 100644
index 00000000..be8540b6
--- /dev/null
+++ b/testsuite/libffi.bhaible/README
@@ -0,0 +1,78 @@
+This package contains a test suite for libffi.
+
+This test suite can be compiled with a C compiler. No need for 'expect'
+or some other package that is often not installed.
+
+The test suite consists of 81 C functions, each with a different signature.
+* test-call verifies that calling each function directly produces the same
+ results as calling the function indirectly through 'ffi_call'.
+* test-callback verifies that calling each function directly produces the same
+ results as calling a function that is a callback (object build by
+ 'ffi_prep_closure_loc') and simulates the original function.
+
+Each direct or indirect invocation should produce one line of output to
+stdout. A correct output consists of paired lines, such as
+
+void f(void):
+void f(void):
+int f(void):->99
+int f(void):->99
+int f(int):(1)->2
+int f(int):(1)->2
+int f(2*int):(1,2)->3
+int f(2*int):(1,2)->3
+...
+
+The Makefile then creates two files:
+* failed-call, which consists of the non-paired lines of output of
+ 'test-call',
+* failed-callback, which consists of the non-paired lines of output of
+ 'test-callback'.
+
+The test suite passes if both failed-call and failed-callback come out
+as empty.
+
+
+How to use the test suite
+-------------------------
+
+1. Modify the Makefile's variables
+ prefix = the directory in which libffi was installed
+ CC = the C compiler, often with options such as "-m32" or "-m64"
+ that enforce a certain ABI,
+ CFLAGS = optimization options (need to change them only for non-GCC
+ compilers)
+2. Run "make". If it fails already in "test-call", run also
+ "make check-callback".
+3. If this failed, inspect the output files.
+
+
+How to interpret the results
+----------------------------
+
+The failed-call and failed-callback files consist of paired lines:
+The first line is the result of the direct invocation.
+The second line is the result of invocation through libffi.
+
+For example, this output
+
+uchar f(uchar,ushort,uint,ulong):(97,2,3,4)->255
+uchar f(uchar,ushort,uint,ulong):(97,2,3,4)->0
+
+indicates that the arguments were passed correctly, but the return
+value came out wrong.
+
+And this output
+
+float f(17*float,3*int,L):(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,6,7,8,561,1105,1729,2465,2821,6601)->15319.1
+float f(17*float,3*int,L):(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,-140443648,10,268042216,-72537980,-140443648,-140443648,-140443648,-140443648,-140443648)->-6.47158e+08
+
+indicates that integer arguments that come after 17 floating-point arguments
+were not passed correctly.
+
+
+Credits
+-------
+
+The test suite is based on the one of GNU libffcall-2.0.
+Authors: Bill Triggs, Bruno Haible
diff --git a/testsuite/libffi.bhaible/alignof.h b/testsuite/libffi.bhaible/alignof.h
new file mode 100644
index 00000000..00604a51
--- /dev/null
+++ b/testsuite/libffi.bhaible/alignof.h
@@ -0,0 +1,50 @@
+/* Determine alignment of types.
+ Copyright (C) 2003-2004, 2006, 2009-2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+#ifndef _ALIGNOF_H
+#define _ALIGNOF_H
+
+#include <stddef.h>
+
+/* alignof_slot (TYPE)
+ Determine the alignment of a structure slot (field) of a given type,
+ at compile time. Note that the result depends on the ABI.
+ This is the same as alignof (TYPE) and _Alignof (TYPE), defined in
+ <stdalign.h> if __alignof_is_defined is 1.
+ Note: The result cannot be used as a value for an 'enum' constant,
+ due to bugs in HP-UX 10.20 cc and AIX 3.2.5 xlc. */
+#if defined __cplusplus
+ template <class type> struct alignof_helper { char __slot1; type __slot2; };
+# define alignof_slot(type) offsetof (alignof_helper<type>, __slot2)
+#else
+# define alignof_slot(type) offsetof (struct { char __slot1; type __slot2; }, __slot2)
+#endif
+
+/* alignof_type (TYPE)
+ Determine the good alignment of an object of the given type at compile time.
+ Note that this is not necessarily the same as alignof_slot(type).
+ For example, with GNU C on x86 platforms: alignof_type(double) = 8, but
+ - when -malign-double is not specified: alignof_slot(double) = 4,
+ - when -malign-double is specified: alignof_slot(double) = 8.
+ Note: The result cannot be used as a value for an 'enum' constant,
+ due to bugs in HP-UX 10.20 cc and AIX 3.2.5 xlc. */
+#if defined __GNUC__ || defined __IBM__ALIGNOF__
+# define alignof_type __alignof__
+#else
+# define alignof_type alignof_slot
+#endif
+
+#endif /* _ALIGNOF_H */
diff --git a/testsuite/libffi.bhaible/bhaible.exp b/testsuite/libffi.bhaible/bhaible.exp
new file mode 100644
index 00000000..44aebc5e
--- /dev/null
+++ b/testsuite/libffi.bhaible/bhaible.exp
@@ -0,0 +1,63 @@
+# Copyright (C) 2003, 2006, 2009, 2010, 2014, 2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+dg-init
+libffi-init
+
+global srcdir subdir
+global compiler_vendor
+
+# The conversion of this testsuite into a dejagnu compatible testsuite
+# was done in a pretty lazy fashion, and requires the use of compiler
+# flags to disable warnings for now.
+if { [string match $compiler_vendor "gnu"] } {
+ set warning_options "-Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-uninitialized";
+}
+if { [string match $compiler_vendor "microsoft"] } {
+ # -wd4996 suggest use of vsprintf_s instead of vsprintf
+ # -wd4116 unnamed type definition
+ # -wd4101 unreferenced local variable
+ # -wd4244 warning about implicit double to float conversion
+ set warning_options "-wd4996 -wd4116 -wd4101 -wd4244";
+}
+if { ![string match $compiler_vendor "microsoft"] && ![string match $compiler_vendor "gnu"] } {
+ set warning_options "-Wno-unused-variable -Wno-unused-parameter -Wno-uninitialized";
+}
+
+
+set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/test-call.c]]
+
+for {set i 1} {$i < 82} {incr i} {
+ run-many-tests $tlist [format "-DDGTEST=%d %s" $i $warning_options]
+}
+
+set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/test-callback.c]]
+
+for {set i 1} {$i < 81} {incr i} {
+ if { [libffi_feature_test "#if FFI_CLOSURES"] } {
+ run-many-tests $tlist [format "-DDGTEST=%d %s" $i $warning_options]
+ } else {
+ foreach test $tlist {
+ unsupported [format "%s -DDGTEST=%d %s" $test $i $warning_options]
+ }
+ }
+}
+
+dg-finish
+
+# Local Variables:
+# tcl-indent-level:4
+# End:
diff --git a/testsuite/libffi.bhaible/test-call.c b/testsuite/libffi.bhaible/test-call.c
new file mode 100644
index 00000000..01a8a215
--- /dev/null
+++ b/testsuite/libffi.bhaible/test-call.c
@@ -0,0 +1,1745 @@
+/**
+ Copyright 1993 Bill Triggs <Bill.Triggs@inrialpes.fr>
+ Copyright 1995-2017 Bruno Haible <bruno@clisp.org>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**/
+
+/* { dg-do run } */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ffi.h>
+#include "alignof.h"
+#include <stdarg.h>
+
+/* libffi testsuite local changes -------------------------------- */
+#ifdef DGTEST
+/* Redefine exit(1) as a test failure */
+#define exit(V) (void)((V) ? (abort(), 1) : exit(0))
+int count = 0;
+char rbuf1[2048];
+char rbuf2[2048];
+int _fprintf(FILE *stream, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ switch (count++)
+ {
+ case 0:
+ case 1:
+ vsprintf(&rbuf1[strlen(rbuf1)], format, args);
+ break;
+ case 2:
+ printf("%s", rbuf1);
+ vsprintf(rbuf2, format, args);
+ break;
+ case 3:
+ vsprintf(&rbuf2[strlen(rbuf2)], format, args);
+ printf("%s", rbuf2);
+ if (strcmp (rbuf1, rbuf2)) abort();
+ break;
+ }
+
+ va_end(args);
+
+ return 0;
+}
+#define fprintf _fprintf
+#endif
+/* --------------------------------------------------------------- */
+
+#include "testcases.c"
+
+#ifndef ABI_NUM
+#define ABI_NUM FFI_DEFAULT_ABI
+#endif
+
+/* Definitions that ought to be part of libffi. */
+static ffi_type ffi_type_char;
+#define ffi_type_slonglong ffi_type_sint64
+#define ffi_type_ulonglong ffi_type_uint64
+
+/* libffi does not support arrays inside structs. */
+#define SKIP_EXTRA_STRUCTS
+
+#define FFI_PREP_CIF(cif,argtypes,rettype) \
+ if (ffi_prep_cif(&(cif),ABI_NUM,sizeof(argtypes)/sizeof(argtypes[0]),&rettype,argtypes) != FFI_OK) abort()
+#define FFI_PREP_CIF_NOARGS(cif,rettype) \
+ if (ffi_prep_cif(&(cif),ABI_NUM,0,&rettype,NULL) != FFI_OK) abort()
+#define FFI_CALL(cif,fn,args,retaddr) \
+ ffi_call(&(cif),(void(*)(void))(fn),retaddr,args)
+
+long clear_traces_i (long a, long b, long c, long d, long e, long f, long g, long h,
+ long i, long j, long k, long l, long m, long n, long o, long p)
+{ return 0; }
+float clear_traces_f (float a, float b, float c, float d, float e, float f, float g,
+ float h, float i, float j, float k, float l, float m, float n,
+ float o, float p)
+{ return 0.0; }
+double clear_traces_d (double a, double b, double c, double d, double e, double f, double g,
+ double h, double i, double j, double k, double l, double m, double n,
+ double o, double p)
+{ return 0.0; }
+J clear_traces_J (void)
+{ J j; j.l1 = j.l2 = 0; return j; }
+void clear_traces (void)
+{ clear_traces_i(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+ clear_traces_f(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
+ clear_traces_d(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
+ clear_traces_J();
+}
+
+void
+ void_tests (void)
+{
+#if (!defined(DGTEST)) || DGTEST == 1
+ v_v();
+ clear_traces();
+ {
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_void);
+ {
+ FFI_CALL(cif,v_v,NULL,NULL);
+ }
+ }
+#endif
+ return;
+}
+void
+ int_tests (void)
+{
+ int ir;
+ ffi_arg retvalue;
+#if (!defined(DGTEST)) || DGTEST == 2
+ ir = i_v();
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ {
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_sint);
+ {
+ FFI_CALL(cif,i_v,NULL,&retvalue);
+ ir = retvalue;
+ }
+ }
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 3
+ ir = i_i(i1);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ {
+ /*const*/ void* args[] = { &i1 };
+ FFI_CALL(cif,i_i,args,&retvalue);
+ ir = retvalue;
+ }
+ }
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 4
+ ir = i_i2(i1,i2);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ {
+ /*const*/ void* args[] = { &i1, &i2 };
+ FFI_CALL(cif,i_i2,args,&retvalue);
+ ir = retvalue;
+ }
+ }
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 5
+ ir = i_i4(i1,i2,i3,i4);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ {
+ /*const*/ void* args[] = { &i1, &i2, &i3, &i4 };
+ FFI_CALL(cif,i_i4,args,&retvalue);
+ ir = retvalue;
+ }
+ }
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 6
+ ir = i_i8(i1,i2,i3,i4,i5,i6,i7,i8);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ {
+ /*const*/ void* args[] = { &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8 };
+ FFI_CALL(cif,i_i8,args,&retvalue);
+ ir = retvalue;
+ }
+ }
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 7
+ ir = i_i16(i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15,i16);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ {
+ /*const*/ void* args[] = { &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9, &i10, &i11, &i12, &i13, &i14, &i15, &i16 };
+ FFI_CALL(cif,i_i16,args,&retvalue);
+ ir = retvalue;
+ }
+ }
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+ return;
+}
+void
+ float_tests (void)
+{
+ float fr;
+
+#if (!defined(DGTEST)) || DGTEST == 8
+ fr = f_f(f1);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1 };
+ FFI_CALL(cif,f_f,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 9
+ fr = f_f2(f1,f2);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2 };
+ FFI_CALL(cif,f_f2,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 10
+ fr = f_f4(f1,f2,f3,f4);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4 };
+ FFI_CALL(cif,f_f4,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 11
+ fr = f_f8(f1,f2,f3,f4,f5,f6,f7,f8);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8 };
+ FFI_CALL(cif,f_f8,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 12
+ fr = f_f16(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8, &f9, &f10, &f11, &f12, &f13, &f14, &f15, &f16 };
+ FFI_CALL(cif,f_f16,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 13
+ fr = f_f24(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,f18,f19,f20,f21,f22,f23,f24);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8, &f9, &f10, &f11, &f12, &f13, &f14, &f15, &f16, &f17, &f18, &f19, &f20, &f21, &f22, &f23, &f24 };
+ FFI_CALL(cif,f_f24,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+}
+void
+ double_tests (void)
+{
+ double dr;
+
+#if (!defined(DGTEST)) || DGTEST == 14
+
+ dr = d_d(d1);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1 };
+ FFI_CALL(cif,d_d,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 15
+ dr = d_d2(d1,d2);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2 };
+ FFI_CALL(cif,d_d2,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 16
+ dr = d_d4(d1,d2,d3,d4);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &d4 };
+ FFI_CALL(cif,d_d4,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 17
+ dr = d_d8(d1,d2,d3,d4,d5,d6,d7,d8);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8 };
+ FFI_CALL(cif,d_d8,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 18
+ dr = d_d16(d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9, &d10, &d11, &d12, &d13, &d14, &d15, &d16 };
+ FFI_CALL(cif,d_d16,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+ return;
+}
+void
+ pointer_tests (void)
+{
+ void* vpr;
+
+#if (!defined(DGTEST)) || DGTEST == 19
+ vpr = vp_vpdpcpsp(&uc1,&d2,str3,&I4);
+ fprintf(out,"->0x%p\n",vpr);
+ fflush(out);
+ vpr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_pointer, &ffi_type_pointer, &ffi_type_pointer, &ffi_type_pointer };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_pointer);
+ {
+ void* puc1 = &uc1;
+ void* pd2 = &d2;
+ void* pstr3 = str3;
+ void* pI4 = &I4;
+ /*const*/ void* args[] = { &puc1, &pd2, &pstr3, &pI4 };
+ FFI_CALL(cif,vp_vpdpcpsp,args,&vpr);
+ }
+ }
+ fprintf(out,"->0x%p\n",vpr);
+ fflush(out);
+#endif
+ return;
+}
+void
+ mixed_number_tests (void)
+{
+ uchar ucr;
+ ushort usr;
+ float fr;
+ double dr;
+ long long llr;
+
+ /* Unsigned types.
+ */
+#if (!defined(DGTEST)) || DGTEST == 20
+ ucr = uc_ucsil(uc1, us2, ui3, ul4);
+ fprintf(out,"->%u\n",ucr);
+ fflush(out);
+ ucr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_uchar, &ffi_type_ushort, &ffi_type_uint, &ffi_type_ulong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_uchar);
+ {
+ ffi_arg r;
+ /*const*/ void* args[] = { &uc1, &us2, &ui3, &ul4 };
+ FFI_CALL(cif,uc_ucsil,args,&r);
+ ucr = (uchar) r;
+ }
+ }
+ fprintf(out,"->%u\n",ucr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 21
+ /* Mixed int & float types.
+ */
+ dr = d_iidd(i1,i2,d3,d4);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &i1, &i2, &d3, &d4 };
+ FFI_CALL(cif,d_iidd,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 22
+ dr = d_iiidi(i1,i2,i3,d4,i5);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &i1, &i2, &i3, &d4, &i5 };
+ FFI_CALL(cif,d_iiidi,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 23
+ dr = d_idid(i1,d2,i3,d4);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_double, &ffi_type_sint, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &i1, &d2, &i3, &d4 };
+ FFI_CALL(cif,d_idid,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 24
+ dr = d_fdi(f1,d2,i3);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &f1, &d2, &i3 };
+ FFI_CALL(cif,d_fdi,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 25
+ usr = us_cdcd(c1,d2,c3,d4);
+ fprintf(out,"->%u\n",usr);
+ fflush(out);
+ usr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_char, &ffi_type_double, &ffi_type_char, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_ushort);
+ {
+ ffi_arg rint;
+ /*const*/ void* args[] = { &c1, &d2, &c3, &d4 };
+ FFI_CALL(cif,us_cdcd,args,&rint);
+ usr = (ushort) rint;
+ }
+ }
+ fprintf(out,"->%u\n",usr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 26
+ /* Long long types.
+ */
+ llr = ll_iiilli(i1,i2,i3,ll1,i13);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_slonglong, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ {
+ /*const*/ void* args[] = { &i1, &i2, &i3, &ll1, &i13 };
+ FFI_CALL(cif,ll_iiilli,args,&llr);
+ }
+ }
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 27
+ llr = ll_flli(f13,ll1,i13);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_slonglong, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ {
+ /*const*/ void* args[] = { &f13, &ll1, &i13 };
+ FFI_CALL(cif,ll_flli,args,&llr);
+ }
+ }
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 28
+ fr = f_fi(f1,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &i9 };
+ FFI_CALL(cif,f_fi,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 29
+ fr = f_f2i(f1,f2,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &i9 };
+ FFI_CALL(cif,f_f2i,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 30
+ fr = f_f3i(f1,f2,f3,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &i9 };
+ FFI_CALL(cif,f_f3i,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 31
+ fr = f_f4i(f1,f2,f3,f4,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4, &i9 };
+ FFI_CALL(cif,f_f4i,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 32
+ fr = f_f7i(f1,f2,f3,f4,f5,f6,f7,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4, &f5, &f6, &f7, &i9 };
+ FFI_CALL(cif,f_f7i,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 33
+ fr = f_f8i(f1,f2,f3,f4,f5,f6,f7,f8,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8, &i9 };
+ FFI_CALL(cif,f_f8i,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 34
+ fr = f_f12i(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8, &f9, &f10, &f11, &f12, &i9 };
+ FFI_CALL(cif,f_f12i,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 35
+ fr = f_f13i(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8, &f9, &f10, &f11, &f12, &f13, &i9 };
+ FFI_CALL(cif,f_f13i,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 36
+ dr = d_di(d1,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &i9 };
+ FFI_CALL(cif,d_di,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 37
+ dr = d_d2i(d1,d2,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &i9 };
+ FFI_CALL(cif,d_d2i,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 38
+ dr = d_d3i(d1,d2,d3,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &i9 };
+ FFI_CALL(cif,d_d3i,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 39
+ dr = d_d4i(d1,d2,d3,d4,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &d4, &i9 };
+ FFI_CALL(cif,d_d4i,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 40
+ dr = d_d7i(d1,d2,d3,d4,d5,d6,d7,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &d4, &d5, &d6, &d7, &i9 };
+ FFI_CALL(cif,d_d7i,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 41
+ dr = d_d8i(d1,d2,d3,d4,d5,d6,d7,d8,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &i9 };
+ FFI_CALL(cif,d_d8i,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 42
+ dr = d_d12i(d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9, &d10, &d11, &d12, &i9 };
+ FFI_CALL(cif,d_d12i,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 43
+ dr = d_d13i(d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9, &d10, &d11, &d12, &d13, &i9 };
+ FFI_CALL(cif,d_d13i,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+ return;
+}
+void
+ small_structure_return_tests (void)
+{
+#if (!defined(DGTEST)) || DGTEST == 44
+ {
+ Size1 r = S1_v();
+ fprintf(out,"->{%c}\n",r.x1);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ {
+ ffi_type* ffi_type_Size1_elements[] = { &ffi_type_char, NULL };
+ ffi_type ffi_type_Size1;
+ ffi_type_Size1.type = FFI_TYPE_STRUCT;
+ ffi_type_Size1.size = sizeof(Size1);
+ ffi_type_Size1.alignment = alignof_slot(Size1);
+ ffi_type_Size1.elements = ffi_type_Size1_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size1);
+ {
+ FFI_CALL(cif,S1_v,NULL,&r);
+ }
+ }
+ fprintf(out,"->{%c}\n",r.x1);
+ fflush(out);
+ }
+#endif
+#if (!defined(DGTEST)) || DGTEST == 45
+ {
+ Size2 r = S2_v();
+ fprintf(out,"->{%c%c}\n",r.x1,r.x2);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ {
+ ffi_type* ffi_type_Size2_elements[] = { &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size2;
+ ffi_type_Size2.type = FFI_TYPE_STRUCT;
+ ffi_type_Size2.size = sizeof(Size2);
+ ffi_type_Size2.alignment = alignof_slot(Size2);
+ ffi_type_Size2.elements = ffi_type_Size2_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size2);
+ {
+ FFI_CALL(cif,S2_v,NULL,&r);
+ }
+ }
+ fprintf(out,"->{%c%c}\n",r.x1,r.x2);
+ fflush(out);
+ }
+#endif
+#if (!defined(DGTEST)) || DGTEST == 46
+ {
+ Size3 r = S3_v();
+ fprintf(out,"->{%c%c%c}\n",r.x1,r.x2,r.x3);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ {
+ ffi_type* ffi_type_Size3_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size3;
+ ffi_type_Size3.type = FFI_TYPE_STRUCT;
+ ffi_type_Size3.size = sizeof(Size3);
+ ffi_type_Size3.alignment = alignof_slot(Size3);
+ ffi_type_Size3.elements = ffi_type_Size3_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size3);
+ {
+ FFI_CALL(cif,S3_v,NULL,&r);
+ }
+ }
+ fprintf(out,"->{%c%c%c}\n",r.x1,r.x2,r.x3);
+ fflush(out);
+ }
+#endif
+#if (!defined(DGTEST)) || DGTEST == 47
+ {
+ Size4 r = S4_v();
+ fprintf(out,"->{%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ {
+ ffi_type* ffi_type_Size4_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size4;
+ ffi_type_Size4.type = FFI_TYPE_STRUCT;
+ ffi_type_Size4.size = sizeof(Size4);
+ ffi_type_Size4.alignment = alignof_slot(Size4);
+ ffi_type_Size4.elements = ffi_type_Size4_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size4);
+ {
+ FFI_CALL(cif,S4_v,NULL,&r);
+ }
+ }
+ fprintf(out,"->{%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4);
+ fflush(out);
+ }
+#endif
+#if (!defined(DGTEST)) || DGTEST == 48
+ {
+ Size7 r = S7_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ {
+ ffi_type* ffi_type_Size7_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size7;
+ ffi_type_Size7.type = FFI_TYPE_STRUCT;
+ ffi_type_Size7.size = sizeof(Size7);
+ ffi_type_Size7.alignment = alignof_slot(Size7);
+ ffi_type_Size7.elements = ffi_type_Size7_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size7);
+ {
+ FFI_CALL(cif,S7_v,NULL,&r);
+ }
+ }
+ fprintf(out,"->{%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7);
+ fflush(out);
+ }
+#endif
+#if (!defined(DGTEST)) || DGTEST == 49
+ {
+ Size8 r = S8_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ {
+ ffi_type* ffi_type_Size8_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size8;
+ ffi_type_Size8.type = FFI_TYPE_STRUCT;
+ ffi_type_Size8.size = sizeof(Size8);
+ ffi_type_Size8.alignment = alignof_slot(Size8);
+ ffi_type_Size8.elements = ffi_type_Size8_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size8);
+ {
+ FFI_CALL(cif,S8_v,NULL,&r);
+ }
+ }
+ fprintf(out,"->{%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8);
+ fflush(out);
+ }
+#endif
+#if (!defined(DGTEST)) || DGTEST == 50
+ {
+ Size12 r = S12_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ {
+ ffi_type* ffi_type_Size12_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size12;
+ ffi_type_Size12.type = FFI_TYPE_STRUCT;
+ ffi_type_Size12.size = sizeof(Size12);
+ ffi_type_Size12.alignment = alignof_slot(Size12);
+ ffi_type_Size12.elements = ffi_type_Size12_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size12);
+ {
+ FFI_CALL(cif,S12_v,NULL,&r);
+ }
+ }
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12);
+ fflush(out);
+ }
+#endif
+#if (!defined(DGTEST)) || DGTEST == 51
+ {
+ Size15 r = S15_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12,r.x13,r.x14,r.x15);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ {
+ ffi_type* ffi_type_Size15_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size15;
+ ffi_type_Size15.type = FFI_TYPE_STRUCT;
+ ffi_type_Size15.size = sizeof(Size15);
+ ffi_type_Size15.alignment = alignof_slot(Size15);
+ ffi_type_Size15.elements = ffi_type_Size15_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size15);
+ {
+ FFI_CALL(cif,S15_v,NULL,&r);
+ }
+ }
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12,r.x13,r.x14,r.x15);
+ fflush(out);
+ }
+#endif
+#if (!defined(DGTEST)) || DGTEST == 52
+ {
+ Size16 r = S16_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12,r.x13,r.x14,r.x15,r.x16);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ {
+ ffi_type* ffi_type_Size16_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size16;
+ ffi_type_Size16.type = FFI_TYPE_STRUCT;
+ ffi_type_Size16.size = sizeof(Size16);
+ ffi_type_Size16.alignment = alignof_slot(Size16);
+ ffi_type_Size16.elements = ffi_type_Size16_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size16);
+ {
+ FFI_CALL(cif,S16_v,NULL,&r);
+ }
+ }
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12,r.x13,r.x14,r.x15,r.x16);
+ fflush(out);
+ }
+#endif
+}
+void
+ structure_tests (void)
+{
+ Int Ir;
+ Char Cr;
+ Float Fr;
+ Double Dr;
+ J Jr;
+#ifndef SKIP_EXTRA_STRUCTS
+ T Tr;
+ X Xr;
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 53
+ Ir = I_III(I1,I2,I3);
+ fprintf(out,"->{%d}\n",Ir.x);
+ fflush(out);
+ Ir.x = 0; clear_traces();
+ {
+ ffi_type* ffi_type_Int_elements[] = { &ffi_type_sint, NULL };
+ ffi_type ffi_type_Int;
+ ffi_type_Int.type = FFI_TYPE_STRUCT;
+ ffi_type_Int.size = sizeof(Int);
+ ffi_type_Int.alignment = alignof_slot(Int);
+ ffi_type_Int.elements = ffi_type_Int_elements;
+ ffi_type* argtypes[] = { &ffi_type_Int, &ffi_type_Int, &ffi_type_Int };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Int);
+ {
+ /*const*/ void* args[] = { &I1, &I2, &I3 };
+ FFI_CALL(cif,I_III,args,&Ir);
+ }
+ }
+ fprintf(out,"->{%d}\n",Ir.x);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 54
+ Cr = C_CdC(C1,d2,C3);
+ fprintf(out,"->{'%c'}\n",Cr.x);
+ fflush(out);
+ Cr.x = '\0'; clear_traces();
+ {
+ ffi_type* ffi_type_Char_elements[] = { &ffi_type_char, NULL };
+ ffi_type ffi_type_Char;
+ ffi_type_Char.type = FFI_TYPE_STRUCT;
+ ffi_type_Char.size = sizeof(Char);
+ ffi_type_Char.alignment = alignof_slot(Char);
+ ffi_type_Char.elements = ffi_type_Char_elements;
+ ffi_type* argtypes[] = { &ffi_type_Char, &ffi_type_double, &ffi_type_Char };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Char);
+ {
+ /*const*/ void* args[] = { &C1, &d2, &C3 };
+ FFI_CALL(cif,C_CdC,args,&Cr);
+ }
+ }
+ fprintf(out,"->{'%c'}\n",Cr.x);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 55
+ Fr = F_Ffd(F1,f2,d3);
+ fprintf(out,"->{%g}\n",Fr.x);
+ fflush(out);
+ Fr.x = 0.0; clear_traces();
+ {
+ ffi_type* ffi_type_Float_elements[] = { &ffi_type_float, NULL };
+ ffi_type ffi_type_Float;
+ ffi_type_Float.type = FFI_TYPE_STRUCT;
+ ffi_type_Float.size = sizeof(Float);
+ ffi_type_Float.alignment = alignof_slot(Float);
+ ffi_type_Float.elements = ffi_type_Float_elements;
+ ffi_type* argtypes[] = { &ffi_type_Float, &ffi_type_float, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Float);
+ {
+ /*const*/ void* args[] = { &F1, &f2, &d3 };
+ FFI_CALL(cif,F_Ffd,args,&Fr);
+ }
+ }
+ fprintf(out,"->{%g}\n",Fr.x);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 56
+ Dr = D_fDd(f1,D2,d3);
+ fprintf(out,"->{%g}\n",Dr.x);
+ fflush(out);
+ Dr.x = 0.0; clear_traces();
+ {
+ ffi_type* ffi_type_Double_elements[] = { &ffi_type_double, NULL };
+ ffi_type ffi_type_Double;
+ ffi_type_Double.type = FFI_TYPE_STRUCT;
+ ffi_type_Double.size = sizeof(Double);
+ ffi_type_Double.alignment = alignof_slot(Double);
+ ffi_type_Double.elements = ffi_type_Double_elements;
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_Double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Double);
+ {
+ /*const*/ void* args[] = { &f1, &D2, &d3 };
+ FFI_CALL(cif,D_fDd,args,&Dr);
+ }
+ }
+ fprintf(out,"->{%g}\n",Dr.x);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 57
+ Dr = D_Dfd(D1,f2,d3);
+ fprintf(out,"->{%g}\n",Dr.x);
+ fflush(out);
+ Dr.x = 0.0; clear_traces();
+ {
+ ffi_type* ffi_type_Double_elements[] = { &ffi_type_double, NULL };
+ ffi_type ffi_type_Double;
+ ffi_type_Double.type = FFI_TYPE_STRUCT;
+ ffi_type_Double.size = sizeof(Double);
+ ffi_type_Double.alignment = alignof_slot(Double);
+ ffi_type_Double.elements = ffi_type_Double_elements;
+ ffi_type* argtypes[] = { &ffi_type_Double, &ffi_type_float, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Double);
+ {
+ /*const*/ void* args[] = { &D1, &f2, &d3 };
+ FFI_CALL(cif,D_Dfd,args,&Dr);
+ }
+ }
+ fprintf(out,"->{%g}\n",Dr.x);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 58
+ Jr = J_JiJ(J1,i2,J2);
+ fprintf(out,"->{%ld,%ld}\n",Jr.l1,Jr.l2);
+ fflush(out);
+ Jr.l1 = Jr.l2 = 0; clear_traces();
+ {
+ ffi_type* ffi_type_J_elements[] = { &ffi_type_slong, &ffi_type_slong, NULL };
+ ffi_type ffi_type_J;
+ ffi_type_J.type = FFI_TYPE_STRUCT;
+ ffi_type_J.size = sizeof(J);
+ ffi_type_J.alignment = alignof_slot(J);
+ ffi_type_J.elements = ffi_type_J_elements;
+ ffi_type* argtypes[] = { &ffi_type_J, &ffi_type_sint, &ffi_type_J };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_J);
+ {
+ /*const*/ void* args[] = { &J1, &i2, &J2 };
+ FFI_CALL(cif,J_JiJ,args,&Jr);
+ }
+ }
+ fprintf(out,"->{%ld,%ld}\n",Jr.l1,Jr.l2);
+ fflush(out);
+#endif
+#ifndef SKIP_EXTRA_STRUCTS
+#if (!defined(DGTEST)) || DGTEST == 59
+ Tr = T_TcT(T1,' ',T2);
+ fprintf(out,"->{\"%c%c%c\"}\n",Tr.c[0],Tr.c[1],Tr.c[2]);
+ fflush(out);
+ Tr.c[0] = Tr.c[1] = Tr.c[2] = 0; clear_traces();
+ {
+ ffi_type* ffi_type_T_elements[] = { ??, NULL };
+ ffi_type ffi_type_T;
+ ffi_type_T.type = FFI_TYPE_STRUCT;
+ ffi_type_T.size = sizeof(T);
+ ffi_type_T.alignment = alignof_slot(T);
+ ffi_type_T.elements = ffi_type_T_elements;
+ ffi_type* argtypes[] = { &ffi_type_T, &ffi_type_char, &ffi_type_T };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_T);
+ {
+ char space = ' ';
+ /*const*/ void* args[] = { &T1, &space, &T2 };
+ FFI_CALL(cif,T_TcT,args,&Tr);
+ }
+ }
+ fprintf(out,"->{\"%c%c%c\"}\n",Tr.c[0],Tr.c[1],Tr.c[2]);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 60
+ Xr = X_BcdB(B1,c2,d3,B2);
+ fprintf(out,"->{\"%s\",'%c'}\n",Xr.c,Xr.c1);
+ fflush(out);
+ Xr.c[0]=Xr.c1='\0'; clear_traces();
+ {
+ ffi_type* ffi_type_X_elements[] = { ??, NULL };
+ ffi_type ffi_type_X;
+ ffi_type_X.type = FFI_TYPE_STRUCT;
+ ffi_type_X.size = sizeof(X);
+ ffi_type_X.alignment = alignof_slot(X);
+ ffi_type_X.elements = ffi_type_X_elements;
+ ffi_type* argtypes[] = { &ffi_type_X, &ffi_type_char, &ffi_type_double, &ffi_type_X };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_X);
+ {
+ /*const*/ void* args[] = { &B1, &c2, &d3, &B2 };
+ FFI_CALL(cif,X_BcdB,args,&Xr);
+ }
+ }
+ fprintf(out,"->{\"%s\",'%c'}\n",Xr.c,Xr.c1);
+ fflush(out);
+#endif
+#endif
+
+ return;
+}
+
+void
+ gpargs_boundary_tests (void)
+{
+ ffi_type* ffi_type_K_elements[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, NULL };
+ ffi_type ffi_type_K;
+ ffi_type* ffi_type_L_elements[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, NULL };
+ ffi_type ffi_type_L;
+ long lr;
+ long long llr;
+ float fr;
+ double dr;
+
+ ffi_type_K.type = FFI_TYPE_STRUCT;
+ ffi_type_K.size = sizeof(K);
+ ffi_type_K.alignment = alignof_slot(K);
+ ffi_type_K.elements = ffi_type_K_elements;
+
+ ffi_type_L.type = FFI_TYPE_STRUCT;
+ ffi_type_L.size = sizeof(L);
+ ffi_type_L.alignment = alignof_slot(L);
+ ffi_type_L.elements = ffi_type_L_elements;
+
+#if (!defined(DGTEST)) || DGTEST == 61
+ lr = l_l0K(K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ {
+ /*const*/ void* args[] = { &K1, &l9 };
+ FFI_CALL(cif,l_l0K,args,&lr);
+ }
+ }
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 62
+ lr = l_l1K(l1,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ {
+ /*const*/ void* args[] = { &l1, &K1, &l9 };
+ FFI_CALL(cif,l_l1K,args,&lr);
+ }
+ }
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 63
+ lr = l_l2K(l1,l2,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &K1, &l9 };
+ FFI_CALL(cif,l_l2K,args,&lr);
+ }
+ }
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 64
+ lr = l_l3K(l1,l2,l3,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &K1, &l9 };
+ FFI_CALL(cif,l_l3K,args,&lr);
+ }
+ }
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 65
+ lr = l_l4K(l1,l2,l3,l4,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &K1, &l9 };
+ FFI_CALL(cif,l_l4K,args,&lr);
+ }
+ }
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 66
+ lr = l_l5K(l1,l2,l3,l4,l5,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &l5, &K1, &l9 };
+ FFI_CALL(cif,l_l5K,args,&lr);
+ }
+ }
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 67
+ lr = l_l6K(l1,l2,l3,l4,l5,l6,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &l5, &l6, &K1, &l9 };
+ FFI_CALL(cif,l_l6K,args,&lr);
+ }
+ }
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 68
+ fr = f_f17l3L(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,l6,l7,l8,L1);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_L };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ {
+ /*const*/ void* args[] = { &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8, &f9, &f10, &f11, &f12, &f13, &f14, &f15, &f16, &f17, &l6, &l7, &l8, &L1 };
+ FFI_CALL(cif,f_f17l3L,args,&fr);
+ }
+ }
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 69
+ dr = d_d17l3L(d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16,d17,l6,l7,l8,L1);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_L };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9, &d10, &d11, &d12, &d13, &d14, &d15, &d16, &d17, &l6, &l7, &l8, &L1 };
+ FFI_CALL(cif,d_d17l3L,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 70
+ llr = ll_l2ll(l1,l2,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &ll1, &l9 };
+ FFI_CALL(cif,ll_l2ll,args,&llr);
+ }
+ }
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 71
+ llr = ll_l3ll(l1,l2,l3,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &ll1, &l9 };
+ FFI_CALL(cif,ll_l3ll,args,&llr);
+ }
+ }
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 72
+ llr = ll_l4ll(l1,l2,l3,l4,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &ll1, &l9 };
+ FFI_CALL(cif,ll_l4ll,args,&llr);
+ }
+ }
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 73
+ llr = ll_l5ll(l1,l2,l3,l4,l5,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &l5, &ll1, &l9 };
+ FFI_CALL(cif,ll_l5ll,args,&llr);
+ }
+ }
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 74
+ llr = ll_l6ll(l1,l2,l3,l4,l5,l6,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &l5, &l6, &ll1, &l9 };
+ FFI_CALL(cif,ll_l6ll,args,&llr);
+ }
+ }
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 75
+ llr = ll_l7ll(l1,l2,l3,l4,l5,l6,l7,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &l5, &l6, &l7, &ll1, &l9 };
+ FFI_CALL(cif,ll_l7ll,args,&llr);
+ }
+ }
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 76
+ dr = d_l2d(l1,l2,d2,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &d2, &l9 };
+ FFI_CALL(cif,d_l2d,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 77
+ dr = d_l3d(l1,l2,l3,d2,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &d2, &l9 };
+ FFI_CALL(cif,d_l3d,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 78
+ dr = d_l4d(l1,l2,l3,l4,d2,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &d2, &l9 };
+ FFI_CALL(cif,d_l4d,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 79
+ dr = d_l5d(l1,l2,l3,l4,l5,d2,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &l5, &d2, &l9 };
+ FFI_CALL(cif,d_l5d,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 80
+ dr = d_l6d(l1,l2,l3,l4,l5,l6,d2,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &l5, &l6, &d2, &l9 };
+ FFI_CALL(cif,d_l6d,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+#if (!defined(DGTEST)) || DGTEST == 81
+ dr = d_l7d(l1,l2,l3,l4,l5,l6,l7,d2,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ {
+ /*const*/ void* args[] = { &l1, &l2, &l3, &l4, &l5, &l6, &l7, &d2, &l9 };
+ FFI_CALL(cif,d_l7d,args,&dr);
+ }
+ }
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+ return;
+}
+
+int
+ main (void)
+{
+ ffi_type_char = (char)(-1) < 0 ? ffi_type_schar : ffi_type_uchar;
+ out = stdout;
+
+ void_tests();
+ int_tests();
+ float_tests();
+ double_tests();
+ pointer_tests();
+ mixed_number_tests();
+ small_structure_return_tests();
+ structure_tests();
+ gpargs_boundary_tests();
+
+ exit(0);
+}
diff --git a/testsuite/libffi.bhaible/test-callback.c b/testsuite/libffi.bhaible/test-callback.c
new file mode 100644
index 00000000..c2633c79
--- /dev/null
+++ b/testsuite/libffi.bhaible/test-callback.c
@@ -0,0 +1,2885 @@
+/*
+ * Copyright 1993 Bill Triggs <Bill.Triggs@inrialpes.fr>
+ * Copyright 1995-2017 Bruno Haible <bruno@clisp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* { dg-do run } */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ffi.h>
+#include "alignof.h"
+#include <stdarg.h>
+
+/* libffi testsuite local changes -------------------------------- */
+#ifdef DGTEST
+/* Redefine exit(1) as a test failure */
+#define exit(V) (void)((V) ? (abort(), 1) : exit(0))
+int count = 0;
+char rbuf1[2048];
+char rbuf2[2048];
+int _fprintf(FILE *stream, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ switch (count++)
+ {
+ case 0:
+ case 1:
+ vsprintf(&rbuf1[strlen(rbuf1)], format, args);
+ break;
+ case 2:
+ printf("%s", rbuf1);
+ vsprintf(rbuf2, format, args);
+ break;
+ case 3:
+ vsprintf(&rbuf2[strlen(rbuf2)], format, args);
+ printf("%s", rbuf2);
+ if (strcmp (rbuf1, rbuf2)) abort();
+ break;
+ }
+
+ va_end(args);
+
+ return 0;
+}
+#define fprintf _fprintf
+#endif
+/* --------------------------------------------------------------- */
+
+#include "testcases.c"
+
+#ifndef ABI_NUM
+#define ABI_NUM FFI_DEFAULT_ABI
+#endif
+
+/* Definitions that ought to be part of libffi. */
+static ffi_type ffi_type_char;
+#define ffi_type_slonglong ffi_type_sint64
+#define ffi_type_ulonglong ffi_type_uint64
+
+/* libffi does not support arrays inside structs. */
+#define SKIP_EXTRA_STRUCTS
+
+#define FFI_PREP_CIF(cif,argtypes,rettype) \
+ if (ffi_prep_cif(&(cif),ABI_NUM,sizeof(argtypes)/sizeof(argtypes[0]),&rettype,argtypes) != FFI_OK) abort()
+#define FFI_PREP_CIF_NOARGS(cif,rettype) \
+ if (ffi_prep_cif(&(cif),ABI_NUM,0,&rettype,NULL) != FFI_OK) abort()
+
+#if defined(__sparc__) && defined(__sun) && defined(__SUNPRO_C) /* SUNWspro cc */
+/* SunPRO cc miscompiles the simulator function for X_BcdB: d.i[1] is
+ * temporarily stored in %l2 and put onto the stack from %l2, but in between
+ * the copy of X has used %l2 as a counter without saving and restoring its
+ * value.
+ */
+#define SKIP_X
+#endif
+#if defined(__mipsn32__) && !defined(__GNUC__)
+/* The X test crashes for an unknown reason. */
+#define SKIP_X
+#endif
+
+
+/* These functions simulate the behaviour of the functions defined in testcases.c. */
+
+/* void tests */
+void v_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&v_v) { fprintf(out,"wrong data for v_v\n"); exit(1); }
+ fprintf(out,"void f(void):\n");
+ fflush(out);
+}
+
+/* int tests */
+void i_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&i_v) { fprintf(out,"wrong data for i_v\n"); exit(1); }
+ {int r=99;
+ fprintf(out,"int f(void):");
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void i_i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&i_i) { fprintf(out,"wrong data for i_i\n"); exit(1); }
+ int a = *(int*)(*args++);
+ int r=a+1;
+ fprintf(out,"int f(int):(%d)",a);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}
+void i_i2_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&i_i2) { fprintf(out,"wrong data for i_i2\n"); exit(1); }
+ {int a = *(int*)(*args++);
+ int b = *(int*)(*args++);
+ int r=a+b;
+ fprintf(out,"int f(2*int):(%d,%d)",a,b);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void i_i4_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&i_i4) { fprintf(out,"wrong data for i_i4\n"); exit(1); }
+ {int a = *(int*)(*args++);
+ int b = *(int*)(*args++);
+ int c = *(int*)(*args++);
+ int d = *(int*)(*args++);
+ int r=a+b+c+d;
+ fprintf(out,"int f(4*int):(%d,%d,%d,%d)",a,b,c,d);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void i_i8_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&i_i8) { fprintf(out,"wrong data for i_i8\n"); exit(1); }
+ {int a = *(int*)(*args++);
+ int b = *(int*)(*args++);
+ int c = *(int*)(*args++);
+ int d = *(int*)(*args++);
+ int e = *(int*)(*args++);
+ int f = *(int*)(*args++);
+ int g = *(int*)(*args++);
+ int h = *(int*)(*args++);
+ int r=a+b+c+d+e+f+g+h;
+ fprintf(out,"int f(8*int):(%d,%d,%d,%d,%d,%d,%d,%d)",a,b,c,d,e,f,g,h);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void i_i16_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&i_i16) { fprintf(out,"wrong data for i_i16\n"); exit(1); }
+ {int a = *(int*)(*args++);
+ int b = *(int*)(*args++);
+ int c = *(int*)(*args++);
+ int d = *(int*)(*args++);
+ int e = *(int*)(*args++);
+ int f = *(int*)(*args++);
+ int g = *(int*)(*args++);
+ int h = *(int*)(*args++);
+ int i = *(int*)(*args++);
+ int j = *(int*)(*args++);
+ int k = *(int*)(*args++);
+ int l = *(int*)(*args++);
+ int m = *(int*)(*args++);
+ int n = *(int*)(*args++);
+ int o = *(int*)(*args++);
+ int p = *(int*)(*args++);
+ int r=a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p;
+ fprintf(out,"int f(16*int):(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
+ a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+
+/* float tests */
+void f_f_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f) { fprintf(out,"wrong data for f_f\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float r=a+1.0;
+ fprintf(out,"float f(float):(%g)",a);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f2_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f2) { fprintf(out,"wrong data for f_f2\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float r=a+b;
+ fprintf(out,"float f(2*float):(%g,%g)",a,b);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f4_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f4) { fprintf(out,"wrong data for f_f4\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ float r=a+b+c+d;
+ fprintf(out,"float f(4*float):(%g,%g,%g,%g)",a,b,c,d);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f8_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f8) { fprintf(out,"wrong data for f_f8\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ float e = *(float*)(*args++);
+ float f = *(float*)(*args++);
+ float g = *(float*)(*args++);
+ float h = *(float*)(*args++);
+ float r=a+b+c+d+e+f+g+h;
+ fprintf(out,"float f(8*float):(%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f16_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f16) { fprintf(out,"wrong data for f_f16\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ float e = *(float*)(*args++);
+ float f = *(float*)(*args++);
+ float g = *(float*)(*args++);
+ float h = *(float*)(*args++);
+ float i = *(float*)(*args++);
+ float j = *(float*)(*args++);
+ float k = *(float*)(*args++);
+ float l = *(float*)(*args++);
+ float m = *(float*)(*args++);
+ float n = *(float*)(*args++);
+ float o = *(float*)(*args++);
+ float p = *(float*)(*args++);
+ float r=a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p;
+ fprintf(out,"float f(16*float):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f24_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f24) { fprintf(out,"wrong data for f_f24\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ float e = *(float*)(*args++);
+ float f = *(float*)(*args++);
+ float g = *(float*)(*args++);
+ float h = *(float*)(*args++);
+ float i = *(float*)(*args++);
+ float j = *(float*)(*args++);
+ float k = *(float*)(*args++);
+ float l = *(float*)(*args++);
+ float m = *(float*)(*args++);
+ float n = *(float*)(*args++);
+ float o = *(float*)(*args++);
+ float p = *(float*)(*args++);
+ float q = *(float*)(*args++);
+ float s = *(float*)(*args++);
+ float t = *(float*)(*args++);
+ float u = *(float*)(*args++);
+ float v = *(float*)(*args++);
+ float w = *(float*)(*args++);
+ float x = *(float*)(*args++);
+ float y = *(float*)(*args++);
+ float r=a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+s+t+u+v+w+x+y;
+ fprintf(out,"float f(24*float):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,s,t,u,v,w,x,y);
+ fflush(out);
+ *(float*)retp = r;
+}}
+
+/* double tests */
+void d_d_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d) { fprintf(out,"wrong data for d_d\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double r=a+1.0;
+ fprintf(out,"double f(double):(%g)",a);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d2_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d2) { fprintf(out,"wrong data for d_d2\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double r=a+b;
+ fprintf(out,"double f(2*double):(%g,%g)",a,b);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d4_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d4) { fprintf(out,"wrong data for d_d4\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ double r=a+b+c+d;
+ fprintf(out,"double f(4*double):(%g,%g,%g,%g)",a,b,c,d);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d8_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d8) { fprintf(out,"wrong data for d_d8\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ double e = *(double*)(*args++);
+ double f = *(double*)(*args++);
+ double g = *(double*)(*args++);
+ double h = *(double*)(*args++);
+ double r=a+b+c+d+e+f+g+h;
+ fprintf(out,"double f(8*double):(%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d16_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d16) { fprintf(out,"wrong data for d_d16\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ double e = *(double*)(*args++);
+ double f = *(double*)(*args++);
+ double g = *(double*)(*args++);
+ double h = *(double*)(*args++);
+ double i = *(double*)(*args++);
+ double j = *(double*)(*args++);
+ double k = *(double*)(*args++);
+ double l = *(double*)(*args++);
+ double m = *(double*)(*args++);
+ double n = *(double*)(*args++);
+ double o = *(double*)(*args++);
+ double p = *(double*)(*args++);
+ double r=a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p;
+ fprintf(out,"double f(16*double):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p);
+ fflush(out);
+ *(double*)retp = r;
+}}
+
+/* pointer tests */
+void vp_vpdpcpsp_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&vp_vpdpcpsp) { fprintf(out,"wrong data for vp_vpdpcpsp\n"); exit(1); }
+ {void* a = *(void* *)(*args++);
+ double* b = *(double* *)(*args++);
+ char* c = *(char* *)(*args++);
+ Int* d = *(Int* *)(*args++);
+ void* ret = (char*)b + 1;
+ fprintf(out,"void* f(void*,double*,char*,Int*):(0x%p,0x%p,0x%p,0x%p)",a,b,c,d);
+ fflush(out);
+ *(void* *)retp = ret;
+}}
+
+/* mixed number tests */
+void uc_ucsil_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&uc_ucsil) { fprintf(out,"wrong data for uc_ucsil\n"); exit(1); }
+ {uchar a = *(unsigned char *)(*args++);
+ ushort b = *(unsigned short *)(*args++);
+ uint c = *(unsigned int *)(*args++);
+ ulong d = *(unsigned long *)(*args++);
+ uchar r = (uchar)-1;
+ fprintf(out,"uchar f(uchar,ushort,uint,ulong):(%u,%u,%u,%lu)",a,b,c,d);
+ fflush(out);
+ *(ffi_arg *)retp = r;
+}}
+void d_iidd_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_iidd) { fprintf(out,"wrong data for d_iidd\n"); exit(1); }
+ {int a = *(int*)(*args++);
+ int b = *(int*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ double r=a+b+c+d;
+ fprintf(out,"double f(int,int,double,double):(%d,%d,%g,%g)",a,b,c,d);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_iiidi_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_iiidi) { fprintf(out,"wrong data for d_iiidi\n"); exit(1); }
+ {int a = *(int*)(*args++);
+ int b = *(int*)(*args++);
+ int c = *(int*)(*args++);
+ double d = *(double*)(*args++);
+ int e = *(int*)(*args++);
+ double r=a+b+c+d+e;
+ fprintf(out,"double f(int,int,int,double,int):(%d,%d,%d,%g,%d)",a,b,c,d,e);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_idid_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_idid) { fprintf(out,"wrong data for d_idid\n"); exit(1); }
+ {int a = *(int*)(*args++);
+ double b = *(double*)(*args++);
+ int c = *(int*)(*args++);
+ double d = *(double*)(*args++);
+ double r=a+b+c+d;
+ fprintf(out,"double f(int,double,int,double):(%d,%g,%d,%g)",a,b,c,d);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_fdi_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_fdi) { fprintf(out,"wrong data for d_fdi\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ double b = *(double*)(*args++);
+ int c = *(int*)(*args++);
+ double r=a+b+c;
+ fprintf(out,"double f(float,double,int):(%g,%g,%d)",a,b,c);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void us_cdcd_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&us_cdcd) { fprintf(out,"wrong data for us_cdcd\n"); exit(1); }
+ {char a = *(char*)(*args++);
+ double b = *(double*)(*args++);
+ char c = *(char*)(*args++);
+ double d = *(double*)(*args++);
+ ushort r = (ushort)(a + b + c + d);
+ fprintf(out,"ushort f(char,double,char,double):('%c',%g,'%c',%g)",a,b,c,d);
+ fflush(out);
+ *(ffi_arg *)retp = r;
+}}
+void ll_iiilli_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&ll_iiilli) { fprintf(out,"wrong data for ll_iiilli\n"); exit(1); }
+ {int a = *(int*)(*args++);
+ int b = *(int*)(*args++);
+ int c = *(int*)(*args++);
+ long long d = *(long long *)(*args++);
+ int e = *(int*)(*args++);
+ long long r = (long long)(int)a + (long long)(int)b + (long long)(int)c + d + (long long)e;
+ fprintf(out,"long long f(int,int,int,long long,int):(%d,%d,%d,0x%lx%08lx,%d)",a,b,c,(long)(d>>32),(long)(d&0xffffffff),e);
+ fflush(out);
+ *(long long *)retp = r;
+}}
+void ll_flli_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&ll_flli) { fprintf(out,"wrong data for ll_flli\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ long long b = *(long long *)(*args++);
+ int c = *(int*)(*args++);
+ long long r = (long long)(int)a + b + (long long)c;
+ fprintf(out,"long long f(float,long long,int):(%g,0x%lx%08lx,0x%lx)",a,(long)(b>>32),(long)(b&0xffffffff),(long)c);
+ fflush(out);
+ *(long long *)retp = r;
+}}
+void f_fi_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_fi) { fprintf(out,"wrong data for f_fi\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ int z = *(int*)(*args++);
+ float r=a+z;
+ fprintf(out,"float f(float,int):(%g,%d)",a,z);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f2i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f2i) { fprintf(out,"wrong data for f_f2i\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ int z = *(int*)(*args++);
+ float r=a+b+z;
+ fprintf(out,"float f(2*float,int):(%g,%g,%d)",a,b,z);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f3i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f3i) { fprintf(out,"wrong data for f_f3i\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ int z = *(int*)(*args++);
+ float r=a+b+c+z;
+ fprintf(out,"float f(3*float,int):(%g,%g,%g,%d)",a,b,c,z);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f4i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f4i) { fprintf(out,"wrong data for f_f4i\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ int z = *(int*)(*args++);
+ float r=a+b+c+d+z;
+ fprintf(out,"float f(4*float,int):(%g,%g,%g,%g,%d)",a,b,c,d,z);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f7i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f7i) { fprintf(out,"wrong data for f_f7i\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ float e = *(float*)(*args++);
+ float f = *(float*)(*args++);
+ float g = *(float*)(*args++);
+ int z = *(int*)(*args++);
+ float r=a+b+c+d+e+f+g+z;
+ fprintf(out,"float f(7*float,int):(%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,z);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f8i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f8i) { fprintf(out,"wrong data for f_f8i\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ float e = *(float*)(*args++);
+ float f = *(float*)(*args++);
+ float g = *(float*)(*args++);
+ float h = *(float*)(*args++);
+ int z = *(int*)(*args++);
+ float r=a+b+c+d+e+f+g+h+z;
+ fprintf(out,"float f(8*float,int):(%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,z);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f12i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f12i) { fprintf(out,"wrong data for f_f12i\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ float e = *(float*)(*args++);
+ float f = *(float*)(*args++);
+ float g = *(float*)(*args++);
+ float h = *(float*)(*args++);
+ float i = *(float*)(*args++);
+ float j = *(float*)(*args++);
+ float k = *(float*)(*args++);
+ float l = *(float*)(*args++);
+ int z = *(int*)(*args++);
+ float r=a+b+c+d+e+f+g+h+i+j+k+l+z;
+ fprintf(out,"float f(12*float,int):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,i,j,k,l,z);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void f_f13i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f13i) { fprintf(out,"wrong data for f_f13i\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ float e = *(float*)(*args++);
+ float f = *(float*)(*args++);
+ float g = *(float*)(*args++);
+ float h = *(float*)(*args++);
+ float i = *(float*)(*args++);
+ float j = *(float*)(*args++);
+ float k = *(float*)(*args++);
+ float l = *(float*)(*args++);
+ float m = *(float*)(*args++);
+ int z = *(int*)(*args++);
+ float r=a+b+c+d+e+f+g+h+i+j+k+l+m+z;
+ fprintf(out,"float f(13*float,int):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,i,j,k,l,m,z);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void d_di_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_di) { fprintf(out,"wrong data for d_di\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ int z = *(int*)(*args++);
+ double r=a+z;
+ fprintf(out,"double f(double,int):(%g,%d)",a,z);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d2i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d2i) { fprintf(out,"wrong data for d_d2i\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ int z = *(int*)(*args++);
+ double r=a+b+z;
+ fprintf(out,"double f(2*double,int):(%g,%g,%d)",a,b,z);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d3i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d3i) { fprintf(out,"wrong data for d_d3i\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ int z = *(int*)(*args++);
+ double r=a+b+c+z;
+ fprintf(out,"double f(3*double,int):(%g,%g,%g,%d)",a,b,c,z);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d4i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d4i) { fprintf(out,"wrong data for d_d4i\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ int z = *(int*)(*args++);
+ double r=a+b+c+d+z;
+ fprintf(out,"double f(4*double,int):(%g,%g,%g,%g,%d)",a,b,c,d,z);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d7i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d7i) { fprintf(out,"wrong data for d_d7i\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ double e = *(double*)(*args++);
+ double f = *(double*)(*args++);
+ double g = *(double*)(*args++);
+ int z = *(int*)(*args++);
+ double r=a+b+c+d+e+f+g+z;
+ fprintf(out,"double f(7*double,int):(%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,z);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d8i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d8i) { fprintf(out,"wrong data for d_d8i\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ double e = *(double*)(*args++);
+ double f = *(double*)(*args++);
+ double g = *(double*)(*args++);
+ double h = *(double*)(*args++);
+ int z = *(int*)(*args++);
+ double r=a+b+c+d+e+f+g+h+z;
+ fprintf(out,"double f(8*double,int):(%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,z);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d12i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d12i) { fprintf(out,"wrong data for d_d12i\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ double e = *(double*)(*args++);
+ double f = *(double*)(*args++);
+ double g = *(double*)(*args++);
+ double h = *(double*)(*args++);
+ double i = *(double*)(*args++);
+ double j = *(double*)(*args++);
+ double k = *(double*)(*args++);
+ double l = *(double*)(*args++);
+ int z = *(int*)(*args++);
+ double r=a+b+c+d+e+f+g+h+i+j+k+l+z;
+ fprintf(out,"double f(12*double,int):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,i,j,k,l,z);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_d13i_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d13i) { fprintf(out,"wrong data for d_d13i\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ double e = *(double*)(*args++);
+ double f = *(double*)(*args++);
+ double g = *(double*)(*args++);
+ double h = *(double*)(*args++);
+ double i = *(double*)(*args++);
+ double j = *(double*)(*args++);
+ double k = *(double*)(*args++);
+ double l = *(double*)(*args++);
+ double m = *(double*)(*args++);
+ int z = *(int*)(*args++);
+ double r=a+b+c+d+e+f+g+h+i+j+k+l+m+z;
+ fprintf(out,"double f(13*double,int):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,i,j,k,l,m,z);
+ fflush(out);
+ *(double*)retp = r;
+}}
+
+/* small structure return tests */
+void S1_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&S1_v) { fprintf(out,"wrong data for S1_v\n"); exit(1); }
+ {Size1 r = Size1_1;
+ fprintf(out,"Size1 f(void):");
+ fflush(out);
+ *(Size1*)retp = r;
+}}
+void S2_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&S2_v) { fprintf(out,"wrong data for S2_v\n"); exit(1); }
+ {Size2 r = Size2_1;
+ fprintf(out,"Size2 f(void):");
+ fflush(out);
+ *(Size2*)retp = r;
+}}
+void S3_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&S3_v) { fprintf(out,"wrong data for S3_v\n"); exit(1); }
+ {Size3 r = Size3_1;
+ fprintf(out,"Size3 f(void):");
+ fflush(out);
+ *(Size3*)retp = r;
+}}
+void S4_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&S4_v) { fprintf(out,"wrong data for S4_v\n"); exit(1); }
+ {Size4 r = Size4_1;
+ fprintf(out,"Size4 f(void):");
+ fflush(out);
+ *(Size4*)retp = r;
+}}
+void S7_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&S7_v) { fprintf(out,"wrong data for S7_v\n"); exit(1); }
+ {Size7 r = Size7_1;
+ fprintf(out,"Size7 f(void):");
+ fflush(out);
+ *(Size7*)retp = r;
+}}
+void S8_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&S8_v) { fprintf(out,"wrong data for S8_v\n"); exit(1); }
+ {Size8 r = Size8_1;
+ fprintf(out,"Size8 f(void):");
+ fflush(out);
+ *(Size8*)retp = r;
+}}
+void S12_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&S12_v) { fprintf(out,"wrong data for S12_v\n"); exit(1); }
+ {Size12 r = Size12_1;
+ fprintf(out,"Size12 f(void):");
+ fflush(out);
+ *(Size12*)retp = r;
+}}
+void S15_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&S15_v) { fprintf(out,"wrong data for S15_v\n"); exit(1); }
+ {Size15 r = Size15_1;
+ fprintf(out,"Size15 f(void):");
+ fflush(out);
+ *(Size15*)retp = r;
+}}
+void S16_v_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&S16_v) { fprintf(out,"wrong data for S16_v\n"); exit(1); }
+ {Size16 r = Size16_1;
+ fprintf(out,"Size16 f(void):");
+ fflush(out);
+ *(Size16*)retp = r;
+}}
+
+/* structure tests */
+void I_III_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&I_III) { fprintf(out,"wrong data for I_III\n"); exit(1); }
+ {Int a = *(Int*)(*args++);
+ Int b = *(Int*)(*args++);
+ Int c = *(Int*)(*args++);
+ Int r;
+ r.x = a.x + b.x + c.x;
+ fprintf(out,"Int f(Int,Int,Int):({%d},{%d},{%d})",a.x,b.x,c.x);
+ fflush(out);
+ *(Int*)retp = r;
+}}
+void C_CdC_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&C_CdC) { fprintf(out,"wrong data for C_CdC\n"); exit(1); }
+ {Char a = *(Char*)(*args++);
+ double b = *(double*)(*args++);
+ Char c = *(Char*)(*args++);
+ Char r;
+ r.x = (a.x + c.x)/2;
+ fprintf(out,"Char f(Char,double,Char):({'%c'},%g,{'%c'})",a.x,b,c.x);
+ fflush(out);
+ *(Char*)retp = r;
+}}
+void F_Ffd_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&F_Ffd) { fprintf(out,"wrong data for F_Ffd\n"); exit(1); }
+ {Float a = *(Float*)(*args++);
+ float b = *(float*)(*args++);
+ double c = *(double*)(*args++);
+ Float r;
+ r.x = a.x + b + c;
+ fprintf(out,"Float f(Float,float,double):({%g},%g,%g)",a.x,b,c);
+ fflush(out);
+ *(Float*)retp = r;
+}}
+void D_fDd_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&D_fDd) { fprintf(out,"wrong data for D_fDd\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ Double b = *(Double*)(*args++);
+ double c = *(double*)(*args++);
+ Double r;
+ r.x = a + b.x + c;
+ fprintf(out,"Double f(float,Double,double):(%g,{%g},%g)",a,b.x,c);
+ fflush(out);
+ *(Double*)retp = r;
+}}
+void D_Dfd_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&D_Dfd) { fprintf(out,"wrong data for D_Dfd\n"); exit(1); }
+ {Double a = *(Double*)(*args++);
+ float b = *(float*)(*args++);
+ double c = *(double*)(*args++);
+ Double r;
+ r.x = a.x + b + c;
+ fprintf(out,"Double f(Double,float,double):({%g},%g,%g)",a.x,b,c);
+ fflush(out);
+ *(Double*)retp = r;
+}}
+void J_JiJ_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&J_JiJ) { fprintf(out,"wrong data for J_JiJ\n"); exit(1); }
+ {J a = *(J*)(*args++);
+ int b= *(int*)(*args++);
+ J c = *(J*)(*args++);
+ J r;
+ r.l1 = a.l1+c.l1; r.l2 = a.l2+b+c.l2;
+ fprintf(out,"J f(J,int,J):({%ld,%ld},%d,{%ld,%ld})",a.l1,a.l2,b,c.l1,c.l2);
+ fflush(out);
+ *(J*)retp = r;
+}}
+#ifndef SKIP_EXTRA_STRUCTS
+void T_TcT_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&T_TcT) { fprintf(out,"wrong data for T_TcT\n"); exit(1); }
+ {T a = *(T*)(*args++);
+ char b = *(char*)(*args++);
+ T c = *(T*)(*args++);
+ T r;
+ r.c[0]='b'; r.c[1]=c.c[1]; r.c[2]=c.c[2];
+ fprintf(out,"T f(T,char,T):({\"%c%c%c\"},'%c',{\"%c%c%c\"})",a.c[0],a.c[1],a.c[2],b,c.c[0],c.c[1],c.c[2]);
+ fflush(out);
+ *(T*)retp = r;
+}}
+void X_BcdB_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&X_BcdB) { fprintf(out,"wrong data for X_BcdB\n"); exit(1); }
+ {B a = *(B*)(*args++);
+ char b = *(char*)(*args++);
+ double c = *(double*)(*args++);
+ B d = *(B*)(*args++);
+ static X xr={"return val",'R'};
+ X r;
+ r = xr;
+ r.c1 = b;
+ fprintf(out,"X f(B,char,double,B):({%g,{%d,%d,%d}},'%c',%g,{%g,{%d,%d,%d}})",
+ a.d,a.i[0],a.i[1],a.i[2],b,c,d.d,d.i[0],d.i[1],d.i[2]);
+ fflush(out);
+ *(X*)retp = r;
+}}
+#endif
+
+/* gpargs boundary tests */
+void l_l0K_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&l_l0K) { fprintf(out,"wrong data for l_l0K\n"); exit(1); }
+ {K b = *(K*)(*args++);
+ long c = *(long*)(*args++);
+ long r = b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(K,long):(%ld,%ld,%ld,%ld,%ld)",b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void l_l1K_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&l_l1K) { fprintf(out,"wrong data for l_l1K\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ K b = *(K*)(*args++);
+ long c = *(long*)(*args++);
+ long r = a1 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld)",a1,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void l_l2K_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&l_l2K) { fprintf(out,"wrong data for l_l2K\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ K b = *(K*)(*args++);
+ long c = *(long*)(*args++);
+ long r = a1 + a2 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(2*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void l_l3K_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&l_l3K) { fprintf(out,"wrong data for l_l3K\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ K b = *(K*)(*args++);
+ long c = *(long*)(*args++);
+ long r = a1 + a2 + a3 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(3*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,a3,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void l_l4K_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&l_l4K) { fprintf(out,"wrong data for l_l4K\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ K b = *(K*)(*args++);
+ long c = *(long*)(*args++);
+ long r = a1 + a2 + a3 + a4 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(4*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,a3,a4,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void l_l5K_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&l_l5K) { fprintf(out,"wrong data for l_l5K\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ long a5 = *(long*)(*args++);
+ K b = *(K*)(*args++);
+ long c = *(long*)(*args++);
+ long r = a1 + a2 + a3 + a4 + a5 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(5*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,a3,a4,a5,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void l_l6K_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&l_l6K) { fprintf(out,"wrong data for l_l6K\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ long a5 = *(long*)(*args++);
+ long a6 = *(long*)(*args++);
+ K b = *(K*)(*args++);
+ long c = *(long*)(*args++);
+ long r = a1 + a2 + a3 + a4 + a5 + a6 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(6*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,a3,a4,a5,a6,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ *(ffi_arg*)retp = r;
+}}
+void f_f17l3L_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&f_f17l3L) { fprintf(out,"wrong data for f_f17l3L\n"); exit(1); }
+ {float a = *(float*)(*args++);
+ float b = *(float*)(*args++);
+ float c = *(float*)(*args++);
+ float d = *(float*)(*args++);
+ float e = *(float*)(*args++);
+ float f = *(float*)(*args++);
+ float g = *(float*)(*args++);
+ float h = *(float*)(*args++);
+ float i = *(float*)(*args++);
+ float j = *(float*)(*args++);
+ float k = *(float*)(*args++);
+ float l = *(float*)(*args++);
+ float m = *(float*)(*args++);
+ float n = *(float*)(*args++);
+ float o = *(float*)(*args++);
+ float p = *(float*)(*args++);
+ float q = *(float*)(*args++);
+ long s = *(long*)(*args++);
+ long t = *(long*)(*args++);
+ long u = *(long*)(*args++);
+ L z = *(L*)(*args++);
+ float r = a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+s+t+u+z.l1+z.l2+z.l3+z.l4+z.l5+z.l6;
+ fprintf(out,"float f(17*float,3*int,L):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,s,t,u,z.l1,z.l2,z.l3,z.l4,z.l5,z.l6);
+ fflush(out);
+ *(float*)retp = r;
+}}
+void d_d17l3L_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_d17l3L) { fprintf(out,"wrong data for d_d17l3L\n"); exit(1); }
+ {double a = *(double*)(*args++);
+ double b = *(double*)(*args++);
+ double c = *(double*)(*args++);
+ double d = *(double*)(*args++);
+ double e = *(double*)(*args++);
+ double f = *(double*)(*args++);
+ double g = *(double*)(*args++);
+ double h = *(double*)(*args++);
+ double i = *(double*)(*args++);
+ double j = *(double*)(*args++);
+ double k = *(double*)(*args++);
+ double l = *(double*)(*args++);
+ double m = *(double*)(*args++);
+ double n = *(double*)(*args++);
+ double o = *(double*)(*args++);
+ double p = *(double*)(*args++);
+ double q = *(double*)(*args++);
+ long s = *(long*)(*args++);
+ long t = *(long*)(*args++);
+ long u = *(long*)(*args++);
+ L z = *(L*)(*args++);
+ double r = a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+s+t+u+z.l1+z.l2+z.l3+z.l4+z.l5+z.l6;
+ fprintf(out,"double f(17*double,3*int,L):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,s,t,u,z.l1,z.l2,z.l3,z.l4,z.l5,z.l6);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void ll_l2ll_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&ll_l2ll) { fprintf(out,"wrong data for ll_l2ll\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long long b = *(long long *)(*args++);
+ long c = *(long*)(*args++);
+ long long r = (long long) (a1 + a2) + b + c;
+ fprintf(out,"long long f(2*long,long long,long):(%ld,%ld,0x%lx%08lx,%ld)",a1,a2,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ *(long long *)retp = r;
+}}
+void ll_l3ll_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&ll_l3ll) { fprintf(out,"wrong data for ll_l3ll\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long long b = *(long long *)(*args++);
+ long c = *(long*)(*args++);
+ long long r = (long long) (a1 + a2 + a3) + b + c;
+ fprintf(out,"long long f(3*long,long long,long):(%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ *(long long *)retp = r;
+}}
+void ll_l4ll_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&ll_l4ll) { fprintf(out,"wrong data for ll_l4ll\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ long long b = *(long long *)(*args++);
+ long c = *(long*)(*args++);
+ long long r = (long long) (a1 + a2 + a3 + a4) + b + c;
+ fprintf(out,"long long f(4*long,long long,long):(%ld,%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,a4,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ *(long long *)retp = r;
+}}
+void ll_l5ll_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&ll_l5ll) { fprintf(out,"wrong data for ll_l5ll\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ long a5 = *(long*)(*args++);
+ long long b = *(long long *)(*args++);
+ long c = *(long*)(*args++);
+ long long r = (long long) (a1 + a2 + a3 + a4 + a5) + b + c;
+ fprintf(out,"long long f(5*long,long long,long):(%ld,%ld,%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,a4,a5,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ *(long long *)retp = r;
+}}
+void ll_l6ll_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&ll_l6ll) { fprintf(out,"wrong data for ll_l6ll\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ long a5 = *(long*)(*args++);
+ long a6 = *(long*)(*args++);
+ long long b = *(long long *)(*args++);
+ long c = *(long*)(*args++);
+ long long r = (long long) (a1 + a2 + a3 + a4 + a5 + a6) + b + c;
+ fprintf(out,"long long f(6*long,long long,long):(%ld,%ld,%ld,%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,a4,a5,a6,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ *(long long *)retp = r;
+}}
+void ll_l7ll_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&ll_l7ll) { fprintf(out,"wrong data for ll_l7ll\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ long a5 = *(long*)(*args++);
+ long a6 = *(long*)(*args++);
+ long a7 = *(long*)(*args++);
+ long long b = *(long long *)(*args++);
+ long c = *(long*)(*args++);
+ long long r = (long long) (a1 + a2 + a3 + a4 + a5 + a6 + a7) + b + c;
+ fprintf(out,"long long f(7*long,long long,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,a4,a5,a6,a7,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ *(long long *)retp = r;
+}}
+void d_l2d_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_l2d) { fprintf(out,"wrong data for d_l2d\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ double b = *(double*)(*args++);
+ long c = *(long*)(*args++);
+ double r = (double) (a1 + a2) + b + c;
+ fprintf(out,"double f(2*long,double,long):(%ld,%ld,%g,%ld)",a1,a2,b,c);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_l3d_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_l3d) { fprintf(out,"wrong data for d_l3d\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ double b = *(double*)(*args++);
+ long c = *(long*)(*args++);
+ double r = (double) (a1 + a2 + a3) + b + c;
+ fprintf(out,"double f(3*long,double,long):(%ld,%ld,%ld,%g,%ld)",a1,a2,a3,b,c);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_l4d_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_l4d) { fprintf(out,"wrong data for d_l4d\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ double b = *(double*)(*args++);
+ long c = *(long*)(*args++);
+ double r = (double) (a1 + a2 + a3 + a4) + b + c;
+ fprintf(out,"double f(4*long,double,long):(%ld,%ld,%ld,%ld,%g,%ld)",a1,a2,a3,a4,b,c);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_l5d_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_l5d) { fprintf(out,"wrong data for d_l5d\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ long a5 = *(long*)(*args++);
+ double b = *(double*)(*args++);
+ long c = *(long*)(*args++);
+ double r = (double) (a1 + a2 + a3 + a4 + a5) + b + c;
+ fprintf(out,"double f(5*long,double,long):(%ld,%ld,%ld,%ld,%ld,%g,%ld)",a1,a2,a3,a4,a5,b,c);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_l6d_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_l6d) { fprintf(out,"wrong data for d_l6d\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ long a5 = *(long*)(*args++);
+ long a6 = *(long*)(*args++);
+ double b = *(double*)(*args++);
+ long c = *(long*)(*args++);
+ double r = (double) (a1 + a2 + a3 + a4 + a5 + a6) + b + c;
+ fprintf(out,"double f(6*long,double,long):(%ld,%ld,%ld,%ld,%ld,%ld,%g,%ld)",a1,a2,a3,a4,a5,a6,b,c);
+ fflush(out);
+ *(double*)retp = r;
+}}
+void d_l7d_simulator (ffi_cif* cif, void* retp, /*const*/ void* /*const*/ *args, void* data)
+{
+ if (data != (void*)&d_l7d) { fprintf(out,"wrong data for d_l7d\n"); exit(1); }
+ {long a1 = *(long*)(*args++);
+ long a2 = *(long*)(*args++);
+ long a3 = *(long*)(*args++);
+ long a4 = *(long*)(*args++);
+ long a5 = *(long*)(*args++);
+ long a6 = *(long*)(*args++);
+ long a7 = *(long*)(*args++);
+ double b = *(double*)(*args++);
+ long c = *(long*)(*args++);
+ double r = (double) (a1 + a2 + a3 + a4 + a5 + a6 + a7) + b + c;
+ fprintf(out,"double f(7*long,double,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%g,%ld)",a1,a2,a3,a4,a5,a6,a7,b,c);
+ fflush(out);
+ *(double*)retp = r;
+}}
+
+
+/*
+ * The way we run these tests - first call the function directly, then
+ * through vacall() - there is the danger that arguments or results seem
+ * to be passed correctly, but what we are seeing are in fact the vestiges
+ * (traces) or the previous call. This may seriously fake the test.
+ * Avoid this by clearing the registers between the first and the second call.
+ */
+long clear_traces_i (long a, long b, long c, long d, long e, long f, long g, long h,
+ long i, long j, long k, long l, long m, long n, long o, long p)
+{ return 0; }
+float clear_traces_f (float a, float b, float c, float d, float e, float f, float g,
+ float h, float i, float j, float k, float l, float m, float n,
+ float o, float p)
+{ return 0.0; }
+double clear_traces_d (double a, double b, double c, double d, double e, double f, double g,
+ double h, double i, double j, double k, double l, double m, double n,
+ double o, double p)
+{ return 0.0; }
+J clear_traces_J (void)
+{ J j; j.l1 = j.l2 = 0; return j; }
+void clear_traces (void)
+{ clear_traces_i(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+ clear_traces_f(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
+ clear_traces_d(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
+ clear_traces_J();
+}
+
+int main (void)
+{
+ void* callback_code;
+ void* callback_writable;
+#define ALLOC_CALLBACK() \
+ callback_writable = ffi_closure_alloc(sizeof(ffi_closure),&callback_code); \
+ if (!callback_writable) abort()
+#define PREP_CALLBACK(cif,simulator,data) \
+ if (ffi_prep_closure_loc(callback_writable,&(cif),simulator,data,callback_code) != FFI_OK) abort()
+#define FREE_CALLBACK() \
+ ffi_closure_free(callback_writable)
+
+ ffi_type_char = (char)(-1) < 0 ? ffi_type_schar : ffi_type_uchar;
+ out = stdout;
+
+#if (!defined(DGTEST)) || DGTEST == 1
+ /* void tests */
+ v_v();
+ clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_void);
+ PREP_CALLBACK(cif,v_v_simulator,(void*)&v_v);
+ ((void (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+#endif
+
+ /* int tests */
+ { int ir;
+
+#if (!defined(DGTEST)) || DGTEST == 2
+ ir = i_v();
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_sint);
+ PREP_CALLBACK(cif,i_v_simulator,(void*)&i_v);
+ ir = ((int (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 3
+ ir = i_i(i1);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ PREP_CALLBACK(cif,i_i_simulator,(void*)&i_i);
+ ir = ((int (ABI_ATTR *) (int)) callback_code) (i1);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 4
+ ir = i_i2(i1,i2);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ PREP_CALLBACK(cif,i_i2_simulator,(void*)&i_i2);
+ ir = ((int (ABI_ATTR *) (int,int)) callback_code) (i1,i2);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 5
+ ir = i_i4(i1,i2,i3,i4);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ PREP_CALLBACK(cif,i_i4_simulator,(void*)&i_i4);
+ ir = ((int (ABI_ATTR *) (int,int,int,int)) callback_code) (i1,i2,i3,i4);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 6
+ ir = i_i8(i1,i2,i3,i4,i5,i6,i7,i8);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ PREP_CALLBACK(cif,i_i8_simulator,(void*)&i_i8);
+ ir = ((int (ABI_ATTR *) (int,int,int,int,int,int,int,int)) callback_code) (i1,i2,i3,i4,i5,i6,i7,i8);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 7
+ ir = i_i16(i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15,i16);
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+ ir = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_sint);
+ PREP_CALLBACK(cif,i_i16_simulator,(void*)&i_i16);
+ ir = ((int (ABI_ATTR *) (int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int)) callback_code) (i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15,i16);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%d\n",ir);
+ fflush(out);
+#endif
+ }
+
+ /* float tests */
+ { float fr;
+
+#if (!defined(DGTEST)) || DGTEST == 8
+ fr = f_f(f1);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f_simulator,(void*)&f_f);
+ fr = ((float (ABI_ATTR *) (float)) callback_code) (f1);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 9
+ fr = f_f2(f1,f2);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f2_simulator,(void*)&f_f2);
+ fr = ((float (ABI_ATTR *) (float,float)) callback_code) (f1,f2);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 10
+ fr = f_f4(f1,f2,f3,f4);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f4_simulator,(void*)&f_f4);
+ fr = ((float (ABI_ATTR *) (float,float,float,float)) callback_code) (f1,f2,f3,f4);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 11
+ fr = f_f8(f1,f2,f3,f4,f5,f6,f7,f8);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f8_simulator,(void*)&f_f8);
+ fr = ((float (ABI_ATTR *) (float,float,float,float,float,float,float,float)) callback_code) (f1,f2,f3,f4,f5,f6,f7,f8);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 12
+ fr = f_f16(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f16_simulator,(void*)&f_f16);
+ fr = ((float (ABI_ATTR *) (float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float)) callback_code) (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 13
+ fr = f_f24(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,f18,f19,f20,f21,f22,f23,f24);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f24_simulator,(void*)&f_f24);
+ fr = ((float (ABI_ATTR *) (float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float)) callback_code) (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,f18,f19,f20,f21,f22,f23,f24);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+ }
+
+ /* double tests */
+ { double dr;
+
+#if (!defined(DGTEST)) || DGTEST == 14
+ dr = d_d(d1);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d_simulator,(void*)&d_d);
+ dr = ((double (ABI_ATTR *) (double)) callback_code) (d1);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 15
+ dr = d_d2(d1,d2);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d2_simulator,(void*)&d_d2);
+ dr = ((double (ABI_ATTR *) (double,double)) callback_code) (d1,d2);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 16
+ dr = d_d4(d1,d2,d3,d4);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d4_simulator,(void*)&d_d4);
+ dr = ((double (ABI_ATTR *) (double,double,double,double)) callback_code) (d1,d2,d3,d4);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 17
+ dr = d_d8(d1,d2,d3,d4,d5,d6,d7,d8);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d8_simulator,(void*)&d_d8);
+ dr = ((double (ABI_ATTR *) (double,double,double,double,double,double,double,double)) callback_code) (d1,d2,d3,d4,d5,d6,d7,d8);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 18
+ dr = d_d16(d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d16_simulator,(void*)&d_d16);
+ dr = ((double (ABI_ATTR *) (double,double,double,double,double,double,double,double,double,double,double,double,double,double,double,double)) callback_code) (d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+ }
+
+ /* pointer tests */
+ { void* vpr;
+
+#if (!defined(DGTEST)) || DGTEST == 19
+ vpr = vp_vpdpcpsp(&uc1,&d2,str3,&I4);
+ fprintf(out,"->0x%p\n",vpr);
+ fflush(out);
+ vpr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_pointer, &ffi_type_pointer, &ffi_type_pointer, &ffi_type_pointer };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_pointer);
+ PREP_CALLBACK(cif,vp_vpdpcpsp_simulator,(void*)&vp_vpdpcpsp);
+ vpr = ((void* (ABI_ATTR *) (void*,double*,char*,Int*)) callback_code) (&uc1,&d2,str3,&I4);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->0x%p\n",vpr);
+ fflush(out);
+#endif
+ }
+
+ /* mixed number tests */
+ { uchar ucr;
+ ushort usr;
+ float fr;
+ double dr;
+ long long llr;
+
+#if (!defined(DGTEST)) || DGTEST == 20
+ ucr = uc_ucsil(uc1,us2,ui3,ul4);
+ fprintf(out,"->%u\n",ucr);
+ fflush(out);
+ ucr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_uchar, &ffi_type_ushort, &ffi_type_uint, &ffi_type_ulong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_uchar);
+ PREP_CALLBACK(cif,uc_ucsil_simulator,(void*)&uc_ucsil);
+ ucr = ((uchar (ABI_ATTR *) (uchar,ushort,uint,ulong)) callback_code) (uc1,us2,ui3,ul4);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%u\n",ucr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 21
+ dr = d_iidd(i1,i2,d3,d4);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_iidd_simulator,(void*)&d_iidd);
+ dr = ((double (ABI_ATTR *) (int,int,double,double)) callback_code) (i1,i2,d3,d4);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 22
+ dr = d_iiidi(i1,i2,i3,d4,i5);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_iiidi_simulator,(void*)&d_iiidi);
+ dr = ((double (ABI_ATTR *) (int,int,int,double,int)) callback_code) (i1,i2,i3,d4,i5);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 23
+ dr = d_idid(i1,d2,i3,d4);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_double, &ffi_type_sint, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_idid_simulator,(void*)&d_idid);
+ dr = ((double (ABI_ATTR *) (int,double,int,double)) callback_code) (i1,d2,i3,d4);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 24
+ dr = d_fdi(f1,d2,i3);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_fdi_simulator,(void*)&d_fdi);
+ dr = ((double (ABI_ATTR *) (float,double,int)) callback_code) (f1,d2,i3);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 25
+ usr = us_cdcd(c1,d2,c3,d4);
+ fprintf(out,"->%u\n",usr);
+ fflush(out);
+ usr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_char, &ffi_type_double, &ffi_type_char, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_ushort);
+ PREP_CALLBACK(cif,us_cdcd_simulator,(void*)&us_cdcd);
+ usr = ((ushort (ABI_ATTR *) (char,double,char,double)) callback_code) (c1,d2,c3,d4);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%u\n",usr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 26
+ llr = ll_iiilli(i1,i2,i3,ll1,i13);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_sint, &ffi_type_sint, &ffi_type_sint, &ffi_type_slonglong, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ PREP_CALLBACK(cif,ll_iiilli_simulator,(void*)&ll_iiilli);
+ llr = ((long long (ABI_ATTR *) (int,int,int,long long,int)) callback_code) (i1,i2,i3,ll1,i13);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 27
+ llr = ll_flli(f13,ll1,i13);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_slonglong, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ PREP_CALLBACK(cif,ll_flli_simulator,(void*)&ll_flli);
+ llr = ((long long (ABI_ATTR *) (float,long long,int)) callback_code) (f13,ll1,i13);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 28
+ fr = f_fi(f1,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_fi_simulator,(void*)&f_fi);
+ fr = ((float (ABI_ATTR *) (float,int)) callback_code) (f1,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 29
+ fr = f_f2i(f1,f2,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f2i_simulator,(void*)&f_f2i);
+ fr = ((float (ABI_ATTR *) (float,float,int)) callback_code) (f1,f2,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 30
+ fr = f_f3i(f1,f2,f3,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f3i_simulator,(void*)&f_f3i);
+ fr = ((float (ABI_ATTR *) (float,float,float,int)) callback_code) (f1,f2,f3,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 31
+ fr = f_f4i(f1,f2,f3,f4,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f4i_simulator,(void*)&f_f4i);
+ fr = ((float (ABI_ATTR *) (float,float,float,float,int)) callback_code) (f1,f2,f3,f4,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 32
+ fr = f_f7i(f1,f2,f3,f4,f5,f6,f7,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f7i_simulator,(void*)&f_f7i);
+ fr = ((float (ABI_ATTR *) (float,float,float,float,float,float,float,int)) callback_code) (f1,f2,f3,f4,f5,f6,f7,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 33
+ fr = f_f8i(f1,f2,f3,f4,f5,f6,f7,f8,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f8i_simulator,(void*)&f_f8i);
+ fr = ((float (ABI_ATTR *) (float,float,float,float,float,float,float,float,int)) callback_code) (f1,f2,f3,f4,f5,f6,f7,f8,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 34
+ fr = f_f13i(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,i9);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f13i_simulator,(void*)&f_f13i);
+ fr = ((float (ABI_ATTR *) (float,float,float,float,float,float,float,float,float,float,float,float,float,int)) callback_code) (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 35
+ dr = d_di(d1,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_di_simulator,(void*)&d_di);
+ dr = ((double (ABI_ATTR *) (double,int)) callback_code) (d1,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 36
+ dr = d_d2i(d1,d2,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d2i_simulator,(void*)&d_d2i);
+ dr = ((double (ABI_ATTR *) (double,double,int)) callback_code) (d1,d2,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 37
+ dr = d_d3i(d1,d2,d3,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d3i_simulator,(void*)&d_d3i);
+ dr = ((double (ABI_ATTR *) (double,double,double,int)) callback_code) (d1,d2,d3,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 38
+ dr = d_d4i(d1,d2,d3,d4,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d4i_simulator,(void*)&d_d4i);
+ dr = ((double (ABI_ATTR *) (double,double,double,double,int)) callback_code) (d1,d2,d3,d4,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 39
+ dr = d_d7i(d1,d2,d3,d4,d5,d6,d7,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d7i_simulator,(void*)&d_d7i);
+ dr = ((double (ABI_ATTR *) (double,double,double,double,double,double,double,int)) callback_code) (d1,d2,d3,d4,d5,d6,d7,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 40
+ dr = d_d8i(d1,d2,d3,d4,d5,d6,d7,d8,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d8i_simulator,(void*)&d_d8i);
+ dr = ((double (ABI_ATTR *) (double,double,double,double,double,double,double,double,int)) callback_code) (d1,d2,d3,d4,d5,d6,d7,d8,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 41
+ dr = d_d12i(d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d12i_simulator,(void*)&d_d12i);
+ dr = ((double (ABI_ATTR *) (double,double,double,double,double,double,double,double,double,double,double,double,int)) callback_code) (d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 42
+ dr = d_d13i(d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,i9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_sint };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d13i_simulator,(void*)&d_d13i);
+ dr = ((double (ABI_ATTR *) (double,double,double,double,double,double,double,double,double,double,double,double,double,int)) callback_code) (d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,i9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+ }
+
+ /* small structure return tests */
+#if (!defined(DGTEST)) || DGTEST == 43
+ {
+ Size1 r = S1_v();
+ fprintf(out,"->{%c}\n",r.x1);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Size1_elements[] = { &ffi_type_char, NULL };
+ ffi_type ffi_type_Size1;
+ ffi_type_Size1.type = FFI_TYPE_STRUCT;
+ ffi_type_Size1.size = sizeof(Size1);
+ ffi_type_Size1.alignment = alignof_slot(Size1);
+ ffi_type_Size1.elements = ffi_type_Size1_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size1);
+ PREP_CALLBACK(cif,S1_v_simulator,(void*)&S1_v);
+ r = ((Size1 (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%c}\n",r.x1);
+ fflush(out);
+ }
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 44
+ {
+ Size2 r = S2_v();
+ fprintf(out,"->{%c%c}\n",r.x1,r.x2);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Size2_elements[] = { &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size2;
+ ffi_type_Size2.type = FFI_TYPE_STRUCT;
+ ffi_type_Size2.size = sizeof(Size2);
+ ffi_type_Size2.alignment = alignof_slot(Size2);
+ ffi_type_Size2.elements = ffi_type_Size2_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size2);
+ PREP_CALLBACK(cif,S2_v_simulator,(void*)&S2_v);
+ r = ((Size2 (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%c%c}\n",r.x1,r.x2);
+ fflush(out);
+ }
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 45
+ {
+ Size3 r = S3_v();
+ fprintf(out,"->{%c%c%c}\n",r.x1,r.x2,r.x3);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Size3_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size3;
+ ffi_type_Size3.type = FFI_TYPE_STRUCT;
+ ffi_type_Size3.size = sizeof(Size3);
+ ffi_type_Size3.alignment = alignof_slot(Size3);
+ ffi_type_Size3.elements = ffi_type_Size3_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size3);
+ PREP_CALLBACK(cif,S3_v_simulator,(void*)&S3_v);
+ r = ((Size3 (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%c%c%c}\n",r.x1,r.x2,r.x3);
+ fflush(out);
+ }
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 46
+ {
+ Size4 r = S4_v();
+ fprintf(out,"->{%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Size4_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size4;
+ ffi_type_Size4.type = FFI_TYPE_STRUCT;
+ ffi_type_Size4.size = sizeof(Size4);
+ ffi_type_Size4.alignment = alignof_slot(Size4);
+ ffi_type_Size4.elements = ffi_type_Size4_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size4);
+ PREP_CALLBACK(cif,S4_v_simulator,(void*)&S4_v);
+ r = ((Size4 (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4);
+ fflush(out);
+ }
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 47
+ {
+ Size7 r = S7_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Size7_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size7;
+ ffi_type_Size7.type = FFI_TYPE_STRUCT;
+ ffi_type_Size7.size = sizeof(Size7);
+ ffi_type_Size7.alignment = alignof_slot(Size7);
+ ffi_type_Size7.elements = ffi_type_Size7_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size7);
+ PREP_CALLBACK(cif,S7_v_simulator,(void*)&S7_v);
+ r = ((Size7 (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7);
+ fflush(out);
+ }
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 48
+ {
+ Size8 r = S8_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Size8_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size8;
+ ffi_type_Size8.type = FFI_TYPE_STRUCT;
+ ffi_type_Size8.size = sizeof(Size8);
+ ffi_type_Size8.alignment = alignof_slot(Size8);
+ ffi_type_Size8.elements = ffi_type_Size8_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size8);
+ PREP_CALLBACK(cif,S8_v_simulator,(void*)&S8_v);
+ r = ((Size8 (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8);
+ fflush(out);
+ }
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 49
+ {
+ Size12 r = S12_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Size12_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size12;
+ ffi_type_Size12.type = FFI_TYPE_STRUCT;
+ ffi_type_Size12.size = sizeof(Size12);
+ ffi_type_Size12.alignment = alignof_slot(Size12);
+ ffi_type_Size12.elements = ffi_type_Size12_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size12);
+ PREP_CALLBACK(cif,S12_v_simulator,(void*)&S12_v);
+ r = ((Size12 (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12);
+ fflush(out);
+ }
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 50
+ {
+ Size15 r = S15_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12,r.x13,r.x14,r.x15);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Size15_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size15;
+ ffi_type_Size15.type = FFI_TYPE_STRUCT;
+ ffi_type_Size15.size = sizeof(Size15);
+ ffi_type_Size15.alignment = alignof_slot(Size15);
+ ffi_type_Size15.elements = ffi_type_Size15_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size15);
+ PREP_CALLBACK(cif,S15_v_simulator,(void*)&S15_v);
+ r = ((Size15 (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12,r.x13,r.x14,r.x15);
+ fflush(out);
+ }
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 51
+ {
+ Size16 r = S16_v();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12,r.x13,r.x14,r.x15,r.x16);
+ fflush(out);
+ memset(&r,0,sizeof(r)); clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Size16_elements[] = { &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, &ffi_type_char, NULL };
+ ffi_type ffi_type_Size16;
+ ffi_type_Size16.type = FFI_TYPE_STRUCT;
+ ffi_type_Size16.size = sizeof(Size16);
+ ffi_type_Size16.alignment = alignof_slot(Size16);
+ ffi_type_Size16.elements = ffi_type_Size16_elements;
+ ffi_cif cif;
+ FFI_PREP_CIF_NOARGS(cif,ffi_type_Size16);
+ PREP_CALLBACK(cif,S16_v_simulator,(void*)&S16_v);
+ r = ((Size16 (ABI_ATTR *) (void)) callback_code) ();
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c}\n",r.x1,r.x2,r.x3,r.x4,r.x5,r.x6,r.x7,r.x8,r.x9,r.x10,r.x11,r.x12,r.x13,r.x14,r.x15,r.x16);
+ fflush(out);
+ }
+#endif
+
+
+ /* structure tests */
+ { Int Ir;
+ Char Cr;
+ Float Fr;
+ Double Dr;
+ J Jr;
+#ifndef SKIP_EXTRA_STRUCTS
+ T Tr;
+ X Xr;
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 52
+ Ir = I_III(I1,I2,I3);
+ fprintf(out,"->{%d}\n",Ir.x);
+ fflush(out);
+ Ir.x = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Int_elements[] = { &ffi_type_sint, NULL };
+ ffi_type ffi_type_Int;
+ ffi_type_Int.type = FFI_TYPE_STRUCT;
+ ffi_type_Int.size = sizeof(Int);
+ ffi_type_Int.alignment = alignof_slot(Int);
+ ffi_type_Int.elements = ffi_type_Int_elements;
+ ffi_type* argtypes[] = { &ffi_type_Int, &ffi_type_Int, &ffi_type_Int };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Int);
+ PREP_CALLBACK(cif,I_III_simulator,(void*)&I_III);
+ Ir = ((Int (ABI_ATTR *) (Int,Int,Int)) callback_code) (I1,I2,I3);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%d}\n",Ir.x);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 53
+ Cr = C_CdC(C1,d2,C3);
+ fprintf(out,"->{'%c'}\n",Cr.x);
+ fflush(out);
+ Cr.x = '\0'; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Char_elements[] = { &ffi_type_char, NULL };
+ ffi_type ffi_type_Char;
+ ffi_type_Char.type = FFI_TYPE_STRUCT;
+ ffi_type_Char.size = sizeof(Char);
+ ffi_type_Char.alignment = alignof_slot(Char);
+ ffi_type_Char.elements = ffi_type_Char_elements;
+ ffi_type* argtypes[] = { &ffi_type_Char, &ffi_type_double, &ffi_type_Char };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Char);
+ PREP_CALLBACK(cif,C_CdC_simulator,(void*)&C_CdC);
+ Cr = ((Char (ABI_ATTR *) (Char,double,Char)) callback_code) (C1,d2,C3);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{'%c'}\n",Cr.x);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 54
+ Fr = F_Ffd(F1,f2,d3);
+ fprintf(out,"->{%g}\n",Fr.x);
+ fflush(out);
+ Fr.x = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Float_elements[] = { &ffi_type_float, NULL };
+ ffi_type ffi_type_Float;
+ ffi_type_Float.type = FFI_TYPE_STRUCT;
+ ffi_type_Float.size = sizeof(Float);
+ ffi_type_Float.alignment = alignof_slot(Float);
+ ffi_type_Float.elements = ffi_type_Float_elements;
+ ffi_type* argtypes[] = { &ffi_type_Float, &ffi_type_float, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Float);
+ PREP_CALLBACK(cif,F_Ffd_simulator,(void*)&F_Ffd);
+ Fr = ((Float (ABI_ATTR *) (Float,float,double)) callback_code) (F1,f2,d3);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%g}\n",Fr.x);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 55
+ Dr = D_fDd(f1,D2,d3);
+ fprintf(out,"->{%g}\n",Dr.x);
+ fflush(out);
+ Dr.x = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Double_elements[] = { &ffi_type_double, NULL };
+ ffi_type ffi_type_Double;
+ ffi_type_Double.type = FFI_TYPE_STRUCT;
+ ffi_type_Double.size = sizeof(Double);
+ ffi_type_Double.alignment = alignof_slot(Double);
+ ffi_type_Double.elements = ffi_type_Double_elements;
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_Double, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Double);
+ PREP_CALLBACK(cif,D_fDd_simulator,(void*)&D_fDd);
+ Dr = ((Double (ABI_ATTR *) (float,Double,double)) callback_code) (f1,D2,d3);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%g}\n",Dr.x);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 56
+ Dr = D_Dfd(D1,f2,d3);
+ fprintf(out,"->{%g}\n",Dr.x);
+ fflush(out);
+ Dr.x = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_Double_elements[] = { &ffi_type_double, NULL };
+ ffi_type ffi_type_Double;
+ ffi_type_Double.type = FFI_TYPE_STRUCT;
+ ffi_type_Double.size = sizeof(Double);
+ ffi_type_Double.alignment = alignof_slot(Double);
+ ffi_type_Double.elements = ffi_type_Double_elements;
+ ffi_type* argtypes[] = { &ffi_type_Double, &ffi_type_float, &ffi_type_double };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_Double);
+ PREP_CALLBACK(cif,D_Dfd_simulator,(void*)&D_Dfd);
+ Dr = ((Double (ABI_ATTR *) (Double,float,double)) callback_code) (D1,f2,d3);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%g}\n",Dr.x);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 57
+ Jr = J_JiJ(J1,i2,J2);
+ fprintf(out,"->{%ld,%ld}\n",Jr.l1,Jr.l2);
+ fflush(out);
+ Jr.l1 = Jr.l2 = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_J_elements[] = { &ffi_type_slong, &ffi_type_slong, NULL };
+ ffi_type ffi_type_J;
+ ffi_type_J.type = FFI_TYPE_STRUCT;
+ ffi_type_J.size = sizeof(J);
+ ffi_type_J.alignment = alignof_slot(J);
+ ffi_type_J.elements = ffi_type_J_elements;
+ ffi_type* argtypes[] = { &ffi_type_J, &ffi_type_sint, &ffi_type_J };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_J);
+ PREP_CALLBACK(cif,J_JiJ_simulator,(void*)&J_JiJ);
+ Jr = ((J (ABI_ATTR *) (J,int,J)) callback_code) (J1,i2,J2);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{%ld,%ld}\n",Jr.l1,Jr.l2);
+ fflush(out);
+#endif
+
+#ifndef SKIP_EXTRA_STRUCTS
+#if (!defined(DGTEST)) || DGTEST == 58
+ Tr = T_TcT(T1,' ',T2);
+ fprintf(out,"->{\"%c%c%c\"}\n",Tr.c[0],Tr.c[1],Tr.c[2]);
+ fflush(out);
+ Tr.c[0] = Tr.c[1] = Tr.c[2] = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_T_elements[] = { ??, NULL };
+ ffi_type ffi_type_T;
+ ffi_type_T.type = FFI_TYPE_STRUCT;
+ ffi_type_T.size = sizeof(T);
+ ffi_type_T.alignment = alignof_slot(T);
+ ffi_type_T.elements = ffi_type_T_elements;
+ ffi_type* argtypes[] = { &ffi_type_T, &ffi_type_char, &ffi_type_T };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_T);
+ PREP_CALLBACK(cif,T_TcT_simulator,(void*)&T_TcT);
+ Tr = ((T (ABI_ATTR *) (T,char,T)) callback_code) (T1,' ',T2);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{\"%c%c%c\"}\n",Tr.c[0],Tr.c[1],Tr.c[2]);
+ fflush(out);
+#endif
+
+#ifndef SKIP_X
+#if (!defined(DGTEST)) || DGTEST == 59
+ Xr = X_BcdB(B1,c2,d3,B2);
+ fprintf(out,"->{\"%s\",'%c'}\n",Xr.c,Xr.c1);
+ fflush(out);
+ Xr.c[0]=Xr.c1='\0'; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* ffi_type_X_elements[] = { ??, NULL };
+ ffi_type ffi_type_X;
+ ffi_type_X.type = FFI_TYPE_STRUCT;
+ ffi_type_X.size = sizeof(X);
+ ffi_type_X.alignment = alignof_slot(X);
+ ffi_type_X.elements = ffi_type_X_elements;
+ ffi_type* argtypes[] = { &ffi_type_X, &ffi_type_char, &ffi_type_double, &ffi_type_X };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_X);
+ PREP_CALLBACK(cif,X_BcdB_simulator,(void*)&X_BcdB);
+ Xr = ((X (ABI_ATTR *) (B,char,double,B)) callback_code) (B1,c2,d3,B2);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->{\"%s\",'%c'}\n",Xr.c,Xr.c1);
+ fflush(out);
+#endif
+#endif
+#endif
+ }
+
+
+ /* gpargs boundary tests */
+ {
+ ffi_type* ffi_type_K_elements[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, NULL };
+ ffi_type ffi_type_K;
+ ffi_type* ffi_type_L_elements[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, NULL };
+ ffi_type ffi_type_L;
+ long lr;
+ long long llr;
+ float fr;
+ double dr;
+
+ ffi_type_K.type = FFI_TYPE_STRUCT;
+ ffi_type_K.size = sizeof(K);
+ ffi_type_K.alignment = alignof_slot(K);
+ ffi_type_K.elements = ffi_type_K_elements;
+
+ ffi_type_L.type = FFI_TYPE_STRUCT;
+ ffi_type_L.size = sizeof(L);
+ ffi_type_L.alignment = alignof_slot(L);
+ ffi_type_L.elements = ffi_type_L_elements;
+
+#if (!defined(DGTEST)) || DGTEST == 60
+ lr = l_l0K(K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ PREP_CALLBACK(cif,l_l0K_simulator,(void*)l_l0K);
+ lr = ((long (ABI_ATTR *) (K,long)) callback_code) (K1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 61
+ lr = l_l1K(l1,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ PREP_CALLBACK(cif,l_l1K_simulator,(void*)l_l1K);
+ lr = ((long (ABI_ATTR *) (long,K,long)) callback_code) (l1,K1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 62
+ lr = l_l2K(l1,l2,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ PREP_CALLBACK(cif,l_l2K_simulator,(void*)l_l2K);
+ lr = ((long (ABI_ATTR *) (long,long,K,long)) callback_code) (l1,l2,K1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 63
+ lr = l_l3K(l1,l2,l3,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ PREP_CALLBACK(cif,l_l3K_simulator,(void*)l_l3K);
+ lr = ((long (ABI_ATTR *) (long,long,long,K,long)) callback_code) (l1,l2,l3,K1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 64
+ lr = l_l4K(l1,l2,l3,l4,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ PREP_CALLBACK(cif,l_l4K_simulator,(void*)l_l4K);
+ lr = ((long (ABI_ATTR *) (long,long,long,long,K,long)) callback_code) (l1,l2,l3,l4,K1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 65
+ lr = l_l5K(l1,l2,l3,l4,l5,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ PREP_CALLBACK(cif,l_l5K_simulator,(void*)l_l5K);
+ lr = ((long (ABI_ATTR *) (long,long,long,long,long,K,long)) callback_code) (l1,l2,l3,l4,l5,K1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 66
+ lr = l_l6K(l1,l2,l3,l4,l5,l6,K1,l9);
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+ lr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_K, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slong);
+ PREP_CALLBACK(cif,l_l6K_simulator,(void*)l_l6K);
+ lr = ((long (ABI_ATTR *) (long,long,long,long,long,long,K,long)) callback_code) (l1,l2,l3,l4,l5,l6,K1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%ld\n",lr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 67
+ fr = f_f17l3L(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,l6,l7,l8,L1);
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+ fr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_float, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_L };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_float);
+ PREP_CALLBACK(cif,f_f17l3L_simulator,(void*)&f_f17l3L);
+ fr = ((float (ABI_ATTR *) (float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,float,long,long,long,L)) callback_code) (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,l6,l7,l8,L1);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",fr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 68
+ dr = d_d17l3L(d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16,d17,l6,l7,l8,L1);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_double, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_L };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_d17l3L_simulator,(void*)&d_d17l3L);
+ dr = ((double (ABI_ATTR *) (double,double,double,double,double,double,double,double,double,double,double,double,double,double,double,double,double,long,long,long,L)) callback_code) (d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16,d17,l6,l7,l8,L1);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 69
+ llr = ll_l2ll(l1,l2,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ PREP_CALLBACK(cif,ll_l2ll_simulator,(void*)ll_l2ll);
+ llr = ((long long (ABI_ATTR *) (long,long,long long,long)) callback_code) (l1,l2,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 70
+ llr = ll_l3ll(l1,l2,l3,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ PREP_CALLBACK(cif,ll_l3ll_simulator,(void*)ll_l3ll);
+ llr = ((long long (ABI_ATTR *) (long,long,long,long long,long)) callback_code) (l1,l2,l3,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 71
+ llr = ll_l4ll(l1,l2,l3,l4,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ PREP_CALLBACK(cif,ll_l4ll_simulator,(void*)ll_l4ll);
+ llr = ((long long (ABI_ATTR *) (long,long,long,long,long long,long)) callback_code) (l1,l2,l3,l4,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 72
+ llr = ll_l5ll(l1,l2,l3,l4,l5,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ PREP_CALLBACK(cif,ll_l5ll_simulator,(void*)ll_l5ll);
+ llr = ((long long (ABI_ATTR *) (long,long,long,long,long,long long,long)) callback_code) (l1,l2,l3,l4,l5,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 73
+ llr = ll_l6ll(l1,l2,l3,l4,l5,l6,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ PREP_CALLBACK(cif,ll_l6ll_simulator,(void*)ll_l6ll);
+ llr = ((long long (ABI_ATTR *) (long,long,long,long,long,long,long long,long)) callback_code) (l1,l2,l3,l4,l5,l6,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 74
+ llr = ll_l7ll(l1,l2,l3,l4,l5,l6,l7,ll1,l9);
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+ llr = 0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slonglong, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_slonglong);
+ PREP_CALLBACK(cif,ll_l7ll_simulator,(void*)ll_l7ll);
+ llr = ((long long (ABI_ATTR *) (long,long,long,long,long,long,long,long long,long)) callback_code) (l1,l2,l3,l4,l5,l6,l7,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->0x%lx%08lx\n",(long)(llr>>32),(long)(llr&0xffffffff));
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 75
+ dr = d_l2d(l1,l2,ll1,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_l2d_simulator,(void*)d_l2d);
+ dr = ((double (ABI_ATTR *) (long,long,double,long)) callback_code) (l1,l2,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 76
+ dr = d_l3d(l1,l2,l3,ll1,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_l3d_simulator,(void*)d_l3d);
+ dr = ((double (ABI_ATTR *) (long,long,long,double,long)) callback_code) (l1,l2,l3,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 77
+ dr = d_l4d(l1,l2,l3,l4,ll1,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_l4d_simulator,(void*)d_l4d);
+ dr = ((double (ABI_ATTR *) (long,long,long,long,double,long)) callback_code) (l1,l2,l3,l4,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 78
+ dr = d_l5d(l1,l2,l3,l4,l5,ll1,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_l5d_simulator,(void*)d_l5d);
+ dr = ((double (ABI_ATTR *) (long,long,long,long,long,double,long)) callback_code) (l1,l2,l3,l4,l5,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 79
+ dr = d_l6d(l1,l2,l3,l4,l5,l6,ll1,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_l6d_simulator,(void*)d_l6d);
+ dr = ((double (ABI_ATTR *) (long,long,long,long,long,long,double,long)) callback_code) (l1,l2,l3,l4,l5,l6,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+#if (!defined(DGTEST)) || DGTEST == 80
+ dr = d_l7d(l1,l2,l3,l4,l5,l6,l7,ll1,l9);
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+ dr = 0.0; clear_traces();
+ ALLOC_CALLBACK();
+ {
+ ffi_type* argtypes[] = { &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_slong, &ffi_type_double, &ffi_type_slong };
+ ffi_cif cif;
+ FFI_PREP_CIF(cif,argtypes,ffi_type_double);
+ PREP_CALLBACK(cif,d_l7d_simulator,(void*)d_l7d);
+ dr = ((double (ABI_ATTR *) (long,long,long,long,long,long,long,double,long)) callback_code) (l1,l2,l3,l4,l5,l6,l7,ll1,l9);
+ }
+ FREE_CALLBACK();
+ fprintf(out,"->%g\n",dr);
+ fflush(out);
+#endif
+
+ }
+
+ exit(0);
+}
+
diff --git a/testsuite/libffi.bhaible/testcases.c b/testsuite/libffi.bhaible/testcases.c
new file mode 100644
index 00000000..d25ebf48
--- /dev/null
+++ b/testsuite/libffi.bhaible/testcases.c
@@ -0,0 +1,743 @@
+/*
+ * Copyright 1993 Bill Triggs <Bill.Triggs@inrialpes.fr>
+ * Copyright 1995-2017 Bruno Haible <bruno@clisp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This file defines test functions of selected signatures, that exercise
+ dark corners of the various ABIs. */
+
+#include <stdio.h>
+
+FILE* out;
+
+#define uchar unsigned char
+#define ushort unsigned short
+#define uint unsigned int
+#define ulong unsigned long
+
+typedef struct { char x; } Char;
+typedef struct { short x; } Short;
+typedef struct { int x; } Int;
+typedef struct { long x; } Long;
+typedef struct { float x; } Float;
+typedef struct { double x; } Double;
+typedef struct { char c; float f; } A;
+typedef struct { double d; int i[3]; } B;
+typedef struct { long l1; long l2; } J;
+typedef struct { long l1; long l2; long l3; long l4; } K;
+typedef struct { long l1; long l2; long l3; long l4; long l5; long l6; } L;
+typedef struct { char x1; } Size1;
+typedef struct { char x1; char x2; } Size2;
+typedef struct { char x1; char x2; char x3; } Size3;
+typedef struct { char x1; char x2; char x3; char x4; } Size4;
+typedef struct {
+ char x1; char x2; char x3; char x4; char x5; char x6; char x7;
+} Size7;
+typedef struct {
+ char x1; char x2; char x3; char x4; char x5; char x6; char x7; char x8;
+} Size8;
+typedef struct {
+ char x1; char x2; char x3; char x4; char x5; char x6; char x7; char x8;
+ char x9; char x10; char x11; char x12;
+} Size12;
+typedef struct {
+ char x1; char x2; char x3; char x4; char x5; char x6; char x7; char x8;
+ char x9; char x10; char x11; char x12; char x13; char x14; char x15;
+} Size15;
+typedef struct {
+ char x1; char x2; char x3; char x4; char x5; char x6; char x7; char x8;
+ char x9; char x10; char x11; char x12; char x13; char x14; char x15; char x16;
+} Size16;
+typedef struct { char c[3]; } T;
+typedef struct { char c[33],c1; } X;
+
+char c1='a', c2=127, c3=(char)128, c4=(char)255, c5=-1;
+short s1=32767, s2=(short)32768, s3=3, s4=4, s5=5, s6=6, s7=7, s8=8, s9=9;
+int i1=1, i2=2, i3=3, i4=4, i5=5, i6=6, i7=7, i8=8, i9=9,
+ i10=11, i11=12, i12=13, i13=14, i14=15, i15=16, i16=17;
+long l1=1, l2=2, l3=3, l4=4, l5=5, l6=6, l7=7, l8=8, l9=9;
+long long ll1 = 3875056143130689530LL;
+float f1=0.1f, f2=0.2f, f3=0.3f, f4=0.4f, f5=0.5f, f6=0.6f, f7=0.7f, f8=0.8f, f9=0.9f,
+ f10=1.1f, f11=1.2f, f12=1.3f, f13=1.4f, f14=1.5f, f15=1.6f, f16=1.7f, f17=1.8f,
+ f18=1.9f, f19=2.1f, f20=2.2f, f21=2.3f, f22=2.4f, f23=2.5f, f24=2.6f;
+double d1=0.1, d2=0.2, d3=0.3, d4=0.4, d5=0.5, d6=0.6, d7=0.7, d8=0.8, d9=0.9,
+ d10=1.1, d11=1.2, d12=1.3, d13=1.4, d14=1.5, d15=1.6, d16=1.7, d17=1.8;
+
+uchar uc1='a', uc2=127, uc3=128, uc4=255, uc5=(uchar)-1;
+ushort us1=1, us2=2, us3=3, us4=4, us5=5, us6=6, us7=7, us8=8, us9=9;
+uint ui1=1, ui2=2, ui3=3, ui4=4, ui5=5, ui6=6, ui7=7, ui8=8, ui9=9;
+ulong ul1=1, ul2=2, ul3=3, ul4=4, ul5=5, ul6=6, ul7=7, ul8=8, ul9=9;
+
+char *str1="hello",str2[]="goodbye",*str3="still here?";
+Char C1={'A'}, C2={'B'}, C3={'C'}, C4={'\377'}, C5={(char)(-1)};
+Short S1={1}, S2={2}, S3={3}, S4={4}, S5={5}, S6={6}, S7={7}, S8={8}, S9={9};
+Int I1={1}, I2={2}, I3={3}, I4={4}, I5={5}, I6={6}, I7={7}, I8={8}, I9={9};
+Float F1={0.1f}, F2={0.2f}, F3={0.3f}, F4={0.4f}, F5={0.5f}, F6={0.6f}, F7={0.7f}, F8={0.8f}, F9={0.9f};
+Double D1={0.1}, D2={0.2}, D3={0.3}, D4={0.4}, D5={0.5}, D6={0.6}, D7={0.7}, D8={0.8}, D9={0.9};
+
+A A1={'a',0.1f},A2={'b',0.2f},A3={'\377',0.3f};
+B B1={0.1,{1,2,3}},B2={0.2,{5,4,3}};
+J J1={47,11},J2={73,55};
+K K1={19,69,12,28};
+L L1={561,1105,1729,2465,2821,6601}; /* A002997 */
+Size1 Size1_1={'a'};
+Size2 Size2_1={'a','b'};
+Size3 Size3_1={'a','b','c'};
+Size4 Size4_1={'a','b','c','d'};
+Size7 Size7_1={'a','b','c','d','e','f','g'};
+Size8 Size8_1={'a','b','c','d','e','f','g','h'};
+Size12 Size12_1={'a','b','c','d','e','f','g','h','i','j','k','l'};
+Size15 Size15_1={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o'};
+Size16 Size16_1={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'};
+T T1={{'t','h','e'}},T2={{'f','o','x'}};
+X X1={"abcdefghijklmnopqrstuvwxyzABCDEF",'G'}, X2={"123",'9'}, X3={"return-return-return",'R'};
+
+#if defined(__GNUC__)
+#define __STDCALL__ __attribute__((stdcall))
+#define __THISCALL__ __attribute__((thiscall))
+#define __FASTCALL__ __attribute__((fastcall))
+#define __MSABI__ __attribute__((ms_abi))
+#else
+#define __STDCALL__ __stdcall
+#define __THISCALL__ __thiscall
+#define __FASTCALL__ __fastcall
+#endif
+
+#ifndef ABI_ATTR
+#define ABI_ATTR
+#endif
+
+/* void tests */
+void ABI_ATTR v_v (void)
+{
+ fprintf(out,"void f(void):\n");
+ fflush(out);
+}
+
+/* int tests */
+int ABI_ATTR i_v (void)
+{
+ int r=99;
+ fprintf(out,"int f(void):");
+ fflush(out);
+ return r;
+}
+int ABI_ATTR i_i (int a)
+{
+ int r=a+1;
+ fprintf(out,"int f(int):(%d)",a);
+ fflush(out);
+ return r;
+}
+int ABI_ATTR i_i2 (int a, int b)
+{
+ int r=a+b;
+ fprintf(out,"int f(2*int):(%d,%d)",a,b);
+ fflush(out);
+ return r;
+}
+int ABI_ATTR i_i4 (int a, int b, int c, int d)
+{
+ int r=a+b+c+d;
+ fprintf(out,"int f(4*int):(%d,%d,%d,%d)",a,b,c,d);
+ fflush(out);
+ return r;
+}
+int ABI_ATTR i_i8 (int a, int b, int c, int d, int e, int f, int g, int h)
+{
+ int r=a+b+c+d+e+f+g+h;
+ fprintf(out,"int f(8*int):(%d,%d,%d,%d,%d,%d,%d,%d)",a,b,c,d,e,f,g,h);
+ fflush(out);
+ return r;
+}
+int ABI_ATTR i_i16 (int a, int b, int c, int d, int e, int f, int g, int h,
+ int i, int j, int k, int l, int m, int n, int o, int p)
+{
+ int r=a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p;
+ fprintf(out,"int f(16*int):(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
+ a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p);
+ fflush(out);
+ return r;
+}
+
+/* float tests */
+float ABI_ATTR f_f (float a)
+{
+ float r=a+1.0f;
+ fprintf(out,"float f(float):(%g)",a);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f2 (float a, float b)
+{
+ float r=a+b;
+ fprintf(out,"float f(2*float):(%g,%g)",a,b);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f4 (float a, float b, float c, float d)
+{
+ float r=a+b+c+d;
+ fprintf(out,"float f(4*float):(%g,%g,%g,%g)",a,b,c,d);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f8 (float a, float b, float c, float d, float e, float f,
+ float g, float h)
+{
+ float r=a+b+c+d+e+f+g+h;
+ fprintf(out,"float f(8*float):(%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f16 (float a, float b, float c, float d, float e, float f, float g, float h,
+ float i, float j, float k, float l, float m, float n, float o, float p)
+{
+ float r=a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p;
+ fprintf(out,"float f(16*float):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f24 (float a, float b, float c, float d, float e, float f, float g, float h,
+ float i, float j, float k, float l, float m, float n, float o, float p,
+ float q, float s, float t, float u, float v, float w, float x, float y)
+{
+ float r=a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+s+t+u+v+w+x+y;
+ fprintf(out,"float f(24*float):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,s,t,u,v,w,x,y);
+ fflush(out);
+ return r;
+}
+
+/* double tests */
+double ABI_ATTR d_d (double a)
+{
+ double r=a+1.0;
+ fprintf(out,"double f(double):(%g)",a);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d2 (double a, double b)
+{
+ double r=a+b;
+ fprintf(out,"double f(2*double):(%g,%g)",a,b);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d4 (double a, double b, double c, double d)
+{
+ double r=a+b+c+d;
+ fprintf(out,"double f(4*double):(%g,%g,%g,%g)",a,b,c,d);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d8 (double a, double b, double c, double d, double e, double f,
+ double g, double h)
+{
+ double r=a+b+c+d+e+f+g+h;
+ fprintf(out,"double f(8*double):(%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d16 (double a, double b, double c, double d, double e, double f,
+ double g, double h, double i, double j, double k, double l,
+ double m, double n, double o, double p)
+{
+ double r=a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p;
+ fprintf(out,"double f(16*double):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p);
+ fflush(out);
+ return r;
+}
+
+/* pointer tests */
+void* ABI_ATTR vp_vpdpcpsp (void* a, double* b, char* c, Int* d)
+{
+ void* ret = (char*)b + 1;
+ fprintf(out,"void* f(void*,double*,char*,Int*):(0x%p,0x%p,0x%p,0x%p)",a,b,c,d);
+ fflush(out);
+ return ret;
+}
+
+/* mixed number tests */
+uchar ABI_ATTR uc_ucsil (uchar a, ushort b, uint c, ulong d)
+{
+ uchar r = (uchar)-1;
+ fprintf(out,"uchar f(uchar,ushort,uint,ulong):(%u,%u,%u,%lu)",a,b,c,d);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_iidd (int a, int b, double c, double d)
+{
+ double r = a+b+c+d;
+ fprintf(out,"double f(int,int,double,double):(%d,%d,%g,%g)",a,b,c,d);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_iiidi (int a, int b, int c, double d, int e)
+{
+ double r = a+b+c+d+e;
+ fprintf(out,"double f(int,int,int,double,int):(%d,%d,%d,%g,%d)",a,b,c,d,e);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_idid (int a, double b, int c, double d)
+{
+ double r = a+b+c+d;
+ fprintf(out,"double f(int,double,int,double):(%d,%g,%d,%g)",a,b,c,d);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_fdi (float a, double b, int c)
+{
+ double r = a+b+c;
+ fprintf(out,"double f(float,double,int):(%g,%g,%d)",a,b,c);
+ fflush(out);
+ return r;
+}
+ushort ABI_ATTR us_cdcd (char a, double b, char c, double d)
+{
+ ushort r = (ushort)(a + b + c + d);
+ fprintf(out,"ushort f(char,double,char,double):('%c',%g,'%c',%g)",a,b,c,d);
+ fflush(out);
+ return r;
+}
+
+long long ABI_ATTR ll_iiilli (int a, int b, int c, long long d, int e)
+{
+ long long r = (long long)(int)a+(long long)(int)b+(long long)(int)c+d+(long long)(int)e;
+ fprintf(out,"long long f(int,int,int,long long,int):(%d,%d,%d,0x%lx%08lx,%d)",a,b,c,(long)(d>>32),(long)(d&0xffffffff),e);
+ fflush(out);
+ return r;
+}
+long long ABI_ATTR ll_flli (float a, long long b, int c)
+{
+ long long r = (long long)(int)a + b + (long long)c;
+ fprintf(out,"long long f(float,long long,int):(%g,0x%lx%08lx,0x%lx)",a,(long)(b>>32),(long)(b&0xffffffff),(long)c);
+ fflush(out);
+ return r;
+}
+
+float ABI_ATTR f_fi (float a, int z)
+{
+ float r = a+z;
+ fprintf(out,"float f(float,int):(%g,%d)",a,z);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f2i (float a, float b, int z)
+{
+ float r = a+b+z;
+ fprintf(out,"float f(2*float,int):(%g,%g,%d)",a,b,z);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f3i (float a, float b, float c, int z)
+{
+ float r = a+b+c+z;
+ fprintf(out,"float f(3*float,int):(%g,%g,%g,%d)",a,b,c,z);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f4i (float a, float b, float c, float d, int z)
+{
+ float r = a+b+c+d+z;
+ fprintf(out,"float f(4*float,int):(%g,%g,%g,%g,%d)",a,b,c,d,z);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f7i (float a, float b, float c, float d, float e, float f, float g,
+ int z)
+{
+ float r = a+b+c+d+e+f+g+z;
+ fprintf(out,"float f(7*float,int):(%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,z);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f8i (float a, float b, float c, float d, float e, float f, float g,
+ float h, int z)
+{
+ float r = a+b+c+d+e+f+g+h+z;
+ fprintf(out,"float f(8*float,int):(%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,z);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f12i (float a, float b, float c, float d, float e, float f, float g,
+ float h, float i, float j, float k, float l, int z)
+{
+ float r = a+b+c+d+e+f+g+h+i+j+k+l+z;
+ fprintf(out,"float f(12*float,int):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,i,j,k,l,z);
+ fflush(out);
+ return r;
+}
+float ABI_ATTR f_f13i (float a, float b, float c, float d, float e, float f, float g,
+ float h, float i, float j, float k, float l, float m, int z)
+{
+ float r = a+b+c+d+e+f+g+h+i+j+k+l+m+z;
+ fprintf(out,"float f(13*float,int):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,i,j,k,l,m,z);
+ fflush(out);
+ return r;
+}
+
+double ABI_ATTR d_di (double a, int z)
+{
+ double r = a+z;
+ fprintf(out,"double f(double,int):(%g,%d)",a,z);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d2i (double a, double b, int z)
+{
+ double r = a+b+z;
+ fprintf(out,"double f(2*double,int):(%g,%g,%d)",a,b,z);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d3i (double a, double b, double c, int z)
+{
+ double r = a+b+c+z;
+ fprintf(out,"double f(3*double,int):(%g,%g,%g,%d)",a,b,c,z);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d4i (double a, double b, double c, double d, int z)
+{
+ double r = a+b+c+d+z;
+ fprintf(out,"double f(4*double,int):(%g,%g,%g,%g,%d)",a,b,c,d,z);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d7i (double a, double b, double c, double d, double e, double f,
+ double g, int z)
+{
+ double r = a+b+c+d+e+f+g+z;
+ fprintf(out,"double f(7*double,int):(%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,z);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d8i (double a, double b, double c, double d, double e, double f,
+ double g, double h, int z)
+{
+ double r = a+b+c+d+e+f+g+h+z;
+ fprintf(out,"double f(8*double,int):(%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,z);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d12i (double a, double b, double c, double d, double e, double f,
+ double g, double h, double i, double j, double k, double l,
+ int z)
+{
+ double r = a+b+c+d+e+f+g+h+i+j+k+l+z;
+ fprintf(out,"double f(12*double,int):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,i,j,k,l,z);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d13i (double a, double b, double c, double d, double e, double f,
+ double g, double h, double i, double j, double k, double l,
+ double m, int z)
+{
+ double r = a+b+c+d+e+f+g+h+i+j+k+l+m+z;
+ fprintf(out,"double f(13*double,int):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%d)",a,b,c,d,e,f,g,h,i,j,k,l,m,z);
+ fflush(out);
+ return r;
+}
+
+/* small structure return tests */
+Size1 ABI_ATTR S1_v (void)
+{
+ fprintf(out,"Size1 f(void):");
+ fflush(out);
+ return Size1_1;
+}
+Size2 ABI_ATTR S2_v (void)
+{
+ fprintf(out,"Size2 f(void):");
+ fflush(out);
+ return Size2_1;
+}
+Size3 ABI_ATTR S3_v (void)
+{
+ fprintf(out,"Size3 f(void):");
+ fflush(out);
+ return Size3_1;
+}
+Size4 ABI_ATTR S4_v (void)
+{
+ fprintf(out,"Size4 f(void):");
+ fflush(out);
+ return Size4_1;
+}
+Size7 ABI_ATTR S7_v (void)
+{
+ fprintf(out,"Size7 f(void):");
+ fflush(out);
+ return Size7_1;
+}
+Size8 ABI_ATTR S8_v (void)
+{
+ fprintf(out,"Size8 f(void):");
+ fflush(out);
+ return Size8_1;
+}
+Size12 ABI_ATTR S12_v (void)
+{
+ fprintf(out,"Size12 f(void):");
+ fflush(out);
+ return Size12_1;
+}
+Size15 ABI_ATTR S15_v (void)
+{
+ fprintf(out,"Size15 f(void):");
+ fflush(out);
+ return Size15_1;
+}
+Size16 ABI_ATTR S16_v (void)
+{
+ fprintf(out,"Size16 f(void):");
+ fflush(out);
+ return Size16_1;
+}
+
+/* structure tests */
+Int ABI_ATTR I_III (Int a, Int b, Int c)
+{
+ Int r;
+ r.x = a.x + b.x + c.x;
+ fprintf(out,"Int f(Int,Int,Int):({%d},{%d},{%d})",a.x,b.x,c.x);
+ fflush(out);
+ return r;
+}
+Char ABI_ATTR C_CdC (Char a, double b, Char c)
+{
+ Char r;
+ r.x = (a.x + c.x)/2;
+ fprintf(out,"Char f(Char,double,Char):({'%c'},%g,{'%c'})",a.x,b,c.x);
+ fflush(out);
+ return r;
+}
+Float ABI_ATTR F_Ffd (Float a, float b, double c)
+{
+ Float r;
+ r.x = (float) (a.x + b + c);
+ fprintf(out,"Float f(Float,float,double):({%g},%g,%g)",a.x,b,c);
+ fflush(out);
+ return r;
+}
+Double ABI_ATTR D_fDd (float a, Double b, double c)
+{
+ Double r;
+ r.x = a + b.x + c;
+ fprintf(out,"Double f(float,Double,double):(%g,{%g},%g)",a,b.x,c);
+ fflush(out);
+ return r;
+}
+Double ABI_ATTR D_Dfd (Double a, float b, double c)
+{
+ Double r;
+ r.x = a.x + b + c;
+ fprintf(out,"Double f(Double,float,double):({%g},%g,%g)",a.x,b,c);
+ fflush(out);
+ return r;
+}
+J ABI_ATTR J_JiJ (J a, int b, J c)
+{
+ J r;
+ r.l1 = a.l1+c.l1; r.l2 = a.l2+b+c.l2;
+ fprintf(out,"J f(J,int,J):({%ld,%ld},%d,{%ld,%ld})",a.l1,a.l2,b,c.l1,c.l2);
+ fflush(out);
+ return r;
+}
+T ABI_ATTR T_TcT (T a, char b, T c)
+{
+ T r;
+ r.c[0]='b'; r.c[1]=c.c[1]; r.c[2]=c.c[2];
+ fprintf(out,"T f(T,char,T):({\"%c%c%c\"},'%c',{\"%c%c%c\"})",a.c[0],a.c[1],a.c[2],b,c.c[0],c.c[1],c.c[2]);
+ fflush(out);
+ return r;
+}
+X ABI_ATTR X_BcdB (B a, char b, double c, B d)
+{
+ static X xr={"return val",'R'};
+ X r;
+ r = xr;
+ r.c1 = b;
+ fprintf(out,"X f(B,char,double,B):({%g,{%d,%d,%d}},'%c',%g,{%g,{%d,%d,%d}})",
+ a.d,a.i[0],a.i[1],a.i[2],b,c,d.d,d.i[0],d.i[1],d.i[2]);
+ fflush(out);
+ return r;
+}
+
+/* Test for cases where some argument (especially structure, 'long long', or
+ 'double') may be passed partially in general-purpose argument registers
+ and partially on the stack. Different ABIs pass between 4 and 8 arguments
+ (or none) in general-purpose argument registers. */
+
+long ABI_ATTR l_l0K (K b, long c)
+{
+ long r = b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(K,long):(%ld,%ld,%ld,%ld,%ld)",b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ return r;
+}
+long ABI_ATTR l_l1K (long a1, K b, long c)
+{
+ long r = a1 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld)",a1,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ return r;
+}
+long ABI_ATTR l_l2K (long a1, long a2, K b, long c)
+{
+ long r = a1 + a2 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(2*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ return r;
+}
+long ABI_ATTR l_l3K (long a1, long a2, long a3, K b, long c)
+{
+ long r = a1 + a2 + a3 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(3*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,a3,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ return r;
+}
+long ABI_ATTR l_l4K (long a1, long a2, long a3, long a4, K b, long c)
+{
+ long r = a1 + a2 + a3 + a4 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(4*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,a3,a4,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ return r;
+}
+long ABI_ATTR l_l5K (long a1, long a2, long a3, long a4, long a5, K b, long c)
+{
+ long r = a1 + a2 + a3 + a4 + a5 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(5*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,a3,a4,a5,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ return r;
+}
+long ABI_ATTR l_l6K (long a1, long a2, long a3, long a4, long a5, long a6, K b, long c)
+{
+ long r = a1 + a2 + a3 + a4 + a5 + a6 + b.l1 + b.l2 + b.l3 + b.l4 + c;
+ fprintf(out,"long f(6*long,K,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a1,a2,a3,a4,a5,a6,b.l1,b.l2,b.l3,b.l4,c);
+ fflush(out);
+ return r;
+}
+/* These tests is crafted on the knowledge that for all known ABIs:
+ * 17 > number of floating-point argument registers,
+ * 3 < number of general-purpose argument registers < 3 + 6. */
+float ABI_ATTR f_f17l3L (float a, float b, float c, float d, float e, float f, float g,
+ float h, float i, float j, float k, float l, float m, float n,
+ float o, float p, float q,
+ long s, long t, long u, L z)
+{
+ float r = a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+s+t+u+z.l1+z.l2+z.l3+z.l4+z.l5+z.l6;
+ fprintf(out,"float f(17*float,3*int,L):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,s,t,u,z.l1,z.l2,z.l3,z.l4,z.l5,z.l6);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_d17l3L (double a, double b, double c, double d, double e, double f,
+ double g, double h, double i, double j, double k, double l,
+ double m, double n, double o, double p, double q,
+ long s, long t, long u, L z)
+{
+ double r = a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+s+t+u+z.l1+z.l2+z.l3+z.l4+z.l5+z.l6;
+ fprintf(out,"double f(17*double,3*int,L):(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld)",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,s,t,u,z.l1,z.l2,z.l3,z.l4,z.l5,z.l6);
+ fflush(out);
+ return r;
+}
+
+long long ABI_ATTR ll_l2ll (long a1, long a2, long long b, long c)
+{
+ long long r = (long long) (a1 + a2) + b + c;
+ fprintf(out,"long long f(2*long,long long,long):(%ld,%ld,0x%lx%08lx,%ld)",a1,a2,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ return r;
+}
+long long ABI_ATTR ll_l3ll (long a1, long a2, long a3, long long b, long c)
+{
+ long long r = (long long) (a1 + a2 + a3) + b + c;
+ fprintf(out,"long long f(3*long,long long,long):(%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ return r;
+}
+long long ABI_ATTR ll_l4ll (long a1, long a2, long a3, long a4, long long b, long c)
+{
+ long long r = (long long) (a1 + a2 + a3 + a4) + b + c;
+ fprintf(out,"long long f(4*long,long long,long):(%ld,%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,a4,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ return r;
+}
+long long ABI_ATTR ll_l5ll (long a1, long a2, long a3, long a4, long a5, long long b, long c)
+{
+ long long r = (long long) (a1 + a2 + a3 + a4 + a5) + b + c;
+ fprintf(out,"long long f(5*long,long long,long):(%ld,%ld,%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,a4,a5,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ return r;
+}
+long long ABI_ATTR ll_l6ll (long a1, long a2, long a3, long a4, long a5, long a6, long long b, long c)
+{
+ long long r = (long long) (a1 + a2 + a3 + a4 + a5 + a6) + b + c;
+ fprintf(out,"long long f(6*long,long long,long):(%ld,%ld,%ld,%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,a4,a5,a6,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ return r;
+}
+long long ABI_ATTR ll_l7ll (long a1, long a2, long a3, long a4, long a5, long a6, long a7, long long b, long c)
+{
+ long long r = (long long) (a1 + a2 + a3 + a4 + a5 + a6 + a7) + b + c;
+ fprintf(out,"long long f(7*long,long long,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,0x%lx%08lx,%ld)",a1,a2,a3,a4,a5,a6,a7,(long)(b>>32),(long)(b&0xffffffff),c);
+ fflush(out);
+ return r;
+}
+
+double ABI_ATTR d_l2d (long a1, long a2, double b, long c)
+{
+ double r = (double) (a1 + a2) + b + c;
+ fprintf(out,"double f(2*long,double,long):(%ld,%ld,%g,%ld)",a1,a2,b,c);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_l3d (long a1, long a2, long a3, double b, long c)
+{
+ double r = (double) (a1 + a2 + a3) + b + c;
+ fprintf(out,"double f(3*long,double,long):(%ld,%ld,%ld,%g,%ld)",a1,a2,a3,b,c);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_l4d (long a1, long a2, long a3, long a4, double b, long c)
+{
+ double r = (double) (a1 + a2 + a3 + a4) + b + c;
+ fprintf(out,"double f(4*long,double,long):(%ld,%ld,%ld,%ld,%g,%ld)",a1,a2,a3,a4,b,c);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_l5d (long a1, long a2, long a3, long a4, long a5, double b, long c)
+{
+ double r = (double) (a1 + a2 + a3 + a4 + a5) + b + c;
+ fprintf(out,"double f(5*long,double,long):(%ld,%ld,%ld,%ld,%ld,%g,%ld)",a1,a2,a3,a4,a5,b,c);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_l6d (long a1, long a2, long a3, long a4, long a5, long a6, double b, long c)
+{
+ double r = (double) (a1 + a2 + a3 + a4 + a5 + a6) + b + c;
+ fprintf(out,"double f(6*long,double,long):(%ld,%ld,%ld,%ld,%ld,%ld,%g,%ld)",a1,a2,a3,a4,a5,a6,b,c);
+ fflush(out);
+ return r;
+}
+double ABI_ATTR d_l7d (long a1, long a2, long a3, long a4, long a5, long a6, long a7, double b, long c)
+{
+ double r = (double) (a1 + a2 + a3 + a4 + a5 + a6 + a7) + b + c;
+ fprintf(out,"double f(7*long,double,long):(%ld,%ld,%ld,%ld,%ld,%ld,%ld,%g,%ld)",a1,a2,a3,a4,a5,a6,a7,b,c);
+ fflush(out);
+ return r;
+}
diff --git a/testsuite/libffi.call/align_mixed.c b/testsuite/libffi.call/align_mixed.c
new file mode 100644
index 00000000..5d4959ce
--- /dev/null
+++ b/testsuite/libffi.call/align_mixed.c
@@ -0,0 +1,46 @@
+/* Area: ffi_call
+ Purpose: Check for proper argument alignment.
+ Limitations: none.
+ PR: none.
+ Originator: <twalljava@java.net> (from many_win32.c) */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+static float ABI_ATTR align_arguments(int i1,
+ double f2,
+ int i3,
+ double f4)
+{
+ return i1+f2+i3+f4;
+}
+
+int main(void)
+{
+ ffi_cif cif;
+ ffi_type *args[4] = {
+ &ffi_type_sint,
+ &ffi_type_double,
+ &ffi_type_sint,
+ &ffi_type_double
+ };
+ double fa[2] = {1,2};
+ int ia[2] = {1,2};
+ void *values[4] = {&ia[0], &fa[0], &ia[1], &fa[1]};
+ float f, ff;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, ABI_NUM, 4,
+ &ffi_type_float, args) == FFI_OK);
+
+ ff = align_arguments(ia[0], fa[0], ia[1], fa[1]);
+
+ ffi_call(&cif, FFI_FN(align_arguments), &f, values);
+
+ if (f == ff)
+ printf("align arguments tests ok!\n");
+ else
+ CHECK(0);
+ exit(0);
+}
diff --git a/testsuite/libffi.call/align_stdcall.c b/testsuite/libffi.call/align_stdcall.c
new file mode 100644
index 00000000..5e5cb860
--- /dev/null
+++ b/testsuite/libffi.call/align_stdcall.c
@@ -0,0 +1,46 @@
+/* Area: ffi_call
+ Purpose: Check for proper argument alignment.
+ Limitations: none.
+ PR: none.
+ Originator: <twalljava@java.net> (from many_win32.c) */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+static float ABI_ATTR align_arguments(int i1,
+ double f2,
+ int i3,
+ double f4)
+{
+ return i1+f2+i3+f4;
+}
+
+int main(void)
+{
+ ffi_cif cif;
+ ffi_type *args[4] = {
+ &ffi_type_sint,
+ &ffi_type_double,
+ &ffi_type_sint,
+ &ffi_type_double
+ };
+ double fa[2] = {1,2};
+ int ia[2] = {1,2};
+ void *values[4] = {&ia[0], &fa[0], &ia[1], &fa[1]};
+ float f, ff;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, ABI_NUM, 4,
+ &ffi_type_float, args) == FFI_OK);
+
+ ff = align_arguments(ia[0], fa[0], ia[1], fa[1]);;
+
+ ffi_call(&cif, FFI_FN(align_arguments), &f, values);
+
+ if (f == ff)
+ printf("align arguments tests ok!\n");
+ else
+ CHECK(0);
+ exit(0);
+}
diff --git a/testsuite/libffi.call/call.exp b/testsuite/libffi.call/call.exp
index 5177f07f..13ba2bdc 100644
--- a/testsuite/libffi.call/call.exp
+++ b/testsuite/libffi.call/call.exp
@@ -19,21 +19,32 @@ libffi-init
global srcdir subdir
-set tlist [lsearch -inline -all -not -glob [lsort [glob -nocomplain -- $srcdir/$subdir/*.{c,cc}]] *complex*]
-set ctlist [lsearch -inline -all -glob [lsort [glob -nocomplain -- $srcdir/$subdir/*.{c,cc}]] *complex*]
+if { [string match $compiler_vendor "microsoft"] } {
+ # -wd4005 macro redefinition
+ # -wd4244 implicit conversion to type of smaller size
+ # -wd4305 truncation to smaller type
+ # -wd4477 printf %lu of uintptr_t
+ # -wd4312 implicit conversion to type of greater size
+ # -wd4311 pointer truncation to unsigned long
+ # -EHsc C++ Exception Handling (no SEH exceptions)
+ set additional_options "-wd4005 -wd4244 -wd4305 -wd4477 -wd4312 -wd4311 -EHsc";
+} else {
+ set additional_options "";
+}
-run-many-tests $tlist ""
+set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.c]]
-if { ![istarget s390*] } {
+run-many-tests $tlist $additional_options
- foreach test $ctlist {
- unsupported "$test"
- }
+set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.cc]]
+# No C++ for or1k
+if { [istarget "or1k-*-*"] } {
+ foreach test $tlist {
+ unsupported "$test"
+ }
} else {
-
- run-many-tests $ctlist ""
-
+ run-many-tests $tlist $additional_options
}
dg-finish
diff --git a/testsuite/libffi.call/ffitest.h b/testsuite/libffi.call/ffitest.h
index 15d5e441..cfce1ad5 100644
--- a/testsuite/libffi.call/ffitest.h
+++ b/testsuite/libffi.call/ffitest.h
@@ -24,6 +24,7 @@
#define __STDCALL__ __attribute__((stdcall))
#define __THISCALL__ __attribute__((thiscall))
#define __FASTCALL__ __attribute__((fastcall))
+#define __MSABI__ __attribute__((ms_abi))
#else
#define __UNUSED__
#define __STDCALL__ __stdcall
@@ -63,7 +64,7 @@
#endif
/* MinGW kludge. */
-#ifdef _WIN64
+#if defined(_WIN64) | defined(_WIN32)
#define PRIdLL "I64d"
#define PRIuLL "I64u"
#else
@@ -123,12 +124,14 @@
/* MSVC kludge. */
#if defined _MSC_VER
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
#define PRIuPTR "lu"
#define PRIu8 "u"
#define PRId8 "d"
#define PRIu64 "I64u"
#define PRId64 "I64d"
#endif
+#endif
#ifndef PRIuPTR
#define PRIuPTR "u"
diff --git a/testsuite/libffi.call/float1.c b/testsuite/libffi.call/float1.c
index 991d059f..c48493c6 100644
--- a/testsuite/libffi.call/float1.c
+++ b/testsuite/libffi.call/float1.c
@@ -8,6 +8,8 @@
#include "ffitest.h"
#include "float.h"
+#include <math.h>
+
typedef union
{
double d;
@@ -47,7 +49,7 @@ int main (void)
/* These are not always the same!! Check for a reasonable delta */
- CHECK(result[0].d - dblit(f) < DBL_EPSILON);
+ CHECK(fabs(result[0].d - dblit(f)) < DBL_EPSILON);
/* Check the canary. */
for (i = 0; i < sizeof (double); ++i)
diff --git a/testsuite/libffi.call/float2.c b/testsuite/libffi.call/float2.c
index a0b296cf..57cd9e30 100644
--- a/testsuite/libffi.call/float2.c
+++ b/testsuite/libffi.call/float2.c
@@ -3,13 +3,13 @@
Limitations: none.
PR: none.
Originator: From the original ffitest.c */
-
-/* { dg-excess-errors "fails" { target x86_64-*-mingw* x86_64-*-cygwin* } } */
-/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
+/* { dg-do run } */
#include "ffitest.h"
#include "float.h"
+#include <math.h>
+
static long double ldblit(float f)
{
return (long double) (((long double) f)/ (long double) 3.0);
@@ -22,6 +22,7 @@ int main (void)
void *values[MAX_ARGS];
float f;
long double ld;
+ long double original;
args[0] = &ffi_type_float;
values[0] = &f;
@@ -32,24 +33,26 @@ int main (void)
f = 3.14159;
-#if 1
- /* This is ifdef'd out for now. long double support under SunOS/gcc
- is pretty much non-existent. You'll get the odd bus error in library
- routines like printf(). */
+#if defined(__sun) && defined(__GNUC__)
+ /* long double support under SunOS/gcc is pretty much non-existent.
+ You'll get the odd bus error in library routines like printf() */
+#else
printf ("%Lf\n", ldblit(f));
#endif
+
ld = 666;
ffi_call(&cif, FFI_FN(ldblit), &ld, values);
-#if 1
- /* This is ifdef'd out for now. long double support under SunOS/gcc
- is pretty much non-existent. You'll get the odd bus error in library
- routines like printf(). */
+#if defined(__sun) && defined(__GNUC__)
+ /* long double support under SunOS/gcc is pretty much non-existent.
+ You'll get the odd bus error in library routines like printf() */
+#else
printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON);
#endif
/* These are not always the same!! Check for a reasonable delta */
- if (ld - ldblit(f) < LDBL_EPSILON)
+ original = ldblit(f);
+ if (((ld > original) ? (ld - original) : (original - ld)) < LDBL_EPSILON)
puts("long double return value tests ok!");
else
CHECK(0);
diff --git a/testsuite/libffi.call/float3.c b/testsuite/libffi.call/float3.c
index 76bd5f28..bab3206a 100644
--- a/testsuite/libffi.call/float3.c
+++ b/testsuite/libffi.call/float3.c
@@ -9,6 +9,8 @@
#include "ffitest.h"
#include "float.h"
+#include <math.h>
+
static double floating_1(float a, double b, long double c)
{
return (double) a + b + (double) c;
@@ -49,7 +51,7 @@ int main (void)
ffi_call(&cif, FFI_FN(floating_1), &rd, values);
- CHECK(rd - floating_1(f, d, ld) < DBL_EPSILON);
+ CHECK(fabs(rd - floating_1(f, d, ld)) < DBL_EPSILON);
args[0] = &ffi_type_longdouble;
values[0] = &ld;
@@ -66,7 +68,7 @@ int main (void)
ffi_call(&cif, FFI_FN(floating_2), &rd, values);
- CHECK(rd - floating_2(ld, d, f) < DBL_EPSILON);
+ CHECK(fabs(rd - floating_2(ld, d, f)) < DBL_EPSILON);
exit (0);
}
diff --git a/testsuite/libffi.call/offsets.c b/testsuite/libffi.call/offsets.c
new file mode 100644
index 00000000..23d88b35
--- /dev/null
+++ b/testsuite/libffi.call/offsets.c
@@ -0,0 +1,46 @@
+/* Area: Struct layout
+ Purpose: Test ffi_get_struct_offsets
+ Limitations: none.
+ PR: none.
+ Originator: Tom Tromey. */
+
+/* { dg-do run } */
+#include "ffitest.h"
+#include <stddef.h>
+
+struct test_1
+{
+ char c;
+ float f;
+ char c2;
+ int i;
+};
+
+int
+main (void)
+{
+ ffi_type test_1_type;
+ ffi_type *test_1_elements[5];
+ size_t test_1_offsets[4];
+
+ test_1_elements[0] = &ffi_type_schar;
+ test_1_elements[1] = &ffi_type_float;
+ test_1_elements[2] = &ffi_type_schar;
+ test_1_elements[3] = &ffi_type_sint;
+ test_1_elements[4] = NULL;
+
+ test_1_type.size = 0;
+ test_1_type.alignment = 0;
+ test_1_type.type = FFI_TYPE_STRUCT;
+ test_1_type.elements = test_1_elements;
+
+ CHECK (ffi_get_struct_offsets (FFI_DEFAULT_ABI, &test_1_type, test_1_offsets)
+ == FFI_OK);
+ CHECK (test_1_type.size == sizeof (struct test_1));
+ CHECK (offsetof (struct test_1, c) == test_1_offsets[0]);
+ CHECK (offsetof (struct test_1, f) == test_1_offsets[1]);
+ CHECK (offsetof (struct test_1, c2) == test_1_offsets[2]);
+ CHECK (offsetof (struct test_1, i) == test_1_offsets[3]);
+
+ return 0;
+}
diff --git a/testsuite/libffi.call/pr1172638.c b/testsuite/libffi.call/pr1172638.c
new file mode 100644
index 00000000..7da1621c
--- /dev/null
+++ b/testsuite/libffi.call/pr1172638.c
@@ -0,0 +1,127 @@
+/* Area: ffi_call
+ Purpose: Reproduce bug found in python ctypes
+ Limitations: none.
+ PR: Fedora 1174037 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct {
+ long x;
+ long y;
+} POINT;
+
+typedef struct {
+ long left;
+ long top;
+ long right;
+ long bottom;
+} RECT;
+
+static RECT ABI_ATTR pr_test(int i __UNUSED__, RECT ar __UNUSED__,
+ RECT* br __UNUSED__, POINT cp __UNUSED__,
+ RECT dr __UNUSED__, RECT *er __UNUSED__,
+ POINT fp, RECT gr __UNUSED__)
+{
+ RECT result;
+
+ result.left = fp.x;
+ result.right = fp.y;
+ result.top = fp.x;
+ result.bottom = fp.y;
+
+ return result;
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_type *args[MAX_ARGS];
+ void *values[MAX_ARGS];
+ ffi_type point_type, rect_type;
+ ffi_type *point_type_elements[3];
+ ffi_type *rect_type_elements[5];
+
+ int i;
+ POINT cp, fp;
+ RECT ar, br, dr, er, gr;
+ RECT *p1, *p2;
+
+ /* This is a hack to get a properly aligned result buffer */
+ RECT *rect_result =
+ (RECT *) malloc (sizeof(RECT));
+
+ point_type.size = 0;
+ point_type.alignment = 0;
+ point_type.type = FFI_TYPE_STRUCT;
+ point_type.elements = point_type_elements;
+ point_type_elements[0] = &ffi_type_slong;
+ point_type_elements[1] = &ffi_type_slong;
+ point_type_elements[2] = NULL;
+
+ rect_type.size = 0;
+ rect_type.alignment = 0;
+ rect_type.type = FFI_TYPE_STRUCT;
+ rect_type.elements = rect_type_elements;
+ rect_type_elements[0] = &ffi_type_slong;
+ rect_type_elements[1] = &ffi_type_slong;
+ rect_type_elements[2] = &ffi_type_slong;
+ rect_type_elements[3] = &ffi_type_slong;
+ rect_type_elements[4] = NULL;
+
+ args[0] = &ffi_type_sint;
+ args[1] = &rect_type;
+ args[2] = &ffi_type_pointer;
+ args[3] = &point_type;
+ args[4] = &rect_type;
+ args[5] = &ffi_type_pointer;
+ args[6] = &point_type;
+ args[7] = &rect_type;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, ABI_NUM, 8, &rect_type, args) == FFI_OK);
+
+ i = 1;
+ ar.left = 2;
+ ar.right = 3;
+ ar.top = 4;
+ ar.bottom = 5;
+ br.left = 6;
+ br.right = 7;
+ br.top = 8;
+ br.bottom = 9;
+ cp.x = 10;
+ cp.y = 11;
+ dr.left = 12;
+ dr.right = 13;
+ dr.top = 14;
+ dr.bottom = 15;
+ er.left = 16;
+ er.right = 17;
+ er.top = 18;
+ er.bottom = 19;
+ fp.x = 20;
+ fp.y = 21;
+ gr.left = 22;
+ gr.right = 23;
+ gr.top = 24;
+ gr.bottom = 25;
+
+ values[0] = &i;
+ values[1] = &ar;
+ p1 = &br;
+ values[2] = &p1;
+ values[3] = &cp;
+ values[4] = &dr;
+ p2 = &er;
+ values[5] = &p2;
+ values[6] = &fp;
+ values[7] = &gr;
+
+ ffi_call (&cif, FFI_FN(pr_test), rect_result, values);
+
+ CHECK(rect_result->top == 20);
+
+ free (rect_result);
+ exit(0);
+}
diff --git a/testsuite/libffi.call/return_ldl.c b/testsuite/libffi.call/return_ldl.c
index 5c2fe65a..52a92fe0 100644
--- a/testsuite/libffi.call/return_ldl.c
+++ b/testsuite/libffi.call/return_ldl.c
@@ -3,8 +3,8 @@
Limitations: none.
PR: none.
Originator: <andreast@gcc.gnu.org> 20071113 */
+/* { dg-do run } */
-/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
#include "ffitest.h"
static long double return_ldl(long double ldl)
diff --git a/testsuite/libffi.call/struct10.c b/testsuite/libffi.call/struct10.c
new file mode 100644
index 00000000..17b13774
--- /dev/null
+++ b/testsuite/libffi.call/struct10.c
@@ -0,0 +1,57 @@
+/* Area: ffi_call
+ Purpose: Check structures.
+ Limitations: none.
+ PR: none.
+ Originator: Sergei Trofimovich <slyfox@gentoo.org>
+
+ The test originally discovered in ruby's bindings
+ for ffi in https://bugs.gentoo.org/634190 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+struct s {
+ int s32;
+ float f32;
+ signed char s8;
+};
+
+struct s make_s(void) {
+ struct s r;
+ r.s32 = 0x1234;
+ r.f32 = 7.0;
+ r.s8 = 0x78;
+ return r;
+}
+
+int main() {
+ ffi_cif cif;
+ struct s r;
+ ffi_type rtype;
+ ffi_type* s_fields[] = {
+ &ffi_type_sint,
+ &ffi_type_float,
+ &ffi_type_schar,
+ NULL,
+ };
+
+ rtype.size = 0;
+ rtype.alignment = 0,
+ rtype.type = FFI_TYPE_STRUCT,
+ rtype.elements = s_fields,
+
+ r.s32 = 0xbad;
+ r.f32 = 999.999;
+ r.s8 = 0x51;
+
+ // Here we emulate the following call:
+ //r = make_s();
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, &rtype, NULL) == FFI_OK);
+ ffi_call(&cif, FFI_FN(make_s), &r, NULL);
+
+ CHECK(r.s32 == 0x1234);
+ CHECK(r.f32 == 7.0);
+ CHECK(r.s8 == 0x78);
+ exit(0);
+}
diff --git a/testsuite/libffi.call/va_1.c b/testsuite/libffi.call/va_1.c
index 7f96809e..59d085c8 100644
--- a/testsuite/libffi.call/va_1.c
+++ b/testsuite/libffi.call/va_1.c
@@ -5,7 +5,7 @@
Originator: ARM Ltd. */
/* { dg-do run } */
-/* { dg-output "" { xfail avr32*-*-* } } */
+/* { dg-output "" { xfail avr32*-*-* m68k-*-* alpha-*-* } } */
#include "ffitest.h"
#include <stdarg.h>
diff --git a/testsuite/libffi.closures/closure.exp b/testsuite/libffi.closures/closure.exp
new file mode 100644
index 00000000..ed4145ca
--- /dev/null
+++ b/testsuite/libffi.closures/closure.exp
@@ -0,0 +1,67 @@
+# Copyright (C) 2003, 2006, 2009, 2010, 2014, 2019 Free Software Foundation, Inc.
+# Copyright (C) 2019 Anthony Green
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+dg-init
+libffi-init
+
+global srcdir subdir
+
+if { [string match $compiler_vendor "microsoft"] } {
+ # -wd4005 macro redefinition
+ # -wd4244 implicit conversion to type of smaller size
+ # -wd4305 truncation to smaller type
+ # -wd4477 printf %lu of uintptr_t
+ # -wd4312 implicit conversion to type of greater size
+ # -wd4311 pointer truncation to unsigned long
+ # -EHsc C++ Exception Handling (no SEH exceptions)
+ set additional_options "-wd4005 -wd4244 -wd4305 -wd4477 -wd4312 -wd4311 -EHsc";
+} else {
+ set additional_options "";
+}
+
+set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.c]]
+
+if { [libffi_feature_test "#if FFI_CLOSURES"] } {
+ run-many-tests $tlist ""
+} else {
+ foreach test $tlist {
+ unsupported "$test"
+ }
+}
+
+set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.cc]]
+
+# No C++ for or1k
+if { [istarget "or1k-*-*"] } {
+ foreach test $tlist {
+ unsupported "$test"
+ }
+} else {
+ if { [libffi_feature_test "#if FFI_CLOSURES"] } {
+ run-many-tests $tlist $additional_options
+ } else {
+ foreach test $tlist {
+ unsupported "$test"
+ }
+ }
+}
+
+dg-finish
+
+# Local Variables:
+# tcl-indent-level:4
+# End:
diff --git a/testsuite/libffi.closures/closure_fn0.c b/testsuite/libffi.closures/closure_fn0.c
new file mode 100644
index 00000000..a579ff6c
--- /dev/null
+++ b/testsuite/libffi.closures/closure_fn0.c
@@ -0,0 +1,89 @@
+/* Area: closure_call
+ Purpose: Check multiple values passing from different type.
+ Also, exceed the limit of gpr and fpr registers on PowerPC
+ Darwin.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+
+
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void
+closure_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata)
+{
+ *(ffi_arg*)resp =
+ (int)*(unsigned long long *)args[0] + (int)(*(int *)args[1]) +
+ (int)(*(unsigned long long *)args[2]) + (int)*(int *)args[3] +
+ (int)(*(signed short *)args[4]) +
+ (int)(*(unsigned long long *)args[5]) +
+ (int)*(int *)args[6] + (int)(*(int *)args[7]) +
+ (int)(*(double *)args[8]) + (int)*(int *)args[9] +
+ (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(int *)args[13]) +
+ (int)(*(int *)args[14]) + *(int *)args[15] + (intptr_t)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(unsigned long long *)args[0], (int)(*(int *)args[1]),
+ (int)(*(unsigned long long *)args[2]),
+ (int)*(int *)args[3], (int)(*(signed short *)args[4]),
+ (int)(*(unsigned long long *)args[5]),
+ (int)*(int *)args[6], (int)(*(int *)args[7]),
+ (int)(*(double *)args[8]), (int)*(int *)args[9],
+ (int)(*(int *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(int *)args[13]),
+ (int)(*(int *)args[14]),*(int *)args[15],
+ (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+
+}
+
+typedef int (*closure_test_type0)(unsigned long long, int, unsigned long long,
+ int, signed short, unsigned long long, int,
+ int, double, int, int, float, int, int,
+ int, int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void * code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[17];
+ int res;
+
+ cl_arg_types[0] = &ffi_type_uint64;
+ cl_arg_types[1] = &ffi_type_sint;
+ cl_arg_types[2] = &ffi_type_uint64;
+ cl_arg_types[3] = &ffi_type_sint;
+ cl_arg_types[4] = &ffi_type_sshort;
+ cl_arg_types[5] = &ffi_type_uint64;
+ cl_arg_types[6] = &ffi_type_sint;
+ cl_arg_types[7] = &ffi_type_sint;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_sint;
+ cl_arg_types[10] = &ffi_type_sint;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_sint;
+ cl_arg_types[13] = &ffi_type_sint;
+ cl_arg_types[14] = &ffi_type_sint;
+ cl_arg_types[15] = &ffi_type_sint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn0,
+ (void *) 3 /* userdata */, code) == FFI_OK);
+
+ res = (*((closure_test_type0)code))
+ (1LL, 2, 3LL, 4, 127, 429LL, 7, 8, 9.5, 10, 11, 12, 13,
+ 19, 21, 1);
+ /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 680" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/closure_fn1.c b/testsuite/libffi.closures/closure_fn1.c
new file mode 100644
index 00000000..91231738
--- /dev/null
+++ b/testsuite/libffi.closures/closure_fn1.c
@@ -0,0 +1,81 @@
+/* Area: closure_call.
+ Purpose: Check multiple values passing from different type.
+ Also, exceed the limit of gpr and fpr registers on PowerPC
+ Darwin.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+
+static void closure_test_fn1(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata)
+{
+ *(ffi_arg*)resp =
+ (int)*(float *)args[0] +(int)(*(float *)args[1]) +
+ (int)(*(float *)args[2]) + (int)*(float *)args[3] +
+ (int)(*(signed short *)args[4]) + (int)(*(float *)args[5]) +
+ (int)*(float *)args[6] + (int)(*(int *)args[7]) +
+ (int)(*(double*)args[8]) + (int)*(int *)args[9] +
+ (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(int *)args[13]) +
+ (int)(*(int *)args[14]) + *(int *)args[15] + (intptr_t)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(float *)args[0], (int)(*(float *)args[1]),
+ (int)(*(float *)args[2]), (int)*(float *)args[3],
+ (int)(*(signed short *)args[4]), (int)(*(float *)args[5]),
+ (int)*(float *)args[6], (int)(*(int *)args[7]),
+ (int)(*(double *)args[8]), (int)*(int *)args[9],
+ (int)(*(int *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(int *)args[13]),
+ (int)(*(int *)args[14]), *(int *)args[15],
+ (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+}
+
+typedef int (*closure_test_type1)(float, float, float, float, signed short,
+ float, float, int, double, int, int, float,
+ int, int, int, int);
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[17];
+ int res;
+
+ cl_arg_types[0] = &ffi_type_float;
+ cl_arg_types[1] = &ffi_type_float;
+ cl_arg_types[2] = &ffi_type_float;
+ cl_arg_types[3] = &ffi_type_float;
+ cl_arg_types[4] = &ffi_type_sshort;
+ cl_arg_types[5] = &ffi_type_float;
+ cl_arg_types[6] = &ffi_type_float;
+ cl_arg_types[7] = &ffi_type_sint;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_sint;
+ cl_arg_types[10] = &ffi_type_sint;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_sint;
+ cl_arg_types[13] = &ffi_type_sint;
+ cl_arg_types[14] = &ffi_type_sint;
+ cl_arg_types[15] = &ffi_type_sint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn1,
+ (void *) 3 /* userdata */, code) == FFI_OK);
+
+ res = (*((closure_test_type1)code))
+ (1.1, 2.2, 3.3, 4.4, 127, 5.5, 6.6, 8, 9, 10, 11, 12.0, 13,
+ 19, 21, 1);
+ /* { dg-output "1 2 3 4 127 5 6 8 9 10 11 12 13 19 21 1 3: 255" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 255" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/closure_fn2.c b/testsuite/libffi.closures/closure_fn2.c
new file mode 100644
index 00000000..08ff9d92
--- /dev/null
+++ b/testsuite/libffi.closures/closure_fn2.c
@@ -0,0 +1,81 @@
+/* Area: closure_call
+ Purpose: Check multiple values passing from different type.
+ Also, exceed the limit of gpr and fpr registers on PowerPC
+ Darwin.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void closure_test_fn2(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata)
+{
+ *(ffi_arg*)resp =
+ (int)*(double *)args[0] +(int)(*(double *)args[1]) +
+ (int)(*(double *)args[2]) + (int)*(double *)args[3] +
+ (int)(*(signed short *)args[4]) + (int)(*(double *)args[5]) +
+ (int)*(double *)args[6] + (int)(*(int *)args[7]) +
+ (int)(*(double *)args[8]) + (int)*(int *)args[9] +
+ (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(float *)args[13]) +
+ (int)(*(int *)args[14]) + *(int *)args[15] + (intptr_t)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(double *)args[0], (int)(*(double *)args[1]),
+ (int)(*(double *)args[2]), (int)*(double *)args[3],
+ (int)(*(signed short *)args[4]), (int)(*(double *)args[5]),
+ (int)*(double *)args[6], (int)(*(int *)args[7]),
+ (int)(*(double*)args[8]), (int)*(int *)args[9],
+ (int)(*(int *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(float *)args[13]),
+ (int)(*(int *)args[14]), *(int *)args[15], (int)(intptr_t)userdata,
+ (int)*(ffi_arg *)resp);
+}
+
+typedef int (*closure_test_type2)(double, double, double, double, signed short,
+ double, double, int, double, int, int, float,
+ int, float, int, int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[17];
+ int res;
+
+ cl_arg_types[0] = &ffi_type_double;
+ cl_arg_types[1] = &ffi_type_double;
+ cl_arg_types[2] = &ffi_type_double;
+ cl_arg_types[3] = &ffi_type_double;
+ cl_arg_types[4] = &ffi_type_sshort;
+ cl_arg_types[5] = &ffi_type_double;
+ cl_arg_types[6] = &ffi_type_double;
+ cl_arg_types[7] = &ffi_type_sint;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_sint;
+ cl_arg_types[10] = &ffi_type_sint;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_sint;
+ cl_arg_types[13] = &ffi_type_float;
+ cl_arg_types[14] = &ffi_type_sint;
+ cl_arg_types[15] = &ffi_type_sint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn2,
+ (void *) 3 /* userdata */, code) == FFI_OK);
+
+ res = (*((closure_test_type2)code))
+ (1, 2, 3, 4, 127, 5, 6, 8, 9, 10, 11, 12.0, 13,
+ 19.0, 21, 1);
+ /* { dg-output "1 2 3 4 127 5 6 8 9 10 11 12 13 19 21 1 3: 255" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 255" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/closure_fn3.c b/testsuite/libffi.closures/closure_fn3.c
new file mode 100644
index 00000000..9b54d805
--- /dev/null
+++ b/testsuite/libffi.closures/closure_fn3.c
@@ -0,0 +1,82 @@
+/* Area: closure_call
+ Purpose: Check multiple values passing from different type.
+ Also, exceed the limit of gpr and fpr registers on PowerPC
+ Darwin.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void closure_test_fn3(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata)
+ {
+ *(ffi_arg*)resp =
+ (int)*(float *)args[0] +(int)(*(float *)args[1]) +
+ (int)(*(float *)args[2]) + (int)*(float *)args[3] +
+ (int)(*(float *)args[4]) + (int)(*(float *)args[5]) +
+ (int)*(float *)args[6] + (int)(*(float *)args[7]) +
+ (int)(*(double *)args[8]) + (int)*(int *)args[9] +
+ (int)(*(float *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(float *)args[13]) +
+ (int)(*(float *)args[14]) + *(int *)args[15] + (intptr_t)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(float *)args[0], (int)(*(float *)args[1]),
+ (int)(*(float *)args[2]), (int)*(float *)args[3],
+ (int)(*(float *)args[4]), (int)(*(float *)args[5]),
+ (int)*(float *)args[6], (int)(*(float *)args[7]),
+ (int)(*(double *)args[8]), (int)*(int *)args[9],
+ (int)(*(float *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(float *)args[13]),
+ (int)(*(float *)args[14]), *(int *)args[15], (int)(intptr_t)userdata,
+ (int)*(ffi_arg *)resp);
+
+ }
+
+typedef int (*closure_test_type3)(float, float, float, float, float, float,
+ float, float, double, int, float, float, int,
+ float, float, int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[17];
+ int res;
+
+ cl_arg_types[0] = &ffi_type_float;
+ cl_arg_types[1] = &ffi_type_float;
+ cl_arg_types[2] = &ffi_type_float;
+ cl_arg_types[3] = &ffi_type_float;
+ cl_arg_types[4] = &ffi_type_float;
+ cl_arg_types[5] = &ffi_type_float;
+ cl_arg_types[6] = &ffi_type_float;
+ cl_arg_types[7] = &ffi_type_float;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_sint;
+ cl_arg_types[10] = &ffi_type_float;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_sint;
+ cl_arg_types[13] = &ffi_type_float;
+ cl_arg_types[14] = &ffi_type_float;
+ cl_arg_types[15] = &ffi_type_sint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn3,
+ (void *) 3 /* userdata */, code) == FFI_OK);
+
+ res = (*((closure_test_type3)code))
+ (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);
+ /* { dg-output "1 2 3 4 5 6 7 8 9 10 11 12 13 19 21 1 3: 135" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 135" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/closure_fn4.c b/testsuite/libffi.closures/closure_fn4.c
new file mode 100644
index 00000000..d4a1530b
--- /dev/null
+++ b/testsuite/libffi.closures/closure_fn4.c
@@ -0,0 +1,89 @@
+/* Area: closure_call
+ Purpose: Check multiple long long values passing.
+ Also, exceed the limit of gpr and fpr registers on PowerPC
+ Darwin.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20031026 */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+static void
+closure_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata)
+{
+ *(ffi_arg*)resp =
+ (int)*(unsigned long long *)args[0] + (int)*(unsigned long long *)args[1] +
+ (int)*(unsigned long long *)args[2] + (int)*(unsigned long long *)args[3] +
+ (int)*(unsigned long long *)args[4] + (int)*(unsigned long long *)args[5] +
+ (int)*(unsigned long long *)args[6] + (int)*(unsigned long long *)args[7] +
+ (int)*(unsigned long long *)args[8] + (int)*(unsigned long long *)args[9] +
+ (int)*(unsigned long long *)args[10] +
+ (int)*(unsigned long long *)args[11] +
+ (int)*(unsigned long long *)args[12] +
+ (int)*(unsigned long long *)args[13] +
+ (int)*(unsigned long long *)args[14] +
+ *(int *)args[15] + (intptr_t)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(unsigned long long *)args[0],
+ (int)*(unsigned long long *)args[1],
+ (int)*(unsigned long long *)args[2],
+ (int)*(unsigned long long *)args[3],
+ (int)*(unsigned long long *)args[4],
+ (int)*(unsigned long long *)args[5],
+ (int)*(unsigned long long *)args[6],
+ (int)*(unsigned long long *)args[7],
+ (int)*(unsigned long long *)args[8],
+ (int)*(unsigned long long *)args[9],
+ (int)*(unsigned long long *)args[10],
+ (int)*(unsigned long long *)args[11],
+ (int)*(unsigned long long *)args[12],
+ (int)*(unsigned long long *)args[13],
+ (int)*(unsigned long long *)args[14],
+ *(int *)args[15],
+ (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+
+}
+
+typedef int (*closure_test_type0)(unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[17];
+ int i, res;
+
+ for (i = 0; i < 15; i++) {
+ cl_arg_types[i] = &ffi_type_uint64;
+ }
+ cl_arg_types[15] = &ffi_type_sint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn0,
+ (void *) 3 /* userdata */, code) == FFI_OK);
+
+ res = (*((closure_test_type0)code))
+ (1LL, 2LL, 3LL, 4LL, 127LL, 429LL, 7LL, 8LL, 9LL, 10LL, 11LL, 12LL,
+ 13LL, 19LL, 21LL, 1);
+ /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 680" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/closure_fn5.c b/testsuite/libffi.closures/closure_fn5.c
new file mode 100644
index 00000000..99074426
--- /dev/null
+++ b/testsuite/libffi.closures/closure_fn5.c
@@ -0,0 +1,92 @@
+/* Area: closure_call
+ Purpose: Check multiple long long values passing.
+ Exceed the limit of gpr registers on PowerPC
+ Darwin.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20031026 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void
+closure_test_fn5(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata)
+{
+ *(ffi_arg*)resp =
+ (int)*(unsigned long long *)args[0] + (int)*(unsigned long long *)args[1] +
+ (int)*(unsigned long long *)args[2] + (int)*(unsigned long long *)args[3] +
+ (int)*(unsigned long long *)args[4] + (int)*(unsigned long long *)args[5] +
+ (int)*(unsigned long long *)args[6] + (int)*(unsigned long long *)args[7] +
+ (int)*(unsigned long long *)args[8] + (int)*(unsigned long long *)args[9] +
+ (int)*(int *)args[10] +
+ (int)*(unsigned long long *)args[11] +
+ (int)*(unsigned long long *)args[12] +
+ (int)*(unsigned long long *)args[13] +
+ (int)*(unsigned long long *)args[14] +
+ *(int *)args[15] + (intptr_t)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(unsigned long long *)args[0],
+ (int)*(unsigned long long *)args[1],
+ (int)*(unsigned long long *)args[2],
+ (int)*(unsigned long long *)args[3],
+ (int)*(unsigned long long *)args[4],
+ (int)*(unsigned long long *)args[5],
+ (int)*(unsigned long long *)args[6],
+ (int)*(unsigned long long *)args[7],
+ (int)*(unsigned long long *)args[8],
+ (int)*(unsigned long long *)args[9],
+ (int)*(int *)args[10],
+ (int)*(unsigned long long *)args[11],
+ (int)*(unsigned long long *)args[12],
+ (int)*(unsigned long long *)args[13],
+ (int)*(unsigned long long *)args[14],
+ *(int *)args[15],
+ (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+
+}
+
+typedef int (*closure_test_type0)(unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, unsigned long long,
+ int, unsigned long long,
+ unsigned long long, unsigned long long,
+ unsigned long long, int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[17];
+ int i, res;
+
+ for (i = 0; i < 10; i++) {
+ cl_arg_types[i] = &ffi_type_uint64;
+ }
+ cl_arg_types[10] = &ffi_type_sint;
+ for (i = 11; i < 15; i++) {
+ cl_arg_types[i] = &ffi_type_uint64;
+ }
+ cl_arg_types[15] = &ffi_type_sint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn5,
+ (void *) 3 /* userdata */, code) == FFI_OK);
+
+ res = (*((closure_test_type0)code))
+ (1LL, 2LL, 3LL, 4LL, 127LL, 429LL, 7LL, 8LL, 9LL, 10LL, 11, 12LL,
+ 13LL, 19LL, 21LL, 1);
+ /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 680" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/closure_fn6.c b/testsuite/libffi.closures/closure_fn6.c
new file mode 100644
index 00000000..73c54fd6
--- /dev/null
+++ b/testsuite/libffi.closures/closure_fn6.c
@@ -0,0 +1,90 @@
+/* Area: closure_call
+ Purpose: Check multiple values passing from different type.
+ Also, exceed the limit of gpr and fpr registers on PowerPC.
+ Limitations: none.
+ PR: PR23404
+ Originator: <andreast@gcc.gnu.org> 20050830 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void
+closure_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata)
+{
+ *(ffi_arg*)resp =
+ (int)*(unsigned long long *)args[0] +
+ (int)(*(unsigned long long *)args[1]) +
+ (int)(*(unsigned long long *)args[2]) +
+ (int)*(unsigned long long *)args[3] +
+ (int)(*(int *)args[4]) + (int)(*(double *)args[5]) +
+ (int)*(double *)args[6] + (int)(*(float *)args[7]) +
+ (int)(*(double *)args[8]) + (int)*(double *)args[9] +
+ (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(int *)args[13]) +
+ (int)(*(double *)args[14]) + (int)*(double *)args[15] +
+ (intptr_t)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(unsigned long long *)args[0],
+ (int)(*(unsigned long long *)args[1]),
+ (int)(*(unsigned long long *)args[2]),
+ (int)*(unsigned long long *)args[3],
+ (int)(*(int *)args[4]), (int)(*(double *)args[5]),
+ (int)*(double *)args[6], (int)(*(float *)args[7]),
+ (int)(*(double *)args[8]), (int)*(double *)args[9],
+ (int)(*(int *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(int *)args[13]),
+ (int)(*(double *)args[14]), (int)(*(double *)args[15]),
+ (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+
+}
+
+typedef int (*closure_test_type0)(unsigned long long,
+ unsigned long long,
+ unsigned long long,
+ unsigned long long,
+ int, double, double, float, double, double,
+ int, float, int, int, double, double);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[17];
+ int res;
+
+ cl_arg_types[0] = &ffi_type_uint64;
+ cl_arg_types[1] = &ffi_type_uint64;
+ cl_arg_types[2] = &ffi_type_uint64;
+ cl_arg_types[3] = &ffi_type_uint64;
+ cl_arg_types[4] = &ffi_type_sint;
+ cl_arg_types[5] = &ffi_type_double;
+ cl_arg_types[6] = &ffi_type_double;
+ cl_arg_types[7] = &ffi_type_float;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_double;
+ cl_arg_types[10] = &ffi_type_sint;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_sint;
+ cl_arg_types[13] = &ffi_type_sint;
+ cl_arg_types[14] = &ffi_type_double;
+ cl_arg_types[15] = &ffi_type_double;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn0,
+ (void *) 3 /* userdata */, code) == FFI_OK);
+
+ res = (*((closure_test_type0)code))
+ (1, 2, 3, 4, 127, 429., 7., 8., 9.5, 10., 11, 12., 13,
+ 19, 21., 1.);
+ /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 680" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/closure_loc_fn0.c b/testsuite/libffi.closures/closure_loc_fn0.c
new file mode 100644
index 00000000..b3afa0bb
--- /dev/null
+++ b/testsuite/libffi.closures/closure_loc_fn0.c
@@ -0,0 +1,95 @@
+/* Area: closure_call
+ Purpose: Check multiple values passing from different type.
+ Also, exceed the limit of gpr and fpr registers on PowerPC
+ Darwin.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+
+
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void
+closure_loc_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata)
+{
+ *(ffi_arg*)resp =
+ (int)*(unsigned long long *)args[0] + (int)(*(int *)args[1]) +
+ (int)(*(unsigned long long *)args[2]) + (int)*(int *)args[3] +
+ (int)(*(signed short *)args[4]) +
+ (int)(*(unsigned long long *)args[5]) +
+ (int)*(int *)args[6] + (int)(*(int *)args[7]) +
+ (int)(*(double *)args[8]) + (int)*(int *)args[9] +
+ (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(int *)args[13]) +
+ (int)(*(int *)args[14]) + *(int *)args[15] + (intptr_t)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(unsigned long long *)args[0], (int)(*(int *)args[1]),
+ (int)(*(unsigned long long *)args[2]),
+ (int)*(int *)args[3], (int)(*(signed short *)args[4]),
+ (int)(*(unsigned long long *)args[5]),
+ (int)*(int *)args[6], (int)(*(int *)args[7]),
+ (int)(*(double *)args[8]), (int)*(int *)args[9],
+ (int)(*(int *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(int *)args[13]),
+ (int)(*(int *)args[14]),*(int *)args[15],
+ (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+
+}
+
+typedef int (*closure_loc_test_type0)(unsigned long long, int, unsigned long long,
+ int, signed short, unsigned long long, int,
+ int, double, int, int, float, int, int,
+ int, int);
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_closure *pcl;
+ ffi_type * cl_arg_types[17];
+ int res;
+ void *codeloc;
+
+ cl_arg_types[0] = &ffi_type_uint64;
+ cl_arg_types[1] = &ffi_type_sint;
+ cl_arg_types[2] = &ffi_type_uint64;
+ cl_arg_types[3] = &ffi_type_sint;
+ cl_arg_types[4] = &ffi_type_sshort;
+ cl_arg_types[5] = &ffi_type_uint64;
+ cl_arg_types[6] = &ffi_type_sint;
+ cl_arg_types[7] = &ffi_type_sint;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_sint;
+ cl_arg_types[10] = &ffi_type_sint;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_sint;
+ cl_arg_types[13] = &ffi_type_sint;
+ cl_arg_types[14] = &ffi_type_sint;
+ cl_arg_types[15] = &ffi_type_sint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ pcl = ffi_closure_alloc(sizeof(ffi_closure), &codeloc);
+ CHECK(pcl != NULL);
+ CHECK(codeloc != NULL);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_loc_test_fn0,
+ (void *) 3 /* userdata */, codeloc) == FFI_OK);
+
+ CHECK(memcmp(pcl, codeloc, sizeof(*pcl)) == 0);
+
+ res = (*((closure_loc_test_type0)codeloc))
+ (1LL, 2, 3LL, 4, 127, 429LL, 7, 8, 9.5, 10, 11, 12, 13,
+ 19, 21, 1);
+ /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 680" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/closure_simple.c b/testsuite/libffi.closures/closure_simple.c
new file mode 100644
index 00000000..5a4e728d
--- /dev/null
+++ b/testsuite/libffi.closures/closure_simple.c
@@ -0,0 +1,55 @@
+/* Area: closure_call
+ Purpose: Check simple closure handling with all ABIs
+ Limitations: none.
+ PR: none.
+ Originator: <twalljava@dev.java.net> */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void
+closure_test(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata)
+{
+ *(ffi_arg*)resp =
+ (int)*(int *)args[0] + (int)(*(int *)args[1])
+ + (int)(*(int *)args[2]) + (int)(*(int *)args[3])
+ + (int)(intptr_t)userdata;
+
+ printf("%d %d %d %d: %d\n",
+ (int)*(int *)args[0], (int)(*(int *)args[1]),
+ (int)(*(int *)args[2]), (int)(*(int *)args[3]),
+ (int)*(ffi_arg *)resp);
+
+}
+
+typedef int (ABI_ATTR *closure_test_type0)(int, int, int, int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[17];
+ int res;
+
+ cl_arg_types[0] = &ffi_type_uint;
+ cl_arg_types[1] = &ffi_type_uint;
+ cl_arg_types[2] = &ffi_type_uint;
+ cl_arg_types[3] = &ffi_type_uint;
+ cl_arg_types[4] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, ABI_NUM, 4,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test,
+ (void *) 3 /* userdata */, code) == FFI_OK);
+
+ res = (*(closure_test_type0)code)(0, 1, 2, 3);
+ /* { dg-output "0 1 2 3: 9" } */
+
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 9" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_12byte.c b/testsuite/libffi.closures/cls_12byte.c
new file mode 100644
index 00000000..ea0825d1
--- /dev/null
+++ b/testsuite/libffi.closures/cls_12byte.c
@@ -0,0 +1,94 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_12byte {
+ int a;
+ int b;
+ int c;
+} cls_struct_12byte;
+
+cls_struct_12byte cls_struct_12byte_fn(struct cls_struct_12byte b1,
+ struct cls_struct_12byte b2)
+{
+ struct cls_struct_12byte result;
+
+ result.a = b1.a + b2.a;
+ result.b = b1.b + b2.b;
+ result.c = b1.c + b2.c;
+
+ printf("%d %d %d %d %d %d: %d %d %d\n", b1.a, b1.b, b1.c, b2.a, b2.b, b2.c,
+ result.a, result.b, result.c);
+
+ return result;
+}
+
+static void cls_struct_12byte_gn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args , void* userdata __UNUSED__)
+{
+ struct cls_struct_12byte b1, b2;
+
+ b1 = *(struct cls_struct_12byte*)(args[0]);
+ b2 = *(struct cls_struct_12byte*)(args[1]);
+
+ *(cls_struct_12byte*)resp = cls_struct_12byte_fn(b1, b2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_12byte h_dbl = { 7, 4, 9 };
+ struct cls_struct_12byte j_dbl = { 1, 5, 3 };
+ struct cls_struct_12byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_sint;
+ cls_struct_fields[1] = &ffi_type_sint;
+ cls_struct_fields[2] = &ffi_type_sint;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &h_dbl;
+ args_dbl[1] = &j_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_12byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "7 4 9 1 5 3: 8 9 12" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 8 9 12" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_12byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl.a = 0;
+ res_dbl.b = 0;
+ res_dbl.c = 0;
+
+ res_dbl = ((cls_struct_12byte(*)(cls_struct_12byte, cls_struct_12byte))(code))(h_dbl, j_dbl);
+ /* { dg-output "\n7 4 9 1 5 3: 8 9 12" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 8 9 12" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_16byte.c b/testsuite/libffi.closures/cls_16byte.c
new file mode 100644
index 00000000..89a08a2d
--- /dev/null
+++ b/testsuite/libffi.closures/cls_16byte.c
@@ -0,0 +1,95 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_16byte {
+ int a;
+ double b;
+ int c;
+} cls_struct_16byte;
+
+cls_struct_16byte cls_struct_16byte_fn(struct cls_struct_16byte b1,
+ struct cls_struct_16byte b2)
+{
+ struct cls_struct_16byte result;
+
+ result.a = b1.a + b2.a;
+ result.b = b1.b + b2.b;
+ result.c = b1.c + b2.c;
+
+ printf("%d %g %d %d %g %d: %d %g %d\n", b1.a, b1.b, b1.c, b2.a, b2.b, b2.c,
+ result.a, result.b, result.c);
+
+ return result;
+}
+
+static void cls_struct_16byte_gn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ struct cls_struct_16byte b1, b2;
+
+ b1 = *(struct cls_struct_16byte*)(args[0]);
+ b2 = *(struct cls_struct_16byte*)(args[1]);
+
+ *(cls_struct_16byte*)resp = cls_struct_16byte_fn(b1, b2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_16byte h_dbl = { 7, 8.0, 9 };
+ struct cls_struct_16byte j_dbl = { 1, 9.0, 3 };
+ struct cls_struct_16byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_sint;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_sint;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &h_dbl;
+ args_dbl[1] = &j_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_16byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "7 8 9 1 9 3: 8 17 12" } */
+ printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 8 17 12" } */
+
+ res_dbl.a = 0;
+ res_dbl.b = 0.0;
+ res_dbl.c = 0;
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_16byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_16byte(*)(cls_struct_16byte, cls_struct_16byte))(code))(h_dbl, j_dbl);
+ /* { dg-output "\n7 8 9 1 9 3: 8 17 12" } */
+ printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 8 17 12" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_18byte.c b/testsuite/libffi.closures/cls_18byte.c
new file mode 100644
index 00000000..9f75da80
--- /dev/null
+++ b/testsuite/libffi.closures/cls_18byte.c
@@ -0,0 +1,96 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Double alignment check on darwin.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030915 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_18byte {
+ double a;
+ unsigned char b;
+ unsigned char c;
+ double d;
+} cls_struct_18byte;
+
+cls_struct_18byte cls_struct_18byte_fn(struct cls_struct_18byte a1,
+ struct cls_struct_18byte a2)
+{
+ struct cls_struct_18byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+ result.d = a1.d + a2.d;
+
+
+ printf("%g %d %d %g %g %d %d %g: %g %d %d %g\n", a1.a, a1.b, a1.c, a1.d,
+ a2.a, a2.b, a2.c, a2.d,
+ result.a, result.b, result.c, result.d);
+ return result;
+}
+
+static void
+cls_struct_18byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_18byte a1, a2;
+
+ a1 = *(struct cls_struct_18byte*)(args[0]);
+ a2 = *(struct cls_struct_18byte*)(args[1]);
+
+ *(cls_struct_18byte*)resp = cls_struct_18byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[5];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[3];
+
+ struct cls_struct_18byte g_dbl = { 1.0, 127, 126, 3.0 };
+ struct cls_struct_18byte f_dbl = { 4.0, 125, 124, 5.0 };
+ struct cls_struct_18byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = &ffi_type_double;
+ cls_struct_fields[4] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_18byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 127 126 3 4 125 124 5: 5 252 250 8" } */
+ printf("res: %g %d %d %g\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 5 252 250 8" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_18byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_18byte(*)(cls_struct_18byte, cls_struct_18byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n1 127 126 3 4 125 124 5: 5 252 250 8" } */
+ printf("res: %g %d %d %g\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 5 252 250 8" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_19byte.c b/testsuite/libffi.closures/cls_19byte.c
new file mode 100644
index 00000000..278794b5
--- /dev/null
+++ b/testsuite/libffi.closures/cls_19byte.c
@@ -0,0 +1,102 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Double alignment check on darwin.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030915 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_19byte {
+ double a;
+ unsigned char b;
+ unsigned char c;
+ double d;
+ unsigned char e;
+} cls_struct_19byte;
+
+cls_struct_19byte cls_struct_19byte_fn(struct cls_struct_19byte a1,
+ struct cls_struct_19byte a2)
+{
+ struct cls_struct_19byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+ result.d = a1.d + a2.d;
+ result.e = a1.e + a2.e;
+
+
+ printf("%g %d %d %g %d %g %d %d %g %d: %g %d %d %g %d\n",
+ a1.a, a1.b, a1.c, a1.d, a1.e,
+ a2.a, a2.b, a2.c, a2.d, a2.e,
+ result.a, result.b, result.c, result.d, result.e);
+ return result;
+}
+
+static void
+cls_struct_19byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_19byte a1, a2;
+
+ a1 = *(struct cls_struct_19byte*)(args[0]);
+ a2 = *(struct cls_struct_19byte*)(args[1]);
+
+ *(cls_struct_19byte*)resp = cls_struct_19byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[6];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[3];
+
+ struct cls_struct_19byte g_dbl = { 1.0, 127, 126, 3.0, 120 };
+ struct cls_struct_19byte f_dbl = { 4.0, 125, 124, 5.0, 119 };
+ struct cls_struct_19byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = &ffi_type_double;
+ cls_struct_fields[4] = &ffi_type_uchar;
+ cls_struct_fields[5] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_19byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 127 126 3 120 4 125 124 5 119: 5 252 250 8 239" } */
+ printf("res: %g %d %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e);
+ /* { dg-output "\nres: 5 252 250 8 239" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_19byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_19byte(*)(cls_struct_19byte, cls_struct_19byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n1 127 126 3 120 4 125 124 5 119: 5 252 250 8 239" } */
+ printf("res: %g %d %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e);
+ /* { dg-output "\nres: 5 252 250 8 239" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_1_1byte.c b/testsuite/libffi.closures/cls_1_1byte.c
new file mode 100644
index 00000000..82492c02
--- /dev/null
+++ b/testsuite/libffi.closures/cls_1_1byte.c
@@ -0,0 +1,89 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Especially with small structures which may fit in one
+ register. Depending on the ABI.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030902 */
+
+
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_1_1byte {
+ unsigned char a;
+} cls_struct_1_1byte;
+
+cls_struct_1_1byte cls_struct_1_1byte_fn(struct cls_struct_1_1byte a1,
+ struct cls_struct_1_1byte a2)
+{
+ struct cls_struct_1_1byte result;
+
+ result.a = a1.a + a2.a;
+
+ printf("%d %d: %d\n", a1.a, a2.a, result.a);
+
+ return result;
+}
+
+static void
+cls_struct_1_1byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_1_1byte a1, a2;
+
+ a1 = *(struct cls_struct_1_1byte*)(args[0]);
+ a2 = *(struct cls_struct_1_1byte*)(args[1]);
+
+ *(cls_struct_1_1byte*)resp = cls_struct_1_1byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[2];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_1_1byte g_dbl = { 12 };
+ struct cls_struct_1_1byte f_dbl = { 178 };
+ struct cls_struct_1_1byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_1_1byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 178: 190" } */
+ printf("res: %d\n", res_dbl.a);
+ /* { dg-output "\nres: 190" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_1_1byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_1_1byte(*)(cls_struct_1_1byte, cls_struct_1_1byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 178: 190" } */
+ printf("res: %d\n", res_dbl.a);
+ /* { dg-output "\nres: 190" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_20byte.c b/testsuite/libffi.closures/cls_20byte.c
new file mode 100644
index 00000000..3f8bb28a
--- /dev/null
+++ b/testsuite/libffi.closures/cls_20byte.c
@@ -0,0 +1,91 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_20byte {
+ double a;
+ double b;
+ int c;
+} cls_struct_20byte;
+
+cls_struct_20byte cls_struct_20byte_fn(struct cls_struct_20byte a1,
+ struct cls_struct_20byte a2)
+{
+ struct cls_struct_20byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%g %g %d %g %g %d: %g %g %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c,
+ result.a, result.b, result.c);
+ return result;
+}
+
+static void
+cls_struct_20byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_20byte a1, a2;
+
+ a1 = *(struct cls_struct_20byte*)(args[0]);
+ a2 = *(struct cls_struct_20byte*)(args[1]);
+
+ *(cls_struct_20byte*)resp = cls_struct_20byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_20byte g_dbl = { 1.0, 2.0, 3 };
+ struct cls_struct_20byte f_dbl = { 4.0, 5.0, 7 };
+ struct cls_struct_20byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_sint;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_20byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 2 3 4 5 7: 5 7 10" } */
+ printf("res: %g %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 5 7 10" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_20byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_20byte(*)(cls_struct_20byte, cls_struct_20byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n1 2 3 4 5 7: 5 7 10" } */
+ printf("res: %g %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 5 7 10" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_20byte1.c b/testsuite/libffi.closures/cls_20byte1.c
new file mode 100644
index 00000000..65627273
--- /dev/null
+++ b/testsuite/libffi.closures/cls_20byte1.c
@@ -0,0 +1,93 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_20byte {
+ int a;
+ double b;
+ double c;
+} cls_struct_20byte;
+
+cls_struct_20byte cls_struct_20byte_fn(struct cls_struct_20byte a1,
+ struct cls_struct_20byte a2)
+{
+ struct cls_struct_20byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %g %g %d %g %g: %d %g %g\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c,
+ result.a, result.b, result.c);
+ return result;
+}
+
+static void
+cls_struct_20byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_20byte a1, a2;
+
+ a1 = *(struct cls_struct_20byte*)(args[0]);
+ a2 = *(struct cls_struct_20byte*)(args[1]);
+
+ *(cls_struct_20byte*)resp = cls_struct_20byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[3];
+
+ struct cls_struct_20byte g_dbl = { 1, 2.0, 3.0 };
+ struct cls_struct_20byte f_dbl = { 4, 5.0, 7.0 };
+ struct cls_struct_20byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_sint;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_double;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_20byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 2 3 4 5 7: 5 7 10" } */
+ printf("res: %d %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 5 7 10" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_20byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_20byte(*)(cls_struct_20byte, cls_struct_20byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n1 2 3 4 5 7: 5 7 10" } */
+ printf("res: %d %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 5 7 10" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_24byte.c b/testsuite/libffi.closures/cls_24byte.c
new file mode 100644
index 00000000..1d82f6e4
--- /dev/null
+++ b/testsuite/libffi.closures/cls_24byte.c
@@ -0,0 +1,113 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_24byte {
+ double a;
+ double b;
+ int c;
+ float d;
+} cls_struct_24byte;
+
+cls_struct_24byte cls_struct_24byte_fn(struct cls_struct_24byte b0,
+ struct cls_struct_24byte b1,
+ struct cls_struct_24byte b2,
+ struct cls_struct_24byte b3)
+{
+ struct cls_struct_24byte result;
+
+ result.a = b0.a + b1.a + b2.a + b3.a;
+ result.b = b0.b + b1.b + b2.b + b3.b;
+ result.c = b0.c + b1.c + b2.c + b3.c;
+ result.d = b0.d + b1.d + b2.d + b3.d;
+
+ printf("%g %g %d %g %g %g %d %g %g %g %d %g %g %g %d %g: %g %g %d %g\n",
+ b0.a, b0.b, b0.c, b0.d,
+ b1.a, b1.b, b1.c, b1.d,
+ b2.a, b2.b, b2.c, b2.d,
+ b3.a, b3.b, b3.c, b2.d,
+ result.a, result.b, result.c, result.d);
+
+ return result;
+}
+
+static void
+cls_struct_24byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_24byte b0, b1, b2, b3;
+
+ b0 = *(struct cls_struct_24byte*)(args[0]);
+ b1 = *(struct cls_struct_24byte*)(args[1]);
+ b2 = *(struct cls_struct_24byte*)(args[2]);
+ b3 = *(struct cls_struct_24byte*)(args[3]);
+
+ *(cls_struct_24byte*)resp = cls_struct_24byte_fn(b0, b1, b2, b3);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[5];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_24byte e_dbl = { 9.0, 2.0, 6, 5.0 };
+ struct cls_struct_24byte f_dbl = { 1.0, 2.0, 3, 7.0 };
+ struct cls_struct_24byte g_dbl = { 4.0, 5.0, 7, 9.0 };
+ struct cls_struct_24byte h_dbl = { 8.0, 6.0, 1, 4.0 };
+ struct cls_struct_24byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_sint;
+ cls_struct_fields[3] = &ffi_type_float;
+ cls_struct_fields[4] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = &cls_struct_type;
+ dbl_arg_types[3] = &cls_struct_type;
+ dbl_arg_types[4] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = &h_dbl;
+ args_dbl[4] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_24byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "9 2 6 5 1 2 3 7 4 5 7 9 8 6 1 9: 22 15 17 25" } */
+ printf("res: %g %g %d %g\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 22 15 17 25" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_24byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_24byte(*)(cls_struct_24byte,
+ cls_struct_24byte,
+ cls_struct_24byte,
+ cls_struct_24byte))
+ (code))(e_dbl, f_dbl, g_dbl, h_dbl);
+ /* { dg-output "\n9 2 6 5 1 2 3 7 4 5 7 9 8 6 1 9: 22 15 17 25" } */
+ printf("res: %g %g %d %g\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 22 15 17 25" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_2byte.c b/testsuite/libffi.closures/cls_2byte.c
new file mode 100644
index 00000000..81bb0a64
--- /dev/null
+++ b/testsuite/libffi.closures/cls_2byte.c
@@ -0,0 +1,90 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Especially with small structures which may fit in one
+ register. Depending on the ABI.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_2byte {
+ unsigned char a;
+ unsigned char b;
+} cls_struct_2byte;
+
+cls_struct_2byte cls_struct_2byte_fn(struct cls_struct_2byte a1,
+ struct cls_struct_2byte a2)
+{
+ struct cls_struct_2byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+
+ printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
+
+ return result;
+}
+
+static void
+cls_struct_2byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_2byte a1, a2;
+
+ a1 = *(struct cls_struct_2byte*)(args[0]);
+ a2 = *(struct cls_struct_2byte*)(args[1]);
+
+ *(cls_struct_2byte*)resp = cls_struct_2byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_2byte g_dbl = { 12, 127 };
+ struct cls_struct_2byte f_dbl = { 1, 13 };
+ struct cls_struct_2byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_2byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 127 1 13: 13 140" } */
+ printf("res: %d %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 13 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_2byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_2byte(*)(cls_struct_2byte, cls_struct_2byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 127 1 13: 13 140" } */
+ printf("res: %d %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 13 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_3_1byte.c b/testsuite/libffi.closures/cls_3_1byte.c
new file mode 100644
index 00000000..b7827466
--- /dev/null
+++ b/testsuite/libffi.closures/cls_3_1byte.c
@@ -0,0 +1,95 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Especially with small structures which may fit in one
+ register. Depending on the ABI.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030902 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_3_1byte {
+ unsigned char a;
+ unsigned char b;
+ unsigned char c;
+} cls_struct_3_1byte;
+
+cls_struct_3_1byte cls_struct_3_1byte_fn(struct cls_struct_3_1byte a1,
+ struct cls_struct_3_1byte a2)
+{
+ struct cls_struct_3_1byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c,
+ a2.a, a2.b, a2.c,
+ result.a, result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_3_1byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_3_1byte a1, a2;
+
+ a1 = *(struct cls_struct_3_1byte*)(args[0]);
+ a2 = *(struct cls_struct_3_1byte*)(args[1]);
+
+ *(cls_struct_3_1byte*)resp = cls_struct_3_1byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_3_1byte g_dbl = { 12, 13, 14 };
+ struct cls_struct_3_1byte f_dbl = { 178, 179, 180 };
+ struct cls_struct_3_1byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_3_1byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 13 14 178 179 180: 190 192 194" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 190 192 194" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3_1byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_3_1byte(*)(cls_struct_3_1byte, cls_struct_3_1byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 13 14 178 179 180: 190 192 194" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 190 192 194" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_3byte1.c b/testsuite/libffi.closures/cls_3byte1.c
new file mode 100644
index 00000000..a02c463a
--- /dev/null
+++ b/testsuite/libffi.closures/cls_3byte1.c
@@ -0,0 +1,90 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Especially with small structures which may fit in one
+ register. Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_3byte {
+ unsigned short a;
+ unsigned char b;
+} cls_struct_3byte;
+
+cls_struct_3byte cls_struct_3byte_fn(struct cls_struct_3byte a1,
+ struct cls_struct_3byte a2)
+{
+ struct cls_struct_3byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+
+ printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
+
+ return result;
+}
+
+static void
+cls_struct_3byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_3byte a1, a2;
+
+ a1 = *(struct cls_struct_3byte*)(args[0]);
+ a2 = *(struct cls_struct_3byte*)(args[1]);
+
+ *(cls_struct_3byte*)resp = cls_struct_3byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_3byte g_dbl = { 12, 119 };
+ struct cls_struct_3byte f_dbl = { 1, 15 };
+ struct cls_struct_3byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_ushort;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_3byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 119 1 15: 13 134" } */
+ printf("res: %d %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 13 134" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_3byte(*)(cls_struct_3byte, cls_struct_3byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 119 1 15: 13 134" } */
+ printf("res: %d %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 13 134" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_3byte2.c b/testsuite/libffi.closures/cls_3byte2.c
new file mode 100644
index 00000000..c7251cea
--- /dev/null
+++ b/testsuite/libffi.closures/cls_3byte2.c
@@ -0,0 +1,90 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Especially with small structures which may fit in one
+ register. Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_3byte_1 {
+ unsigned char a;
+ unsigned short b;
+} cls_struct_3byte_1;
+
+cls_struct_3byte_1 cls_struct_3byte_fn1(struct cls_struct_3byte_1 a1,
+ struct cls_struct_3byte_1 a2)
+{
+ struct cls_struct_3byte_1 result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+
+ printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
+
+ return result;
+}
+
+static void
+cls_struct_3byte_gn1(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_3byte_1 a1, a2;
+
+ a1 = *(struct cls_struct_3byte_1*)(args[0]);
+ a2 = *(struct cls_struct_3byte_1*)(args[1]);
+
+ *(cls_struct_3byte_1*)resp = cls_struct_3byte_fn1(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_3byte_1 g_dbl = { 15, 125 };
+ struct cls_struct_3byte_1 f_dbl = { 9, 19 };
+ struct cls_struct_3byte_1 res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_ushort;
+ cls_struct_fields[2] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_3byte_fn1), &res_dbl, args_dbl);
+ /* { dg-output "15 125 9 19: 24 144" } */
+ printf("res: %d %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 24 144" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3byte_gn1, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_3byte_1(*)(cls_struct_3byte_1, cls_struct_3byte_1))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n15 125 9 19: 24 144" } */
+ printf("res: %d %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 24 144" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_3float.c b/testsuite/libffi.closures/cls_3float.c
new file mode 100644
index 00000000..48888f84
--- /dev/null
+++ b/testsuite/libffi.closures/cls_3float.c
@@ -0,0 +1,95 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations:>none.
+ PR: none.
+ Originator: <compnerd@compnerd.org> 20171026 */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+typedef struct cls_struct_3float {
+ float f;
+ float g;
+ float h;
+} cls_struct_3float;
+
+cls_struct_3float cls_struct_3float_fn(struct cls_struct_3float a1,
+ struct cls_struct_3float a2)
+{
+ struct cls_struct_3float result;
+
+ result.f = a1.f + a2.f;
+ result.g = a1.g + a2.g;
+ result.h = a1.h + a2.h;
+
+ printf("%g %g %g %g %g %g: %g %g %g\n", a1.f, a1.g, a1.h,
+ a2.f, a2.g, a2.h, result.f, result.g, result.h);
+
+ return result;
+}
+
+static void
+cls_struct_3float_gn(ffi_cif *cif __UNUSED__, void* resp, void **args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_3float a1, a2;
+
+ a1 = *(struct cls_struct_3float*)(args[0]);
+ a2 = *(struct cls_struct_3float*)(args[1]);
+
+ *(cls_struct_3float*)resp = cls_struct_3float_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void *args_dbl[3];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[3];
+
+ struct cls_struct_3float g_dbl = { 1.0f, 2.0f, 3.0f };
+ struct cls_struct_3float f_dbl = { 1.0f, 2.0f, 3.0f };
+ struct cls_struct_3float res_dbl;
+
+ cls_struct_fields[0] = &ffi_type_float;
+ cls_struct_fields[1] = &ffi_type_float;
+ cls_struct_fields[2] = &ffi_type_float;
+ cls_struct_fields[3] = NULL;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_3float_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 2 3 1 2 3: 2 4 6" } */
+ printf("res: %g %g %g\n", res_dbl.f, res_dbl.g, res_dbl.h);
+ /* { dg-output "\nres: 2 4 6" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3float_gn, NULL, code) ==
+ FFI_OK);
+
+ res_dbl = ((cls_struct_3float(*)(cls_struct_3float,
+ cls_struct_3float))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n1 2 3 1 2 3: 2 4 6" } */
+ printf("res: %g %g %g\n", res_dbl.f, res_dbl.g, res_dbl.h);
+ /* { dg-output "\nres: 2 4 6" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_4_1byte.c b/testsuite/libffi.closures/cls_4_1byte.c
new file mode 100644
index 00000000..2d6d8b62
--- /dev/null
+++ b/testsuite/libffi.closures/cls_4_1byte.c
@@ -0,0 +1,98 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Especially with small structures which may fit in one
+ register. Depending on the ABI.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030902 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_4_1byte {
+ unsigned char a;
+ unsigned char b;
+ unsigned char c;
+ unsigned char d;
+} cls_struct_4_1byte;
+
+cls_struct_4_1byte cls_struct_4_1byte_fn(struct cls_struct_4_1byte a1,
+ struct cls_struct_4_1byte a2)
+{
+ struct cls_struct_4_1byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+ result.d = a1.d + a2.d;
+
+ printf("%d %d %d %d %d %d %d %d: %d %d %d %d\n", a1.a, a1.b, a1.c, a1.d,
+ a2.a, a2.b, a2.c, a2.d,
+ result.a, result.b, result.c, result.d);
+
+ return result;
+}
+
+static void
+cls_struct_4_1byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_4_1byte a1, a2;
+
+ a1 = *(struct cls_struct_4_1byte*)(args[0]);
+ a2 = *(struct cls_struct_4_1byte*)(args[1]);
+
+ *(cls_struct_4_1byte*)resp = cls_struct_4_1byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[5];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_4_1byte g_dbl = { 12, 13, 14, 15 };
+ struct cls_struct_4_1byte f_dbl = { 178, 179, 180, 181 };
+ struct cls_struct_4_1byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = &ffi_type_uchar;
+ cls_struct_fields[4] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_4_1byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 13 14 15 178 179 180 181: 190 192 194 196" } */
+ printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 190 192 194 196" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_4_1byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_4_1byte(*)(cls_struct_4_1byte, cls_struct_4_1byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 13 14 15 178 179 180 181: 190 192 194 196" } */
+ printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 190 192 194 196" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_4byte.c b/testsuite/libffi.closures/cls_4byte.c
new file mode 100644
index 00000000..4ac37877
--- /dev/null
+++ b/testsuite/libffi.closures/cls_4byte.c
@@ -0,0 +1,90 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+typedef struct cls_struct_4byte {
+ unsigned short a;
+ unsigned short b;
+} cls_struct_4byte;
+
+cls_struct_4byte cls_struct_4byte_fn(struct cls_struct_4byte a1,
+ struct cls_struct_4byte a2)
+{
+ struct cls_struct_4byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+
+ printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
+
+ return result;
+}
+
+static void
+cls_struct_4byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_4byte a1, a2;
+
+ a1 = *(struct cls_struct_4byte*)(args[0]);
+ a2 = *(struct cls_struct_4byte*)(args[1]);
+
+ *(cls_struct_4byte*)resp = cls_struct_4byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_4byte g_dbl = { 127, 120 };
+ struct cls_struct_4byte f_dbl = { 12, 128 };
+ struct cls_struct_4byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_ushort;
+ cls_struct_fields[1] = &ffi_type_ushort;
+ cls_struct_fields[2] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_4byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "127 120 12 128: 139 248" } */
+ printf("res: %d %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 139 248" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_4byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_4byte(*)(cls_struct_4byte, cls_struct_4byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n127 120 12 128: 139 248" } */
+ printf("res: %d %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 139 248" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_5_1_byte.c b/testsuite/libffi.closures/cls_5_1_byte.c
new file mode 100644
index 00000000..ad9d51c2
--- /dev/null
+++ b/testsuite/libffi.closures/cls_5_1_byte.c
@@ -0,0 +1,109 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20050708 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_5byte {
+ unsigned char a;
+ unsigned char b;
+ unsigned char c;
+ unsigned char d;
+ unsigned char e;
+} cls_struct_5byte;
+
+cls_struct_5byte cls_struct_5byte_fn(struct cls_struct_5byte a1,
+ struct cls_struct_5byte a2)
+{
+ struct cls_struct_5byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+ result.d = a1.d + a2.d;
+ result.e = a1.e + a2.e;
+
+ printf("%d %d %d %d %d %d %d %d %d %d: %d %d %d %d %d\n",
+ a1.a, a1.b, a1.c, a1.d, a1.e,
+ a2.a, a2.b, a2.c, a2.d, a2.e,
+ result.a, result.b, result.c, result.d, result.e);
+
+ return result;
+}
+
+static void
+cls_struct_5byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_5byte a1, a2;
+
+ a1 = *(struct cls_struct_5byte*)(args[0]);
+ a2 = *(struct cls_struct_5byte*)(args[1]);
+
+ *(cls_struct_5byte*)resp = cls_struct_5byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[6];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_5byte g_dbl = { 127, 120, 1, 3, 4 };
+ struct cls_struct_5byte f_dbl = { 12, 128, 9, 3, 4 };
+ struct cls_struct_5byte res_dbl = { 0, 0, 0, 0, 0 };
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = &ffi_type_uchar;
+ cls_struct_fields[4] = &ffi_type_uchar;
+ cls_struct_fields[5] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_5byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "127 120 1 3 4 12 128 9 3 4: 139 248 10 6 8" } */
+ printf("res: %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e);
+ /* { dg-output "\nres: 139 248 10 6 8" } */
+
+ res_dbl.a = 0;
+ res_dbl.b = 0;
+ res_dbl.c = 0;
+ res_dbl.d = 0;
+ res_dbl.e = 0;
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_5byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_5byte(*)(cls_struct_5byte, cls_struct_5byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n127 120 1 3 4 12 128 9 3 4: 139 248 10 6 8" } */
+ printf("res: %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e);
+ /* { dg-output "\nres: 139 248 10 6 8" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_5byte.c b/testsuite/libffi.closures/cls_5byte.c
new file mode 100644
index 00000000..4e0c0003
--- /dev/null
+++ b/testsuite/libffi.closures/cls_5byte.c
@@ -0,0 +1,98 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_5byte {
+ unsigned short a;
+ unsigned short b;
+ unsigned char c;
+} cls_struct_5byte;
+
+cls_struct_5byte cls_struct_5byte_fn(struct cls_struct_5byte a1,
+ struct cls_struct_5byte a2)
+{
+ struct cls_struct_5byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c,
+ a2.a, a2.b, a2.c,
+ result.a, result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_5byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_5byte a1, a2;
+
+ a1 = *(struct cls_struct_5byte*)(args[0]);
+ a2 = *(struct cls_struct_5byte*)(args[1]);
+
+ *(cls_struct_5byte*)resp = cls_struct_5byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_5byte g_dbl = { 127, 120, 1 };
+ struct cls_struct_5byte f_dbl = { 12, 128, 9 };
+ struct cls_struct_5byte res_dbl = { 0, 0, 0 };
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_ushort;
+ cls_struct_fields[1] = &ffi_type_ushort;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_5byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "127 120 1 12 128 9: 139 248 10" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 139 248 10" } */
+
+ res_dbl.a = 0;
+ res_dbl.b = 0;
+ res_dbl.c = 0;
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_5byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_5byte(*)(cls_struct_5byte, cls_struct_5byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n127 120 1 12 128 9: 139 248 10" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 139 248 10" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_64byte.c b/testsuite/libffi.closures/cls_64byte.c
new file mode 100644
index 00000000..a55edc2c
--- /dev/null
+++ b/testsuite/libffi.closures/cls_64byte.c
@@ -0,0 +1,124 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check bigger struct which overlaps
+ the gp and fp register count on Darwin/AIX/ppc64.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_64byte {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ double g;
+ double h;
+} cls_struct_64byte;
+
+cls_struct_64byte cls_struct_64byte_fn(struct cls_struct_64byte b0,
+ struct cls_struct_64byte b1,
+ struct cls_struct_64byte b2,
+ struct cls_struct_64byte b3)
+{
+ struct cls_struct_64byte result;
+
+ result.a = b0.a + b1.a + b2.a + b3.a;
+ result.b = b0.b + b1.b + b2.b + b3.b;
+ result.c = b0.c + b1.c + b2.c + b3.c;
+ result.d = b0.d + b1.d + b2.d + b3.d;
+ result.e = b0.e + b1.e + b2.e + b3.e;
+ result.f = b0.f + b1.f + b2.f + b3.f;
+ result.g = b0.g + b1.g + b2.g + b3.g;
+ result.h = b0.h + b1.h + b2.h + b3.h;
+
+ printf("%g %g %g %g %g %g %g %g\n", result.a, result.b, result.c,
+ result.d, result.e, result.f, result.g, result.h);
+
+ return result;
+}
+
+static void
+cls_struct_64byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_64byte b0, b1, b2, b3;
+
+ b0 = *(struct cls_struct_64byte*)(args[0]);
+ b1 = *(struct cls_struct_64byte*)(args[1]);
+ b2 = *(struct cls_struct_64byte*)(args[2]);
+ b3 = *(struct cls_struct_64byte*)(args[3]);
+
+ *(cls_struct_64byte*)resp = cls_struct_64byte_fn(b0, b1, b2, b3);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[9];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_64byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0 };
+ struct cls_struct_64byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0 };
+ struct cls_struct_64byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0 };
+ struct cls_struct_64byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0 };
+ struct cls_struct_64byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_double;
+ cls_struct_fields[3] = &ffi_type_double;
+ cls_struct_fields[4] = &ffi_type_double;
+ cls_struct_fields[5] = &ffi_type_double;
+ cls_struct_fields[6] = &ffi_type_double;
+ cls_struct_fields[7] = &ffi_type_double;
+ cls_struct_fields[8] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = &cls_struct_type;
+ dbl_arg_types[3] = &cls_struct_type;
+ dbl_arg_types[4] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = &h_dbl;
+ args_dbl[4] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_64byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "22 15 17 25 6 13 19 18" } */
+ printf("res: %g %g %g %g %g %g %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_64byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_64byte(*)(cls_struct_64byte,
+ cls_struct_64byte,
+ cls_struct_64byte,
+ cls_struct_64byte))
+ (code))(e_dbl, f_dbl, g_dbl, h_dbl);
+ /* { dg-output "\n22 15 17 25 6 13 19 18" } */
+ printf("res: %g %g %g %g %g %g %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_6_1_byte.c b/testsuite/libffi.closures/cls_6_1_byte.c
new file mode 100644
index 00000000..b4dcdba4
--- /dev/null
+++ b/testsuite/libffi.closures/cls_6_1_byte.c
@@ -0,0 +1,113 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20050708 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_6byte {
+ unsigned char a;
+ unsigned char b;
+ unsigned char c;
+ unsigned char d;
+ unsigned char e;
+ unsigned char f;
+} cls_struct_6byte;
+
+cls_struct_6byte cls_struct_6byte_fn(struct cls_struct_6byte a1,
+ struct cls_struct_6byte a2)
+{
+ struct cls_struct_6byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+ result.d = a1.d + a2.d;
+ result.e = a1.e + a2.e;
+ result.f = a1.f + a2.f;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d: %d %d %d %d %d %d\n",
+ a1.a, a1.b, a1.c, a1.d, a1.e, a1.f,
+ a2.a, a2.b, a2.c, a2.d, a2.e, a2.f,
+ result.a, result.b, result.c, result.d, result.e, result.f);
+
+ return result;
+}
+
+static void
+cls_struct_6byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_6byte a1, a2;
+
+ a1 = *(struct cls_struct_6byte*)(args[0]);
+ a2 = *(struct cls_struct_6byte*)(args[1]);
+
+ *(cls_struct_6byte*)resp = cls_struct_6byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[7];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_6byte g_dbl = { 127, 120, 1, 3, 4, 5 };
+ struct cls_struct_6byte f_dbl = { 12, 128, 9, 3, 4, 5 };
+ struct cls_struct_6byte res_dbl = { 0, 0, 0, 0, 0, 0 };
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = &ffi_type_uchar;
+ cls_struct_fields[4] = &ffi_type_uchar;
+ cls_struct_fields[5] = &ffi_type_uchar;
+ cls_struct_fields[6] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_6byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "127 120 1 3 4 5 12 128 9 3 4 5: 139 248 10 6 8 10" } */
+ printf("res: %d %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f);
+ /* { dg-output "\nres: 139 248 10 6 8 10" } */
+
+ res_dbl.a = 0;
+ res_dbl.b = 0;
+ res_dbl.c = 0;
+ res_dbl.d = 0;
+ res_dbl.e = 0;
+ res_dbl.f = 0;
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_6byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_6byte(*)(cls_struct_6byte, cls_struct_6byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n127 120 1 3 4 5 12 128 9 3 4 5: 139 248 10 6 8 10" } */
+ printf("res: %d %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f);
+ /* { dg-output "\nres: 139 248 10 6 8 10" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_6byte.c b/testsuite/libffi.closures/cls_6byte.c
new file mode 100644
index 00000000..74067801
--- /dev/null
+++ b/testsuite/libffi.closures/cls_6byte.c
@@ -0,0 +1,99 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_6byte {
+ unsigned short a;
+ unsigned short b;
+ unsigned char c;
+ unsigned char d;
+} cls_struct_6byte;
+
+cls_struct_6byte cls_struct_6byte_fn(struct cls_struct_6byte a1,
+ struct cls_struct_6byte a2)
+{
+ struct cls_struct_6byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+ result.d = a1.d + a2.d;
+
+ printf("%d %d %d %d %d %d %d %d: %d %d %d %d\n", a1.a, a1.b, a1.c, a1.d,
+ a2.a, a2.b, a2.c, a2.d,
+ result.a, result.b, result.c, result.d);
+
+ return result;
+}
+
+static void
+cls_struct_6byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_6byte a1, a2;
+
+ a1 = *(struct cls_struct_6byte*)(args[0]);
+ a2 = *(struct cls_struct_6byte*)(args[1]);
+
+ *(cls_struct_6byte*)resp = cls_struct_6byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[5];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_6byte g_dbl = { 127, 120, 1, 128 };
+ struct cls_struct_6byte f_dbl = { 12, 128, 9, 127 };
+ struct cls_struct_6byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_ushort;
+ cls_struct_fields[1] = &ffi_type_ushort;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = &ffi_type_uchar;
+ cls_struct_fields[4] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_6byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "127 120 1 128 12 128 9 127: 139 248 10 255" } */
+ printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 139 248 10 255" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_6byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_6byte(*)(cls_struct_6byte, cls_struct_6byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n127 120 1 128 12 128 9 127: 139 248 10 255" } */
+ printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 139 248 10 255" } */
+
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_7_1_byte.c b/testsuite/libffi.closures/cls_7_1_byte.c
new file mode 100644
index 00000000..14a7e96f
--- /dev/null
+++ b/testsuite/libffi.closures/cls_7_1_byte.c
@@ -0,0 +1,117 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20050708 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_7byte {
+ unsigned char a;
+ unsigned char b;
+ unsigned char c;
+ unsigned char d;
+ unsigned char e;
+ unsigned char f;
+ unsigned char g;
+} cls_struct_7byte;
+
+cls_struct_7byte cls_struct_7byte_fn(struct cls_struct_7byte a1,
+ struct cls_struct_7byte a2)
+{
+ struct cls_struct_7byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+ result.d = a1.d + a2.d;
+ result.e = a1.e + a2.e;
+ result.f = a1.f + a2.f;
+ result.g = a1.g + a2.g;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d %d %d %d %d %d %d\n",
+ a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g,
+ a2.a, a2.b, a2.c, a2.d, a2.e, a2.f, a2.g,
+ result.a, result.b, result.c, result.d, result.e, result.f, result.g);
+
+ return result;
+}
+
+static void
+cls_struct_7byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_7byte a1, a2;
+
+ a1 = *(struct cls_struct_7byte*)(args[0]);
+ a2 = *(struct cls_struct_7byte*)(args[1]);
+
+ *(cls_struct_7byte*)resp = cls_struct_7byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[8];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_7byte g_dbl = { 127, 120, 1, 3, 4, 5, 6 };
+ struct cls_struct_7byte f_dbl = { 12, 128, 9, 3, 4, 5, 6 };
+ struct cls_struct_7byte res_dbl = { 0, 0, 0, 0, 0, 0, 0 };
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = &ffi_type_uchar;
+ cls_struct_fields[4] = &ffi_type_uchar;
+ cls_struct_fields[5] = &ffi_type_uchar;
+ cls_struct_fields[6] = &ffi_type_uchar;
+ cls_struct_fields[7] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_7byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "127 120 1 3 4 5 6 12 128 9 3 4 5 6: 139 248 10 6 8 10 12" } */
+ printf("res: %d %d %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g);
+ /* { dg-output "\nres: 139 248 10 6 8 10 12" } */
+
+ res_dbl.a = 0;
+ res_dbl.b = 0;
+ res_dbl.c = 0;
+ res_dbl.d = 0;
+ res_dbl.e = 0;
+ res_dbl.f = 0;
+ res_dbl.g = 0;
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_7byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_7byte(*)(cls_struct_7byte, cls_struct_7byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n127 120 1 3 4 5 6 12 128 9 3 4 5 6: 139 248 10 6 8 10 12" } */
+ printf("res: %d %d %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g);
+ /* { dg-output "\nres: 139 248 10 6 8 10 12" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_7byte.c b/testsuite/libffi.closures/cls_7byte.c
new file mode 100644
index 00000000..1645cc63
--- /dev/null
+++ b/testsuite/libffi.closures/cls_7byte.c
@@ -0,0 +1,97 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_7byte {
+ unsigned short a;
+ unsigned short b;
+ unsigned char c;
+ unsigned short d;
+} cls_struct_7byte;
+
+cls_struct_7byte cls_struct_7byte_fn(struct cls_struct_7byte a1,
+ struct cls_struct_7byte a2)
+{
+ struct cls_struct_7byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+ result.d = a1.d + a2.d;
+
+ printf("%d %d %d %d %d %d %d %d: %d %d %d %d\n", a1.a, a1.b, a1.c, a1.d,
+ a2.a, a2.b, a2.c, a2.d,
+ result.a, result.b, result.c, result.d);
+
+ return result;
+}
+
+static void
+cls_struct_7byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_7byte a1, a2;
+
+ a1 = *(struct cls_struct_7byte*)(args[0]);
+ a2 = *(struct cls_struct_7byte*)(args[1]);
+
+ *(cls_struct_7byte*)resp = cls_struct_7byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[5];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_7byte g_dbl = { 127, 120, 1, 254 };
+ struct cls_struct_7byte f_dbl = { 12, 128, 9, 255 };
+ struct cls_struct_7byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_ushort;
+ cls_struct_fields[1] = &ffi_type_ushort;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = &ffi_type_ushort;
+ cls_struct_fields[4] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_7byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "127 120 1 254 12 128 9 255: 139 248 10 509" } */
+ printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 139 248 10 509" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_7byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_7byte(*)(cls_struct_7byte, cls_struct_7byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n127 120 1 254 12 128 9 255: 139 248 10 509" } */
+ printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d);
+ /* { dg-output "\nres: 139 248 10 509" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_8byte.c b/testsuite/libffi.closures/cls_8byte.c
new file mode 100644
index 00000000..f6c1ea57
--- /dev/null
+++ b/testsuite/libffi.closures/cls_8byte.c
@@ -0,0 +1,88 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Check overlapping.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_8byte {
+ int a;
+ float b;
+} cls_struct_8byte;
+
+cls_struct_8byte cls_struct_8byte_fn(struct cls_struct_8byte a1,
+ struct cls_struct_8byte a2)
+{
+ struct cls_struct_8byte result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+
+ printf("%d %g %d %g: %d %g\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
+
+ return result;
+}
+
+static void
+cls_struct_8byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_8byte a1, a2;
+
+ a1 = *(struct cls_struct_8byte*)(args[0]);
+ a2 = *(struct cls_struct_8byte*)(args[1]);
+
+ *(cls_struct_8byte*)resp = cls_struct_8byte_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_8byte g_dbl = { 1, 2.0 };
+ struct cls_struct_8byte f_dbl = { 4, 5.0 };
+ struct cls_struct_8byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_sint;
+ cls_struct_fields[1] = &ffi_type_float;
+ cls_struct_fields[2] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_8byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 2 4 5: 5 7" } */
+ printf("res: %d %g\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 5 7" } */
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_8byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_8byte(*)(cls_struct_8byte, cls_struct_8byte))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n1 2 4 5: 5 7" } */
+ printf("res: %d %g\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 5 7" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_9byte1.c b/testsuite/libffi.closures/cls_9byte1.c
new file mode 100644
index 00000000..0b857222
--- /dev/null
+++ b/testsuite/libffi.closures/cls_9byte1.c
@@ -0,0 +1,90 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Darwin/AIX do double-word
+ alignment of the struct if the first element is a double.
+ Check that it does not here.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030914 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_9byte {
+ int a;
+ double b;
+} cls_struct_9byte;
+
+cls_struct_9byte cls_struct_9byte_fn(struct cls_struct_9byte b1,
+ struct cls_struct_9byte b2)
+{
+ struct cls_struct_9byte result;
+
+ result.a = b1.a + b2.a;
+ result.b = b1.b + b2.b;
+
+ printf("%d %g %d %g: %d %g\n", b1.a, b1.b, b2.a, b2.b,
+ result.a, result.b);
+
+ return result;
+}
+
+static void cls_struct_9byte_gn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ struct cls_struct_9byte b1, b2;
+
+ b1 = *(struct cls_struct_9byte*)(args[0]);
+ b2 = *(struct cls_struct_9byte*)(args[1]);
+
+ *(cls_struct_9byte*)resp = cls_struct_9byte_fn(b1, b2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[3];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[3];
+
+ struct cls_struct_9byte h_dbl = { 7, 8.0};
+ struct cls_struct_9byte j_dbl = { 1, 9.0};
+ struct cls_struct_9byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_sint;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &h_dbl;
+ args_dbl[1] = &j_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_9byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "7 8 1 9: 8 17" } */
+ printf("res: %d %g\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 8 17" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_9byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_9byte(*)(cls_struct_9byte, cls_struct_9byte))(code))(h_dbl, j_dbl);
+ /* { dg-output "\n7 8 1 9: 8 17" } */
+ printf("res: %d %g\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 8 17" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_9byte2.c b/testsuite/libffi.closures/cls_9byte2.c
new file mode 100644
index 00000000..edf991de
--- /dev/null
+++ b/testsuite/libffi.closures/cls_9byte2.c
@@ -0,0 +1,91 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Depending on the ABI. Darwin/AIX do double-word
+ alignment of the struct if the first element is a double.
+ Check that it does here.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030914 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_9byte {
+ double a;
+ int b;
+} cls_struct_9byte;
+
+cls_struct_9byte cls_struct_9byte_fn(struct cls_struct_9byte b1,
+ struct cls_struct_9byte b2)
+{
+ struct cls_struct_9byte result;
+
+ result.a = b1.a + b2.a;
+ result.b = b1.b + b2.b;
+
+ printf("%g %d %g %d: %g %d\n", b1.a, b1.b, b2.a, b2.b,
+ result.a, result.b);
+
+ return result;
+}
+
+static void cls_struct_9byte_gn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ struct cls_struct_9byte b1, b2;
+
+ b1 = *(struct cls_struct_9byte*)(args[0]);
+ b2 = *(struct cls_struct_9byte*)(args[1]);
+
+ *(cls_struct_9byte*)resp = cls_struct_9byte_fn(b1, b2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[3];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[3];
+
+ struct cls_struct_9byte h_dbl = { 7.0, 8};
+ struct cls_struct_9byte j_dbl = { 1.0, 9};
+ struct cls_struct_9byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_sint;
+ cls_struct_fields[2] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &h_dbl;
+ args_dbl[1] = &j_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_9byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "7 8 1 9: 8 17" } */
+ printf("res: %g %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 8 17" } */
+
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_9byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_9byte(*)(cls_struct_9byte, cls_struct_9byte))(code))(h_dbl, j_dbl);
+ /* { dg-output "\n7 8 1 9: 8 17" } */
+ printf("res: %g %d\n", res_dbl.a, res_dbl.b);
+ /* { dg-output "\nres: 8 17" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_double.c b/testsuite/libffi.closures/cls_align_double.c
new file mode 100644
index 00000000..aad5f3ce
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_double.c
@@ -0,0 +1,93 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of double.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ double b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %g %d %d %g %d: %d %g %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, 4951, 127 };
+ struct cls_struct_align f_dbl = { 1, 9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_float.c b/testsuite/libffi.closures/cls_align_float.c
new file mode 100644
index 00000000..37e08552
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_float.c
@@ -0,0 +1,91 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of float.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ float b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %g %d %d %g %d: %d %g %d\n", a1.a, (double)a1.b, a1.c, a2.a, (double)a2.b, a2.c, result.a, (double)result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, 4951, 127 };
+ struct cls_struct_align f_dbl = { 1, 9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_float;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %g %d\n", res_dbl.a, (double)res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %g %d\n", res_dbl.a, (double)res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_longdouble.c b/testsuite/libffi.closures/cls_align_longdouble.c
new file mode 100644
index 00000000..b3322d86
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_longdouble.c
@@ -0,0 +1,92 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of long double.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ long double b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %g %d %d %g %d: %d %g %d\n", a1.a, (double)a1.b, a1.c, a2.a, (double)a2.b, a2.c, result.a, (double)result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, 4951, 127 };
+ struct cls_struct_align f_dbl = { 1, 9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_longdouble;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %g %d\n", res_dbl.a, (double)res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %g %d\n", res_dbl.a, (double)res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_longdouble_split.c b/testsuite/libffi.closures/cls_align_longdouble_split.c
new file mode 100644
index 00000000..cc1c43b8
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_longdouble_split.c
@@ -0,0 +1,132 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of long double.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
+
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ long double a;
+ long double b;
+ long double c;
+ long double d;
+ long double e;
+ long double f;
+ long double g;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(
+ cls_struct_align a1,
+ cls_struct_align a2)
+{
+ struct cls_struct_align r;
+
+ r.a = a1.a + a2.a;
+ r.b = a1.b + a2.b;
+ r.c = a1.c + a2.c;
+ r.d = a1.d + a2.d;
+ r.e = a1.e + a2.e;
+ r.f = a1.f + a2.f;
+ r.g = a1.g + a2.g;
+
+ printf("%Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg: "
+ "%Lg %Lg %Lg %Lg %Lg %Lg %Lg\n",
+ a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g,
+ a2.a, a2.b, a2.c, a2.d, a2.e, a2.f, a2.g,
+ r.a, r.b, r.c, r.d, r.e, r.f, r.g);
+
+ return r;
+}
+
+cls_struct_align cls_struct_align_fn2(
+ cls_struct_align a1)
+{
+ struct cls_struct_align r;
+
+ r.a = a1.a + 1;
+ r.b = a1.b + 1;
+ r.c = a1.c + 1;
+ r.d = a1.d + 1;
+ r.e = a1.e + 1;
+ r.f = a1.f + 1;
+ r.g = a1.g + 1;
+
+ printf("%Lg %Lg %Lg %Lg %Lg %Lg %Lg: "
+ "%Lg %Lg %Lg %Lg %Lg %Lg %Lg\n",
+ a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g,
+ r.a, r.b, r.c, r.d, r.e, r.f, r.g);
+
+ return r;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[8];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[3];
+
+ struct cls_struct_align g_dbl = { 1, 2, 3, 4, 5, 6, 7 };
+ struct cls_struct_align f_dbl = { 8, 9, 10, 11, 12, 13, 14 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_longdouble;
+ cls_struct_fields[1] = &ffi_type_longdouble;
+ cls_struct_fields[2] = &ffi_type_longdouble;
+ cls_struct_fields[3] = &ffi_type_longdouble;
+ cls_struct_fields[4] = &ffi_type_longdouble;
+ cls_struct_fields[5] = &ffi_type_longdouble;
+ cls_struct_fields[6] = &ffi_type_longdouble;
+ cls_struct_fields[7] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 2 3 4 5 6 7 8 9 10 11 12 13 14: 9 11 13 15 17 19 21" } */
+ printf("res: %Lg %Lg %Lg %Lg %Lg %Lg %Lg\n", res_dbl.a, res_dbl.b,
+ res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g);
+ /* { dg-output "\nres: 9 11 13 15 17 19 21" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n1 2 3 4 5 6 7 8 9 10 11 12 13 14: 9 11 13 15 17 19 21" } */
+ printf("res: %Lg %Lg %Lg %Lg %Lg %Lg %Lg\n", res_dbl.a, res_dbl.b,
+ res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g);
+ /* { dg-output "\nres: 9 11 13 15 17 19 21" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_longdouble_split2.c b/testsuite/libffi.closures/cls_align_longdouble_split2.c
new file mode 100644
index 00000000..5d3bec07
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_longdouble_split2.c
@@ -0,0 +1,115 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of long double.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/18/2007
+*/
+
+/* { dg-do run { xfail strongarm*-*-* } } */
+/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
+
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ long double a;
+ long double b;
+ long double c;
+ long double d;
+ long double e;
+ double f;
+ long double g;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(
+ cls_struct_align a1,
+ cls_struct_align a2)
+{
+ struct cls_struct_align r;
+
+ r.a = a1.a + a2.a;
+ r.b = a1.b + a2.b;
+ r.c = a1.c + a2.c;
+ r.d = a1.d + a2.d;
+ r.e = a1.e + a2.e;
+ r.f = a1.f + a2.f;
+ r.g = a1.g + a2.g;
+
+ printf("%Lg %Lg %Lg %Lg %Lg %g %Lg %Lg %Lg %Lg %Lg %Lg %g %Lg: "
+ "%Lg %Lg %Lg %Lg %Lg %g %Lg\n",
+ a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g,
+ a2.a, a2.b, a2.c, a2.d, a2.e, a2.f, a2.g,
+ r.a, r.b, r.c, r.d, r.e, r.f, r.g);
+
+ return r;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[8];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[3];
+
+ struct cls_struct_align g_dbl = { 1, 2, 3, 4, 5, 6, 7 };
+ struct cls_struct_align f_dbl = { 8, 9, 10, 11, 12, 13, 14 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_longdouble;
+ cls_struct_fields[1] = &ffi_type_longdouble;
+ cls_struct_fields[2] = &ffi_type_longdouble;
+ cls_struct_fields[3] = &ffi_type_longdouble;
+ cls_struct_fields[4] = &ffi_type_longdouble;
+ cls_struct_fields[5] = &ffi_type_double;
+ cls_struct_fields[6] = &ffi_type_longdouble;
+ cls_struct_fields[7] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 2 3 4 5 6 7 8 9 10 11 12 13 14: 9 11 13 15 17 19 21" } */
+ printf("res: %Lg %Lg %Lg %Lg %Lg %g %Lg\n", res_dbl.a, res_dbl.b,
+ res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g);
+ /* { dg-output "\nres: 9 11 13 15 17 19 21" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n1 2 3 4 5 6 7 8 9 10 11 12 13 14: 9 11 13 15 17 19 21" } */
+ printf("res: %Lg %Lg %Lg %Lg %Lg %g %Lg\n", res_dbl.a, res_dbl.b,
+ res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g);
+ /* { dg-output "\nres: 9 11 13 15 17 19 21" } */
+
+ exit(0);
+}
+
+
+
diff --git a/testsuite/libffi.closures/cls_align_pointer.c b/testsuite/libffi.closures/cls_align_pointer.c
new file mode 100644
index 00000000..8fbf36a5
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_pointer.c
@@ -0,0 +1,95 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of pointer.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ void *b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = (void *)((uintptr_t)a1.b + (uintptr_t)a2.b);
+ result.c = a1.c + a2.c;
+
+ printf("%d %" PRIuPTR " %d %d %" PRIuPTR " %d: %d %" PRIuPTR " %d\n",
+ a1.a, (uintptr_t)a1.b, a1.c,
+ a2.a, (uintptr_t)a2.b, a2.c,
+ result.a, (uintptr_t)result.b,
+ result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, (void *)4951, 127 };
+ struct cls_struct_align f_dbl = { 1, (void *)9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_pointer;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %" PRIuPTR " %d\n", res_dbl.a, (uintptr_t)res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %" PRIuPTR " %d\n", res_dbl.a, (uintptr_t)res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_sint16.c b/testsuite/libffi.closures/cls_align_sint16.c
new file mode 100644
index 00000000..039b8747
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_sint16.c
@@ -0,0 +1,91 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of sint16.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ signed short b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, 4951, 127 };
+ struct cls_struct_align f_dbl = { 1, 9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_sshort;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_sint32.c b/testsuite/libffi.closures/cls_align_sint32.c
new file mode 100644
index 00000000..c96c6d13
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_sint32.c
@@ -0,0 +1,91 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of sint32.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ signed int b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, 4951, 127 };
+ struct cls_struct_align f_dbl = { 1, 9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_sint;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_sint64.c b/testsuite/libffi.closures/cls_align_sint64.c
new file mode 100644
index 00000000..9aa7bddd
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_sint64.c
@@ -0,0 +1,92 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of sint64.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+/* { dg-do run } */
+/* { dg-options "-Wno-format" { target alpha*-dec-osf* } } */
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ signed long long b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %" PRIdLL " %d %d %" PRIdLL " %d: %d %" PRIdLL " %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, 4951, 127 };
+ struct cls_struct_align f_dbl = { 1, 9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_sint64;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_uint16.c b/testsuite/libffi.closures/cls_align_uint16.c
new file mode 100644
index 00000000..97620b79
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_uint16.c
@@ -0,0 +1,91 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of uint16.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ unsigned short b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, 4951, 127 };
+ struct cls_struct_align f_dbl = { 1, 9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_ushort;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_uint32.c b/testsuite/libffi.closures/cls_align_uint32.c
new file mode 100644
index 00000000..5766fadf
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_uint32.c
@@ -0,0 +1,91 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of uint32.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ unsigned int b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, 4951, 127 };
+ struct cls_struct_align f_dbl = { 1, 9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_uint;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_align_uint64.c b/testsuite/libffi.closures/cls_align_uint64.c
new file mode 100644
index 00000000..a52cb893
--- /dev/null
+++ b/testsuite/libffi.closures/cls_align_uint64.c
@@ -0,0 +1,93 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of uint64.
+ Limitations: none.
+ PR: none.
+ Originator: <hos@tamanegi.org> 20031203 */
+
+
+/* { dg-do run } */
+/* { dg-options "-Wno-format" { target alpha*-dec-osf* } } */
+#include "ffitest.h"
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ unsigned long long b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
+ struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %" PRIdLL " %d %d %" PRIdLL " %d: %d %" PRIdLL " %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_align g_dbl = { 12, 4951, 127 };
+ struct cls_struct_align f_dbl = { 1, 9320, 13 };
+ struct cls_struct_align res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_uint64;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &g_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
+ /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
+ /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
+ printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
+ /* { dg-output "\nres: 13 14271 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_dbls_struct.c b/testsuite/libffi.closures/cls_dbls_struct.c
new file mode 100644
index 00000000..e451dea5
--- /dev/null
+++ b/testsuite/libffi.closures/cls_dbls_struct.c
@@ -0,0 +1,66 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check double arguments in structs.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/23/2007 */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+typedef struct Dbls {
+ double x;
+ double y;
+} Dbls;
+
+void
+closure_test_fn(Dbls p)
+{
+ printf("%.1f %.1f\n", p.x, p.y);
+}
+
+void
+closure_test_gn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__,
+ void** args, void* userdata __UNUSED__)
+{
+ closure_test_fn(*(Dbls*)args[0]);
+}
+
+int main(int argc __UNUSED__, char** argv __UNUSED__)
+{
+ ffi_cif cif;
+
+ void *code;
+ ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type* cl_arg_types[1];
+
+ ffi_type ts1_type;
+ ffi_type* ts1_type_elements[4];
+
+ Dbls arg = { 1.0, 2.0 };
+
+ ts1_type.size = 0;
+ ts1_type.alignment = 0;
+ ts1_type.type = FFI_TYPE_STRUCT;
+ ts1_type.elements = ts1_type_elements;
+
+ ts1_type_elements[0] = &ffi_type_double;
+ ts1_type_elements[1] = &ffi_type_double;
+ ts1_type_elements[2] = NULL;
+
+ cl_arg_types[0] = &ts1_type;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_void, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_gn, NULL, code) == FFI_OK);
+
+ ((void*(*)(Dbls))(code))(arg);
+ /* { dg-output "1.0 2.0" } */
+
+ closure_test_fn(arg);
+ /* { dg-output "\n1.0 2.0" } */
+
+ return 0;
+}
diff --git a/testsuite/libffi.closures/cls_double.c b/testsuite/libffi.closures/cls_double.c
new file mode 100644
index 00000000..84ad4cb7
--- /dev/null
+++ b/testsuite/libffi.closures/cls_double.c
@@ -0,0 +1,43 @@
+/* Area: closure_call
+ Purpose: Check return value double.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void cls_ret_double_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+ {
+ *(double *)resp = *(double *)args[0];
+
+ printf("%f: %f\n",*(double *)args[0],
+ *(double *)resp);
+ }
+typedef double (*cls_ret_double)(double);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ double res;
+
+ cl_arg_types[0] = &ffi_type_double;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_double, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_double_fn, NULL, code) == FFI_OK);
+
+ res = (*((cls_ret_double)code))(21474.789);
+ /* { dg-output "21474.789000: 21474.789000" } */
+ printf("res: %.6f\n", res);
+ /* { dg-output "\nres: 21474.789000" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_double_va.c b/testsuite/libffi.closures/cls_double_va.c
new file mode 100644
index 00000000..e077f92b
--- /dev/null
+++ b/testsuite/libffi.closures/cls_double_va.c
@@ -0,0 +1,61 @@
+/* Area: ffi_call, closure_call
+ Purpose: Test doubles passed in variable argument lists.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/6/2007 */
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+/* { dg-output "" { xfail avr32*-*-* } } */
+/* { dg-output "" { xfail mips-sgi-irix6* } } PR libffi/46660 */
+
+#include "ffitest.h"
+
+static void
+cls_double_va_fn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ char* format = *(char**)args[0];
+ double doubleValue = *(double*)args[1];
+
+ *(ffi_arg*)resp = printf(format, doubleValue);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args[3];
+ ffi_type* arg_types[3];
+
+ char* format = "%.1f\n";
+ double doubleArg = 7;
+ ffi_arg res = 0;
+
+ arg_types[0] = &ffi_type_pointer;
+ arg_types[1] = &ffi_type_double;
+ arg_types[2] = NULL;
+
+ /* This printf call is variadic */
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
+ arg_types) == FFI_OK);
+
+ args[0] = &format;
+ args[1] = &doubleArg;
+ args[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(printf), &res, args);
+ /* { dg-output "7.0" } */
+ printf("res: %d\n", (int) res);
+ /* { dg-output "\nres: 4" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL,
+ code) == FFI_OK);
+
+ res = ((int(*)(char*, ...))(code))(format, doubleArg);
+ /* { dg-output "\n7.0" } */
+ printf("res: %d\n", (int) res);
+ /* { dg-output "\nres: 4" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_float.c b/testsuite/libffi.closures/cls_float.c
new file mode 100644
index 00000000..0090fed9
--- /dev/null
+++ b/testsuite/libffi.closures/cls_float.c
@@ -0,0 +1,42 @@
+/* Area: closure_call
+ Purpose: Check return value float.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void cls_ret_float_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+ {
+ *(float *)resp = *(float *)args[0];
+
+ printf("%g: %g\n",*(float *)args[0],
+ *(float *)resp);
+ }
+
+typedef float (*cls_ret_float)(float);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ float res;
+
+ cl_arg_types[0] = &ffi_type_float;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_float, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_float_fn, NULL, code) == FFI_OK);
+ res = ((((cls_ret_float)code)(-2122.12)));
+ /* { dg-output "\\-2122.12: \\-2122.12" } */
+ printf("res: %.6f\n", res);
+ /* { dg-output "\nres: \-2122.120117" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_longdouble.c b/testsuite/libffi.closures/cls_longdouble.c
new file mode 100644
index 00000000..d24e72e4
--- /dev/null
+++ b/testsuite/libffi.closures/cls_longdouble.c
@@ -0,0 +1,105 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check long double arguments.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin */
+
+/* This test is known to PASS on armv7l-unknown-linux-gnueabihf, so I have
+ remove the xfail for arm*-*-* below, until we know more. */
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
+
+#include "ffitest.h"
+
+long double cls_ldouble_fn(
+ long double a1,
+ long double a2,
+ long double a3,
+ long double a4,
+ long double a5,
+ long double a6,
+ long double a7,
+ long double a8)
+{
+ long double r = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8;
+
+ printf("%Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg: %Lg\n",
+ a1, a2, a3, a4, a5, a6, a7, a8, r);
+
+ return r;
+}
+
+static void
+cls_ldouble_gn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ long double a1 = *(long double*)args[0];
+ long double a2 = *(long double*)args[1];
+ long double a3 = *(long double*)args[2];
+ long double a4 = *(long double*)args[3];
+ long double a5 = *(long double*)args[4];
+ long double a6 = *(long double*)args[5];
+ long double a7 = *(long double*)args[6];
+ long double a8 = *(long double*)args[7];
+
+ *(long double*)resp = cls_ldouble_fn(
+ a1, a2, a3, a4, a5, a6, a7, a8);
+}
+
+int main(void)
+{
+ ffi_cif cif;
+ void* code;
+ ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args[9];
+ ffi_type* arg_types[9];
+ long double res = 0;
+
+ long double arg1 = 1;
+ long double arg2 = 2;
+ long double arg3 = 3;
+ long double arg4 = 4;
+ long double arg5 = 5;
+ long double arg6 = 6;
+ long double arg7 = 7;
+ long double arg8 = 8;
+
+ arg_types[0] = &ffi_type_longdouble;
+ arg_types[1] = &ffi_type_longdouble;
+ arg_types[2] = &ffi_type_longdouble;
+ arg_types[3] = &ffi_type_longdouble;
+ arg_types[4] = &ffi_type_longdouble;
+ arg_types[5] = &ffi_type_longdouble;
+ arg_types[6] = &ffi_type_longdouble;
+ arg_types[7] = &ffi_type_longdouble;
+ arg_types[8] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 8, &ffi_type_longdouble,
+ arg_types) == FFI_OK);
+
+ args[0] = &arg1;
+ args[1] = &arg2;
+ args[2] = &arg3;
+ args[3] = &arg4;
+ args[4] = &arg5;
+ args[5] = &arg6;
+ args[6] = &arg7;
+ args[7] = &arg8;
+ args[8] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_ldouble_fn), &res, args);
+ /* { dg-output "1 2 3 4 5 6 7 8: 36" } */
+ printf("res: %Lg\n", res);
+ /* { dg-output "\nres: 36" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ldouble_gn, NULL, code) == FFI_OK);
+
+ res = ((long double(*)(long double, long double, long double, long double,
+ long double, long double, long double, long double))(code))(arg1, arg2,
+ arg3, arg4, arg5, arg6, arg7, arg8);
+ /* { dg-output "\n1 2 3 4 5 6 7 8: 36" } */
+ printf("res: %Lg\n", res);
+ /* { dg-output "\nres: 36" } */
+
+ return 0;
+}
diff --git a/testsuite/libffi.closures/cls_longdouble_va.c b/testsuite/libffi.closures/cls_longdouble_va.c
new file mode 100644
index 00000000..39b438b2
--- /dev/null
+++ b/testsuite/libffi.closures/cls_longdouble_va.c
@@ -0,0 +1,61 @@
+/* Area: ffi_call, closure_call
+ Purpose: Test long doubles passed in variable argument lists.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/6/2007 */
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+/* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
+/* { dg-output "" { xfail mips-sgi-irix6* } } PR libffi/46660 */
+
+#include "ffitest.h"
+
+static void
+cls_longdouble_va_fn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ char* format = *(char**)args[0];
+ long double ldValue = *(long double*)args[1];
+
+ *(ffi_arg*)resp = printf(format, ldValue);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args[3];
+ ffi_type* arg_types[3];
+
+ char* format = "%.1Lf\n";
+ long double ldArg = 7;
+ ffi_arg res = 0;
+
+ arg_types[0] = &ffi_type_pointer;
+ arg_types[1] = &ffi_type_longdouble;
+ arg_types[2] = NULL;
+
+ /* This printf call is variadic */
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
+ arg_types) == FFI_OK);
+
+ args[0] = &format;
+ args[1] = &ldArg;
+ args[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(printf), &res, args);
+ /* { dg-output "7.0" } */
+ printf("res: %d\n", (int) res);
+ /* { dg-output "\nres: 4" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL,
+ code) == FFI_OK);
+
+ res = ((int(*)(char*, ...))(code))(format, ldArg);
+ /* { dg-output "\n7.0" } */
+ printf("res: %d\n", (int) res);
+ /* { dg-output "\nres: 4" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_many_mixed_args.c b/testsuite/libffi.closures/cls_many_mixed_args.c
new file mode 100644
index 00000000..7fd6c820
--- /dev/null
+++ b/testsuite/libffi.closures/cls_many_mixed_args.c
@@ -0,0 +1,70 @@
+/* Area: closure_call
+ Purpose: Check closures called with many args of mixed types
+ Limitations: none.
+ PR: none.
+ Originator: <david.schneider@picle.org> */
+
+/* { dg-do run } */
+#include "ffitest.h"
+#include <float.h>
+#include <math.h>
+
+#define NARGS 16
+
+static void cls_ret_double_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ int i;
+ double r = 0;
+ double t;
+ for(i = 0; i < NARGS; i++)
+ {
+ if(i == 4 || i == 9 || i == 11 || i == 13 || i == 15)
+ {
+ t = *(long int *)args[i];
+ CHECK(t == i+1);
+ }
+ else
+ {
+ t = *(double *)args[i];
+ CHECK(fabs(t - ((i+1) * 0.1)) < FLT_EPSILON);
+ }
+ r += t;
+ }
+ *(double *)resp = r;
+}
+typedef double (*cls_ret_double)(double, double, double, double, long int,
+double, double, double, double, long int, double, long int, double, long int,
+double, long int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[NARGS];
+ double res;
+ int i;
+ double expected = 64.9;
+
+ for(i = 0; i < NARGS; i++)
+ {
+ if(i == 4 || i == 9 || i == 11 || i == 13 || i == 15)
+ cl_arg_types[i] = &ffi_type_slong;
+ else
+ cl_arg_types[i] = &ffi_type_double;
+ }
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NARGS,
+ &ffi_type_double, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_double_fn, NULL, code) == FFI_OK);
+
+ res = (((cls_ret_double)code))(0.1, 0.2, 0.3, 0.4, 5, 0.6, 0.7, 0.8, 0.9, 10,
+ 1.1, 12, 1.3, 14, 1.5, 16);
+ if (fabs(res - expected) < FLT_EPSILON)
+ exit(0);
+ else
+ abort();
+}
diff --git a/testsuite/libffi.closures/cls_many_mixed_float_double.c b/testsuite/libffi.closures/cls_many_mixed_float_double.c
new file mode 100644
index 00000000..62b0697a
--- /dev/null
+++ b/testsuite/libffi.closures/cls_many_mixed_float_double.c
@@ -0,0 +1,55 @@
+/* Area: closure_call
+ Purpose: Check register allocation for closure calls with many float and double arguments
+ Limitations: none.
+ PR: none.
+ Originator: <david.schneider@picle.org> */
+
+/* { dg-do run } */
+#include "ffitest.h"
+#include <float.h>
+#include <math.h>
+
+#define NARGS 16
+
+static void cls_mixed_float_double_fn(ffi_cif* cif , void* ret, void** args,
+ void* userdata __UNUSED__)
+{
+ double r = 0;
+ unsigned int i;
+ double t;
+ for(i=0; i < cif->nargs; i++)
+ {
+ if(cif->arg_types[i] == &ffi_type_double) {
+ t = *(((double**)(args))[i]);
+ } else {
+ t = *(((float**)(args))[i]);
+ }
+ r += t;
+ }
+ *((double*)ret) = r;
+}
+typedef double (*cls_mixed)(double, float, double, double, double, double, double, float, float, double, float, float);
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_closure *closure;
+ void* code;
+ ffi_type *argtypes[12] = {&ffi_type_double, &ffi_type_float, &ffi_type_double,
+ &ffi_type_double, &ffi_type_double, &ffi_type_double,
+ &ffi_type_double, &ffi_type_float, &ffi_type_float,
+ &ffi_type_double, &ffi_type_float, &ffi_type_float};
+
+
+ closure = ffi_closure_alloc(sizeof(ffi_closure), (void**)&code);
+ if(closure ==NULL)
+ abort();
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 12, &ffi_type_double, argtypes) == FFI_OK);
+ CHECK(ffi_prep_closure_loc(closure, &cif, cls_mixed_float_double_fn, NULL, code) == FFI_OK);
+ double ret = ((cls_mixed)code)(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2);
+ ffi_closure_free(closure);
+ if(fabs(ret - 7.8) < FLT_EPSILON)
+ exit(0);
+ else
+ abort();
+}
diff --git a/testsuite/libffi.closures/cls_multi_schar.c b/testsuite/libffi.closures/cls_multi_schar.c
new file mode 100644
index 00000000..71df7b65
--- /dev/null
+++ b/testsuite/libffi.closures/cls_multi_schar.c
@@ -0,0 +1,74 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check passing of multiple signed char values.
+ Limitations: none.
+ PR: PR13221.
+ Originator: <hos@tamanegi.org> 20031129 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+signed char test_func_fn(signed char a1, signed char a2)
+{
+ signed char result;
+
+ result = a1 + a2;
+
+ printf("%d %d: %d\n", a1, a2, result);
+
+ return result;
+
+}
+
+static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals,
+ void *data __UNUSED__)
+{
+ signed char a1, a2;
+
+ a1 = *(signed char *)avals[0];
+ a2 = *(signed char *)avals[1];
+
+ *(ffi_arg *)rval = test_func_fn(a1, a2);
+
+}
+
+typedef signed char (*test_type)(signed char, signed char);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void * args_dbl[3];
+ ffi_type * cl_arg_types[3];
+ ffi_arg res_call;
+ signed char a, b, res_closure;
+
+ a = 2;
+ b = 125;
+
+ args_dbl[0] = &a;
+ args_dbl[1] = &b;
+ args_dbl[2] = NULL;
+
+ cl_arg_types[0] = &ffi_type_schar;
+ cl_arg_types[1] = &ffi_type_schar;
+ cl_arg_types[2] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2,
+ &ffi_type_schar, cl_arg_types) == FFI_OK);
+
+ ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl);
+ /* { dg-output "2 125: 127" } */
+ printf("res: %d\n", (signed char)res_call);
+ /* { dg-output "\nres: 127" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK);
+
+ res_closure = (*((test_type)code))(2, 125);
+ /* { dg-output "\n2 125: 127" } */
+ printf("res: %d\n", res_closure);
+ /* { dg-output "\nres: 127" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_multi_sshort.c b/testsuite/libffi.closures/cls_multi_sshort.c
new file mode 100644
index 00000000..4c391532
--- /dev/null
+++ b/testsuite/libffi.closures/cls_multi_sshort.c
@@ -0,0 +1,74 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check passing of multiple signed short values.
+ Limitations: none.
+ PR: PR13221.
+ Originator: <andreast@gcc.gnu.org> 20031129 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+signed short test_func_fn(signed short a1, signed short a2)
+{
+ signed short result;
+
+ result = a1 + a2;
+
+ printf("%d %d: %d\n", a1, a2, result);
+
+ return result;
+
+}
+
+static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals,
+ void *data __UNUSED__)
+{
+ signed short a1, a2;
+
+ a1 = *(signed short *)avals[0];
+ a2 = *(signed short *)avals[1];
+
+ *(ffi_arg *)rval = test_func_fn(a1, a2);
+
+}
+
+typedef signed short (*test_type)(signed short, signed short);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void * args_dbl[3];
+ ffi_type * cl_arg_types[3];
+ ffi_arg res_call;
+ unsigned short a, b, res_closure;
+
+ a = 2;
+ b = 32765;
+
+ args_dbl[0] = &a;
+ args_dbl[1] = &b;
+ args_dbl[2] = NULL;
+
+ cl_arg_types[0] = &ffi_type_sshort;
+ cl_arg_types[1] = &ffi_type_sshort;
+ cl_arg_types[2] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2,
+ &ffi_type_sshort, cl_arg_types) == FFI_OK);
+
+ ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl);
+ /* { dg-output "2 32765: 32767" } */
+ printf("res: %d\n", (unsigned short)res_call);
+ /* { dg-output "\nres: 32767" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK);
+
+ res_closure = (*((test_type)code))(2, 32765);
+ /* { dg-output "\n2 32765: 32767" } */
+ printf("res: %d\n", res_closure);
+ /* { dg-output "\nres: 32767" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_multi_sshortchar.c b/testsuite/libffi.closures/cls_multi_sshortchar.c
new file mode 100644
index 00000000..1c3aeb5a
--- /dev/null
+++ b/testsuite/libffi.closures/cls_multi_sshortchar.c
@@ -0,0 +1,86 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check passing of multiple signed short/char values.
+ Limitations: none.
+ PR: PR13221.
+ Originator: <andreast@gcc.gnu.org> 20031129 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+signed short test_func_fn(signed char a1, signed short a2,
+ signed char a3, signed short a4)
+{
+ signed short result;
+
+ result = a1 + a2 + a3 + a4;
+
+ printf("%d %d %d %d: %d\n", a1, a2, a3, a4, result);
+
+ return result;
+
+}
+
+static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals,
+ void *data __UNUSED__)
+{
+ signed char a1, a3;
+ signed short a2, a4;
+
+ a1 = *(signed char *)avals[0];
+ a2 = *(signed short *)avals[1];
+ a3 = *(signed char *)avals[2];
+ a4 = *(signed short *)avals[3];
+
+ *(ffi_arg *)rval = test_func_fn(a1, a2, a3, a4);
+
+}
+
+typedef signed short (*test_type)(signed char, signed short,
+ signed char, signed short);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void * args_dbl[5];
+ ffi_type * cl_arg_types[5];
+ ffi_arg res_call;
+ signed char a, c;
+ signed short b, d, res_closure;
+
+ a = 1;
+ b = 32765;
+ c = 127;
+ d = -128;
+
+ args_dbl[0] = &a;
+ args_dbl[1] = &b;
+ args_dbl[2] = &c;
+ args_dbl[3] = &d;
+ args_dbl[4] = NULL;
+
+ cl_arg_types[0] = &ffi_type_schar;
+ cl_arg_types[1] = &ffi_type_sshort;
+ cl_arg_types[2] = &ffi_type_schar;
+ cl_arg_types[3] = &ffi_type_sshort;
+ cl_arg_types[4] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
+ &ffi_type_sshort, cl_arg_types) == FFI_OK);
+
+ ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl);
+ /* { dg-output "1 32765 127 -128: 32765" } */
+ printf("res: %d\n", (signed short)res_call);
+ /* { dg-output "\nres: 32765" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK);
+
+ res_closure = (*((test_type)code))(1, 32765, 127, -128);
+ /* { dg-output "\n1 32765 127 -128: 32765" } */
+ printf("res: %d\n", res_closure);
+ /* { dg-output "\nres: 32765" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_multi_uchar.c b/testsuite/libffi.closures/cls_multi_uchar.c
new file mode 100644
index 00000000..009c02c7
--- /dev/null
+++ b/testsuite/libffi.closures/cls_multi_uchar.c
@@ -0,0 +1,91 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check passing of multiple unsigned char values.
+ Limitations: none.
+ PR: PR13221.
+ Originator: <andreast@gcc.gnu.org> 20031129 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+unsigned char test_func_fn(unsigned char a1, unsigned char a2,
+ unsigned char a3, unsigned char a4)
+{
+ unsigned char result;
+
+ result = a1 + a2 + a3 + a4;
+
+ printf("%d %d %d %d: %d\n", a1, a2, a3, a4, result);
+
+ return result;
+
+}
+
+static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals,
+ void *data __UNUSED__)
+{
+ unsigned char a1, a2, a3, a4;
+
+ a1 = *(unsigned char *)avals[0];
+ a2 = *(unsigned char *)avals[1];
+ a3 = *(unsigned char *)avals[2];
+ a4 = *(unsigned char *)avals[3];
+
+ *(ffi_arg *)rval = test_func_fn(a1, a2, a3, a4);
+
+}
+
+typedef unsigned char (*test_type)(unsigned char, unsigned char,
+ unsigned char, unsigned char);
+
+void test_func(ffi_cif *cif __UNUSED__, void *rval __UNUSED__, void **avals,
+ void *data __UNUSED__)
+{
+ printf("%d %d %d %d\n", *(unsigned char *)avals[0],
+ *(unsigned char *)avals[1], *(unsigned char *)avals[2],
+ *(unsigned char *)avals[3]);
+}
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void * args_dbl[5];
+ ffi_type * cl_arg_types[5];
+ ffi_arg res_call;
+ unsigned char a, b, c, d, res_closure;
+
+ a = 1;
+ b = 2;
+ c = 127;
+ d = 125;
+
+ args_dbl[0] = &a;
+ args_dbl[1] = &b;
+ args_dbl[2] = &c;
+ args_dbl[3] = &d;
+ args_dbl[4] = NULL;
+
+ cl_arg_types[0] = &ffi_type_uchar;
+ cl_arg_types[1] = &ffi_type_uchar;
+ cl_arg_types[2] = &ffi_type_uchar;
+ cl_arg_types[3] = &ffi_type_uchar;
+ cl_arg_types[4] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
+ &ffi_type_uchar, cl_arg_types) == FFI_OK);
+
+ ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl);
+ /* { dg-output "1 2 127 125: 255" } */
+ printf("res: %d\n", (unsigned char)res_call);
+ /* { dg-output "\nres: 255" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK);
+
+ res_closure = (*((test_type)code))(1, 2, 127, 125);
+ /* { dg-output "\n1 2 127 125: 255" } */
+ printf("res: %d\n", res_closure);
+ /* { dg-output "\nres: 255" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_multi_ushort.c b/testsuite/libffi.closures/cls_multi_ushort.c
new file mode 100644
index 00000000..dd10ca73
--- /dev/null
+++ b/testsuite/libffi.closures/cls_multi_ushort.c
@@ -0,0 +1,74 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check passing of multiple unsigned short values.
+ Limitations: none.
+ PR: PR13221.
+ Originator: <andreast@gcc.gnu.org> 20031129 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+unsigned short test_func_fn(unsigned short a1, unsigned short a2)
+{
+ unsigned short result;
+
+ result = a1 + a2;
+
+ printf("%d %d: %d\n", a1, a2, result);
+
+ return result;
+
+}
+
+static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals,
+ void *data __UNUSED__)
+{
+ unsigned short a1, a2;
+
+ a1 = *(unsigned short *)avals[0];
+ a2 = *(unsigned short *)avals[1];
+
+ *(ffi_arg *)rval = test_func_fn(a1, a2);
+
+}
+
+typedef unsigned short (*test_type)(unsigned short, unsigned short);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void * args_dbl[3];
+ ffi_type * cl_arg_types[3];
+ ffi_arg res_call;
+ unsigned short a, b, res_closure;
+
+ a = 2;
+ b = 32765;
+
+ args_dbl[0] = &a;
+ args_dbl[1] = &b;
+ args_dbl[2] = NULL;
+
+ cl_arg_types[0] = &ffi_type_ushort;
+ cl_arg_types[1] = &ffi_type_ushort;
+ cl_arg_types[2] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2,
+ &ffi_type_ushort, cl_arg_types) == FFI_OK);
+
+ ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl);
+ /* { dg-output "2 32765: 32767" } */
+ printf("res: %d\n", (unsigned short)res_call);
+ /* { dg-output "\nres: 32767" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK);
+
+ res_closure = (*((test_type)code))(2, 32765);
+ /* { dg-output "\n2 32765: 32767" } */
+ printf("res: %d\n", res_closure);
+ /* { dg-output "\nres: 32767" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_multi_ushortchar.c b/testsuite/libffi.closures/cls_multi_ushortchar.c
new file mode 100644
index 00000000..2588e97f
--- /dev/null
+++ b/testsuite/libffi.closures/cls_multi_ushortchar.c
@@ -0,0 +1,86 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check passing of multiple unsigned short/char values.
+ Limitations: none.
+ PR: PR13221.
+ Originator: <andreast@gcc.gnu.org> 20031129 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+unsigned short test_func_fn(unsigned char a1, unsigned short a2,
+ unsigned char a3, unsigned short a4)
+{
+ unsigned short result;
+
+ result = a1 + a2 + a3 + a4;
+
+ printf("%d %d %d %d: %d\n", a1, a2, a3, a4, result);
+
+ return result;
+
+}
+
+static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals,
+ void *data __UNUSED__)
+{
+ unsigned char a1, a3;
+ unsigned short a2, a4;
+
+ a1 = *(unsigned char *)avals[0];
+ a2 = *(unsigned short *)avals[1];
+ a3 = *(unsigned char *)avals[2];
+ a4 = *(unsigned short *)avals[3];
+
+ *(ffi_arg *)rval = test_func_fn(a1, a2, a3, a4);
+
+}
+
+typedef unsigned short (*test_type)(unsigned char, unsigned short,
+ unsigned char, unsigned short);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void * args_dbl[5];
+ ffi_type * cl_arg_types[5];
+ ffi_arg res_call;
+ unsigned char a, c;
+ unsigned short b, d, res_closure;
+
+ a = 1;
+ b = 2;
+ c = 127;
+ d = 128;
+
+ args_dbl[0] = &a;
+ args_dbl[1] = &b;
+ args_dbl[2] = &c;
+ args_dbl[3] = &d;
+ args_dbl[4] = NULL;
+
+ cl_arg_types[0] = &ffi_type_uchar;
+ cl_arg_types[1] = &ffi_type_ushort;
+ cl_arg_types[2] = &ffi_type_uchar;
+ cl_arg_types[3] = &ffi_type_ushort;
+ cl_arg_types[4] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
+ &ffi_type_ushort, cl_arg_types) == FFI_OK);
+
+ ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl);
+ /* { dg-output "1 2 127 128: 258" } */
+ printf("res: %d\n", (unsigned short)res_call);
+ /* { dg-output "\nres: 258" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK);
+
+ res_closure = (*((test_type)code))(1, 2, 127, 128);
+ /* { dg-output "\n1 2 127 128: 258" } */
+ printf("res: %d\n", res_closure);
+ /* { dg-output "\nres: 258" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_pointer.c b/testsuite/libffi.closures/cls_pointer.c
new file mode 100644
index 00000000..d82a87a7
--- /dev/null
+++ b/testsuite/libffi.closures/cls_pointer.c
@@ -0,0 +1,74 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check pointer arguments.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/6/2007 */
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+#include "ffitest.h"
+
+void* cls_pointer_fn(void* a1, void* a2)
+{
+ void* result = (void*)((intptr_t)a1 + (intptr_t)a2);
+
+ printf("0x%08x 0x%08x: 0x%08x\n",
+ (unsigned int)(uintptr_t) a1,
+ (unsigned int)(uintptr_t) a2,
+ (unsigned int)(uintptr_t) result);
+
+ return result;
+}
+
+static void
+cls_pointer_gn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ void* a1 = *(void**)(args[0]);
+ void* a2 = *(void**)(args[1]);
+
+ *(void**)resp = cls_pointer_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args[3];
+ /* ffi_type cls_pointer_type; */
+ ffi_type* arg_types[3];
+
+/* cls_pointer_type.size = sizeof(void*);
+ cls_pointer_type.alignment = 0;
+ cls_pointer_type.type = FFI_TYPE_POINTER;
+ cls_pointer_type.elements = NULL;*/
+
+ void* arg1 = (void*)0x12345678;
+ void* arg2 = (void*)0x89abcdef;
+ ffi_arg res = 0;
+
+ arg_types[0] = &ffi_type_pointer;
+ arg_types[1] = &ffi_type_pointer;
+ arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_pointer,
+ arg_types) == FFI_OK);
+
+ args[0] = &arg1;
+ args[1] = &arg2;
+ args[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_pointer_fn), &res, args);
+ /* { dg-output "0x12345678 0x89abcdef: 0x9be02467" } */
+ printf("res: 0x%08x\n", (unsigned int) res);
+ /* { dg-output "\nres: 0x9be02467" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_pointer_gn, NULL, code) == FFI_OK);
+
+ res = (ffi_arg)(uintptr_t)((void*(*)(void*, void*))(code))(arg1, arg2);
+ /* { dg-output "\n0x12345678 0x89abcdef: 0x9be02467" } */
+ printf("res: 0x%08x\n", (unsigned int) res);
+ /* { dg-output "\nres: 0x9be02467" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_pointer_stack.c b/testsuite/libffi.closures/cls_pointer_stack.c
new file mode 100644
index 00000000..1f1d9157
--- /dev/null
+++ b/testsuite/libffi.closures/cls_pointer_stack.c
@@ -0,0 +1,142 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check pointer arguments across multiple hideous stack frames.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/7/2007 */
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+#include "ffitest.h"
+
+static long dummyVar;
+
+long dummy_func(
+ long double a1, char b1,
+ long double a2, char b2,
+ long double a3, char b3,
+ long double a4, char b4)
+{
+ return a1 + b1 + a2 + b2 + a3 + b3 + a4 + b4;
+}
+
+void* cls_pointer_fn2(void* a1, void* a2)
+{
+ long double trample1 = (intptr_t)a1 + (intptr_t)a2;
+ char trample2 = ((char*)&a1)[0] + ((char*)&a2)[0];
+ long double trample3 = (intptr_t)trample1 + (intptr_t)a1;
+ char trample4 = trample2 + ((char*)&a1)[1];
+ long double trample5 = (intptr_t)trample3 + (intptr_t)a2;
+ char trample6 = trample4 + ((char*)&a2)[1];
+ long double trample7 = (intptr_t)trample5 + (intptr_t)trample1;
+ char trample8 = trample6 + trample2;
+ void* result;
+
+ dummyVar = dummy_func(trample1, trample2, trample3, trample4,
+ trample5, trample6, trample7, trample8);
+
+ result = (void*)((intptr_t)a1 + (intptr_t)a2);
+
+ printf("0x%08x 0x%08x: 0x%08x\n",
+ (unsigned int)(uintptr_t) a1,
+ (unsigned int)(uintptr_t) a2,
+ (unsigned int)(uintptr_t) result);
+
+ return result;
+}
+
+void* cls_pointer_fn1(void* a1, void* a2)
+{
+ long double trample1 = (intptr_t)a1 + (intptr_t)a2;
+ char trample2 = ((char*)&a1)[0] + ((char*)&a2)[0];
+ long double trample3 = (intptr_t)trample1 + (intptr_t)a1;
+ char trample4 = trample2 + ((char*)&a1)[1];
+ long double trample5 = (intptr_t)trample3 + (intptr_t)a2;
+ char trample6 = trample4 + ((char*)&a2)[1];
+ long double trample7 = (intptr_t)trample5 + (intptr_t)trample1;
+ char trample8 = trample6 + trample2;
+ void* result;
+
+ dummyVar = dummy_func(trample1, trample2, trample3, trample4,
+ trample5, trample6, trample7, trample8);
+
+ result = (void*)((intptr_t)a1 + (intptr_t)a2);
+
+ printf("0x%08x 0x%08x: 0x%08x\n",
+ (unsigned int)(intptr_t) a1,
+ (unsigned int)(intptr_t) a2,
+ (unsigned int)(intptr_t) result);
+
+ result = cls_pointer_fn2(result, a1);
+
+ return result;
+}
+
+static void
+cls_pointer_gn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ void* a1 = *(void**)(args[0]);
+ void* a2 = *(void**)(args[1]);
+
+ long double trample1 = (intptr_t)a1 + (intptr_t)a2;
+ char trample2 = ((char*)&a1)[0] + ((char*)&a2)[0];
+ long double trample3 = (intptr_t)trample1 + (intptr_t)a1;
+ char trample4 = trample2 + ((char*)&a1)[1];
+ long double trample5 = (intptr_t)trample3 + (intptr_t)a2;
+ char trample6 = trample4 + ((char*)&a2)[1];
+ long double trample7 = (intptr_t)trample5 + (intptr_t)trample1;
+ char trample8 = trample6 + trample2;
+
+ dummyVar = dummy_func(trample1, trample2, trample3, trample4,
+ trample5, trample6, trample7, trample8);
+
+ *(void**)resp = cls_pointer_fn1(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args[3];
+ /* ffi_type cls_pointer_type; */
+ ffi_type* arg_types[3];
+
+/* cls_pointer_type.size = sizeof(void*);
+ cls_pointer_type.alignment = 0;
+ cls_pointer_type.type = FFI_TYPE_POINTER;
+ cls_pointer_type.elements = NULL;*/
+
+ void* arg1 = (void*)0x01234567;
+ void* arg2 = (void*)0x89abcdef;
+ ffi_arg res = 0;
+
+ arg_types[0] = &ffi_type_pointer;
+ arg_types[1] = &ffi_type_pointer;
+ arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_pointer,
+ arg_types) == FFI_OK);
+
+ args[0] = &arg1;
+ args[1] = &arg2;
+ args[2] = NULL;
+
+ printf("\n");
+ ffi_call(&cif, FFI_FN(cls_pointer_fn1), &res, args);
+
+ printf("res: 0x%08x\n", (unsigned int) res);
+ /* { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } */
+ /* { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } */
+ /* { dg-output "\nres: 0x8bf258bd" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_pointer_gn, NULL, code) == FFI_OK);
+
+ res = (ffi_arg)(uintptr_t)((void*(*)(void*, void*))(code))(arg1, arg2);
+
+ printf("res: 0x%08x\n", (unsigned int) res);
+ /* { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } */
+ /* { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } */
+ /* { dg-output "\nres: 0x8bf258bd" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_schar.c b/testsuite/libffi.closures/cls_schar.c
new file mode 100644
index 00000000..82986b17
--- /dev/null
+++ b/testsuite/libffi.closures/cls_schar.c
@@ -0,0 +1,44 @@
+/* Area: closure_call
+ Purpose: Check return value schar.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20031108 */
+
+
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void cls_ret_schar_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ *(ffi_arg*)resp = *(signed char *)args[0];
+ printf("%d: %d\n",*(signed char *)args[0],
+ (int)*(ffi_arg *)(resp));
+}
+typedef signed char (*cls_ret_schar)(signed char);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ signed char res;
+
+ cl_arg_types[0] = &ffi_type_schar;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_schar, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_schar_fn, NULL, code) == FFI_OK);
+
+ res = (*((cls_ret_schar)code))(127);
+ /* { dg-output "127: 127" } */
+ printf("res: %d\n", res);
+ /* { dg-output "\nres: 127" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_sint.c b/testsuite/libffi.closures/cls_sint.c
new file mode 100644
index 00000000..c7e13b73
--- /dev/null
+++ b/testsuite/libffi.closures/cls_sint.c
@@ -0,0 +1,42 @@
+/* Area: closure_call
+ Purpose: Check return value sint32.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20031108 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void cls_ret_sint_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ *(ffi_arg*)resp = *(signed int *)args[0];
+ printf("%d: %d\n",*(signed int *)args[0],
+ (int)*(ffi_arg *)(resp));
+}
+typedef signed int (*cls_ret_sint)(signed int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ signed int res;
+
+ cl_arg_types[0] = &ffi_type_sint;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_sint_fn, NULL, code) == FFI_OK);
+
+ res = (*((cls_ret_sint)code))(65534);
+ /* { dg-output "65534: 65534" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 65534" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_sshort.c b/testsuite/libffi.closures/cls_sshort.c
new file mode 100644
index 00000000..846d57ed
--- /dev/null
+++ b/testsuite/libffi.closures/cls_sshort.c
@@ -0,0 +1,42 @@
+/* Area: closure_call
+ Purpose: Check return value sshort.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20031108 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void cls_ret_sshort_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ *(ffi_arg*)resp = *(signed short *)args[0];
+ printf("%d: %d\n",*(signed short *)args[0],
+ (int)*(ffi_arg *)(resp));
+}
+typedef signed short (*cls_ret_sshort)(signed short);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ signed short res;
+
+ cl_arg_types[0] = &ffi_type_sshort;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_sshort, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_sshort_fn, NULL, code) == FFI_OK);
+
+ res = (*((cls_ret_sshort)code))(255);
+ /* { dg-output "255: 255" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 255" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_struct_va1.c b/testsuite/libffi.closures/cls_struct_va1.c
new file mode 100644
index 00000000..6d1fdaeb
--- /dev/null
+++ b/testsuite/libffi.closures/cls_struct_va1.c
@@ -0,0 +1,114 @@
+/* Area: ffi_call, closure_call
+ Purpose: Test doubles passed in variable argument lists.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/6/2007 */
+
+/* { dg-do run } */
+/* { dg-output "" { xfail avr32*-*-* } } */
+#include "ffitest.h"
+
+struct small_tag
+{
+ unsigned char a;
+ unsigned char b;
+};
+
+struct large_tag
+{
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned d;
+ unsigned e;
+};
+
+static void
+test_fn (ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ int n = *(int*)args[0];
+ struct small_tag s1 = * (struct small_tag *) args[1];
+ struct large_tag l1 = * (struct large_tag *) args[2];
+ struct small_tag s2 = * (struct small_tag *) args[3];
+
+ printf ("%d %d %d %d %d %d %d %d %d %d\n", n, s1.a, s1.b,
+ l1.a, l1.b, l1.c, l1.d, l1.e,
+ s2.a, s2.b);
+ * (ffi_arg*) resp = 42;
+}
+
+int
+main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc (sizeof (ffi_closure), &code);
+ ffi_type* arg_types[5];
+
+ ffi_arg res = 0;
+
+ ffi_type s_type;
+ ffi_type *s_type_elements[3];
+
+ ffi_type l_type;
+ ffi_type *l_type_elements[6];
+
+ struct small_tag s1;
+ struct small_tag s2;
+ struct large_tag l1;
+
+ int si;
+
+ s_type.size = 0;
+ s_type.alignment = 0;
+ s_type.type = FFI_TYPE_STRUCT;
+ s_type.elements = s_type_elements;
+
+ s_type_elements[0] = &ffi_type_uchar;
+ s_type_elements[1] = &ffi_type_uchar;
+ s_type_elements[2] = NULL;
+
+ l_type.size = 0;
+ l_type.alignment = 0;
+ l_type.type = FFI_TYPE_STRUCT;
+ l_type.elements = l_type_elements;
+
+ l_type_elements[0] = &ffi_type_uint;
+ l_type_elements[1] = &ffi_type_uint;
+ l_type_elements[2] = &ffi_type_uint;
+ l_type_elements[3] = &ffi_type_uint;
+ l_type_elements[4] = &ffi_type_uint;
+ l_type_elements[5] = NULL;
+
+ arg_types[0] = &ffi_type_sint;
+ arg_types[1] = &s_type;
+ arg_types[2] = &l_type;
+ arg_types[3] = &s_type;
+ arg_types[4] = NULL;
+
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 4, &ffi_type_sint,
+ arg_types) == FFI_OK);
+
+ si = 4;
+ s1.a = 5;
+ s1.b = 6;
+
+ s2.a = 20;
+ s2.b = 21;
+
+ l1.a = 10;
+ l1.b = 11;
+ l1.c = 12;
+ l1.d = 13;
+ l1.e = 14;
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, test_fn, NULL, code) == FFI_OK);
+
+ res = ((int (*)(int, ...))(code))(si, s1, l1, s2);
+ /* { dg-output "4 5 6 10 11 12 13 14 20 21" } */
+ printf("res: %d\n", (int) res);
+ /* { dg-output "\nres: 42" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_uchar.c b/testsuite/libffi.closures/cls_uchar.c
new file mode 100644
index 00000000..c1317e79
--- /dev/null
+++ b/testsuite/libffi.closures/cls_uchar.c
@@ -0,0 +1,42 @@
+/* Area: closure_call
+ Purpose: Check return value uchar.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void cls_ret_uchar_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ *(ffi_arg*)resp = *(unsigned char *)args[0];
+ printf("%d: %d\n",*(unsigned char *)args[0],
+ (int)*(ffi_arg *)(resp));
+}
+typedef unsigned char (*cls_ret_uchar)(unsigned char);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ unsigned char res;
+
+ cl_arg_types[0] = &ffi_type_uchar;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_uchar, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_uchar_fn, NULL, code) == FFI_OK);
+
+ res = (*((cls_ret_uchar)code))(127);
+ /* { dg-output "127: 127" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 127" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_uchar_va.c b/testsuite/libffi.closures/cls_uchar_va.c
new file mode 100644
index 00000000..6491c5b3
--- /dev/null
+++ b/testsuite/libffi.closures/cls_uchar_va.c
@@ -0,0 +1,44 @@
+/* Area: closure_call
+ Purpose: Test anonymous unsigned char argument.
+ Limitations: none.
+ PR: none.
+ Originator: ARM Ltd. */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef unsigned char T;
+
+static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+ {
+ *(ffi_arg *)resp = *(T *)args[0];
+
+ printf("%d: %d %d\n", (int)(*(ffi_arg *)resp), *(T *)args[0], *(T *)args[1]);
+ }
+
+typedef T (*cls_ret_T)(T, ...);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[3];
+ T res;
+
+ cl_arg_types[0] = &ffi_type_uchar;
+ cl_arg_types[1] = &ffi_type_uchar;
+ cl_arg_types[2] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2,
+ &ffi_type_uchar, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_T_fn, NULL, code) == FFI_OK);
+ res = ((((cls_ret_T)code)(67, 4)));
+ /* { dg-output "67: 67 4" } */
+ printf("res: %d\n", res);
+ /* { dg-output "\nres: 67" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_uint.c b/testsuite/libffi.closures/cls_uint.c
new file mode 100644
index 00000000..885cff5c
--- /dev/null
+++ b/testsuite/libffi.closures/cls_uint.c
@@ -0,0 +1,43 @@
+/* Area: closure_call
+ Purpose: Check return value uint.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void cls_ret_uint_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ *(ffi_arg *)resp = *(unsigned int *)args[0];
+
+ printf("%d: %d\n",*(unsigned int *)args[0],
+ (int)*(ffi_arg *)(resp));
+}
+typedef unsigned int (*cls_ret_uint)(unsigned int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ unsigned int res;
+
+ cl_arg_types[0] = &ffi_type_uint;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_uint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_uint_fn, NULL, code) == FFI_OK);
+
+ res = (*((cls_ret_uint)code))(2147483647);
+ /* { dg-output "2147483647: 2147483647" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 2147483647" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_uint_va.c b/testsuite/libffi.closures/cls_uint_va.c
new file mode 100644
index 00000000..b04cfd19
--- /dev/null
+++ b/testsuite/libffi.closures/cls_uint_va.c
@@ -0,0 +1,45 @@
+/* Area: closure_call
+ Purpose: Test anonymous unsigned int argument.
+ Limitations: none.
+ PR: none.
+ Originator: ARM Ltd. */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+typedef unsigned int T;
+
+static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+ {
+ *(ffi_arg *)resp = *(T *)args[0];
+
+ printf("%d: %d %d\n", (int)*(ffi_arg *)resp, *(T *)args[0], *(T *)args[1]);
+ }
+
+typedef T (*cls_ret_T)(T, ...);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[3];
+ T res;
+
+ cl_arg_types[0] = &ffi_type_uint;
+ cl_arg_types[1] = &ffi_type_uint;
+ cl_arg_types[2] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2,
+ &ffi_type_uint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_T_fn, NULL, code) == FFI_OK);
+ res = ((((cls_ret_T)code)(67, 4)));
+ /* { dg-output "67: 67 4" } */
+ printf("res: %d\n", res);
+ /* { dg-output "\nres: 67" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_ulong_va.c b/testsuite/libffi.closures/cls_ulong_va.c
new file mode 100644
index 00000000..0315082e
--- /dev/null
+++ b/testsuite/libffi.closures/cls_ulong_va.c
@@ -0,0 +1,45 @@
+/* Area: closure_call
+ Purpose: Test anonymous unsigned long argument.
+ Limitations: none.
+ PR: none.
+ Originator: ARM Ltd. */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+typedef unsigned long T;
+
+static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+ {
+ *(T *)resp = *(T *)args[0];
+
+ printf("%ld: %ld %ld\n", *(T *)resp, *(T *)args[0], *(T *)args[1]);
+ }
+
+typedef T (*cls_ret_T)(T, ...);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[3];
+ T res;
+
+ cl_arg_types[0] = &ffi_type_ulong;
+ cl_arg_types[1] = &ffi_type_ulong;
+ cl_arg_types[2] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2,
+ &ffi_type_ulong, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_T_fn, NULL, code) == FFI_OK);
+ res = ((((cls_ret_T)code)(67, 4)));
+ /* { dg-output "67: 67 4" } */
+ printf("res: %ld\n", res);
+ /* { dg-output "\nres: 67" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_ulonglong.c b/testsuite/libffi.closures/cls_ulonglong.c
new file mode 100644
index 00000000..62f2cae6
--- /dev/null
+++ b/testsuite/libffi.closures/cls_ulonglong.c
@@ -0,0 +1,47 @@
+/* Area: closure_call
+ Purpose: Check return value long long.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+/* { dg-options "-Wno-format" { target alpha*-dec-osf* } } */
+#include "ffitest.h"
+
+static void cls_ret_ulonglong_fn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ *(unsigned long long *)resp= 0xfffffffffffffffLL ^ *(unsigned long long *)args[0];
+
+ printf("%" PRIuLL ": %" PRIuLL "\n",*(unsigned long long *)args[0],
+ *(unsigned long long *)(resp));
+}
+typedef unsigned long long (*cls_ret_ulonglong)(unsigned long long);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ unsigned long long res;
+
+ cl_arg_types[0] = &ffi_type_uint64;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_uint64, cl_arg_types) == FFI_OK);
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_ulonglong_fn, NULL, code) == FFI_OK);
+ res = (*((cls_ret_ulonglong)code))(214LL);
+ /* { dg-output "214: 1152921504606846761" } */
+ printf("res: %" PRIdLL "\n", res);
+ /* { dg-output "\nres: 1152921504606846761" } */
+
+ res = (*((cls_ret_ulonglong)code))(9223372035854775808LL);
+ /* { dg-output "\n9223372035854775808: 8070450533247928831" } */
+ printf("res: %" PRIdLL "\n", res);
+ /* { dg-output "\nres: 8070450533247928831" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_ushort.c b/testsuite/libffi.closures/cls_ushort.c
new file mode 100644
index 00000000..a00100e0
--- /dev/null
+++ b/testsuite/libffi.closures/cls_ushort.c
@@ -0,0 +1,43 @@
+/* Area: closure_call
+ Purpose: Check return value ushort.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static void cls_ret_ushort_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ *(ffi_arg*)resp = *(unsigned short *)args[0];
+
+ printf("%d: %d\n",*(unsigned short *)args[0],
+ (int)*(ffi_arg *)(resp));
+}
+typedef unsigned short (*cls_ret_ushort)(unsigned short);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ unsigned short res;
+
+ cl_arg_types[0] = &ffi_type_ushort;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_ushort, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_ushort_fn, NULL, code) == FFI_OK);
+
+ res = (*((cls_ret_ushort)code))(65535);
+ /* { dg-output "65535: 65535" } */
+ printf("res: %d\n",res);
+ /* { dg-output "\nres: 65535" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/cls_ushort_va.c b/testsuite/libffi.closures/cls_ushort_va.c
new file mode 100644
index 00000000..37aa1064
--- /dev/null
+++ b/testsuite/libffi.closures/cls_ushort_va.c
@@ -0,0 +1,44 @@
+/* Area: closure_call
+ Purpose: Test anonymous unsigned short argument.
+ Limitations: none.
+ PR: none.
+ Originator: ARM Ltd. */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef unsigned short T;
+
+static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+ {
+ *(ffi_arg *)resp = *(T *)args[0];
+
+ printf("%d: %d %d\n", (int)(*(ffi_arg *)resp), *(T *)args[0], *(T *)args[1]);
+ }
+
+typedef T (*cls_ret_T)(T, ...);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[3];
+ T res;
+
+ cl_arg_types[0] = &ffi_type_ushort;
+ cl_arg_types[1] = &ffi_type_ushort;
+ cl_arg_types[2] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2,
+ &ffi_type_ushort, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_T_fn, NULL, code) == FFI_OK);
+ res = ((((cls_ret_T)code)(67, 4)));
+ /* { dg-output "67: 67 4" } */
+ printf("res: %d\n", res);
+ /* { dg-output "\nres: 67" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/err_bad_abi.c b/testsuite/libffi.closures/err_bad_abi.c
new file mode 100644
index 00000000..f5a73179
--- /dev/null
+++ b/testsuite/libffi.closures/err_bad_abi.c
@@ -0,0 +1,36 @@
+/* Area: ffi_prep_cif, ffi_prep_closure
+ Purpose: Test error return for bad ABIs.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/6/2007 */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+static void
+dummy_fn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__,
+ void** args __UNUSED__, void* userdata __UNUSED__)
+{}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type* arg_types[1];
+
+ arg_types[0] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, 255, 0, &ffi_type_void,
+ arg_types) == FFI_BAD_ABI);
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, &ffi_type_void,
+ arg_types) == FFI_OK);
+
+ cif.abi= 255;
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, dummy_fn, NULL, code) == FFI_BAD_ABI);
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/ffitest.h b/testsuite/libffi.closures/ffitest.h
new file mode 100644
index 00000000..cfce1ad5
--- /dev/null
+++ b/testsuite/libffi.closures/ffitest.h
@@ -0,0 +1,138 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ffi.h>
+#include "fficonfig.h"
+
+#if defined HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#if defined HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#define MAX_ARGS 256
+
+#define CHECK(x) (void)(!(x) ? (abort(), 1) : 0)
+
+/* Define macros so that compilers other than gcc can run the tests. */
+#undef __UNUSED__
+#if defined(__GNUC__)
+#define __UNUSED__ __attribute__((__unused__))
+#define __STDCALL__ __attribute__((stdcall))
+#define __THISCALL__ __attribute__((thiscall))
+#define __FASTCALL__ __attribute__((fastcall))
+#define __MSABI__ __attribute__((ms_abi))
+#else
+#define __UNUSED__
+#define __STDCALL__ __stdcall
+#define __THISCALL__ __thiscall
+#define __FASTCALL__ __fastcall
+#endif
+
+#ifndef ABI_NUM
+#define ABI_NUM FFI_DEFAULT_ABI
+#define ABI_ATTR
+#endif
+
+/* Prefer MAP_ANON(YMOUS) to /dev/zero, since we don't need to keep a
+ file open. */
+#ifdef HAVE_MMAP_ANON
+# undef HAVE_MMAP_DEV_ZERO
+
+# include <sys/mman.h>
+# ifndef MAP_FAILED
+# define MAP_FAILED -1
+# endif
+# if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
+# define MAP_ANONYMOUS MAP_ANON
+# endif
+# define USING_MMAP
+
+#endif
+
+#ifdef HAVE_MMAP_DEV_ZERO
+
+# include <sys/mman.h>
+# ifndef MAP_FAILED
+# define MAP_FAILED -1
+# endif
+# define USING_MMAP
+
+#endif
+
+/* MinGW kludge. */
+#if defined(_WIN64) | defined(_WIN32)
+#define PRIdLL "I64d"
+#define PRIuLL "I64u"
+#else
+#define PRIdLL "lld"
+#define PRIuLL "llu"
+#endif
+
+/* Tru64 UNIX kludge. */
+#if defined(__alpha__) && defined(__osf__)
+/* Tru64 UNIX V4.0 doesn't support %lld/%lld, but long is 64-bit. */
+#undef PRIdLL
+#define PRIdLL "ld"
+#undef PRIuLL
+#define PRIuLL "lu"
+#define PRId8 "hd"
+#define PRIu8 "hu"
+#define PRId64 "ld"
+#define PRIu64 "lu"
+#define PRIuPTR "lu"
+#endif
+
+/* PA HP-UX kludge. */
+#if defined(__hppa__) && defined(__hpux__) && !defined(PRIuPTR)
+#define PRIuPTR "lu"
+#endif
+
+/* IRIX kludge. */
+#if defined(__sgi)
+/* IRIX 6.5 <inttypes.h> provides all definitions, but only for C99
+ compilations. */
+#define PRId8 "hhd"
+#define PRIu8 "hhu"
+#if (_MIPS_SZLONG == 32)
+#define PRId64 "lld"
+#define PRIu64 "llu"
+#endif
+/* This doesn't match <inttypes.h>, which always has "lld" here, but the
+ arguments are uint64_t, int64_t, which are unsigned long, long for
+ 64-bit in <sgidefs.h>. */
+#if (_MIPS_SZLONG == 64)
+#define PRId64 "ld"
+#define PRIu64 "lu"
+#endif
+/* This doesn't match <inttypes.h>, which has "u" here, but the arguments
+ are uintptr_t, which is always unsigned long. */
+#define PRIuPTR "lu"
+#endif
+
+/* Solaris < 10 kludge. */
+#if defined(__sun__) && defined(__svr4__) && !defined(PRIuPTR)
+#if defined(__arch64__) || defined (__x86_64__)
+#define PRIuPTR "lu"
+#else
+#define PRIuPTR "u"
+#endif
+#endif
+
+/* MSVC kludge. */
+#if defined _MSC_VER
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
+#define PRIuPTR "lu"
+#define PRIu8 "u"
+#define PRId8 "d"
+#define PRIu64 "I64u"
+#define PRId64 "I64d"
+#endif
+#endif
+
+#ifndef PRIuPTR
+#define PRIuPTR "u"
+#endif
diff --git a/testsuite/libffi.closures/huge_struct.c b/testsuite/libffi.closures/huge_struct.c
new file mode 100644
index 00000000..1915c3f1
--- /dev/null
+++ b/testsuite/libffi.closures/huge_struct.c
@@ -0,0 +1,341 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check large structure returns.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/18/2007
+*/
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
+/* { dg-options -Wformat=0 { target moxie*-*-elf or1k-*-* } } */
+
+#include "ffitest.h"
+
+typedef struct BigStruct{
+ uint8_t a;
+ int8_t b;
+ uint16_t c;
+ int16_t d;
+ uint32_t e;
+ int32_t f;
+ uint64_t g;
+ int64_t h;
+ float i;
+ double j;
+ long double k;
+ char* l;
+ uint8_t m;
+ int8_t n;
+ uint16_t o;
+ int16_t p;
+ uint32_t q;
+ int32_t r;
+ uint64_t s;
+ int64_t t;
+ float u;
+ double v;
+ long double w;
+ char* x;
+ uint8_t y;
+ int8_t z;
+ uint16_t aa;
+ int16_t bb;
+ uint32_t cc;
+ int32_t dd;
+ uint64_t ee;
+ int64_t ff;
+ float gg;
+ double hh;
+ long double ii;
+ char* jj;
+ uint8_t kk;
+ int8_t ll;
+ uint16_t mm;
+ int16_t nn;
+ uint32_t oo;
+ int32_t pp;
+ uint64_t qq;
+ int64_t rr;
+ float ss;
+ double tt;
+ long double uu;
+ char* vv;
+ uint8_t ww;
+ int8_t xx;
+} BigStruct;
+
+BigStruct
+test_large_fn(
+ uint8_t ui8_1,
+ int8_t si8_1,
+ uint16_t ui16_1,
+ int16_t si16_1,
+ uint32_t ui32_1,
+ int32_t si32_1,
+ uint64_t ui64_1,
+ int64_t si64_1,
+ float f_1,
+ double d_1,
+ long double ld_1,
+ char* p_1,
+ uint8_t ui8_2,
+ int8_t si8_2,
+ uint16_t ui16_2,
+ int16_t si16_2,
+ uint32_t ui32_2,
+ int32_t si32_2,
+ uint64_t ui64_2,
+ int64_t si64_2,
+ float f_2,
+ double d_2,
+ long double ld_2,
+ char* p_2,
+ uint8_t ui8_3,
+ int8_t si8_3,
+ uint16_t ui16_3,
+ int16_t si16_3,
+ uint32_t ui32_3,
+ int32_t si32_3,
+ uint64_t ui64_3,
+ int64_t si64_3,
+ float f_3,
+ double d_3,
+ long double ld_3,
+ char* p_3,
+ uint8_t ui8_4,
+ int8_t si8_4,
+ uint16_t ui16_4,
+ int16_t si16_4,
+ uint32_t ui32_4,
+ int32_t si32_4,
+ uint64_t ui64_4,
+ int64_t si64_4,
+ float f_4,
+ double d_4,
+ long double ld_4,
+ char* p_4,
+ uint8_t ui8_5,
+ int8_t si8_5)
+{
+ BigStruct retVal = {
+ ui8_1 + 1, si8_1 + 1, ui16_1 + 1, si16_1 + 1, ui32_1 + 1, si32_1 + 1,
+ ui64_1 + 1, si64_1 + 1, f_1 + 1, d_1 + 1, ld_1 + 1, (char*)((intptr_t)p_1 + 1),
+ ui8_2 + 2, si8_2 + 2, ui16_2 + 2, si16_2 + 2, ui32_2 + 2, si32_2 + 2,
+ ui64_2 + 2, si64_2 + 2, f_2 + 2, d_2 + 2, ld_2 + 2, (char*)((intptr_t)p_2 + 2),
+ ui8_3 + 3, si8_3 + 3, ui16_3 + 3, si16_3 + 3, ui32_3 + 3, si32_3 + 3,
+ ui64_3 + 3, si64_3 + 3, f_3 + 3, d_3 + 3, ld_3 + 3, (char*)((intptr_t)p_3 + 3),
+ ui8_4 + 4, si8_4 + 4, ui16_4 + 4, si16_4 + 4, ui32_4 + 4, si32_4 + 4,
+ ui64_4 + 4, si64_4 + 4, f_4 + 4, d_4 + 4, ld_4 + 4, (char*)((intptr_t)p_4 + 4),
+ ui8_5 + 5, si8_5 + 5};
+
+ printf("%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx %" PRIu8 " %" PRId8 ": "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx %" PRIu8 " %" PRId8 "\n",
+ ui8_1, si8_1, ui16_1, si16_1, ui32_1, si32_1, ui64_1, si64_1, f_1, d_1, ld_1, (unsigned long)p_1,
+ ui8_2, si8_2, ui16_2, si16_2, ui32_2, si32_2, ui64_2, si64_2, f_2, d_2, ld_2, (unsigned long)p_2,
+ ui8_3, si8_3, ui16_3, si16_3, ui32_3, si32_3, ui64_3, si64_3, f_3, d_3, ld_3, (unsigned long)p_3,
+ ui8_4, si8_4, ui16_4, si16_4, ui32_4, si32_4, ui64_4, si64_4, f_4, d_4, ld_4, (unsigned long)p_4, ui8_5, si8_5,
+ retVal.a, retVal.b, retVal.c, retVal.d, retVal.e, retVal.f,
+ retVal.g, retVal.h, retVal.i, retVal.j, retVal.k, (unsigned long)retVal.l,
+ retVal.m, retVal.n, retVal.o, retVal.p, retVal.q, retVal.r,
+ retVal.s, retVal.t, retVal.u, retVal.v, retVal.w, (unsigned long)retVal.x,
+ retVal.y, retVal.z, retVal.aa, retVal.bb, retVal.cc, retVal.dd,
+ retVal.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (unsigned long)retVal.jj,
+ retVal.kk, retVal.ll, retVal.mm, retVal.nn, retVal.oo, retVal.pp,
+ retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (unsigned long)retVal.vv, retVal.ww, retVal.xx);
+
+ return retVal;
+}
+
+static void
+cls_large_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__)
+{
+ uint8_t ui8_1 = *(uint8_t*)args[0];
+ int8_t si8_1 = *(int8_t*)args[1];
+ uint16_t ui16_1 = *(uint16_t*)args[2];
+ int16_t si16_1 = *(int16_t*)args[3];
+ uint32_t ui32_1 = *(uint32_t*)args[4];
+ int32_t si32_1 = *(int32_t*)args[5];
+ uint64_t ui64_1 = *(uint64_t*)args[6];
+ int64_t si64_1 = *(int64_t*)args[7];
+ float f_1 = *(float*)args[8];
+ double d_1 = *(double*)args[9];
+ long double ld_1 = *(long double*)args[10];
+ char* p_1 = *(char**)args[11];
+ uint8_t ui8_2 = *(uint8_t*)args[12];
+ int8_t si8_2 = *(int8_t*)args[13];
+ uint16_t ui16_2 = *(uint16_t*)args[14];
+ int16_t si16_2 = *(int16_t*)args[15];
+ uint32_t ui32_2 = *(uint32_t*)args[16];
+ int32_t si32_2 = *(int32_t*)args[17];
+ uint64_t ui64_2 = *(uint64_t*)args[18];
+ int64_t si64_2 = *(int64_t*)args[19];
+ float f_2 = *(float*)args[20];
+ double d_2 = *(double*)args[21];
+ long double ld_2 = *(long double*)args[22];
+ char* p_2 = *(char**)args[23];
+ uint8_t ui8_3 = *(uint8_t*)args[24];
+ int8_t si8_3 = *(int8_t*)args[25];
+ uint16_t ui16_3 = *(uint16_t*)args[26];
+ int16_t si16_3 = *(int16_t*)args[27];
+ uint32_t ui32_3 = *(uint32_t*)args[28];
+ int32_t si32_3 = *(int32_t*)args[29];
+ uint64_t ui64_3 = *(uint64_t*)args[30];
+ int64_t si64_3 = *(int64_t*)args[31];
+ float f_3 = *(float*)args[32];
+ double d_3 = *(double*)args[33];
+ long double ld_3 = *(long double*)args[34];
+ char* p_3 = *(char**)args[35];
+ uint8_t ui8_4 = *(uint8_t*)args[36];
+ int8_t si8_4 = *(int8_t*)args[37];
+ uint16_t ui16_4 = *(uint16_t*)args[38];
+ int16_t si16_4 = *(int16_t*)args[39];
+ uint32_t ui32_4 = *(uint32_t*)args[40];
+ int32_t si32_4 = *(int32_t*)args[41];
+ uint64_t ui64_4 = *(uint64_t*)args[42];
+ int64_t si64_4 = *(int64_t*)args[43];
+ float f_4 = *(float*)args[44];
+ double d_4 = *(double*)args[45];
+ long double ld_4 = *(long double*)args[46];
+ char* p_4 = *(char**)args[47];
+ uint8_t ui8_5 = *(uint8_t*)args[48];
+ int8_t si8_5 = *(int8_t*)args[49];
+
+ *(BigStruct*)resp = test_large_fn(
+ ui8_1, si8_1, ui16_1, si16_1, ui32_1, si32_1, ui64_1, si64_1, f_1, d_1, ld_1, p_1,
+ ui8_2, si8_2, ui16_2, si16_2, ui32_2, si32_2, ui64_2, si64_2, f_2, d_2, ld_2, p_2,
+ ui8_3, si8_3, ui16_3, si16_3, ui32_3, si32_3, ui64_3, si64_3, f_3, d_3, ld_3, p_3,
+ ui8_4, si8_4, ui16_4, si16_4, ui32_4, si32_4, ui64_4, si64_4, f_4, d_4, ld_4, p_4,
+ ui8_5, si8_5);
+}
+
+int
+main(int argc __UNUSED__, const char** argv __UNUSED__)
+{
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+
+ ffi_cif cif;
+ ffi_type* argTypes[51];
+ void* argValues[51];
+
+ ffi_type ret_struct_type;
+ ffi_type* st_fields[51];
+ BigStruct retVal;
+
+ uint8_t ui8 = 1;
+ int8_t si8 = 2;
+ uint16_t ui16 = 3;
+ int16_t si16 = 4;
+ uint32_t ui32 = 5;
+ int32_t si32 = 6;
+ uint64_t ui64 = 7;
+ int64_t si64 = 8;
+ float f = 9;
+ double d = 10;
+ long double ld = 11;
+ char* p = (char*)0x12345678;
+
+ memset (&retVal, 0, sizeof(retVal));
+
+ ret_struct_type.size = 0;
+ ret_struct_type.alignment = 0;
+ ret_struct_type.type = FFI_TYPE_STRUCT;
+ ret_struct_type.elements = st_fields;
+
+ st_fields[0] = st_fields[12] = st_fields[24] = st_fields[36] = st_fields[48] = &ffi_type_uint8;
+ st_fields[1] = st_fields[13] = st_fields[25] = st_fields[37] = st_fields[49] = &ffi_type_sint8;
+ st_fields[2] = st_fields[14] = st_fields[26] = st_fields[38] = &ffi_type_uint16;
+ st_fields[3] = st_fields[15] = st_fields[27] = st_fields[39] = &ffi_type_sint16;
+ st_fields[4] = st_fields[16] = st_fields[28] = st_fields[40] = &ffi_type_uint32;
+ st_fields[5] = st_fields[17] = st_fields[29] = st_fields[41] = &ffi_type_sint32;
+ st_fields[6] = st_fields[18] = st_fields[30] = st_fields[42] = &ffi_type_uint64;
+ st_fields[7] = st_fields[19] = st_fields[31] = st_fields[43] = &ffi_type_sint64;
+ st_fields[8] = st_fields[20] = st_fields[32] = st_fields[44] = &ffi_type_float;
+ st_fields[9] = st_fields[21] = st_fields[33] = st_fields[45] = &ffi_type_double;
+ st_fields[10] = st_fields[22] = st_fields[34] = st_fields[46] = &ffi_type_longdouble;
+ st_fields[11] = st_fields[23] = st_fields[35] = st_fields[47] = &ffi_type_pointer;
+
+ st_fields[50] = NULL;
+
+ argTypes[0] = argTypes[12] = argTypes[24] = argTypes[36] = argTypes[48] = &ffi_type_uint8;
+ argValues[0] = argValues[12] = argValues[24] = argValues[36] = argValues[48] = &ui8;
+ argTypes[1] = argTypes[13] = argTypes[25] = argTypes[37] = argTypes[49] = &ffi_type_sint8;
+ argValues[1] = argValues[13] = argValues[25] = argValues[37] = argValues[49] = &si8;
+ argTypes[2] = argTypes[14] = argTypes[26] = argTypes[38] = &ffi_type_uint16;
+ argValues[2] = argValues[14] = argValues[26] = argValues[38] = &ui16;
+ argTypes[3] = argTypes[15] = argTypes[27] = argTypes[39] = &ffi_type_sint16;
+ argValues[3] = argValues[15] = argValues[27] = argValues[39] = &si16;
+ argTypes[4] = argTypes[16] = argTypes[28] = argTypes[40] = &ffi_type_uint32;
+ argValues[4] = argValues[16] = argValues[28] = argValues[40] = &ui32;
+ argTypes[5] = argTypes[17] = argTypes[29] = argTypes[41] = &ffi_type_sint32;
+ argValues[5] = argValues[17] = argValues[29] = argValues[41] = &si32;
+ argTypes[6] = argTypes[18] = argTypes[30] = argTypes[42] = &ffi_type_uint64;
+ argValues[6] = argValues[18] = argValues[30] = argValues[42] = &ui64;
+ argTypes[7] = argTypes[19] = argTypes[31] = argTypes[43] = &ffi_type_sint64;
+ argValues[7] = argValues[19] = argValues[31] = argValues[43] = &si64;
+ argTypes[8] = argTypes[20] = argTypes[32] = argTypes[44] = &ffi_type_float;
+ argValues[8] = argValues[20] = argValues[32] = argValues[44] = &f;
+ argTypes[9] = argTypes[21] = argTypes[33] = argTypes[45] = &ffi_type_double;
+ argValues[9] = argValues[21] = argValues[33] = argValues[45] = &d;
+ argTypes[10] = argTypes[22] = argTypes[34] = argTypes[46] = &ffi_type_longdouble;
+ argValues[10] = argValues[22] = argValues[34] = argValues[46] = &ld;
+ argTypes[11] = argTypes[23] = argTypes[35] = argTypes[47] = &ffi_type_pointer;
+ argValues[11] = argValues[23] = argValues[35] = argValues[47] = &p;
+
+ argTypes[50] = NULL;
+ argValues[50] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 50, &ret_struct_type, argTypes) == FFI_OK);
+
+ ffi_call(&cif, FFI_FN(test_large_fn), &retVal, argValues);
+ /* { dg-output "1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } */
+ printf("res: %" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx %" PRIu8 " %" PRId8 "\n",
+ retVal.a, retVal.b, retVal.c, retVal.d, retVal.e, retVal.f,
+ retVal.g, retVal.h, retVal.i, retVal.j, retVal.k, (unsigned long)retVal.l,
+ retVal.m, retVal.n, retVal.o, retVal.p, retVal.q, retVal.r,
+ retVal.s, retVal.t, retVal.u, retVal.v, retVal.w, (unsigned long)retVal.x,
+ retVal.y, retVal.z, retVal.aa, retVal.bb, retVal.cc, retVal.dd,
+ retVal.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (unsigned long)retVal.jj,
+ retVal.kk, retVal.ll, retVal.mm, retVal.nn, retVal.oo, retVal.pp,
+ retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (unsigned long)retVal.vv, retVal.ww, retVal.xx);
+ /* { dg-output "\nres: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_large_fn, NULL, code) == FFI_OK);
+
+ retVal = ((BigStruct(*)(
+ uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, long double, char*,
+ uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, long double, char*,
+ uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, long double, char*,
+ uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, long double, char*,
+ uint8_t, int8_t))(code))(
+ ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p,
+ ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p,
+ ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p,
+ ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p,
+ ui8, si8);
+ /* { dg-output "\n1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } */
+ printf("res: %" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx "
+ "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx %" PRIu8 " %" PRId8 "\n",
+ retVal.a, retVal.b, retVal.c, retVal.d, retVal.e, retVal.f,
+ retVal.g, retVal.h, retVal.i, retVal.j, retVal.k, (unsigned long)retVal.l,
+ retVal.m, retVal.n, retVal.o, retVal.p, retVal.q, retVal.r,
+ retVal.s, retVal.t, retVal.u, retVal.v, retVal.w, (unsigned long)retVal.x,
+ retVal.y, retVal.z, retVal.aa, retVal.bb, retVal.cc, retVal.dd,
+ retVal.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (unsigned long)retVal.jj,
+ retVal.kk, retVal.ll, retVal.mm, retVal.nn, retVal.oo, retVal.pp,
+ retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (unsigned long)retVal.vv, retVal.ww, retVal.xx);
+ /* { dg-output "\nres: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } */
+
+ return 0;
+}
diff --git a/testsuite/libffi.closures/nested_struct.c b/testsuite/libffi.closures/nested_struct.c
new file mode 100644
index 00000000..c15e3a03
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct.c
@@ -0,0 +1,152 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_16byte1 {
+ double a;
+ float b;
+ int c;
+} cls_struct_16byte1;
+
+typedef struct cls_struct_16byte2 {
+ int ii;
+ double dd;
+ float ff;
+} cls_struct_16byte2;
+
+typedef struct cls_struct_combined {
+ cls_struct_16byte1 d;
+ cls_struct_16byte2 e;
+} cls_struct_combined;
+
+cls_struct_combined cls_struct_combined_fn(struct cls_struct_16byte1 b0,
+ struct cls_struct_16byte2 b1,
+ struct cls_struct_combined b2)
+{
+ struct cls_struct_combined result;
+
+ result.d.a = b0.a + b1.dd + b2.d.a;
+ result.d.b = b0.b + b1.ff + b2.d.b;
+ result.d.c = b0.c + b1.ii + b2.d.c;
+ result.e.ii = b0.c + b1.ii + b2.e.ii;
+ result.e.dd = b0.a + b1.dd + b2.e.dd;
+ result.e.ff = b0.b + b1.ff + b2.e.ff;
+
+ printf("%g %g %d %d %g %g %g %g %d %d %g %g: %g %g %d %d %g %g\n",
+ b0.a, b0.b, b0.c,
+ b1.ii, b1.dd, b1.ff,
+ b2.d.a, b2.d.b, b2.d.c,
+ b2.e.ii, b2.e.dd, b2.e.ff,
+ result.d.a, result.d.b, result.d.c,
+ result.e.ii, result.e.dd, result.e.ff);
+
+ return result;
+}
+
+static void
+cls_struct_combined_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_16byte1 b0;
+ struct cls_struct_16byte2 b1;
+ struct cls_struct_combined b2;
+
+ b0 = *(struct cls_struct_16byte1*)(args[0]);
+ b1 = *(struct cls_struct_16byte2*)(args[1]);
+ b2 = *(struct cls_struct_combined*)(args[2]);
+
+
+ *(cls_struct_combined*)resp = cls_struct_combined_fn(b0, b1, b2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[5];
+ ffi_type* cls_struct_fields1[5];
+ ffi_type* cls_struct_fields2[5];
+ ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_16byte1 e_dbl = { 9.0, 2.0, 6};
+ struct cls_struct_16byte2 f_dbl = { 1, 2.0, 3.0};
+ struct cls_struct_combined g_dbl = {{4.0, 5.0, 6},
+ {3, 1.0, 8.0}};
+ struct cls_struct_combined res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_type2.size = 0;
+ cls_struct_type2.alignment = 0;
+ cls_struct_type2.type = FFI_TYPE_STRUCT;
+ cls_struct_type2.elements = cls_struct_fields2;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_float;
+ cls_struct_fields[2] = &ffi_type_sint;
+ cls_struct_fields[3] = NULL;
+
+ cls_struct_fields1[0] = &ffi_type_sint;
+ cls_struct_fields1[1] = &ffi_type_double;
+ cls_struct_fields1[2] = &ffi_type_float;
+ cls_struct_fields1[3] = NULL;
+
+ cls_struct_fields2[0] = &cls_struct_type;
+ cls_struct_fields2[1] = &cls_struct_type1;
+ cls_struct_fields2[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = &cls_struct_type2;
+ dbl_arg_types[3] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type2,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_combined_fn), &res_dbl, args_dbl);
+ /* { dg-output "9 2 6 1 2 3 4 5 6 3 1 8: 15 10 13 10 12 13" } */
+ CHECK( res_dbl.d.a == (e_dbl.a + f_dbl.dd + g_dbl.d.a));
+ CHECK( res_dbl.d.b == (e_dbl.b + f_dbl.ff + g_dbl.d.b));
+ CHECK( res_dbl.d.c == (e_dbl.c + f_dbl.ii + g_dbl.d.c));
+ CHECK( res_dbl.e.ii == (e_dbl.c + f_dbl.ii + g_dbl.e.ii));
+ CHECK( res_dbl.e.dd == (e_dbl.a + f_dbl.dd + g_dbl.e.dd));
+ CHECK( res_dbl.e.ff == (e_dbl.b + f_dbl.ff + g_dbl.e.ff));
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_combined_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_combined(*)(cls_struct_16byte1,
+ cls_struct_16byte2,
+ cls_struct_combined))
+ (code))(e_dbl, f_dbl, g_dbl);
+ /* { dg-output "\n9 2 6 1 2 3 4 5 6 3 1 8: 15 10 13 10 12 13" } */
+ CHECK( res_dbl.d.a == (e_dbl.a + f_dbl.dd + g_dbl.d.a));
+ CHECK( res_dbl.d.b == (e_dbl.b + f_dbl.ff + g_dbl.d.b));
+ CHECK( res_dbl.d.c == (e_dbl.c + f_dbl.ii + g_dbl.d.c));
+ CHECK( res_dbl.e.ii == (e_dbl.c + f_dbl.ii + g_dbl.e.ii));
+ CHECK( res_dbl.e.dd == (e_dbl.a + f_dbl.dd + g_dbl.e.dd));
+ CHECK( res_dbl.e.ff == (e_dbl.b + f_dbl.ff + g_dbl.e.ff));
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct1.c b/testsuite/libffi.closures/nested_struct1.c
new file mode 100644
index 00000000..477a6b9b
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct1.c
@@ -0,0 +1,161 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_16byte1 {
+ double a;
+ float b;
+ int c;
+} cls_struct_16byte1;
+
+typedef struct cls_struct_16byte2 {
+ int ii;
+ double dd;
+ float ff;
+} cls_struct_16byte2;
+
+typedef struct cls_struct_combined {
+ cls_struct_16byte1 d;
+ cls_struct_16byte2 e;
+} cls_struct_combined;
+
+cls_struct_combined cls_struct_combined_fn(struct cls_struct_16byte1 b0,
+ struct cls_struct_16byte2 b1,
+ struct cls_struct_combined b2,
+ struct cls_struct_16byte1 b3)
+{
+ struct cls_struct_combined result;
+
+ result.d.a = b0.a + b1.dd + b2.d.a;
+ result.d.b = b0.b + b1.ff + b2.d.b;
+ result.d.c = b0.c + b1.ii + b2.d.c;
+ result.e.ii = b0.c + b1.ii + b2.e.ii;
+ result.e.dd = b0.a + b1.dd + b2.e.dd;
+ result.e.ff = b0.b + b1.ff + b2.e.ff;
+
+ printf("%g %g %d %d %g %g %g %g %d %d %g %g %g %g %d: %g %g %d %d %g %g\n",
+ b0.a, b0.b, b0.c,
+ b1.ii, b1.dd, b1.ff,
+ b2.d.a, b2.d.b, b2.d.c,
+ b2.e.ii, b2.e.dd, b2.e.ff,
+ b3.a, b3.b, b3.c,
+ result.d.a, result.d.b, result.d.c,
+ result.e.ii, result.e.dd, result.e.ff);
+
+ return result;
+}
+
+static void
+cls_struct_combined_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct cls_struct_16byte1 b0;
+ struct cls_struct_16byte2 b1;
+ struct cls_struct_combined b2;
+ struct cls_struct_16byte1 b3;
+
+ b0 = *(struct cls_struct_16byte1*)(args[0]);
+ b1 = *(struct cls_struct_16byte2*)(args[1]);
+ b2 = *(struct cls_struct_combined*)(args[2]);
+ b3 = *(struct cls_struct_16byte1*)(args[3]);
+
+
+ *(cls_struct_combined*)resp = cls_struct_combined_fn(b0, b1, b2, b3);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[5];
+ ffi_type* cls_struct_fields1[5];
+ ffi_type* cls_struct_fields2[5];
+ ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_16byte1 e_dbl = { 9.0, 2.0, 6};
+ struct cls_struct_16byte2 f_dbl = { 1, 2.0, 3.0};
+ struct cls_struct_combined g_dbl = {{4.0, 5.0, 6},
+ {3, 1.0, 8.0}};
+ struct cls_struct_16byte1 h_dbl = { 3.0, 2.0, 4};
+ struct cls_struct_combined res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_type2.size = 0;
+ cls_struct_type2.alignment = 0;
+ cls_struct_type2.type = FFI_TYPE_STRUCT;
+ cls_struct_type2.elements = cls_struct_fields2;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_float;
+ cls_struct_fields[2] = &ffi_type_sint;
+ cls_struct_fields[3] = NULL;
+
+ cls_struct_fields1[0] = &ffi_type_sint;
+ cls_struct_fields1[1] = &ffi_type_double;
+ cls_struct_fields1[2] = &ffi_type_float;
+ cls_struct_fields1[3] = NULL;
+
+ cls_struct_fields2[0] = &cls_struct_type;
+ cls_struct_fields2[1] = &cls_struct_type1;
+ cls_struct_fields2[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = &cls_struct_type2;
+ dbl_arg_types[3] = &cls_struct_type;
+ dbl_arg_types[4] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type2,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = &h_dbl;
+ args_dbl[4] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_combined_fn), &res_dbl, args_dbl);
+ /* { dg-output "9 2 6 1 2 3 4 5 6 3 1 8 3 2 4: 15 10 13 10 12 13" } */
+ CHECK( res_dbl.d.a == (e_dbl.a + f_dbl.dd + g_dbl.d.a));
+ CHECK( res_dbl.d.b == (e_dbl.b + f_dbl.ff + g_dbl.d.b));
+ CHECK( res_dbl.d.c == (e_dbl.c + f_dbl.ii + g_dbl.d.c));
+ CHECK( res_dbl.e.ii == (e_dbl.c + f_dbl.ii + g_dbl.e.ii));
+ CHECK( res_dbl.e.dd == (e_dbl.a + f_dbl.dd + g_dbl.e.dd));
+ CHECK( res_dbl.e.ff == (e_dbl.b + f_dbl.ff + g_dbl.e.ff));
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_combined_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((cls_struct_combined(*)(cls_struct_16byte1,
+ cls_struct_16byte2,
+ cls_struct_combined,
+ cls_struct_16byte1))
+ (code))(e_dbl, f_dbl, g_dbl, h_dbl);
+ /* { dg-output "\n9 2 6 1 2 3 4 5 6 3 1 8 3 2 4: 15 10 13 10 12 13" } */
+ CHECK( res_dbl.d.a == (e_dbl.a + f_dbl.dd + g_dbl.d.a));
+ CHECK( res_dbl.d.b == (e_dbl.b + f_dbl.ff + g_dbl.d.b));
+ CHECK( res_dbl.d.c == (e_dbl.c + f_dbl.ii + g_dbl.d.c));
+ CHECK( res_dbl.e.ii == (e_dbl.c + f_dbl.ii + g_dbl.e.ii));
+ CHECK( res_dbl.e.dd == (e_dbl.a + f_dbl.dd + g_dbl.e.dd));
+ CHECK( res_dbl.e.ff == (e_dbl.b + f_dbl.ff + g_dbl.e.ff));
+ /* CHECK( 1 == 0); */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct10.c b/testsuite/libffi.closures/nested_struct10.c
new file mode 100644
index 00000000..3cf2b44a
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct10.c
@@ -0,0 +1,134 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Sample taken from Alan Modras patch to src/prep_cif.c.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20051010 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ unsigned long long a;
+ unsigned char b;
+} A;
+
+typedef struct B {
+ unsigned char y;
+ struct A x;
+ unsigned int z;
+} B;
+
+typedef struct C {
+ unsigned long long d;
+ unsigned char e;
+} C;
+
+static B B_fn(struct A b2, struct B b3, struct C b4)
+{
+ struct B result;
+
+ result.x.a = b2.a + b3.x.a + b3.z + b4.d;
+ result.x.b = b2.b + b3.x.b + b3.y + b4.e;
+ result.y = b2.b + b3.x.b + b4.e;
+ result.z = 0;
+
+ printf("%d %d %d %d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b,
+ (int)b3.x.a, b3.x.b, b3.y, b3.z, (int)b4.d, b4.e,
+ (int)result.x.a, result.x.b, result.y);
+
+ return result;
+}
+
+static void
+B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct A b0;
+ struct B b1;
+ struct C b2;
+
+ b0 = *(struct A*)(args[0]);
+ b1 = *(struct B*)(args[1]);
+ b2 = *(struct C*)(args[2]);
+
+ *(B*)resp = B_fn(b0, b1, b2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[4];
+ ffi_type* cls_struct_fields[3];
+ ffi_type* cls_struct_fields1[4];
+ ffi_type* cls_struct_fields2[3];
+ ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2;
+ ffi_type* dbl_arg_types[4];
+
+ struct A e_dbl = { 1LL, 7};
+ struct B f_dbl = { 99, {12LL , 127}, 255};
+ struct C g_dbl = { 2LL, 9};
+
+ struct B res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_type2.size = 0;
+ cls_struct_type2.alignment = 0;
+ cls_struct_type2.type = FFI_TYPE_STRUCT;
+ cls_struct_type2.elements = cls_struct_fields2;
+
+ cls_struct_fields[0] = &ffi_type_uint64;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ cls_struct_fields1[0] = &ffi_type_uchar;
+ cls_struct_fields1[1] = &cls_struct_type;
+ cls_struct_fields1[2] = &ffi_type_uint;
+ cls_struct_fields1[3] = NULL;
+
+ cls_struct_fields2[0] = &ffi_type_uint64;
+ cls_struct_fields2[1] = &ffi_type_uchar;
+ cls_struct_fields2[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = &cls_struct_type2;
+ dbl_arg_types[3] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type1,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = NULL;
+
+ ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 7 12 127 99 255 2 9: 270 242 143" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + f_dbl.z + g_dbl.d));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e));
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((B(*)(A, B, C))(code))(e_dbl, f_dbl, g_dbl);
+ /* { dg-output "\n1 7 12 127 99 255 2 9: 270 242 143" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + f_dbl.z + g_dbl.d));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct11.c b/testsuite/libffi.closures/nested_struct11.c
new file mode 100644
index 00000000..35104938
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct11.c
@@ -0,0 +1,121 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check parameter passing with nested structs
+ of a single type. This tests the special cases
+ for homogeneous floating-point aggregates in the
+ AArch64 PCS.
+ Limitations: none.
+ PR: none.
+ Originator: ARM Ltd. */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ float a_x;
+ float a_y;
+} A;
+
+typedef struct B {
+ float b_x;
+ float b_y;
+} B;
+
+typedef struct C {
+ A a;
+ B b;
+} C;
+
+static C C_fn (int x, int y, int z, C source, int i, int j, int k)
+{
+ C result;
+ result.a.a_x = source.a.a_x;
+ result.a.a_y = source.a.a_y;
+ result.b.b_x = source.b.b_x;
+ result.b.b_y = source.b.b_y;
+
+ printf ("%d, %d, %d, %d, %d, %d\n", x, y, z, i, j, k);
+
+ printf ("%.1f, %.1f, %.1f, %.1f, "
+ "%.1f, %.1f, %.1f, %.1f\n",
+ source.a.a_x, source.a.a_y,
+ source.b.b_x, source.b.b_y,
+ result.a.a_x, result.a.a_y,
+ result.b.b_x, result.b.b_y);
+
+ return result;
+}
+
+int main (void)
+{
+ ffi_cif cif;
+
+ ffi_type* struct_fields_source_a[3];
+ ffi_type* struct_fields_source_b[3];
+ ffi_type* struct_fields_source_c[3];
+ ffi_type* arg_types[8];
+
+ ffi_type struct_type_a, struct_type_b, struct_type_c;
+
+ struct A source_fld_a = {1.0, 2.0};
+ struct B source_fld_b = {4.0, 8.0};
+ int k = 1;
+
+ struct C result;
+ struct C source = {source_fld_a, source_fld_b};
+
+ struct_type_a.size = 0;
+ struct_type_a.alignment = 0;
+ struct_type_a.type = FFI_TYPE_STRUCT;
+ struct_type_a.elements = struct_fields_source_a;
+
+ struct_type_b.size = 0;
+ struct_type_b.alignment = 0;
+ struct_type_b.type = FFI_TYPE_STRUCT;
+ struct_type_b.elements = struct_fields_source_b;
+
+ struct_type_c.size = 0;
+ struct_type_c.alignment = 0;
+ struct_type_c.type = FFI_TYPE_STRUCT;
+ struct_type_c.elements = struct_fields_source_c;
+
+ struct_fields_source_a[0] = &ffi_type_float;
+ struct_fields_source_a[1] = &ffi_type_float;
+ struct_fields_source_a[2] = NULL;
+
+ struct_fields_source_b[0] = &ffi_type_float;
+ struct_fields_source_b[1] = &ffi_type_float;
+ struct_fields_source_b[2] = NULL;
+
+ struct_fields_source_c[0] = &struct_type_a;
+ struct_fields_source_c[1] = &struct_type_b;
+ struct_fields_source_c[2] = NULL;
+
+ arg_types[0] = &ffi_type_sint32;
+ arg_types[1] = &ffi_type_sint32;
+ arg_types[2] = &ffi_type_sint32;
+ arg_types[3] = &struct_type_c;
+ arg_types[4] = &ffi_type_sint32;
+ arg_types[5] = &ffi_type_sint32;
+ arg_types[6] = &ffi_type_sint32;
+ arg_types[7] = NULL;
+
+ void *args[7];
+ args[0] = &k;
+ args[1] = &k;
+ args[2] = &k;
+ args[3] = &source;
+ args[4] = &k;
+ args[5] = &k;
+ args[6] = &k;
+ CHECK (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, 7, &struct_type_c,
+ arg_types) == FFI_OK);
+
+ ffi_call (&cif, FFI_FN (C_fn), &result, args);
+ /* { dg-output "1, 1, 1, 1, 1, 1\n" } */
+ /* { dg-output "1.0, 2.0, 4.0, 8.0, 1.0, 2.0, 4.0, 8.0" } */
+ CHECK (result.a.a_x == source.a.a_x);
+ CHECK (result.a.a_y == source.a.a_y);
+ CHECK (result.b.b_x == source.b.b_x);
+ CHECK (result.b.b_y == source.b.b_y);
+ exit (0);
+}
diff --git a/testsuite/libffi.closures/nested_struct2.c b/testsuite/libffi.closures/nested_struct2.c
new file mode 100644
index 00000000..69268cdb
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct2.c
@@ -0,0 +1,110 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Sample taken from Alan Modras patch to src/prep_cif.c.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030911 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ unsigned long a;
+ unsigned char b;
+} A;
+
+typedef struct B {
+ struct A x;
+ unsigned char y;
+} B;
+
+B B_fn(struct A b0, struct B b1)
+{
+ struct B result;
+
+ result.x.a = b0.a + b1.x.a;
+ result.x.b = b0.b + b1.x.b + b1.y;
+ result.y = b0.b + b1.x.b;
+
+ printf("%lu %d %lu %d %d: %lu %d %d\n", b0.a, b0.b, b1.x.a, b1.x.b, b1.y,
+ result.x.a, result.x.b, result.y);
+
+ return result;
+}
+
+static void
+B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct A b0;
+ struct B b1;
+
+ b0 = *(struct A*)(args[0]);
+ b1 = *(struct B*)(args[1]);
+
+ *(B*)resp = B_fn(b0, b1);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[3];
+ ffi_type* cls_struct_fields1[3];
+ ffi_type cls_struct_type, cls_struct_type1;
+ ffi_type* dbl_arg_types[3];
+
+ struct A e_dbl = { 1, 7};
+ struct B f_dbl = {{12 , 127}, 99};
+
+ struct B res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_fields[0] = &ffi_type_ulong;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ cls_struct_fields1[0] = &cls_struct_type;
+ cls_struct_fields1[1] = &ffi_type_uchar;
+ cls_struct_fields1[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl);
+ /* { dg-output "\n1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct3.c b/testsuite/libffi.closures/nested_struct3.c
new file mode 100644
index 00000000..ab18cad7
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct3.c
@@ -0,0 +1,111 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Sample taken from Alan Modras patch to src/prep_cif.c.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030911 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ unsigned long long a;
+ unsigned char b;
+} A;
+
+typedef struct B {
+ struct A x;
+ unsigned char y;
+} B;
+
+B B_fn(struct A b0, struct B b1)
+{
+ struct B result;
+
+ result.x.a = b0.a + b1.x.a;
+ result.x.b = b0.b + b1.x.b + b1.y;
+ result.y = b0.b + b1.x.b;
+
+ printf("%d %d %d %d %d: %d %d %d\n", (int)b0.a, b0.b,
+ (int)b1.x.a, b1.x.b, b1.y,
+ (int)result.x.a, result.x.b, result.y);
+
+ return result;
+}
+
+static void
+B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct A b0;
+ struct B b1;
+
+ b0 = *(struct A*)(args[0]);
+ b1 = *(struct B*)(args[1]);
+
+ *(B*)resp = B_fn(b0, b1);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[3];
+ ffi_type* cls_struct_fields1[3];
+ ffi_type cls_struct_type, cls_struct_type1;
+ ffi_type* dbl_arg_types[3];
+
+ struct A e_dbl = { 1LL, 7};
+ struct B f_dbl = {{12LL , 127}, 99};
+
+ struct B res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_fields[0] = &ffi_type_uint64;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ cls_struct_fields1[0] = &cls_struct_type;
+ cls_struct_fields1[1] = &ffi_type_uchar;
+ cls_struct_fields1[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl);
+ /* { dg-output "\n1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct4.c b/testsuite/libffi.closures/nested_struct4.c
new file mode 100644
index 00000000..2ffb4d65
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct4.c
@@ -0,0 +1,111 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Sample taken from Alan Modras patch to src/prep_cif.c.
+ Limitations: none.
+ PR: PR 25630.
+ Originator: <andreast@gcc.gnu.org> 20051010 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ double a;
+ unsigned char b;
+} A;
+
+typedef struct B {
+ struct A x;
+ unsigned char y;
+} B;
+
+static B B_fn(struct A b2, struct B b3)
+{
+ struct B result;
+
+ result.x.a = b2.a + b3.x.a;
+ result.x.b = b2.b + b3.x.b + b3.y;
+ result.y = b2.b + b3.x.b;
+
+ printf("%d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b,
+ (int)b3.x.a, b3.x.b, b3.y,
+ (int)result.x.a, result.x.b, result.y);
+
+ return result;
+}
+
+static void
+B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct A b0;
+ struct B b1;
+
+ b0 = *(struct A*)(args[0]);
+ b1 = *(struct B*)(args[1]);
+
+ *(B*)resp = B_fn(b0, b1);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[3];
+ ffi_type* cls_struct_fields1[3];
+ ffi_type cls_struct_type, cls_struct_type1;
+ ffi_type* dbl_arg_types[3];
+
+ struct A e_dbl = { 1.0, 7};
+ struct B f_dbl = {{12.0 , 127}, 99};
+
+ struct B res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ cls_struct_fields1[0] = &cls_struct_type;
+ cls_struct_fields1[1] = &ffi_type_uchar;
+ cls_struct_fields1[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl);
+ /* { dg-output "\n1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct5.c b/testsuite/libffi.closures/nested_struct5.c
new file mode 100644
index 00000000..6c79845d
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct5.c
@@ -0,0 +1,112 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Sample taken from Alan Modras patch to src/prep_cif.c.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20051010 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ long double a;
+ unsigned char b;
+} A;
+
+typedef struct B {
+ struct A x;
+ unsigned char y;
+} B;
+
+static B B_fn(struct A b2, struct B b3)
+{
+ struct B result;
+
+ result.x.a = b2.a + b3.x.a;
+ result.x.b = b2.b + b3.x.b + b3.y;
+ result.y = b2.b + b3.x.b;
+
+ printf("%d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b,
+ (int)b3.x.a, b3.x.b, b3.y,
+ (int)result.x.a, result.x.b, result.y);
+
+ return result;
+}
+
+static void
+B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct A b0;
+ struct B b1;
+
+ b0 = *(struct A*)(args[0]);
+ b1 = *(struct B*)(args[1]);
+
+ *(B*)resp = B_fn(b0, b1);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[3];
+ ffi_type* cls_struct_fields1[3];
+ ffi_type cls_struct_type, cls_struct_type1;
+ ffi_type* dbl_arg_types[3];
+
+ struct A e_dbl = { 1.0, 7};
+ struct B f_dbl = {{12.0 , 127}, 99};
+
+ struct B res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_fields[0] = &ffi_type_longdouble;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ cls_struct_fields1[0] = &cls_struct_type;
+ cls_struct_fields1[1] = &ffi_type_uchar;
+ cls_struct_fields1[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl);
+ /* { dg-output "\n1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct6.c b/testsuite/libffi.closures/nested_struct6.c
new file mode 100644
index 00000000..59d35796
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct6.c
@@ -0,0 +1,131 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Sample taken from Alan Modras patch to src/prep_cif.c.
+ Limitations: none.
+ PR: PR 25630.
+ Originator: <andreast@gcc.gnu.org> 20051010 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ double a;
+ unsigned char b;
+} A;
+
+typedef struct B {
+ struct A x;
+ unsigned char y;
+} B;
+
+typedef struct C {
+ long d;
+ unsigned char e;
+} C;
+
+static B B_fn(struct A b2, struct B b3, struct C b4)
+{
+ struct B result;
+
+ result.x.a = b2.a + b3.x.a + b4.d;
+ result.x.b = b2.b + b3.x.b + b3.y + b4.e;
+ result.y = b2.b + b3.x.b + b4.e;
+
+ printf("%d %d %d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b,
+ (int)b3.x.a, b3.x.b, b3.y, (int)b4.d, b4.e,
+ (int)result.x.a, result.x.b, result.y);
+
+ return result;
+}
+
+static void
+B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct A b0;
+ struct B b1;
+ struct C b2;
+
+ b0 = *(struct A*)(args[0]);
+ b1 = *(struct B*)(args[1]);
+ b2 = *(struct C*)(args[2]);
+
+ *(B*)resp = B_fn(b0, b1, b2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[4];
+ ffi_type* cls_struct_fields[3];
+ ffi_type* cls_struct_fields1[3];
+ ffi_type* cls_struct_fields2[3];
+ ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2;
+ ffi_type* dbl_arg_types[4];
+
+ struct A e_dbl = { 1.0, 7};
+ struct B f_dbl = {{12.0 , 127}, 99};
+ struct C g_dbl = { 2, 9};
+
+ struct B res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_type2.size = 0;
+ cls_struct_type2.alignment = 0;
+ cls_struct_type2.type = FFI_TYPE_STRUCT;
+ cls_struct_type2.elements = cls_struct_fields2;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ cls_struct_fields1[0] = &cls_struct_type;
+ cls_struct_fields1[1] = &ffi_type_uchar;
+ cls_struct_fields1[2] = NULL;
+
+ cls_struct_fields2[0] = &ffi_type_slong;
+ cls_struct_fields2[1] = &ffi_type_uchar;
+ cls_struct_fields2[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = &cls_struct_type2;
+ dbl_arg_types[3] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type1,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = NULL;
+
+ ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 7 12 127 99 2 9: 15 242 143" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e));
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((B(*)(A, B, C))(code))(e_dbl, f_dbl, g_dbl);
+ /* { dg-output "\n1 7 12 127 99 2 9: 15 242 143" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct7.c b/testsuite/libffi.closures/nested_struct7.c
new file mode 100644
index 00000000..27595e6f
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct7.c
@@ -0,0 +1,111 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Sample taken from Alan Modras patch to src/prep_cif.c.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20051010 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ unsigned long long a;
+ unsigned char b;
+} A;
+
+typedef struct B {
+ struct A x;
+ unsigned char y;
+} B;
+
+static B B_fn(struct A b2, struct B b3)
+{
+ struct B result;
+
+ result.x.a = b2.a + b3.x.a;
+ result.x.b = b2.b + b3.x.b + b3.y;
+ result.y = b2.b + b3.x.b;
+
+ printf("%d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b,
+ (int)b3.x.a, b3.x.b, b3.y,
+ (int)result.x.a, result.x.b, result.y);
+
+ return result;
+}
+
+static void
+B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct A b0;
+ struct B b1;
+
+ b0 = *(struct A*)(args[0]);
+ b1 = *(struct B*)(args[1]);
+
+ *(B*)resp = B_fn(b0, b1);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[3];
+ ffi_type* cls_struct_fields[3];
+ ffi_type* cls_struct_fields1[3];
+ ffi_type cls_struct_type, cls_struct_type1;
+ ffi_type* dbl_arg_types[3];
+
+ struct A e_dbl = { 1LL, 7};
+ struct B f_dbl = {{12.0 , 127}, 99};
+
+ struct B res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_fields[0] = &ffi_type_uint64;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ cls_struct_fields1[0] = &cls_struct_type;
+ cls_struct_fields1[1] = &ffi_type_uchar;
+ cls_struct_fields1[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl);
+ /* { dg-output "\n1 7 12 127 99: 13 233 134" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct8.c b/testsuite/libffi.closures/nested_struct8.c
new file mode 100644
index 00000000..0e6c6828
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct8.c
@@ -0,0 +1,131 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Sample taken from Alan Modras patch to src/prep_cif.c.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20051010 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ unsigned long long a;
+ unsigned char b;
+} A;
+
+typedef struct B {
+ struct A x;
+ unsigned char y;
+} B;
+
+typedef struct C {
+ unsigned long long d;
+ unsigned char e;
+} C;
+
+static B B_fn(struct A b2, struct B b3, struct C b4)
+{
+ struct B result;
+
+ result.x.a = b2.a + b3.x.a + b4.d;
+ result.x.b = b2.b + b3.x.b + b3.y + b4.e;
+ result.y = b2.b + b3.x.b + b4.e;
+
+ printf("%d %d %d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b,
+ (int)b3.x.a, b3.x.b, b3.y, (int)b4.d, b4.e,
+ (int)result.x.a, result.x.b, result.y);
+
+ return result;
+}
+
+static void
+B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct A b0;
+ struct B b1;
+ struct C b2;
+
+ b0 = *(struct A*)(args[0]);
+ b1 = *(struct B*)(args[1]);
+ b2 = *(struct C*)(args[2]);
+
+ *(B*)resp = B_fn(b0, b1, b2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[4];
+ ffi_type* cls_struct_fields[3];
+ ffi_type* cls_struct_fields1[3];
+ ffi_type* cls_struct_fields2[3];
+ ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2;
+ ffi_type* dbl_arg_types[4];
+
+ struct A e_dbl = { 1LL, 7};
+ struct B f_dbl = {{12LL , 127}, 99};
+ struct C g_dbl = { 2LL, 9};
+
+ struct B res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_type2.size = 0;
+ cls_struct_type2.alignment = 0;
+ cls_struct_type2.type = FFI_TYPE_STRUCT;
+ cls_struct_type2.elements = cls_struct_fields2;
+
+ cls_struct_fields[0] = &ffi_type_uint64;
+ cls_struct_fields[1] = &ffi_type_uchar;
+ cls_struct_fields[2] = NULL;
+
+ cls_struct_fields1[0] = &cls_struct_type;
+ cls_struct_fields1[1] = &ffi_type_uchar;
+ cls_struct_fields1[2] = NULL;
+
+ cls_struct_fields2[0] = &ffi_type_uint64;
+ cls_struct_fields2[1] = &ffi_type_uchar;
+ cls_struct_fields2[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = &cls_struct_type2;
+ dbl_arg_types[3] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type1,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = NULL;
+
+ ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 7 12 127 99 2 9: 15 242 143" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e));
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((B(*)(A, B, C))(code))(e_dbl, f_dbl, g_dbl);
+ /* { dg-output "\n1 7 12 127 99 2 9: 15 242 143" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/nested_struct9.c b/testsuite/libffi.closures/nested_struct9.c
new file mode 100644
index 00000000..5f7ac677
--- /dev/null
+++ b/testsuite/libffi.closures/nested_struct9.c
@@ -0,0 +1,131 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Contains structs as parameter of the struct itself.
+ Sample taken from Alan Modras patch to src/prep_cif.c.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20051010 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct A {
+ unsigned char a;
+ unsigned long long b;
+} A;
+
+typedef struct B {
+ struct A x;
+ unsigned char y;
+} B;
+
+typedef struct C {
+ unsigned long d;
+ unsigned char e;
+} C;
+
+static B B_fn(struct A b2, struct B b3, struct C b4)
+{
+ struct B result;
+
+ result.x.a = b2.a + b3.x.a + b4.d;
+ result.x.b = b2.b + b3.x.b + b3.y + b4.e;
+ result.y = b2.b + b3.x.b + b4.e;
+
+ printf("%d %d %d %d %d %d %d: %d %d %d\n", b2.a, (int)b2.b,
+ b3.x.a, (int)b3.x.b, b3.y, (int)b4.d, b4.e,
+ result.x.a, (int)result.x.b, result.y);
+
+ return result;
+}
+
+static void
+B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct A b0;
+ struct B b1;
+ struct C b2;
+
+ b0 = *(struct A*)(args[0]);
+ b1 = *(struct B*)(args[1]);
+ b2 = *(struct C*)(args[2]);
+
+ *(B*)resp = B_fn(b0, b1, b2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[4];
+ ffi_type* cls_struct_fields[3];
+ ffi_type* cls_struct_fields1[3];
+ ffi_type* cls_struct_fields2[3];
+ ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2;
+ ffi_type* dbl_arg_types[4];
+
+ struct A e_dbl = { 1, 7LL};
+ struct B f_dbl = {{12.0 , 127}, 99};
+ struct C g_dbl = { 2, 9};
+
+ struct B res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_type1.size = 0;
+ cls_struct_type1.alignment = 0;
+ cls_struct_type1.type = FFI_TYPE_STRUCT;
+ cls_struct_type1.elements = cls_struct_fields1;
+
+ cls_struct_type2.size = 0;
+ cls_struct_type2.alignment = 0;
+ cls_struct_type2.type = FFI_TYPE_STRUCT;
+ cls_struct_type2.elements = cls_struct_fields2;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &ffi_type_uint64;
+ cls_struct_fields[2] = NULL;
+
+ cls_struct_fields1[0] = &cls_struct_type;
+ cls_struct_fields1[1] = &ffi_type_uchar;
+ cls_struct_fields1[2] = NULL;
+
+ cls_struct_fields2[0] = &ffi_type_ulong;
+ cls_struct_fields2[1] = &ffi_type_uchar;
+ cls_struct_fields2[2] = NULL;
+
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type1;
+ dbl_arg_types[2] = &cls_struct_type2;
+ dbl_arg_types[3] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type1,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = NULL;
+
+ ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
+ /* { dg-output "1 7 12 127 99 2 9: 15 242 143" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e));
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((B(*)(A, B, C))(code))(e_dbl, f_dbl, g_dbl);
+ /* { dg-output "\n1 7 12 127 99 2 9: 15 242 143" } */
+ CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d));
+ CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e));
+ CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/problem1.c b/testsuite/libffi.closures/problem1.c
new file mode 100644
index 00000000..6a91555a
--- /dev/null
+++ b/testsuite/libffi.closures/problem1.c
@@ -0,0 +1,90 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure passing with different structure size.
+ Limitations: none.
+ PR: none.
+ Originator: <andreast@gcc.gnu.org> 20030828 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct my_ffi_struct {
+ double a;
+ double b;
+ double c;
+} my_ffi_struct;
+
+my_ffi_struct callee(struct my_ffi_struct a1, struct my_ffi_struct a2)
+{
+ struct my_ffi_struct result;
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+
+ printf("%g %g %g %g %g %g: %g %g %g\n", a1.a, a1.b, a1.c,
+ a2.a, a2.b, a2.c, result.a, result.b, result.c);
+
+ return result;
+}
+
+void stub(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+ struct my_ffi_struct a1;
+ struct my_ffi_struct a2;
+
+ a1 = *(struct my_ffi_struct*)(args[0]);
+ a2 = *(struct my_ffi_struct*)(args[1]);
+
+ *(my_ffi_struct *)resp = callee(a1, a2);
+}
+
+
+int main(void)
+{
+ ffi_type* my_ffi_struct_fields[4];
+ ffi_type my_ffi_struct_type;
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args[4];
+ ffi_type* arg_types[3];
+
+ struct my_ffi_struct g = { 1.0, 2.0, 3.0 };
+ struct my_ffi_struct f = { 1.0, 2.0, 3.0 };
+ struct my_ffi_struct res;
+
+ my_ffi_struct_type.size = 0;
+ my_ffi_struct_type.alignment = 0;
+ my_ffi_struct_type.type = FFI_TYPE_STRUCT;
+ my_ffi_struct_type.elements = my_ffi_struct_fields;
+
+ my_ffi_struct_fields[0] = &ffi_type_double;
+ my_ffi_struct_fields[1] = &ffi_type_double;
+ my_ffi_struct_fields[2] = &ffi_type_double;
+ my_ffi_struct_fields[3] = NULL;
+
+ arg_types[0] = &my_ffi_struct_type;
+ arg_types[1] = &my_ffi_struct_type;
+ arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &my_ffi_struct_type,
+ arg_types) == FFI_OK);
+
+ args[0] = &g;
+ args[1] = &f;
+ args[2] = NULL;
+ ffi_call(&cif, FFI_FN(callee), &res, args);
+ /* { dg-output "1 2 3 1 2 3: 2 4 6" } */
+ printf("res: %g %g %g\n", res.a, res.b, res.c);
+ /* { dg-output "\nres: 2 4 6" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, stub, NULL, code) == FFI_OK);
+
+ res = ((my_ffi_struct(*)(struct my_ffi_struct, struct my_ffi_struct))(code))(g, f);
+ /* { dg-output "\n1 2 3 1 2 3: 2 4 6" } */
+ printf("res: %g %g %g\n", res.a, res.b, res.c);
+ /* { dg-output "\nres: 2 4 6" } */
+
+ exit(0);;
+}
diff --git a/testsuite/libffi.closures/stret_large.c b/testsuite/libffi.closures/stret_large.c
new file mode 100644
index 00000000..71c2469e
--- /dev/null
+++ b/testsuite/libffi.closures/stret_large.c
@@ -0,0 +1,145 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure returning with different structure size.
+ Depending on the ABI. Check bigger struct which overlaps
+ the gp and fp register count on Darwin/AIX/ppc64.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/21/2007 */
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+#include "ffitest.h"
+
+/* 13 FPRs: 104 bytes */
+/* 14 FPRs: 112 bytes */
+
+typedef struct struct_108byte {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ double g;
+ double h;
+ double i;
+ double j;
+ double k;
+ double l;
+ double m;
+ int n;
+} struct_108byte;
+
+struct_108byte cls_struct_108byte_fn(
+ struct_108byte b0,
+ struct_108byte b1,
+ struct_108byte b2,
+ struct_108byte b3)
+{
+ struct_108byte result;
+
+ result.a = b0.a + b1.a + b2.a + b3.a;
+ result.b = b0.b + b1.b + b2.b + b3.b;
+ result.c = b0.c + b1.c + b2.c + b3.c;
+ result.d = b0.d + b1.d + b2.d + b3.d;
+ result.e = b0.e + b1.e + b2.e + b3.e;
+ result.f = b0.f + b1.f + b2.f + b3.f;
+ result.g = b0.g + b1.g + b2.g + b3.g;
+ result.h = b0.h + b1.h + b2.h + b3.h;
+ result.i = b0.i + b1.i + b2.i + b3.i;
+ result.j = b0.j + b1.j + b2.j + b3.j;
+ result.k = b0.k + b1.k + b2.k + b3.k;
+ result.l = b0.l + b1.l + b2.l + b3.l;
+ result.m = b0.m + b1.m + b2.m + b3.m;
+ result.n = b0.n + b1.n + b2.n + b3.n;
+
+ printf("%g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", result.a, result.b, result.c,
+ result.d, result.e, result.f, result.g, result.h, result.i,
+ result.j, result.k, result.l, result.m, result.n);
+
+ return result;
+}
+
+static void
+cls_struct_108byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__)
+{
+ struct_108byte b0, b1, b2, b3;
+
+ b0 = *(struct_108byte*)(args[0]);
+ b1 = *(struct_108byte*)(args[1]);
+ b2 = *(struct_108byte*)(args[2]);
+ b3 = *(struct_108byte*)(args[3]);
+
+ *(struct_108byte*)resp = cls_struct_108byte_fn(b0, b1, b2, b3);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[15];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct_108byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0, 1.0, 2.0, 3.0, 7.0, 2.0, 7 };
+ struct_108byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0, 4.0, 5.0, 7.0, 9.0, 1.0, 4 };
+ struct_108byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0, 8.0, 6.0, 1.0, 4.0, 0.0, 3 };
+ struct_108byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0, 9.0, 2.0, 6.0, 5.0, 3.0, 2 };
+ struct_108byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_double;
+ cls_struct_fields[3] = &ffi_type_double;
+ cls_struct_fields[4] = &ffi_type_double;
+ cls_struct_fields[5] = &ffi_type_double;
+ cls_struct_fields[6] = &ffi_type_double;
+ cls_struct_fields[7] = &ffi_type_double;
+ cls_struct_fields[8] = &ffi_type_double;
+ cls_struct_fields[9] = &ffi_type_double;
+ cls_struct_fields[10] = &ffi_type_double;
+ cls_struct_fields[11] = &ffi_type_double;
+ cls_struct_fields[12] = &ffi_type_double;
+ cls_struct_fields[13] = &ffi_type_sint32;
+ cls_struct_fields[14] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = &cls_struct_type;
+ dbl_arg_types[3] = &cls_struct_type;
+ dbl_arg_types[4] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = &h_dbl;
+ args_dbl[4] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_108byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "22 15 17 25 6 13 19 18 22 15 17 25 6 16" } */
+ printf("res: %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", res_dbl.a, res_dbl.b,
+ res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i,
+ res_dbl.j, res_dbl.k, res_dbl.l, res_dbl.m, res_dbl.n);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18 22 15 17 25 6 16" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_108byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((struct_108byte(*)(struct_108byte, struct_108byte,
+ struct_108byte, struct_108byte))(code))(e_dbl, f_dbl, g_dbl, h_dbl);
+ /* { dg-output "\n22 15 17 25 6 13 19 18 22 15 17 25 6 16" } */
+ printf("res: %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", res_dbl.a, res_dbl.b,
+ res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i,
+ res_dbl.j, res_dbl.k, res_dbl.l, res_dbl.m, res_dbl.n);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18 22 15 17 25 6 16" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/stret_large2.c b/testsuite/libffi.closures/stret_large2.c
new file mode 100644
index 00000000..d9c750ee
--- /dev/null
+++ b/testsuite/libffi.closures/stret_large2.c
@@ -0,0 +1,148 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure returning with different structure size.
+ Depending on the ABI. Check bigger struct which overlaps
+ the gp and fp register count on Darwin/AIX/ppc64.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/21/2007 */
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+#include "ffitest.h"
+
+/* 13 FPRs: 104 bytes */
+/* 14 FPRs: 112 bytes */
+
+typedef struct struct_116byte {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ double g;
+ double h;
+ double i;
+ double j;
+ double k;
+ double l;
+ double m;
+ double n;
+ int o;
+} struct_116byte;
+
+struct_116byte cls_struct_116byte_fn(
+ struct_116byte b0,
+ struct_116byte b1,
+ struct_116byte b2,
+ struct_116byte b3)
+{
+ struct_116byte result;
+
+ result.a = b0.a + b1.a + b2.a + b3.a;
+ result.b = b0.b + b1.b + b2.b + b3.b;
+ result.c = b0.c + b1.c + b2.c + b3.c;
+ result.d = b0.d + b1.d + b2.d + b3.d;
+ result.e = b0.e + b1.e + b2.e + b3.e;
+ result.f = b0.f + b1.f + b2.f + b3.f;
+ result.g = b0.g + b1.g + b2.g + b3.g;
+ result.h = b0.h + b1.h + b2.h + b3.h;
+ result.i = b0.i + b1.i + b2.i + b3.i;
+ result.j = b0.j + b1.j + b2.j + b3.j;
+ result.k = b0.k + b1.k + b2.k + b3.k;
+ result.l = b0.l + b1.l + b2.l + b3.l;
+ result.m = b0.m + b1.m + b2.m + b3.m;
+ result.n = b0.n + b1.n + b2.n + b3.n;
+ result.o = b0.o + b1.o + b2.o + b3.o;
+
+ printf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", result.a, result.b, result.c,
+ result.d, result.e, result.f, result.g, result.h, result.i,
+ result.j, result.k, result.l, result.m, result.n, result.o);
+
+ return result;
+}
+
+static void
+cls_struct_116byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__)
+{
+ struct_116byte b0, b1, b2, b3;
+
+ b0 = *(struct_116byte*)(args[0]);
+ b1 = *(struct_116byte*)(args[1]);
+ b2 = *(struct_116byte*)(args[2]);
+ b3 = *(struct_116byte*)(args[3]);
+
+ *(struct_116byte*)resp = cls_struct_116byte_fn(b0, b1, b2, b3);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[16];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct_116byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0, 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 7 };
+ struct_116byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0, 4.0, 5.0, 7.0, 9.0, 1.0, 6.0, 4 };
+ struct_116byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0, 8.0, 6.0, 1.0, 4.0, 0.0, 7.0, 3 };
+ struct_116byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0, 9.0, 2.0, 6.0, 5.0, 3.0, 8.0, 2 };
+ struct_116byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_double;
+ cls_struct_fields[3] = &ffi_type_double;
+ cls_struct_fields[4] = &ffi_type_double;
+ cls_struct_fields[5] = &ffi_type_double;
+ cls_struct_fields[6] = &ffi_type_double;
+ cls_struct_fields[7] = &ffi_type_double;
+ cls_struct_fields[8] = &ffi_type_double;
+ cls_struct_fields[9] = &ffi_type_double;
+ cls_struct_fields[10] = &ffi_type_double;
+ cls_struct_fields[11] = &ffi_type_double;
+ cls_struct_fields[12] = &ffi_type_double;
+ cls_struct_fields[13] = &ffi_type_double;
+ cls_struct_fields[14] = &ffi_type_sint32;
+ cls_struct_fields[15] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = &cls_struct_type;
+ dbl_arg_types[3] = &cls_struct_type;
+ dbl_arg_types[4] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = &h_dbl;
+ args_dbl[4] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_116byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "22 15 17 25 6 13 19 18 22 15 17 25 6 26 16" } */
+ printf("res: %g %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", res_dbl.a, res_dbl.b,
+ res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i,
+ res_dbl.j, res_dbl.k, res_dbl.l, res_dbl.m, res_dbl.n, res_dbl.o);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18 22 15 17 25 6 26 16" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_116byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((struct_116byte(*)(struct_116byte, struct_116byte,
+ struct_116byte, struct_116byte))(code))(e_dbl, f_dbl, g_dbl, h_dbl);
+ /* { dg-output "\n22 15 17 25 6 13 19 18 22 15 17 25 6 26 16" } */
+ printf("res: %g %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", res_dbl.a, res_dbl.b,
+ res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i,
+ res_dbl.j, res_dbl.k, res_dbl.l, res_dbl.m, res_dbl.n, res_dbl.o);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18 22 15 17 25 6 26 16" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/stret_medium.c b/testsuite/libffi.closures/stret_medium.c
new file mode 100644
index 00000000..973ee02e
--- /dev/null
+++ b/testsuite/libffi.closures/stret_medium.c
@@ -0,0 +1,124 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure returning with different structure size.
+ Depending on the ABI. Check bigger struct which overlaps
+ the gp and fp register count on Darwin/AIX/ppc64.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/21/2007 */
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+#include "ffitest.h"
+
+typedef struct struct_72byte {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ double g;
+ double h;
+ double i;
+} struct_72byte;
+
+struct_72byte cls_struct_72byte_fn(
+ struct_72byte b0,
+ struct_72byte b1,
+ struct_72byte b2,
+ struct_72byte b3)
+{
+ struct_72byte result;
+
+ result.a = b0.a + b1.a + b2.a + b3.a;
+ result.b = b0.b + b1.b + b2.b + b3.b;
+ result.c = b0.c + b1.c + b2.c + b3.c;
+ result.d = b0.d + b1.d + b2.d + b3.d;
+ result.e = b0.e + b1.e + b2.e + b3.e;
+ result.f = b0.f + b1.f + b2.f + b3.f;
+ result.g = b0.g + b1.g + b2.g + b3.g;
+ result.h = b0.h + b1.h + b2.h + b3.h;
+ result.i = b0.i + b1.i + b2.i + b3.i;
+
+ printf("%g %g %g %g %g %g %g %g %g\n", result.a, result.b, result.c,
+ result.d, result.e, result.f, result.g, result.h, result.i);
+
+ return result;
+}
+
+static void
+cls_struct_72byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__)
+{
+ struct_72byte b0, b1, b2, b3;
+
+ b0 = *(struct_72byte*)(args[0]);
+ b1 = *(struct_72byte*)(args[1]);
+ b2 = *(struct_72byte*)(args[2]);
+ b3 = *(struct_72byte*)(args[3]);
+
+ *(struct_72byte*)resp = cls_struct_72byte_fn(b0, b1, b2, b3);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[10];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct_72byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0, 7.0 };
+ struct_72byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0, 4.0 };
+ struct_72byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0, 3.0 };
+ struct_72byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0, 2.0 };
+ struct_72byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_double;
+ cls_struct_fields[3] = &ffi_type_double;
+ cls_struct_fields[4] = &ffi_type_double;
+ cls_struct_fields[5] = &ffi_type_double;
+ cls_struct_fields[6] = &ffi_type_double;
+ cls_struct_fields[7] = &ffi_type_double;
+ cls_struct_fields[8] = &ffi_type_double;
+ cls_struct_fields[9] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = &cls_struct_type;
+ dbl_arg_types[3] = &cls_struct_type;
+ dbl_arg_types[4] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = &h_dbl;
+ args_dbl[4] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_72byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "22 15 17 25 6 13 19 18 16" } */
+ printf("res: %g %g %g %g %g %g %g %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_72byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((struct_72byte(*)(struct_72byte, struct_72byte,
+ struct_72byte, struct_72byte))(code))(e_dbl, f_dbl, g_dbl, h_dbl);
+ /* { dg-output "\n22 15 17 25 6 13 19 18 16" } */
+ printf("res: %g %g %g %g %g %g %g %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/stret_medium2.c b/testsuite/libffi.closures/stret_medium2.c
new file mode 100644
index 00000000..84323d16
--- /dev/null
+++ b/testsuite/libffi.closures/stret_medium2.c
@@ -0,0 +1,125 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure returning with different structure size.
+ Depending on the ABI. Check bigger struct which overlaps
+ the gp and fp register count on Darwin/AIX/ppc64.
+ Limitations: none.
+ PR: none.
+ Originator: Blake Chaffin 6/21/2007 */
+
+/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
+/* { dg-options "-Wno-format" { target alpha*-dec-osf* } } */
+#include "ffitest.h"
+
+typedef struct struct_72byte {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ double g;
+ double h;
+ long long i;
+} struct_72byte;
+
+struct_72byte cls_struct_72byte_fn(
+ struct_72byte b0,
+ struct_72byte b1,
+ struct_72byte b2,
+ struct_72byte b3)
+{
+ struct_72byte result;
+
+ result.a = b0.a + b1.a + b2.a + b3.a;
+ result.b = b0.b + b1.b + b2.b + b3.b;
+ result.c = b0.c + b1.c + b2.c + b3.c;
+ result.d = b0.d + b1.d + b2.d + b3.d;
+ result.e = b0.e + b1.e + b2.e + b3.e;
+ result.f = b0.f + b1.f + b2.f + b3.f;
+ result.g = b0.g + b1.g + b2.g + b3.g;
+ result.h = b0.h + b1.h + b2.h + b3.h;
+ result.i = b0.i + b1.i + b2.i + b3.i;
+
+ printf("%g %g %g %g %g %g %g %g %" PRIdLL "\n", result.a, result.b, result.c,
+ result.d, result.e, result.f, result.g, result.h, result.i);
+
+ return result;
+}
+
+static void
+cls_struct_72byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__)
+{
+ struct_72byte b0, b1, b2, b3;
+
+ b0 = *(struct_72byte*)(args[0]);
+ b1 = *(struct_72byte*)(args[1]);
+ b2 = *(struct_72byte*)(args[2]);
+ b3 = *(struct_72byte*)(args[3]);
+
+ *(struct_72byte*)resp = cls_struct_72byte_fn(b0, b1, b2, b3);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_dbl[5];
+ ffi_type* cls_struct_fields[10];
+ ffi_type cls_struct_type;
+ ffi_type* dbl_arg_types[5];
+
+ struct_72byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0, 7 };
+ struct_72byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0, 4 };
+ struct_72byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0, 3 };
+ struct_72byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0, 2 };
+ struct_72byte res_dbl;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_double;
+ cls_struct_fields[1] = &ffi_type_double;
+ cls_struct_fields[2] = &ffi_type_double;
+ cls_struct_fields[3] = &ffi_type_double;
+ cls_struct_fields[4] = &ffi_type_double;
+ cls_struct_fields[5] = &ffi_type_double;
+ cls_struct_fields[6] = &ffi_type_double;
+ cls_struct_fields[7] = &ffi_type_double;
+ cls_struct_fields[8] = &ffi_type_sint64;
+ cls_struct_fields[9] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type;
+ dbl_arg_types[1] = &cls_struct_type;
+ dbl_arg_types[2] = &cls_struct_type;
+ dbl_arg_types[3] = &cls_struct_type;
+ dbl_arg_types[4] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type,
+ dbl_arg_types) == FFI_OK);
+
+ args_dbl[0] = &e_dbl;
+ args_dbl[1] = &f_dbl;
+ args_dbl[2] = &g_dbl;
+ args_dbl[3] = &h_dbl;
+ args_dbl[4] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_72byte_fn), &res_dbl, args_dbl);
+ /* { dg-output "22 15 17 25 6 13 19 18 16" } */
+ printf("res: %g %g %g %g %g %g %g %g %" PRIdLL "\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_72byte_gn, NULL, code) == FFI_OK);
+
+ res_dbl = ((struct_72byte(*)(struct_72byte, struct_72byte,
+ struct_72byte, struct_72byte))(code))(e_dbl, f_dbl, g_dbl, h_dbl);
+ /* { dg-output "\n22 15 17 25 6 13 19 18 16" } */
+ printf("res: %g %g %g %g %g %g %g %g %" PRIdLL "\n", res_dbl.a, res_dbl.b, res_dbl.c,
+ res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i);
+ /* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/testclosure.c b/testsuite/libffi.closures/testclosure.c
new file mode 100644
index 00000000..ca31056d
--- /dev/null
+++ b/testsuite/libffi.closures/testclosure.c
@@ -0,0 +1,70 @@
+/* Area: closure_call
+ Purpose: Check return value float.
+ Limitations: none.
+ PR: 41908.
+ Originator: <rfm@gnu.org> 20091102 */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct cls_struct_combined {
+ float a;
+ float b;
+ float c;
+ float d;
+} cls_struct_combined;
+
+void cls_struct_combined_fn(struct cls_struct_combined arg)
+{
+ printf("%g %g %g %g\n",
+ arg.a, arg.b,
+ arg.c, arg.d);
+ fflush(stdout);
+}
+
+static void
+cls_struct_combined_gn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__,
+ void** args, void* userdata __UNUSED__)
+{
+ struct cls_struct_combined a0;
+
+ a0 = *(struct cls_struct_combined*)(args[0]);
+
+ cls_struct_combined_fn(a0);
+}
+
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type* cls_struct_fields0[5];
+ ffi_type cls_struct_type0;
+ ffi_type* dbl_arg_types[5];
+
+ struct cls_struct_combined g_dbl = {4.0, 5.0, 1.0, 8.0};
+
+ cls_struct_type0.size = 0;
+ cls_struct_type0.alignment = 0;
+ cls_struct_type0.type = FFI_TYPE_STRUCT;
+ cls_struct_type0.elements = cls_struct_fields0;
+
+ cls_struct_fields0[0] = &ffi_type_float;
+ cls_struct_fields0[1] = &ffi_type_float;
+ cls_struct_fields0[2] = &ffi_type_float;
+ cls_struct_fields0[3] = &ffi_type_float;
+ cls_struct_fields0[4] = NULL;
+
+ dbl_arg_types[0] = &cls_struct_type0;
+ dbl_arg_types[1] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_void,
+ dbl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_combined_gn, NULL, code) == FFI_OK);
+
+ ((void(*)(cls_struct_combined)) (code))(g_dbl);
+ /* { dg-output "4 5 1 8" } */
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/unwindtest.cc b/testsuite/libffi.closures/unwindtest.cc
new file mode 100644
index 00000000..e1145657
--- /dev/null
+++ b/testsuite/libffi.closures/unwindtest.cc
@@ -0,0 +1,117 @@
+/* Area: ffi_closure, unwind info
+ Purpose: Check if the unwind information is passed correctly.
+ Limitations: none.
+ PR: none.
+ Originator: Jeff Sturm <jsturm@one-point.com> */
+
+/* { dg-do run { xfail x86_64-apple-darwin* moxie*-*-* } } */
+
+#include "ffitest.h"
+
+void ABI_ATTR
+closure_test_fn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__,
+ void** args __UNUSED__, void* userdata __UNUSED__)
+{
+ throw 9;
+}
+
+typedef void (*closure_test_type)();
+
+void closure_test_fn1(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+ {
+ *(ffi_arg*)resp =
+ (int)*(float *)args[0] +(int)(*(float *)args[1]) +
+ (int)(*(float *)args[2]) + (int)*(float *)args[3] +
+ (int)(*(signed short *)args[4]) + (int)(*(float *)args[5]) +
+ (int)*(float *)args[6] + (int)(*(int *)args[7]) +
+ (int)(*(double*)args[8]) + (int)*(int *)args[9] +
+ (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(int *)args[13]) +
+ (int)(*(int *)args[14]) + *(int *)args[15] + (int)(intptr_t)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(float *)args[0], (int)(*(float *)args[1]),
+ (int)(*(float *)args[2]), (int)*(float *)args[3],
+ (int)(*(signed short *)args[4]), (int)(*(float *)args[5]),
+ (int)*(float *)args[6], (int)(*(int *)args[7]),
+ (int)(*(double *)args[8]), (int)*(int *)args[9],
+ (int)(*(int *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(int *)args[13]),
+ (int)(*(int *)args[14]), *(int *)args[15],
+ (int)(intptr_t)userdata, (int)*(ffi_arg*)resp);
+
+ throw (int)*(ffi_arg*)resp;
+}
+
+typedef int (*closure_test_type1)(float, float, float, float, signed short,
+ float, float, int, double, int, int, float,
+ int, int, int, int);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = (ffi_closure *)ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[17];
+
+ {
+ cl_arg_types[1] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0,
+ &ffi_type_void, cl_arg_types) == FFI_OK);
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn, NULL, code) == FFI_OK);
+
+ try
+ {
+ (*((closure_test_type)(code)))();
+ } catch (int exception_code)
+ {
+ CHECK(exception_code == 9);
+ }
+
+ printf("part one OK\n");
+ /* { dg-output "part one OK" } */
+ }
+
+ {
+
+ cl_arg_types[0] = &ffi_type_float;
+ cl_arg_types[1] = &ffi_type_float;
+ cl_arg_types[2] = &ffi_type_float;
+ cl_arg_types[3] = &ffi_type_float;
+ cl_arg_types[4] = &ffi_type_sshort;
+ cl_arg_types[5] = &ffi_type_float;
+ cl_arg_types[6] = &ffi_type_float;
+ cl_arg_types[7] = &ffi_type_uint;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_uint;
+ cl_arg_types[10] = &ffi_type_uint;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_uint;
+ cl_arg_types[13] = &ffi_type_uint;
+ cl_arg_types[14] = &ffi_type_uint;
+ cl_arg_types[15] = &ffi_type_uint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn1,
+ (void *) 3 /* userdata */, code) == FFI_OK);
+ try
+ {
+ (*((closure_test_type1)code))
+ (1.1, 2.2, 3.3, 4.4, 127, 5.5, 6.6, 8, 9, 10, 11, 12.0, 13,
+ 19, 21, 1);
+ /* { dg-output "\n1 2 3 4 127 5 6 8 9 10 11 12 13 19 21 1 3: 255" } */
+ } catch (int exception_code)
+ {
+ CHECK(exception_code == 255);
+ }
+ printf("part two OK\n");
+ /* { dg-output "\npart two OK" } */
+ }
+ exit(0);
+}
diff --git a/testsuite/libffi.closures/unwindtest_ffi_call.cc b/testsuite/libffi.closures/unwindtest_ffi_call.cc
new file mode 100644
index 00000000..153d2409
--- /dev/null
+++ b/testsuite/libffi.closures/unwindtest_ffi_call.cc
@@ -0,0 +1,54 @@
+/* Area: ffi_call, unwind info
+ Purpose: Check if the unwind information is passed correctly.
+ Limitations: none.
+ PR: none.
+ Originator: Andreas Tobler <andreast@gcc.gnu.org> 20061213 */
+
+/* { dg-do run { xfail moxie*-*-* } } */
+
+#include "ffitest.h"
+
+static int checking(int a __UNUSED__, short b __UNUSED__,
+ signed char c __UNUSED__)
+{
+ throw 9;
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_type *args[MAX_ARGS];
+ void *values[MAX_ARGS];
+ ffi_arg rint;
+
+ signed int si;
+ signed short ss;
+ signed char sc;
+
+ args[0] = &ffi_type_sint;
+ values[0] = &si;
+ args[1] = &ffi_type_sshort;
+ values[1] = &ss;
+ args[2] = &ffi_type_schar;
+ values[2] = &sc;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3,
+ &ffi_type_sint, args) == FFI_OK);
+
+ si = -6;
+ ss = -12;
+ sc = -1;
+ {
+ try
+ {
+ ffi_call(&cif, FFI_FN(checking), &rint, values);
+ } catch (int exception_code)
+ {
+ CHECK(exception_code == 9);
+ }
+ printf("part one OK\n");
+ /* { dg-output "part one OK" } */
+ }
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/cls_align_complex.inc b/testsuite/libffi.complex/cls_align_complex.inc
new file mode 100644
index 00000000..4a812edf
--- /dev/null
+++ b/testsuite/libffi.complex/cls_align_complex.inc
@@ -0,0 +1,91 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+typedef struct cls_struct_align {
+ unsigned char a;
+ _Complex T_C_TYPE b;
+ unsigned char c;
+} cls_struct_align;
+
+cls_struct_align cls_struct_align_fn(
+ struct cls_struct_align a1, struct cls_struct_align a2)
+{
+ struct cls_struct_align result;
+
+ result.a = a1.a + a2.a;
+ result.b = a1.b + a2.b;
+ result.c = a1.c + a2.c;
+
+ printf("%d %f,%fi %d %d %f,%fi %d: %d %f,%fi %d\n",
+ a1.a, T_CONV creal (a1.b), T_CONV cimag (a1.b), a1.c,
+ a2.a, T_CONV creal (a2.b), T_CONV cimag (a2.b), a2.c,
+ result.a, T_CONV creal (result.b), T_CONV cimag (result.b), result.c);
+
+ return result;
+}
+
+static void
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+{
+
+ struct cls_struct_align a1, a2;
+
+ a1 = *(struct cls_struct_align*)(args[0]);
+ a2 = *(struct cls_struct_align*)(args[1]);
+
+ *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args_c[5];
+ ffi_type* cls_struct_fields[4];
+ ffi_type cls_struct_type;
+ ffi_type* c_arg_types[5];
+
+ struct cls_struct_align g_c = { 12, 4951 + 7 * I, 127 };
+ struct cls_struct_align f_c = { 1, 9320 + 1 * I, 13 };
+ struct cls_struct_align res_c;
+
+ cls_struct_type.size = 0;
+ cls_struct_type.alignment = 0;
+ cls_struct_type.type = FFI_TYPE_STRUCT;
+ cls_struct_type.elements = cls_struct_fields;
+
+ cls_struct_fields[0] = &ffi_type_uchar;
+ cls_struct_fields[1] = &T_FFI_TYPE;
+ cls_struct_fields[2] = &ffi_type_uchar;
+ cls_struct_fields[3] = NULL;
+
+ c_arg_types[0] = &cls_struct_type;
+ c_arg_types[1] = &cls_struct_type;
+ c_arg_types[2] = NULL;
+
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type,
+ c_arg_types) == FFI_OK);
+
+ args_c[0] = &g_c;
+ args_c[1] = &f_c;
+ args_c[2] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_c, args_c);
+ /* { dg-output "12 4951,7i 127 1 9320,1i 13: 13 14271,8i 140" } */
+ printf("res: %d %f,%fi %d\n",
+ res_c.a, T_CONV creal (res_c.b), T_CONV cimag (res_c.b), res_c.c);
+ /* { dg-output "\nres: 13 14271,8i 140" } */
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
+
+ res_c = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_c, f_c);
+ /* { dg-output "\n12 4951,7i 127 1 9320,1i 13: 13 14271,8i 140" } */
+ printf("res: %d %f,%fi %d\n",
+ res_c.a, T_CONV creal (res_c.b), T_CONV cimag (res_c.b), res_c.c);
+ /* { dg-output "\nres: 13 14271,8i 140" } */
+
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/cls_align_complex_double.c b/testsuite/libffi.complex/cls_align_complex_double.c
new file mode 100644
index 00000000..0dff23ae
--- /dev/null
+++ b/testsuite/libffi.complex/cls_align_complex_double.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "cls_align_complex.inc"
diff --git a/testsuite/libffi.complex/cls_align_complex_float.c b/testsuite/libffi.complex/cls_align_complex_float.c
new file mode 100644
index 00000000..0affbd07
--- /dev/null
+++ b/testsuite/libffi.complex/cls_align_complex_float.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "cls_align_complex.inc"
diff --git a/testsuite/libffi.complex/cls_align_complex_longdouble.c b/testsuite/libffi.complex/cls_align_complex_longdouble.c
new file mode 100644
index 00000000..7889ba85
--- /dev/null
+++ b/testsuite/libffi.complex/cls_align_complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check structure alignment of complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "cls_align_complex.inc"
diff --git a/testsuite/libffi.complex/cls_complex.inc b/testsuite/libffi.complex/cls_complex.inc
new file mode 100644
index 00000000..f9374044
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex.inc
@@ -0,0 +1,42 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+static void cls_ret_complex_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
+ void* userdata __UNUSED__)
+ {
+ _Complex T_C_TYPE *pa;
+ _Complex T_C_TYPE *pr;
+ pa = (_Complex T_C_TYPE *)args[0];
+ pr = (_Complex T_C_TYPE *)resp;
+ *pr = *pa;
+
+ printf("%.6f,%.6fi: %.6f,%.6fi\n",
+ T_CONV creal (*pa), T_CONV cimag (*pa),
+ T_CONV creal (*pr), T_CONV cimag (*pr));
+ }
+typedef _Complex T_C_TYPE (*cls_ret_complex)(_Complex T_C_TYPE);
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type * cl_arg_types[2];
+ _Complex T_C_TYPE res;
+
+ cl_arg_types[0] = &T_FFI_TYPE;
+ cl_arg_types[1] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &T_FFI_TYPE, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_complex_fn, NULL, code) == FFI_OK);
+
+ res = (*((cls_ret_complex)code))(0.125 + 128.0 * I);
+ printf("res: %.6f,%.6fi\n", T_CONV creal (res), T_CONV cimag (res));
+ CHECK (res == (0.125 + 128.0 * I));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/cls_complex_double.c b/testsuite/libffi.complex/cls_complex_double.c
new file mode 100644
index 00000000..05e35340
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_double.c
@@ -0,0 +1,10 @@
+/* Area: closure_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "cls_complex.inc"
diff --git a/testsuite/libffi.complex/cls_complex_float.c b/testsuite/libffi.complex/cls_complex_float.c
new file mode 100644
index 00000000..5df7849d
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_float.c
@@ -0,0 +1,10 @@
+/* Area: closure_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "cls_complex.inc"
diff --git a/testsuite/libffi.complex/cls_complex_longdouble.c b/testsuite/libffi.complex/cls_complex_longdouble.c
new file mode 100644
index 00000000..2b1c320a
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area: closure_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "cls_complex.inc"
diff --git a/testsuite/libffi.complex/cls_complex_struct.inc b/testsuite/libffi.complex/cls_complex_struct.inc
new file mode 100644
index 00000000..df8708d1
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_struct.inc
@@ -0,0 +1,71 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+typedef struct Cs {
+ _Complex T_C_TYPE x;
+ _Complex T_C_TYPE y;
+} Cs;
+
+Cs gc;
+
+void
+closure_test_fn(Cs p)
+{
+ printf("%.1f,%.1fi %.1f,%.1fi\n",
+ T_CONV creal (p.x), T_CONV cimag (p.x),
+ T_CONV creal (p.y), T_CONV cimag (p.y));
+ gc = p;
+}
+
+void
+closure_test_gn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__,
+ void** args, void* userdata __UNUSED__)
+{
+ closure_test_fn(*(Cs*)args[0]);
+}
+
+int main(int argc __UNUSED__, char** argv __UNUSED__)
+{
+ ffi_cif cif;
+
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ ffi_type *cl_arg_types[1];
+
+ ffi_type ts1_type;
+ ffi_type* ts1_type_elements[4];
+
+ Cs arg = { 1.0 + 11.0 * I, 2.0 + 22.0 * I};
+
+ ts1_type.size = 0;
+ ts1_type.alignment = 0;
+ ts1_type.type = FFI_TYPE_STRUCT;
+ ts1_type.elements = ts1_type_elements;
+
+ ts1_type_elements[0] = &T_FFI_TYPE;
+ ts1_type_elements[1] = &T_FFI_TYPE;
+ ts1_type_elements[2] = NULL;
+
+ cl_arg_types[0] = &ts1_type;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_void, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_gn, NULL, code) == FFI_OK);
+
+ gc.x = 0.0 + 0.0 * I;
+ gc.y = 0.0 + 0.0 * I;
+ ((void*(*)(Cs))(code))(arg);
+ /* { dg-output "1.0,11.0i 2.0,22.0i\n" } */
+ CHECK (gc.x == arg.x && gc.y == arg.y);
+
+ gc.x = 0.0 + 0.0 * I;
+ gc.y = 0.0 + 0.0 * I;
+ closure_test_fn(arg);
+ /* { dg-output "1.0,11.0i 2.0,22.0i\n" } */
+ CHECK (gc.x == arg.x && gc.y == arg.y);
+
+ return 0;
+}
diff --git a/testsuite/libffi.complex/cls_complex_struct_double.c b/testsuite/libffi.complex/cls_complex_struct_double.c
new file mode 100644
index 00000000..ec71346a
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_struct_double.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check complex arguments in structs.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "cls_complex_struct.inc"
diff --git a/testsuite/libffi.complex/cls_complex_struct_float.c b/testsuite/libffi.complex/cls_complex_struct_float.c
new file mode 100644
index 00000000..96fdf750
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_struct_float.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check complex arguments in structs.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "cls_complex_struct.inc"
diff --git a/testsuite/libffi.complex/cls_complex_struct_longdouble.c b/testsuite/libffi.complex/cls_complex_struct_longdouble.c
new file mode 100644
index 00000000..005b4673
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_struct_longdouble.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call, closure_call
+ Purpose: Check complex arguments in structs.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "cls_complex_struct.inc"
diff --git a/testsuite/libffi.complex/cls_complex_va.inc b/testsuite/libffi.complex/cls_complex_va.inc
new file mode 100644
index 00000000..8a3e15f0
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_va.inc
@@ -0,0 +1,80 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <complex.h>
+
+static _Complex T_C_TYPE gComplexValue1 = 1 + 2 * I;
+static _Complex T_C_TYPE gComplexValue2 = 3 + 4 * I;
+
+static int cls_variadic(const char *format, ...)
+{
+ va_list ap;
+ _Complex T_C_TYPE p1, p2;
+
+ va_start (ap, format);
+ p1 = va_arg (ap, _Complex T_C_TYPE);
+ p2 = va_arg (ap, _Complex T_C_TYPE);
+ va_end (ap);
+
+ return printf(format, T_CONV creal (p1), T_CONV cimag (p1),
+ T_CONV creal (p2), T_CONV cimag (p2));
+}
+
+static void
+cls_complex_va_fn(ffi_cif* cif __UNUSED__, void* resp,
+ void** args, void* userdata __UNUSED__)
+{
+ char* format = *(char**)args[0];
+ gComplexValue1 = *(_Complex T_C_TYPE*)args[1];
+ gComplexValue2 = *(_Complex T_C_TYPE*)args[2];
+
+ *(ffi_arg*)resp =
+ printf(format,
+ T_CONV creal (gComplexValue1), T_CONV cimag (gComplexValue1),
+ T_CONV creal (gComplexValue2), T_CONV cimag (gComplexValue2));
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ void *code;
+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+ void* args[4];
+ ffi_type* arg_types[4];
+ char *format = "%.1f,%.1fi %.1f,%.1fi\n";
+
+ _Complex T_C_TYPE complexArg1 = 1.0 + 22.0 *I;
+ _Complex T_C_TYPE complexArg2 = 333.0 + 4444.0 *I;
+ ffi_arg res = 0;
+
+ arg_types[0] = &ffi_type_pointer;
+ arg_types[1] = &T_FFI_TYPE;
+ arg_types[2] = &T_FFI_TYPE;
+ arg_types[3] = NULL;
+
+ /* This printf call is variadic */
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 3, &ffi_type_sint,
+ arg_types) == FFI_OK);
+
+ args[0] = &format;
+ args[1] = &complexArg1;
+ args[2] = &complexArg2;
+ args[3] = NULL;
+
+ ffi_call(&cif, FFI_FN(cls_variadic), &res, args);
+ printf("res: %d\n", (int) res);
+ CHECK (res == 24);
+
+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_complex_va_fn, NULL, code)
+ == FFI_OK);
+
+ res = ((int(*)(char *, ...))(code))(format, complexArg1, complexArg2);
+ CHECK (gComplexValue1 == complexArg1);
+ CHECK (gComplexValue2 == complexArg2);
+ printf("res: %d\n", (int) res);
+ CHECK (res == 24);
+
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/cls_complex_va_double.c b/testsuite/libffi.complex/cls_complex_va_double.c
new file mode 100644
index 00000000..879ccf3b
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_va_double.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call, closure_call
+ Purpose: Test complex' passed in variable argument lists.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "cls_complex_va.inc"
diff --git a/testsuite/libffi.complex/cls_complex_va_float.c b/testsuite/libffi.complex/cls_complex_va_float.c
new file mode 100644
index 00000000..2b178260
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_va_float.c
@@ -0,0 +1,16 @@
+/* Area: ffi_call, closure_call
+ Purpose: Test complex' passed in variable argument lists.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+/* Alpha splits _Complex into two arguments. It's illegal to pass
+ float through varargs, so _Complex float goes badly. In sort of
+ gets passed as _Complex double, but the compiler doesn't agree
+ with itself on this issue. */
+/* { dg-do run { xfail alpha*-*-* } } */
+
+#include "complex_defs_float.inc"
+#include "cls_complex_va.inc"
diff --git a/testsuite/libffi.complex/cls_complex_va_longdouble.c b/testsuite/libffi.complex/cls_complex_va_longdouble.c
new file mode 100644
index 00000000..6eca9656
--- /dev/null
+++ b/testsuite/libffi.complex/cls_complex_va_longdouble.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call, closure_call
+ Purpose: Test complex' passed in variable argument lists.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "cls_complex_va.inc"
diff --git a/testsuite/libffi.complex/complex.exp b/testsuite/libffi.complex/complex.exp
new file mode 100644
index 00000000..4631db28
--- /dev/null
+++ b/testsuite/libffi.complex/complex.exp
@@ -0,0 +1,36 @@
+# Copyright (C) 2003, 2006, 2009, 2010, 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+dg-init
+libffi-init
+
+global srcdir subdir
+
+set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.{c,cc}]]
+
+if { [libffi_feature_test "#ifdef FFI_TARGET_HAS_COMPLEX_TYPE"] } {
+ run-many-tests $tlist ""
+} else {
+ foreach test $tlist {
+ unsupported "$test"
+ }
+}
+
+dg-finish
+
+# Local Variables:
+# tcl-indent-level:4
+# End:
diff --git a/testsuite/libffi.complex/complex.inc b/testsuite/libffi.complex/complex.inc
new file mode 100644
index 00000000..515ae3e6
--- /dev/null
+++ b/testsuite/libffi.complex/complex.inc
@@ -0,0 +1,51 @@
+/* -*-c-*-*/
+#include "ffitest.h"
+#include <complex.h>
+
+static _Complex T_C_TYPE f_complex(_Complex T_C_TYPE c, int x, int *py)
+{
+ c = -(2 * creal (c)) + (cimag (c) + 1)* I;
+ *py += x;
+
+ return c;
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_type *args[MAX_ARGS];
+ void *values[MAX_ARGS];
+
+ _Complex T_C_TYPE tc_arg;
+ _Complex T_C_TYPE tc_result;
+ int tc_int_arg_x;
+ int tc_y;
+ int *tc_ptr_arg_y = &tc_y;
+
+ args[0] = &T_FFI_TYPE;
+ args[1] = &ffi_type_sint;
+ args[2] = &ffi_type_pointer;
+ values[0] = &tc_arg;
+ values[1] = &tc_int_arg_x;
+ values[2] = &tc_ptr_arg_y;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3,
+ &T_FFI_TYPE, args) == FFI_OK);
+
+ tc_arg = 1 + 7 * I;
+ tc_int_arg_x = 1234;
+ tc_y = 9876;
+ ffi_call(&cif, FFI_FN(f_complex), &tc_result, values);
+
+ printf ("%f,%fi %f,%fi, x %d 1234, y %d 11110\n",
+ T_CONV creal (tc_result), T_CONV cimag (tc_result),
+ T_CONV creal (2.0), T_CONV creal (8.0), tc_int_arg_x, tc_y);
+
+ CHECK (creal (tc_result) == -2);
+ CHECK (cimag (tc_result) == 8);
+ CHECK (tc_int_arg_x == 1234);
+ CHECK (*tc_ptr_arg_y == 11110);
+
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/complex_defs_double.inc b/testsuite/libffi.complex/complex_defs_double.inc
new file mode 100644
index 00000000..3583e166
--- /dev/null
+++ b/testsuite/libffi.complex/complex_defs_double.inc
@@ -0,0 +1,7 @@
+/* -*-c-*- */
+/* Complex base type. */
+#define T_FFI_TYPE ffi_type_complex_double
+/* C type corresponding to the base type. */
+#define T_C_TYPE double
+/* C cast for a value of type T_C_TYPE that is passed to printf. */
+#define T_CONV
diff --git a/testsuite/libffi.complex/complex_defs_float.inc b/testsuite/libffi.complex/complex_defs_float.inc
new file mode 100644
index 00000000..bbd9375c
--- /dev/null
+++ b/testsuite/libffi.complex/complex_defs_float.inc
@@ -0,0 +1,7 @@
+/* -*-c-*- */
+/* Complex base type. */
+#define T_FFI_TYPE ffi_type_complex_float
+/* C type corresponding to the base type. */
+#define T_C_TYPE float
+/* C cast for a value of type T_C_TYPE that is passed to printf. */
+#define T_CONV (double)
diff --git a/testsuite/libffi.complex/complex_defs_longdouble.inc b/testsuite/libffi.complex/complex_defs_longdouble.inc
new file mode 100644
index 00000000..14b9f243
--- /dev/null
+++ b/testsuite/libffi.complex/complex_defs_longdouble.inc
@@ -0,0 +1,7 @@
+/* -*-c-*- */
+/* Complex base type. */
+#define T_FFI_TYPE ffi_type_complex_longdouble
+/* C type corresponding to the base type. */
+#define T_C_TYPE long double
+/* C cast for a value of type T_C_TYPE that is passed to printf. */
+#define T_CONV
diff --git a/testsuite/libffi.complex/complex_double.c b/testsuite/libffi.complex/complex_double.c
new file mode 100644
index 00000000..8a3297b2
--- /dev/null
+++ b/testsuite/libffi.complex/complex_double.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check complex types.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "complex.inc"
diff --git a/testsuite/libffi.complex/complex_float.c b/testsuite/libffi.complex/complex_float.c
new file mode 100644
index 00000000..5044ebbc
--- /dev/null
+++ b/testsuite/libffi.complex/complex_float.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check complex types.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "complex.inc"
diff --git a/testsuite/libffi.complex/complex_int.c b/testsuite/libffi.complex/complex_int.c
new file mode 100644
index 00000000..bac31908
--- /dev/null
+++ b/testsuite/libffi.complex/complex_int.c
@@ -0,0 +1,86 @@
+/* Area: ffi_call
+ Purpose: Check non-standard complex types.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+#include "ffi.h"
+#include <complex.h>
+
+_Complex int f_complex(_Complex int c, int x, int *py)
+{
+ __real__ c = -2 * __real__ c;
+ __imag__ c = __imag__ c + 1;
+ *py += x;
+ return c;
+}
+
+/*
+ * This macro can be used to define new complex type descriptors
+ * in a platform independent way.
+ *
+ * name: Name of the new descriptor is ffi_type_complex_<name>.
+ * type: The C base type of the complex type.
+ */
+#define FFI_COMPLEX_TYPEDEF(name, type, ffitype) \
+ static ffi_type *ffi_elements_complex_##name [2] = { \
+ (ffi_type *)(&ffitype), NULL \
+ }; \
+ struct struct_align_complex_##name { \
+ char c; \
+ _Complex type x; \
+ }; \
+ ffi_type ffi_type_complex_##name = { \
+ sizeof(_Complex type), \
+ offsetof(struct struct_align_complex_##name, x), \
+ FFI_TYPE_COMPLEX, \
+ (ffi_type **)ffi_elements_complex_##name \
+ }
+
+/* Define new complex type descriptors using the macro: */
+/* ffi_type_complex_sint */
+FFI_COMPLEX_TYPEDEF(sint, int, ffi_type_sint);
+/* ffi_type_complex_uchar */
+FFI_COMPLEX_TYPEDEF(uchar, unsigned char, ffi_type_uint8);
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_type *args[MAX_ARGS];
+ void *values[MAX_ARGS];
+
+ _Complex int tc_arg;
+ _Complex int tc_result;
+ int tc_int_arg_x;
+ int tc_y;
+ int *tc_ptr_arg_y = &tc_y;
+
+ args[0] = &ffi_type_complex_sint;
+ args[1] = &ffi_type_sint;
+ args[2] = &ffi_type_pointer;
+ values[0] = &tc_arg;
+ values[1] = &tc_int_arg_x;
+ values[2] = &tc_ptr_arg_y;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &ffi_type_complex_sint, args)
+ == FFI_OK);
+
+ tc_arg = 1 + 7 * I;
+ tc_int_arg_x = 1234;
+ tc_y = 9876;
+ ffi_call(&cif, FFI_FN(f_complex), &tc_result, values);
+
+ printf ("%d,%di %d,%di, x %d 1234, y %d 11110\n",
+ (int)tc_result, (int)(tc_result * -I), 2, 8, tc_int_arg_x, tc_y);
+ /* dg-output "-2,8i 2,8i, x 1234 1234, y 11110 11110" */
+ CHECK (creal (tc_result) == -2);
+ CHECK (cimag (tc_result) == 8);
+ CHECK (tc_int_arg_x == 1234);
+ CHECK (*tc_ptr_arg_y == 11110);
+
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/complex_longdouble.c b/testsuite/libffi.complex/complex_longdouble.c
new file mode 100644
index 00000000..7e783660
--- /dev/null
+++ b/testsuite/libffi.complex/complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check complex types.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "complex.inc"
diff --git a/testsuite/libffi.complex/ffitest.h b/testsuite/libffi.complex/ffitest.h
new file mode 100644
index 00000000..d27d362d
--- /dev/null
+++ b/testsuite/libffi.complex/ffitest.h
@@ -0,0 +1 @@
+#include "../libffi.call/ffitest.h"
diff --git a/testsuite/libffi.complex/many_complex.inc b/testsuite/libffi.complex/many_complex.inc
new file mode 100644
index 00000000..e37a7743
--- /dev/null
+++ b/testsuite/libffi.complex/many_complex.inc
@@ -0,0 +1,78 @@
+/* -*-c-*- */
+#include "ffitest.h"
+
+#include <stdlib.h>
+#include <complex.h>
+
+static _Complex T_C_TYPE many(_Complex T_C_TYPE c1,
+ _Complex T_C_TYPE c2,
+ _Complex T_C_TYPE c3,
+ _Complex T_C_TYPE c4,
+ _Complex T_C_TYPE c5,
+ _Complex T_C_TYPE c6,
+ _Complex T_C_TYPE c7,
+ _Complex T_C_TYPE c8,
+ _Complex T_C_TYPE c9,
+ _Complex T_C_TYPE c10,
+ _Complex T_C_TYPE c11,
+ _Complex T_C_TYPE c12,
+ _Complex T_C_TYPE c13)
+{
+ printf("0 :%f,%fi\n"
+ "1 :%f,%fi\n"
+ "2 :%f,%fi\n"
+ "3 :%f,%fi\n"
+ "4 :%f,%fi\n"
+ "5 :%f,%fi\n"
+ "6 :%f,%fi\n"
+ "7 :%f,%fi\n"
+ "8 :%f,%fi\n"
+ "9 :%f,%fi\n"
+ "10:%f,%fi\n"
+ "11:%f,%fi\n"
+ "12:%f,%fi\n",
+ T_CONV creal (c1), T_CONV cimag (c1),
+ T_CONV creal (c2), T_CONV cimag (c2),
+ T_CONV creal (c3), T_CONV cimag (c3),
+ T_CONV creal (c4), T_CONV cimag (c4),
+ T_CONV creal (c5), T_CONV cimag (c5),
+ T_CONV creal (c6), T_CONV cimag (c6),
+ T_CONV creal (c7), T_CONV cimag (c7),
+ T_CONV creal (c8), T_CONV cimag (c8),
+ T_CONV creal (c9), T_CONV cimag (c9),
+ T_CONV creal (c10), T_CONV cimag (c10),
+ T_CONV creal (c11), T_CONV cimag (c11),
+ T_CONV creal (c12), T_CONV cimag (c12),
+ T_CONV creal (c13), T_CONV cimag (c13));
+
+ return (c1+c2-c3-c4+c5+c6+c7-c8-c9-c10-c11+c12+c13);
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_type *args[13];
+ void *values[13];
+ _Complex T_C_TYPE ca[13];
+ _Complex T_C_TYPE c, cc;
+ int i;
+
+ for (i = 0; i < 13; i++)
+ {
+ args[i] = &T_FFI_TYPE;
+ values[i] = &ca[i];
+ ca[i] = i + (-20 - i) * I;
+ }
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, &T_FFI_TYPE, args) == FFI_OK);
+
+ ffi_call(&cif, FFI_FN(many), &c, values);
+
+ cc = many(ca[0], ca[1], ca[2], ca[3], ca[4], ca[5], ca[6], ca[7], ca[8],
+ ca[9], ca[10], ca[11], ca[12]);
+ CHECK(creal (cc) == creal (c));
+ CHECK(cimag (cc) == cimag (c));
+
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/many_complex_double.c b/testsuite/libffi.complex/many_complex_double.c
new file mode 100644
index 00000000..3fd53c33
--- /dev/null
+++ b/testsuite/libffi.complex/many_complex_double.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex, with many arguments
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "many_complex.inc"
diff --git a/testsuite/libffi.complex/many_complex_float.c b/testsuite/libffi.complex/many_complex_float.c
new file mode 100644
index 00000000..c43d21cd
--- /dev/null
+++ b/testsuite/libffi.complex/many_complex_float.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex, with many arguments
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "many_complex.inc"
diff --git a/testsuite/libffi.complex/many_complex_longdouble.c b/testsuite/libffi.complex/many_complex_longdouble.c
new file mode 100644
index 00000000..dbab7239
--- /dev/null
+++ b/testsuite/libffi.complex/many_complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex, with many arguments
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "many_complex.inc"
diff --git a/testsuite/libffi.complex/return_complex.inc b/testsuite/libffi.complex/return_complex.inc
new file mode 100644
index 00000000..8bf0c1fb
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex.inc
@@ -0,0 +1,37 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+static _Complex T_C_TYPE return_c(_Complex T_C_TYPE c)
+{
+ printf ("%f,%fi\n", T_CONV creal (c), T_CONV cimag (c));
+ return 2 * c;
+}
+int main (void)
+{
+ ffi_cif cif;
+ ffi_type *args[MAX_ARGS];
+ void *values[MAX_ARGS];
+ _Complex T_C_TYPE c, rc, rc2;
+ T_C_TYPE cr, ci;
+
+ args[0] = &T_FFI_TYPE;
+ values[0] = &c;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &T_FFI_TYPE, args) == FFI_OK);
+
+ for (cr = -127.0; cr < 127; cr++)
+ {
+ ci = 1000.0 - cr;
+ c = cr + ci * I;
+ ffi_call(&cif, FFI_FN(return_c), &rc, values);
+ rc2 = return_c(c);
+ printf ("%f,%fi vs %f,%fi\n",
+ T_CONV creal (rc), T_CONV cimag (rc),
+ T_CONV creal (rc2), T_CONV cimag (rc2));
+ CHECK(rc == 2 * c);
+ }
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/return_complex1.inc b/testsuite/libffi.complex/return_complex1.inc
new file mode 100644
index 00000000..7cecc0fe
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex1.inc
@@ -0,0 +1,41 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+static _Complex T_C_TYPE return_c(_Complex T_C_TYPE c1, float fl2, unsigned int in3, _Complex T_C_TYPE c4)
+{
+ return c1 + fl2 + in3 + c4;
+}
+int main (void)
+{
+ ffi_cif cif;
+ ffi_type *args[MAX_ARGS];
+ void *values[MAX_ARGS];
+ _Complex T_C_TYPE c1, c4, rc, rc2;
+ float fl2;
+ unsigned int in3;
+ args[0] = &T_FFI_TYPE;
+ args[1] = &ffi_type_float;
+ args[2] = &ffi_type_uint;
+ args[3] = &T_FFI_TYPE;
+ values[0] = &c1;
+ values[1] = &fl2;
+ values[2] = &in3;
+ values[3] = &c4;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
+ &T_FFI_TYPE, args) == FFI_OK);
+ c1 = 127.0 + 255.0 * I;
+ fl2 = 128.0;
+ in3 = 255;
+ c4 = 512.7 + 1024.1 * I;
+
+ ffi_call(&cif, FFI_FN(return_c), &rc, values);
+ rc2 = return_c(c1, fl2, in3, c4);
+ printf ("%f,%fi vs %f,%fi\n",
+ T_CONV creal (rc), T_CONV cimag (rc),
+ T_CONV creal (rc2), T_CONV cimag (rc2));
+ CHECK(rc == rc2);
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/return_complex1_double.c b/testsuite/libffi.complex/return_complex1_double.c
new file mode 100644
index 00000000..727410d5
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex1_double.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "return_complex1.inc"
diff --git a/testsuite/libffi.complex/return_complex1_float.c b/testsuite/libffi.complex/return_complex1_float.c
new file mode 100644
index 00000000..a2aeada8
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex1_float.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "return_complex1.inc"
diff --git a/testsuite/libffi.complex/return_complex1_longdouble.c b/testsuite/libffi.complex/return_complex1_longdouble.c
new file mode 100644
index 00000000..103504bf
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex1_longdouble.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "return_complex1.inc"
diff --git a/testsuite/libffi.complex/return_complex2.inc b/testsuite/libffi.complex/return_complex2.inc
new file mode 100644
index 00000000..265170bf
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex2.inc
@@ -0,0 +1,44 @@
+/* -*-c-*- */
+#include "ffitest.h"
+#include <complex.h>
+
+_Complex T_C_TYPE
+return_c(_Complex T_C_TYPE c1, _Complex T_C_TYPE c2,
+ unsigned int in3, _Complex T_C_TYPE c4)
+{
+ volatile _Complex T_C_TYPE r = c1 + c2 + in3 + c4;
+ return r;
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_type *args[MAX_ARGS];
+ void *values[MAX_ARGS];
+ _Complex T_C_TYPE c1, c2, c4, rc, rc2;
+ unsigned int in3;
+ args[0] = &T_FFI_TYPE;
+ args[1] = &T_FFI_TYPE;
+ args[2] = &ffi_type_uint;
+ args[3] = &T_FFI_TYPE;
+ values[0] = &c1;
+ values[1] = &c2;
+ values[2] = &in3;
+ values[3] = &c4;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
+ &T_FFI_TYPE, args) == FFI_OK);
+ c1 = 127.0 + 255.0 * I;
+ c2 = 128.0 + 256.0;
+ in3 = 255;
+ c4 = 512.7 + 1024.1 * I;
+
+ ffi_call(&cif, FFI_FN(return_c), &rc, values);
+ rc2 = return_c(c1, c2, in3, c4);
+ printf ("%f,%fi vs %f,%fi\n",
+ T_CONV creal (rc), T_CONV cimag (rc),
+ T_CONV creal (rc2), T_CONV cimag (rc2));
+ CHECK(rc == rc2);
+ exit(0);
+}
diff --git a/testsuite/libffi.complex/return_complex2_double.c b/testsuite/libffi.complex/return_complex2_double.c
new file mode 100644
index 00000000..ab9efacb
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex2_double.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "return_complex2.inc"
diff --git a/testsuite/libffi.complex/return_complex2_float.c b/testsuite/libffi.complex/return_complex2_float.c
new file mode 100644
index 00000000..d7f22c2a
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex2_float.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "return_complex2.inc"
diff --git a/testsuite/libffi.complex/return_complex2_longdouble.c b/testsuite/libffi.complex/return_complex2_longdouble.c
new file mode 100644
index 00000000..3edea629
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex2_longdouble.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "return_complex2.inc"
diff --git a/testsuite/libffi.complex/return_complex_double.c b/testsuite/libffi.complex/return_complex_double.c
new file mode 100644
index 00000000..e2497cc8
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex_double.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_double.inc"
+#include "return_complex.inc"
diff --git a/testsuite/libffi.complex/return_complex_float.c b/testsuite/libffi.complex/return_complex_float.c
new file mode 100644
index 00000000..a35528ff
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex_float.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_float.inc"
+#include "return_complex.inc"
diff --git a/testsuite/libffi.complex/return_complex_longdouble.c b/testsuite/libffi.complex/return_complex_longdouble.c
new file mode 100644
index 00000000..142d7bec
--- /dev/null
+++ b/testsuite/libffi.complex/return_complex_longdouble.c
@@ -0,0 +1,10 @@
+/* Area: ffi_call
+ Purpose: Check return value complex.
+ Limitations: none.
+ PR: none.
+ Originator: <vogt@linux.vnet.ibm.com>. */
+
+/* { dg-do run } */
+
+#include "complex_defs_longdouble.inc"
+#include "return_complex.inc"
diff --git a/testsuite/libffi.go/aa-direct.c b/testsuite/libffi.go/aa-direct.c
new file mode 100644
index 00000000..b00c404a
--- /dev/null
+++ b/testsuite/libffi.go/aa-direct.c
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+
+#include "static-chain.h"
+
+#if defined(__GNUC__) && !defined(__clang__) && defined(STATIC_CHAIN_REG)
+
+#include "ffitest.h"
+
+/* Blatent assumption here that the prologue doesn't clobber the
+ static chain for trivial functions. If this is not true, don't
+ define STATIC_CHAIN_REG, and we'll test what we can via other tests. */
+void *doit(void)
+{
+ register void *chain __asm__(STATIC_CHAIN_REG);
+ return chain;
+}
+
+int main()
+{
+ ffi_cif cif;
+ void *result;
+
+ CHECK(ffi_prep_cif(&cif, ABI_NUM, 0, &ffi_type_pointer, NULL) == FFI_OK);
+
+ ffi_call_go(&cif, FFI_FN(doit), &result, NULL, &result);
+
+ CHECK(result == &result);
+
+ return 0;
+}
+
+#else /* UNSUPPORTED */
+int main() { return 0; }
+#endif
diff --git a/testsuite/libffi.go/closure1.c b/testsuite/libffi.go/closure1.c
new file mode 100644
index 00000000..7b34afc8
--- /dev/null
+++ b/testsuite/libffi.go/closure1.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+void doit(ffi_cif *cif, void *rvalue, void **avalue, void *closure)
+{
+ (void)cif;
+ (void)avalue;
+ *(void **)rvalue = closure;
+}
+
+typedef void * (*FN)(void);
+
+int main()
+{
+ ffi_cif cif;
+ ffi_go_closure cl;
+ void *result;
+
+ CHECK(ffi_prep_cif(&cif, ABI_NUM, 0, &ffi_type_pointer, NULL) == FFI_OK);
+ CHECK(ffi_prep_go_closure(&cl, &cif, doit) == FFI_OK);
+
+ ffi_call_go(&cif, FFI_FN(*(FN *)&cl), &result, NULL, &cl);
+
+ CHECK(result == &cl);
+
+ exit(0);
+}
diff --git a/testsuite/libffi.go/ffitest.h b/testsuite/libffi.go/ffitest.h
new file mode 100644
index 00000000..d27d362d
--- /dev/null
+++ b/testsuite/libffi.go/ffitest.h
@@ -0,0 +1 @@
+#include "../libffi.call/ffitest.h"
diff --git a/testsuite/libffi.go/go.exp b/testsuite/libffi.go/go.exp
new file mode 100644
index 00000000..100c5e75
--- /dev/null
+++ b/testsuite/libffi.go/go.exp
@@ -0,0 +1,36 @@
+# Copyright (C) 2003, 2006, 2009, 2010, 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+dg-init
+libffi-init
+
+global srcdir subdir
+
+set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.{c,cc}]]
+
+if { [libffi_feature_test "#ifdef FFI_GO_CLOSURES"] } {
+ run-many-tests $tlist ""
+} else {
+ foreach test $tlist {
+ unsupported "$test"
+ }
+}
+
+dg-finish
+
+# Local Variables:
+# tcl-indent-level:4
+# End:
diff --git a/testsuite/libffi.go/static-chain.h b/testsuite/libffi.go/static-chain.h
new file mode 100644
index 00000000..3675b40a
--- /dev/null
+++ b/testsuite/libffi.go/static-chain.h
@@ -0,0 +1,19 @@
+#ifdef __aarch64__
+# define STATIC_CHAIN_REG "x18"
+#elif defined(__alpha__)
+# define STATIC_CHAIN_REG "$1"
+#elif defined(__arm__)
+# define STATIC_CHAIN_REG "ip"
+#elif defined(__sparc__)
+# if defined(__arch64__) || defined(__sparcv9)
+# define STATIC_CHAIN_REG "g5"
+# else
+# define STATIC_CHAIN_REG "g2"
+# endif
+#elif defined(__x86_64__)
+# define STATIC_CHAIN_REG "r10"
+#elif defined(__i386__)
+# ifndef ABI_NUM
+# define STATIC_CHAIN_REG "ecx" /* FFI_DEFAULT_ABI only */
+# endif
+#endif