]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libffi: Sync with libffi 3.5.2
authorPietro Monteiro <pietro@sociotechnical.xyz>
Thu, 21 May 2026 21:59:56 +0000 (17:59 -0400)
committerPietro Monteiro <pietro@sociotechnical.xyz>
Thu, 21 May 2026 21:59:56 +0000 (17:59 -0400)
Merged commit: e2eda0cf72a0598b44278cc91860ea402273fa29

Signed-off-by: Pietro Monteiro <pietro@sociotechnical.xyz>
208 files changed:
libffi/LICENSE
libffi/MERGE
libffi/Makefile.am
libffi/README.md
libffi/acinclude.m4
libffi/configure.ac
libffi/configure.host
libffi/doc/libffi.texi
libffi/doc/version.texi
libffi/generate-darwin-source-and-headers.py
libffi/include/Makefile.am
libffi/include/ffi.h.in
libffi/include/ffi_cfi.h
libffi/include/ffi_common.h
libffi/libffi.map.in
libffi/libtool-version
libffi/src/aarch64/ffi.c
libffi/src/aarch64/ffitarget.h
libffi/src/aarch64/internal.h
libffi/src/aarch64/sysv.S
libffi/src/arc/arcompact.S
libffi/src/arc/ffi.c
libffi/src/arc/ffitarget.h
libffi/src/arm/ffi.c
libffi/src/arm/sysv.S
libffi/src/closures.c
libffi/src/debug.c
libffi/src/dlmalloc.c
libffi/src/ia64/ffi.c
libffi/src/ia64/unix.S
libffi/src/loongarch64/ffi.c
libffi/src/m32r/ffi.c
libffi/src/mips/ffi.c
libffi/src/mips/ffitarget.h
libffi/src/mips/n32.S
libffi/src/mips/o32.S
libffi/src/moxie/ffi.c
libffi/src/or1k/ffi.c
libffi/src/pa/ffi.c
libffi/src/pa/ffi64.c [new file with mode: 0644]
libffi/src/pa/ffitarget.h
libffi/src/pa/hpux32.S
libffi/src/pa/hpux64.S [new file with mode: 0644]
libffi/src/pa/linux.S
libffi/src/powerpc/ffi.c
libffi/src/powerpc/ffi_darwin.c
libffi/src/powerpc/ffi_linux64.c
libffi/src/powerpc/ffi_sysv.c
libffi/src/powerpc/internal.h [new file with mode: 0644]
libffi/src/powerpc/linux64_closure.S
libffi/src/powerpc/ppc_closure.S
libffi/src/powerpc/t-aix [new file with mode: 0644]
libffi/src/prep_cif.c
libffi/src/riscv/ffi.c
libffi/src/s390/ffi.c
libffi/src/s390/internal.h
libffi/src/s390/sysv.S
libffi/src/sparc/ffi64.c
libffi/src/tramp.c
libffi/src/types.c
libffi/src/wasm/ffi.c [new file with mode: 0644]
libffi/src/wasm/ffitarget.h [new file with mode: 0644]
libffi/src/x86/ffi.c
libffi/src/x86/ffi64.c
libffi/src/x86/ffitarget.h
libffi/src/x86/ffiw64.c
libffi/src/x86/sysv_intel.S
libffi/src/x86/unix64.S
libffi/src/xtensa/ffi.c
libffi/src/xtensa/ffitarget.h
libffi/src/xtensa/sysv.S
libffi/testsuite/Makefile.am
libffi/testsuite/emscripten/build-tests.sh [new file with mode: 0755]
libffi/testsuite/emscripten/build.sh [new file with mode: 0755]
libffi/testsuite/emscripten/conftest.py [new file with mode: 0644]
libffi/testsuite/emscripten/node-tests.sh [new file with mode: 0755]
libffi/testsuite/emscripten/test.html [new file with mode: 0644]
libffi/testsuite/emscripten/test_libffi.py [new file with mode: 0644]
libffi/testsuite/lib/libffi.exp
libffi/testsuite/lib/target-libpath.exp
libffi/testsuite/libffi.bhaible/test-call.c
libffi/testsuite/libffi.bhaible/testcases.c
libffi/testsuite/libffi.call/bpo_38748.c [new file with mode: 0644]
libffi/testsuite/libffi.call/callback.c [new file with mode: 0644]
libffi/testsuite/libffi.call/callback2.c [new file with mode: 0644]
libffi/testsuite/libffi.call/callback3.c [new file with mode: 0644]
libffi/testsuite/libffi.call/callback4.c [new file with mode: 0644]
libffi/testsuite/libffi.call/ffitest.h
libffi/testsuite/libffi.call/float_va.c
libffi/testsuite/libffi.call/longjmp.c [new file with mode: 0644]
libffi/testsuite/libffi.call/overread.c [new file with mode: 0644]
libffi/testsuite/libffi.call/pyobjc_tc.c [new file with mode: 0644]
libffi/testsuite/libffi.call/return_ll1.c
libffi/testsuite/libffi.call/return_sl.c
libffi/testsuite/libffi.call/return_ul.c
libffi/testsuite/libffi.call/s55.c [new file with mode: 0644]
libffi/testsuite/libffi.call/strlen.c
libffi/testsuite/libffi.call/strlen2.c
libffi/testsuite/libffi.call/strlen3.c
libffi/testsuite/libffi.call/strlen4.c
libffi/testsuite/libffi.call/struct10.c
libffi/testsuite/libffi.call/struct_by_value_2.c [new file with mode: 0644]
libffi/testsuite/libffi.call/struct_by_value_3.c [new file with mode: 0644]
libffi/testsuite/libffi.call/struct_by_value_3f.c [new file with mode: 0644]
libffi/testsuite/libffi.call/struct_by_value_4.c [new file with mode: 0644]
libffi/testsuite/libffi.call/struct_by_value_4f.c [new file with mode: 0644]
libffi/testsuite/libffi.call/struct_by_value_big.c [new file with mode: 0644]
libffi/testsuite/libffi.call/struct_by_value_small.c [new file with mode: 0644]
libffi/testsuite/libffi.call/struct_int_float.c [new file with mode: 0644]
libffi/testsuite/libffi.call/struct_return_2H.c [new file with mode: 0644]
libffi/testsuite/libffi.call/struct_return_8H.c [new file with mode: 0644]
libffi/testsuite/libffi.call/va_2.c
libffi/testsuite/libffi.call/va_3.c [new file with mode: 0644]
libffi/testsuite/libffi.call/va_struct1.c
libffi/testsuite/libffi.call/va_struct2.c
libffi/testsuite/libffi.call/va_struct3.c
libffi/testsuite/libffi.call/x32.c [new file with mode: 0644]
libffi/testsuite/libffi.closures/closure_fn0.c
libffi/testsuite/libffi.closures/closure_fn1.c
libffi/testsuite/libffi.closures/closure_fn2.c
libffi/testsuite/libffi.closures/closure_fn3.c
libffi/testsuite/libffi.closures/closure_fn4.c
libffi/testsuite/libffi.closures/closure_fn5.c
libffi/testsuite/libffi.closures/closure_fn6.c
libffi/testsuite/libffi.closures/closure_loc_fn0.c
libffi/testsuite/libffi.closures/closure_simple.c
libffi/testsuite/libffi.closures/cls_12byte.c
libffi/testsuite/libffi.closures/cls_16byte.c
libffi/testsuite/libffi.closures/cls_18byte.c
libffi/testsuite/libffi.closures/cls_19byte.c
libffi/testsuite/libffi.closures/cls_1_1byte.c
libffi/testsuite/libffi.closures/cls_20byte.c
libffi/testsuite/libffi.closures/cls_20byte1.c
libffi/testsuite/libffi.closures/cls_24byte.c
libffi/testsuite/libffi.closures/cls_2byte.c
libffi/testsuite/libffi.closures/cls_3_1byte.c
libffi/testsuite/libffi.closures/cls_3byte1.c
libffi/testsuite/libffi.closures/cls_3byte2.c
libffi/testsuite/libffi.closures/cls_3float.c
libffi/testsuite/libffi.closures/cls_4_1byte.c
libffi/testsuite/libffi.closures/cls_4byte.c
libffi/testsuite/libffi.closures/cls_5_1_byte.c
libffi/testsuite/libffi.closures/cls_5byte.c
libffi/testsuite/libffi.closures/cls_64byte.c
libffi/testsuite/libffi.closures/cls_6_1_byte.c
libffi/testsuite/libffi.closures/cls_6byte.c
libffi/testsuite/libffi.closures/cls_7_1_byte.c
libffi/testsuite/libffi.closures/cls_7byte.c
libffi/testsuite/libffi.closures/cls_8byte.c
libffi/testsuite/libffi.closures/cls_9byte1.c
libffi/testsuite/libffi.closures/cls_9byte2.c
libffi/testsuite/libffi.closures/cls_align_double.c
libffi/testsuite/libffi.closures/cls_align_float.c
libffi/testsuite/libffi.closures/cls_align_longdouble.c
libffi/testsuite/libffi.closures/cls_align_longdouble_split.c
libffi/testsuite/libffi.closures/cls_align_longdouble_split2.c
libffi/testsuite/libffi.closures/cls_align_pointer.c
libffi/testsuite/libffi.closures/cls_align_sint16.c
libffi/testsuite/libffi.closures/cls_align_sint32.c
libffi/testsuite/libffi.closures/cls_align_sint64.c
libffi/testsuite/libffi.closures/cls_align_uint16.c
libffi/testsuite/libffi.closures/cls_align_uint32.c
libffi/testsuite/libffi.closures/cls_align_uint64.c
libffi/testsuite/libffi.closures/cls_dbls_struct.c
libffi/testsuite/libffi.closures/cls_double_va.c
libffi/testsuite/libffi.closures/cls_float.c
libffi/testsuite/libffi.closures/cls_longdouble.c
libffi/testsuite/libffi.closures/cls_longdouble_va.c
libffi/testsuite/libffi.closures/cls_multi_schar.c
libffi/testsuite/libffi.closures/cls_multi_sshort.c
libffi/testsuite/libffi.closures/cls_multi_sshortchar.c
libffi/testsuite/libffi.closures/cls_multi_uchar.c
libffi/testsuite/libffi.closures/cls_multi_ushort.c
libffi/testsuite/libffi.closures/cls_multi_ushortchar.c
libffi/testsuite/libffi.closures/cls_pointer.c
libffi/testsuite/libffi.closures/cls_pointer_stack.c
libffi/testsuite/libffi.closures/cls_schar.c
libffi/testsuite/libffi.closures/cls_sint.c
libffi/testsuite/libffi.closures/cls_sshort.c
libffi/testsuite/libffi.closures/cls_struct_va1.c
libffi/testsuite/libffi.closures/cls_uchar.c
libffi/testsuite/libffi.closures/cls_uint.c
libffi/testsuite/libffi.closures/cls_uint_va.c
libffi/testsuite/libffi.closures/cls_ulong_va.c
libffi/testsuite/libffi.closures/cls_ulonglong.c
libffi/testsuite/libffi.closures/cls_ushort.c
libffi/testsuite/libffi.closures/ffitest.h
libffi/testsuite/libffi.closures/huge_struct.c
libffi/testsuite/libffi.closures/nested_struct.c
libffi/testsuite/libffi.closures/nested_struct10.c
libffi/testsuite/libffi.closures/nested_struct11.c
libffi/testsuite/libffi.closures/nested_struct12.c
libffi/testsuite/libffi.closures/nested_struct13.c
libffi/testsuite/libffi.closures/nested_struct2.c
libffi/testsuite/libffi.closures/nested_struct3.c
libffi/testsuite/libffi.closures/nested_struct4.c
libffi/testsuite/libffi.closures/nested_struct5.c
libffi/testsuite/libffi.closures/nested_struct6.c
libffi/testsuite/libffi.closures/nested_struct7.c
libffi/testsuite/libffi.closures/nested_struct8.c
libffi/testsuite/libffi.closures/nested_struct9.c
libffi/testsuite/libffi.closures/testclosure.c
libffi/testsuite/libffi.closures/unwindtest.cc
libffi/testsuite/libffi.closures/unwindtest_ffi_call.cc
libffi/testsuite/libffi.complex/complex_int.c
libffi/testsuite/libffi.threads/ffitest.h [new file with mode: 0644]
libffi/testsuite/libffi.threads/threads.exp [new file with mode: 0644]
libffi/testsuite/libffi.threads/tsan.c [new file with mode: 0644]

index e4034b09af090e5d0fc55cc6500567672ceadb6c..12b4970e0ddcb4c35f51ba632fcc0bbcd2e69540 100644 (file)
@@ -1,4 +1,4 @@
-libffi - Copyright (c) 1996-2021  Anthony Green, Red Hat, Inc and others.
+libffi - Copyright (c) 1996-2025  Anthony Green, Red Hat, Inc and others.
 See source files for details.
 
 Permission is hereby granted, free of charge, to any person obtaining
index fd0076e6509c950bfb4dab2ef9590348228df55b..836e06db0e926fb1fb3d42ff40b34c2815416b0c 100644 (file)
@@ -1,4 +1,4 @@
-f9ea41683444ebe11cfa45b05223899764df28fb
+e2eda0cf72a0598b44278cc91860ea402273fa29
 
 The first line of this file holds the git revision number of the
 last merge done from the master library sources.
index 067cf8e1a69d8aed247865654748929fa18d5433..c3bcf00b3279558910e539188166851acb6edfdf 100644 (file)
 ## Process this with automake to create Makefile.in
 
-AUTOMAKE_OPTIONS = foreign subdir-objects info-in-builddir
+AUTOMAKE_OPTIONS = foreign subdir-objects
 
-ACLOCAL_AMFLAGS = -I .. -I ../config
+ACLOCAL_AMFLAGS = -I m4
+
+# Alias required by AX_ENABLE_BUILDDIR / config-ml
+.PHONY: all-configured
+all-configured: all
 
 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.old                                     \
-       m4/libtool.m4 m4/lt~obsolete.m4                                 \
-        m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4                  \
-        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      
+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/debug.c msvcc.sh                      \
+  generate-darwin-source-and-headers.py                     \
+  libffi.xcodeproj/project.pbxproj                          \
+  src/powerpc/t-aix                                         \
+  libtool-ldflags libtool-version configure.host README.md  \
+  libffi.map.in LICENSE-BUILDTOOLS msvc_build make_sunver.pl
 
 # local.exp is generated by configure
 DISTCLEANFILES = local.exp
 
-# Automake Documentation:
-# If your package has Texinfo files in many directories, you can use the
-# variable TEXINFO_TEX to tell Automake where to find the canonical
-# `texinfo.tex' for your package. The value of this variable should be
-# the relative path from the current `Makefile.am' to `texinfo.tex'.
-TEXINFO_TEX   = ../gcc/doc/include/texinfo.tex
-
-# Defines info, dvi, pdf and html targets
-MAKEINFOFLAGS = -I $(srcdir)/../gcc/doc/include
-info_TEXINFOS = doc/libffi.texi
-
-# AM_CONDITIONAL on configure option --generated-files-in-srcdir
-if GENINSRC
-STAMP_GENINSRC = stamp-geninsrc
-else
-STAMP_GENINSRC =
-endif
-
-# AM_CONDITIONAL on configure check ACX_CHECK_PROG_VER([MAKEINFO])
-if BUILD_DOCS
-STAMP_BUILD_INFO = stamp-build-info
-else
-STAMP_BUILD_INFO =
-endif
-
-all-local: $(STAMP_GENINSRC)
-
-stamp-geninsrc: doc/libffi.info
-       cp -p $(top_builddir)/doc/libffi.info $(srcdir)/doc/libffi.info
-       @touch $@
-
-doc/libffi.info: $(STAMP_BUILD_INFO)
-
-stamp-build-info: doc/libffi.texi $(srcdir)/doc/version.texi doc/$(am__dirstamp)
-       $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)/doc -o doc/libffi.info $(srcdir)/doc/libffi.texi
-       @touch $@
-
-CLEANFILES = $(STAMP_GENINSRC) $(STAMP_BUILD_INFO)
-MAINTAINERCLEANFILES = $(srcdir)/doc/libffi.info
-
-## ################################################################
-
-##
-## This section is for make and multilib madness.
-##
-
-# 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)"
-
 # Subdir rules rely on $(FLAGS_TO_PASS)
 FLAGS_TO_PASS = $(AM_MAKEFLAGS)
 
@@ -130,16 +59,19 @@ noinst_HEADERS = src/aarch64/ffitarget.h src/aarch64/internal.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/moxie/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/powerpc/ffi_powerpc.h src/powerpc/internal.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/wasm/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        \
-       src/kvx/ffitarget.h src/loongarch64/ffitarget.h
+       src/kvx/ffitarget.h src/kvx/asm.h                               \
+       src/loongarch64/ffitarget.h
 
 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      \
@@ -153,9 +85,9 @@ EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.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/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/pa/hpux64.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                     \
@@ -166,6 +98,7 @@ EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S               \
        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/wasm/ffi.c \
        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 src/kvx/ffi.c                \
@@ -180,9 +113,9 @@ 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))
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/libtool-ldflags $(LDFLAGS))
 
-AM_CFLAGS = -Wall -g -fexceptions $(CET_FLAGS)
+AM_CFLAGS =
 if FFI_DEBUG
 # Build debug. Define FFI_DEBUG on the commandline so that, when building with
 # MSVC, it can link against the debug CRT.
@@ -197,10 +130,11 @@ 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)/../contrib/make_sunver.pl \
+libffi.map-sun : libffi.map $(top_srcdir)/make_sunver.pl \
                 $(libffi_la_OBJECTS) $(libffi_la_LIBADD)
-       perl $(top_srcdir)/../contrib/make_sunver.pl libffi.map \
-        $(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
@@ -213,23 +147,16 @@ libffi.map: $(top_srcdir)/libffi.map.in
        $(COMPILE) -D$(TARGET) -DGENERATE_LIBFFI_MAP \
         -E -x assembler-with-cpp -o $@ $(top_srcdir)/libffi.map.in
 
-if ENABLE_DARWIN_AT_RPATH
-libffi_darwin_rpath = -Wl,-rpath,@loader_path
-endif
-libffi_la_LDFLAGS = -no-undefined $(libffi_version_info) \
-       $(libffi_version_script) $(LTLDFLAGS) $(AM_LTLDFLAGS) \
-       $(libffi_darwin_rpath)
+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) $(CET_FLAGS)
+AM_CCASFLAGS = '$(AM_CPPFLAGS)'
 
-# Multilib support.  Automake should provide these on its own.
-all-recursive: all-multi
-install-recursive: install-multi
-mostlyclean-recursive: mostlyclean-multi
-clean-recursive: clean-multi
-distclean-recursive: distclean-multi
-maintainer-clean-recursive: maintainer-clean-multi
+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
 
-include $(top_srcdir)/../multilib.am
+# target overrides
+-include $(tmake_file)
index b95bd74d8ba48f217cbedc74aeda3239c7b224ea..f093c324f66b38006f301c8615491917bb3e563f 100644 (file)
@@ -1,8 +1,7 @@
 Status
 ======
 
-libffi-3.4.1 was released on June 28, 2021.  Check the libffi web page
-for updates: <URL:http://sourceware.org/libffi/>.
+libffi-3.5.2 was released on August 2, 2025.
 
 
 What is libffi?
@@ -52,6 +51,8 @@ tested:
 | Alpha           | Linux            | GCC                     |
 | Alpha           | Tru64            | GCC                     |
 | ARC             | Linux            | GCC                     |
+| ARC32           | Linux            | GCC                     |
+| ARC64           | Linux            | GCC                     |
 | ARM             | Linux            | GCC                     |
 | ARM             | iOS              | GCC                     |
 | ARM             | Windows          | MSVC                    |
@@ -59,8 +60,10 @@ tested:
 | Blackfin        | uClinux          | GCC                     |
 | CSKY            | Linux            | GCC                     |
 | HPPA            | HPUX             | GCC                     |
+| HPPA64          | HPUX             | GCC                     |
 | KVX             | Linux            | GCC                     |
 | IA-64           | Linux            | GCC                     |
+| LoongArch64     | Linux            | GCC                     |
 | M68K            | FreeMiNT         | GCC                     |
 | M68K            | Linux            | GCC                     |
 | M68K            | RTEMS            | GCC                     |
@@ -72,8 +75,8 @@ tested:
 | MIPS            | RTEMS            | GCC                     |
 | MIPS64          | Linux            | GCC                     |
 | Moxie           | Bare metal       | GCC                     |
-| Nios II         | Linux            | GCC                     |
 | OpenRISC        | Linux            | GCC                     |
+| PowerPC 32-bit  | AIX              | GCC                     |
 | PowerPC 32-bit  | AIX              | IBM XL C                |
 | PowerPC 64-bit  | AIX              | IBM XL C                |
 | PowerPC         | AMIGA            | GCC                     |
@@ -87,6 +90,9 @@ tested:
 | RISC-V 64-bit   | Linux            | GCC                     |
 | S390            | Linux            | GCC                     |
 | S390X           | Linux            | GCC                     |
+| SH3             | Linux            | GCC                     |
+| SH4             | Linux            | GCC                     |
+| SH5/SH64        | Linux            | GCC                     |
 | SPARC           | Linux            | GCC                     |
 | SPARC           | Solaris          | GCC                     |
 | SPARC           | Solaris          | Oracle Solaris Studio C |
@@ -95,6 +101,8 @@ tested:
 | SPARC64         | Solaris          | Oracle Solaris Studio C |
 | TILE-Gx/TILEPro | Linux            | GCC                     |
 | VAX             | OpenBSD/vax      | GCC                     |
+| WASM32          | Emscripten       | EMCC                    |
+| WASM64          | Emscripten       | EMCC                    |
 | X86             | FreeBSD          | GCC                     |
 | X86             | GNU HURD         | GCC                     |
 | X86             | Interix          | GCC                     |
@@ -105,14 +113,15 @@ tested:
 | X86             | Solaris          | GCC                     |
 | X86             | Solaris          | Oracle Solaris Studio C |
 | X86             | Windows/Cygwin   | GCC                     |
-| X86             | Windows/MingW    | GCC                     |
+| X86             | Windows/MinGW    | GCC                     |
+| X86-64          | DragonFly BSD    | 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          | Windows/MinGW    | GCC                     |
 | X86-64          | Mac OSX          | GCC                     |
 | Xtensa          | Linux            | GCC                     |
 
@@ -130,7 +139,7 @@ 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.
+install autoconf, automake, libtool and texinfo.
 
 You may want to tell configure where to install the libffi library and
 header files. To do that, use the ``--prefix`` configure switch.  Libffi
@@ -152,7 +161,7 @@ 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"
+    path/to/configure CC=path/to/msvcc.sh CXX=path/to/msvcc.sh LD=link CPP="cl -nologo -EP" CXXCPP="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
@@ -195,7 +204,66 @@ History
 
 See the git log for details at http://github.com/libffi/libffi.
 
-    3.4.2 Jun-28-21
+    3.5.2 Aug-2-2025
+        Add wasm64 support.
+        Add DragonFly BSD support.
+        Ensure trampoline file descriptors are closed on exec.
+
+    3.5.1 Jun-10-2025
+        Fix symbol versioning error.
+
+    3.5.0 Jun-8-2025
+        Add FFI_VERSION_STRING and FFI_VERSION_NUMBER macros, as well
+          as ffi_get_version() and ffi_get_version_number() functions.
+        Add ffi_get_default_abi() and ffi_get_closure_size() functions.
+        Fix closures on powerpc64-linux when statically linking.
+        Mark the PA stack as non-executable.
+
+    3.4.8 Apr-9-2025
+        Add static trampoline support for powerpc-linux (32-bit SYSV BE),
+          powerpc64-linux (64-bit ELFv1 BE) and
+          powerpc64le-linux (64-bit ELFv2 LE)
+        Various x86-64 bug fixes (x32 ABI and improper memory access for
+          small argument calls).
+        Fix to enable pointer authentication for aarch64.
+
+    3.4.7 Feb-8-2025
+        Add static trampoline support for Linux on s390x.
+        Fix BTI support for ARM64.
+        Support pointer authentication for ARM64.
+        Fix ASAN compatibility.
+        Fix x86-64 calls with 6 GP registers and some SSE registers.
+        Miscellaneous fixes for ARC and Darwin ARM64.
+        Fix OpenRISC or1k and Solaris 10 builds.
+        Remove nios2 port.
+
+    3.4.6 Feb-18-2024
+        Fix long double regression on mips64 and alpha.
+
+    3.4.5 Feb-15-2024
+        Add support for wasm32.
+        Add support for aarch64 branch target identification (bti).
+        Add support for ARCv3: ARC32 & ARC64.
+        Add support for HPPA64, and many HPPA fixes.
+        Add support for Haikuos on PowerPC.
+        Fixes for AIX, loongson, MIPS, power, sparc64, and x86 Darwin.
+
+    3.4.4 Oct-23-2022
+        Important aarch64 fixes, including support for linux builds
+          with Link Time Optimization (-flto).
+        Fix x86 stdcall stack alignment.
+        Fix x86 Windows msvc assembler compatibility.
+        Fix moxie and or1k small structure args.
+
+    3.4.3 Sep-19-2022
+        All struct args are passed by value, regardless of size, as per ABIs.
+        Enable static trampolines for Cygwin.
+        Add support for Loongson's LoongArch64 architecture.
+        Fix x32 static trampolines.
+        Fix 32-bit x86 stdcall stack corruption.
+        Fix ILP32 aarch64 support.
+
+    3.4.2 Jun-28-2021
         Add static trampoline support for Linux on x86_64 and ARM64.
         Add support for Alibaba's CSKY architecture.
         Add support for Kalray's KVX architecture.
@@ -208,7 +276,7 @@ See the git log for details at http://github.com/libffi/libffi.
         Reject float and small integer argument in ffi_prep_cif_var().
           Callers must promote these types themselves.
 
-    3.3 Nov-23-19
+    3.3 Nov-23-2019
         Add RISC-V support.
         New API in support of GO closures.
         Add IEEE754 binary128 long double support for 64-bit Power
@@ -220,10 +288,10 @@ See the git log for details at http://github.com/libffi/libffi.
         Add pre-built PDF documentation to source distribution.
         Many new test cases and bug fixes.
 
-    3.2.1 Nov-12-14
+    3.2.1 Nov-12-2014
         Build fix for non-iOS AArch64 targets.
 
-    3.2 Nov-11-14
+    3.2 Nov-11-2014
         Add C99 Complex Type support (currently only supported on
           s390).
         Add support for PASCAL and REGISTER calling conventions on x86
@@ -231,7 +299,7 @@ See the git log for details at http://github.com/libffi/libffi.
         Add OpenRISC and Cygwin-64 support.
         Bug fixes.
 
-    3.1 May-19-14
+    3.1 May-19-2014
         Add AArch64 (ARM64) iOS support.
         Add Nios II support.
         Add m88k and DEC VAX support.
@@ -244,7 +312,7 @@ See the git log for details at http://github.com/libffi/libffi.
         Archive off the manually maintained ChangeLog in favor of git
           log.
 
-    3.0.13 Mar-17-13
+    3.0.13 Mar-17-2013
         Add Meta support.
         Add missing Moxie bits.
         Fix stack alignment bug on 32-bit x86.
@@ -254,7 +322,7 @@ See the git log for details at http://github.com/libffi/libffi.
           with GCC (OS X, Solaris).
         Fix Cygwin regression.
 
-    3.0.12 Feb-11-13
+    3.0.12 Feb-11-2013
         Add Moxie support.
         Add AArch64 support.
         Add Blackfin support.
@@ -266,7 +334,7 @@ See the git log for details at http://github.com/libffi/libffi.
           Solaris and AIX.
         Work around LLVM/GCC interoperability issue on x86_64.
 
-    3.0.11 Apr-11-12
+    3.0.11 Apr-11-2012
         Lots of build fixes.
         Add support for variadic functions (ffi_prep_cif_var).
         Add Linux/x32 support.
@@ -277,7 +345,7 @@ See the git log for details at http://github.com/libffi/libffi.
         Fix Octeon and MC68881 support.
         Fix code pessimizations.
 
-    3.0.10 Aug-23-11
+    3.0.10 Aug-23-2011
         Add support for Apple's iOS.
         Add support for ARM VFP ABI.
         Add RTEMS support for MIPS and M68K.
@@ -291,71 +359,71 @@ See the git log for details at http://github.com/libffi/libffi.
         Testsuite fixes for Tru64 Unix.
         Additional platform support.
 
-    3.0.9 Dec-31-09
+    3.0.9 Dec-31-2009
         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
+    3.0.8 Dec-19-2008
         Add *BSD, BeOS, and PA-Linux support.
 
-    3.0.7 Nov-11-08
+    3.0.7 Nov-11-2008
         Fix for ppc FreeBSD.
         (thanks to Andreas Tobler)
 
-    3.0.6 Jul-17-08
+    3.0.6 Jul-17-2008
         Fix for closures on sh.
         Mark the sh/sh64 stack as non-executable.
         (both thanks to Kaz Kojima)
 
-    3.0.5 Apr-3-08
+    3.0.5 Apr-3-2008
         Fix libffi.pc file.
         Fix #define ARM for IcedTea users.
         Fix x86 closure bug.
 
-    3.0.4 Feb-24-08
+    3.0.4 Feb-24-2008
         Fix x86 OpenBSD configury.
 
-    3.0.3 Feb-22-08
+    3.0.3 Feb-22-2008
         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
+    3.0.2 Feb-21-2008
         Improved x86 FreeBSD support.
         Thanks to Björn König.
 
-    3.0.1 Feb-15-08
+    3.0.1 Feb-15-2008
         Fix instruction cache flushing bug on MIPS.
         Thanks to David Daney.
 
-    3.0.0 Feb-15-08
+    3.0.0 Feb-15-2008
         Many changes, mostly thanks to the GCC project.
         Cygnus Solutions is now Red Hat.
 
       [10 years go by...]
 
-    1.20 Oct-5-98
+    1.20 Oct-5-1998
         Raffaele Sena produces ARM port.
 
-    1.19 Oct-5-98
+    1.19 Oct-5-1998
         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
+    1.18 Apr-17-1998
         Bug fixes and MIPS configuration changes.
 
-    1.17 Feb-24-98
+    1.17 Feb-24-1998
         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
+    1.16 Feb-11-1998
         Richard Henderson produces Alpha port.
 
-    1.15 Dec-4-97
+    1.15 Dec-4-1997
         Fixed an n32 ABI bug. New libtool, auto* support.
 
     1.14 May-13-97
@@ -363,56 +431,56 @@ See the git log for details at http://github.com/libffi/libffi.
         Fixed a minor portability problem reported by Russ McManus
         <mcmanr@eq.gs.com>.
 
-    1.13 Dec-2-96
+    1.13 Dec-2-1996
         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
+    1.12 Nov-22-1996
         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
+    1.11 Oct-30-1996
         Added notes about GNU make.
 
-    1.10 Oct-29-96
+    1.10 Oct-29-1996
         Added configuration fix for non GNU compilers.
 
-    1.09 Oct-29-96
+    1.09 Oct-29-1996
         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
+    1.08 Oct-15-1996
         Fixed n32 problem. Many clean-ups.
 
-    1.07 Oct-14-96
+    1.07 Oct-14-1996
         Gordon Irlam rewrites v8.S again. Bug fixes.
 
-    1.06 Oct-14-96
+    1.06 Oct-14-1996
         Gordon Irlam improved the sparc port.
 
-    1.05 Oct-14-96
+    1.05 Oct-14-1996
         Interface changes based on feedback.
 
-    1.04 Oct-11-96
+    1.04 Oct-11-1996
         Sparc port complete (modulo struct passing bug).
 
-    1.03 Oct-10-96
+    1.03 Oct-10-1996
         Passing struct args, and returning struct values works for
         all architectures/calling conventions. Expanded tests.
 
-    1.02 Oct-9-96
+    1.02 Oct-9-1996
         Added SGI n32 support. Fixed bugs in both o32 and Linux support.
         Added "make test".
 
-    1.01 Oct-8-96
+    1.01 Oct-8-1996
         Fixed float passing bug in mips version. Restructured some
         of the code. Builds cleanly with SGI tools.
 
-    1.00 Oct-7-96
+    1.00 Oct-7-1996
         First release. No public announcement.
 
 Authors & Credits
@@ -444,6 +512,8 @@ developers:
     frv                 Anthony Green
     ia64                Hans Boehm
     kvx                 Yann Sionneau
+    loongarch64         Cheng Lulu, Xi Ruoyao, Xu Hao,
+                        Zhang Wenlong, Pan Xuefeng
     m32r                Kazuhiro Inaoka
     m68k                Andreas Schwab
     m88k                Miod Vallat
@@ -455,6 +525,7 @@ developers:
     nios ii             Sandra Loosemore
     openrisc            Sebastian Macke
     pa                  Randolph Chung, Dave Anglin, Andreas Tobler
+    pa64                Dave Anglin
     powerpc             Geoffrey Keating, Andreas Tobler,
                         David Edelsohn, John Hornkvist
     powerpc64           Jakub Jelinek
@@ -465,6 +536,7 @@ developers:
     sparc               Anthony Green, Gordon Irlam
     tile-gx/tilepro     Walter Lee
     vax                 Miod Vallat
+    wasm32              Hood Chatham, Brion Vibber, Kleis Auke Wolthuizen
     x86                 Anthony Green, Jon Beniston
     x86-64              Bo Thorsen
     xtensa              Chris Zankel
index 1a70efb010dc045bb4287ca1afcff76bfa0d74a1..9624bbed0bdf8fa208c19384d5329b28e3805b30 100644 (file)
@@ -45,16 +45,16 @@ else
 
    # Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for.
    AC_CACHE_CHECK([for MAP_ANON(YMOUS)], ac_cv_decl_map_anon,
-    [AC_TRY_COMPILE(
-[#include <sys/types.h>
+    [AC_COMPILE_IFELSE(
+[AC_LANG_PROGRAM([[#include <sys/types.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
 #ifndef MAP_ANONYMOUS
 #define MAP_ANONYMOUS MAP_ANON
 #endif
-],
-[int n = MAP_ANONYMOUS;],
+]],
+[[int n = MAP_ANONYMOUS;]])],
     ac_cv_decl_map_anon=yes,
     ac_cv_decl_map_anon=no)])
 
@@ -104,7 +104,7 @@ 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
+m4_define([_g_help],[AS_HELP_STRING([_g_switch$3],[$4 @<:@default=$2@:>@])])dnl
  AC_ARG_ENABLE($1,_g_help,
   m4_bmatch([$5],
    [^permit ],
@@ -152,109 +152,7 @@ AC_DEFUN([LIBFFI_CHECK_LINKER_FEATURES], [
   # 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([LT_PATH_LD])
   AC_REQUIRE([AC_PROG_AWK])
 
   # The name set by libtool depends on the version of libtool.  Shame on us
@@ -282,6 +180,10 @@ AC_DEFUN([LIBFFI_CHECK_LINKER_FEATURES], [
   if $LD --version 2>/dev/null | grep 'LLD '> /dev/null 2>&1; then
     libat_ld_is_lld=yes
   fi
+  libat_ld_is_mold=no
+  if $LD --version 2>/dev/null | grep 'mold '> /dev/null 2>&1; then
+    libat_ld_is_mold=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'`
@@ -307,14 +209,14 @@ AC_DEFUN([LIBFFI_CHECK_LINKER_FEATURES], [
     # .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([
+    AC_RUN_IFELSE([AC_LANG_SOURCE([[
      int main(void)
      {
        try { throw 1; }
        catch (...) { };
        return 0;
      }
-    ], [ac_sectionLDflags=yes],[ac_sectionLDflags=no], [ac_sectionLDflags=yes])
+    ]])],[ac_sectionLDflags=yes],[ac_sectionLDflags=no],[ac_sectionLDflags=yes])
     if test "$ac_test_CFLAGS" = set; then
       CFLAGS="$ac_save_CFLAGS"
     else
@@ -401,7 +303,7 @@ 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)
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[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
@@ -416,7 +318,7 @@ 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)
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[return 0;]])],[libat_shared_libgcc=yes],[])
       CFLAGS="$ac_save_CFLAGS"
     fi
   fi
@@ -438,6 +340,8 @@ if test $enable_symvers != no && test $libat_shared_libgcc = yes; then
       enable_symvers=gnu
     elif test $libat_ld_is_lld = yes ; then
       enable_symvers=gnu
+    elif test $libat_ld_is_mold = 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)
index c89b2460d7c293e8ce7a9444642eeb0bb8cfe409..dcfc7b242d02b32e822b3dd780aed38b4a2d8648 100644 (file)
@@ -1,34 +1,27 @@
 dnl Process this with autoconf to create configure
 
-AC_PREREQ(2.68)
+AC_PREREQ([2.68])
 
-AC_INIT([libffi], [3.4.2], [http://github.com/libffi/libffi/issues])
+AC_INIT([libffi],[3.5.2],[http://github.com/libffi/libffi/issues])
 AC_CONFIG_HEADERS([fficonfig.h])
 
-AM_ENABLE_MULTILIB(, ..)
+FFI_VERSION_STRING="3.5.2"
+FFI_VERSION_NUMBER=30502
+AC_SUBST(FFI_VERSION_STRING)
+AC_SUBST(FFI_VERSION_NUMBER)
 
-AC_CANONICAL_SYSTEM
+AC_CANONICAL_TARGET
 target_alias=${target_alias-$host_alias}
 
-AM_INIT_AUTOMAKE([no-dist])
-
-# We would like our source tree to be readonly. However when releases or
-# pre-releases are generated, the flex/bison generated files as well as the
-# various formats of manuals need to be included along with the rest of the
-# sources.  Therefore we have --enable-generated-files-in-srcdir to do
-# just that.
-AC_MSG_CHECKING(generated-files-in-srcdir)
-AC_ARG_ENABLE(generated-files-in-srcdir,
-AS_HELP_STRING([--enable-generated-files-in-srcdir],
- [put copies of generated files in source dir intended for creating source tarballs for users without texinfo bison or flex]),
-[case "$enableval" in
- yes) enable_generated_files_in_srcdir=yes ;;
- no)  enable_generated_files_in_srcdir=no ;;
- *)   AC_MSG_ERROR([Unknown argument to enable/disable version-specific libs]);;
- esac],
-[enable_generated_files_in_srcdir=no])
-AC_MSG_RESULT($enable_generated_files_in_srcdir)
-AM_CONDITIONAL(GENINSRC, test "$enable_generated_files_in_srcdir" = yes)
+case "${host}" in
+  frv*-elf)
+    LDFLAGS=`echo $LDFLAGS | sed "s/\-B[^ ]*libgloss\/frv\///"`\ -B`pwd`/../libgloss/frv/
+    ;;
+esac
+
+AX_ENABLE_BUILDDIR
+
+AM_INIT_AUTOMAKE
 
 # The same as in boehm-gc and libstdc++. Have to borrow it from there.
 # We must force CC to /not/ be precious variables; otherwise
@@ -48,24 +41,32 @@ m4_rename_force([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS])
 
 AC_SUBST(CFLAGS)
 
-# Add CET specific flags if CET is enabled
-GCC_CET_FLAGS(CET_FLAGS)
-AC_SUBST(CET_FLAGS)
-
 AM_PROG_AS
 AM_PROG_CC_C_O
-AC_PROG_LIBTOOL
-AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes])
+AC_PROG_EGREP
+LT_INIT
+AC_CONFIG_MACRO_DIR([m4])
 
-AC_CHECK_TOOL(READELF, readelf)
+AC_CHECK_TOOLS([READELF], [readelf greadelf])
 
 # Test for 64-bit build.
 AC_CHECK_SIZEOF([size_t])
 
-AC_SUBST(SYSROOT_CFLAGS_FOR_TARGET)
+AX_COMPILER_VENDOR
+AX_CC_MAXOPT
+# The AX_CFLAGS_WARN_ALL macro doesn't currently work for sunpro
+# compiler.
+if test "$ax_cv_c_compiler_vendor" != "sun"; then
+  AX_CFLAGS_WARN_ALL
+fi
+
+if test "x$GCC" = "xyes"; then
+  CFLAGS="$CFLAGS -fexceptions"
+fi
 
 cat > local.exp <<EOF
-set SYSROOT_CFLAGS_FOR_TARGET "$SYSROOT_CFLAGS_FOR_TARGET"
+set CC_FOR_TARGET "$CC"
+set CXX_FOR_TARGET "$CXX"
 set compiler_vendor "$ax_cv_c_compiler_vendor"
 EOF
 
@@ -74,10 +75,6 @@ AM_MAINTAINER_MODE
 AC_CHECK_HEADERS(sys/memfd.h)
 AC_CHECK_FUNCS([memfd_create])
 
-AC_CHECK_HEADERS(sys/mman.h)
-AC_CHECK_FUNCS([mmap mkostemp mkstemp])
-AC_FUNC_MMAP_BLACKLIST
-
 dnl The -no-testsuite modules omit the test subdir.
 AM_CONDITIONAL(TESTSUBDIR, test -d $srcdir/testsuite)
 
@@ -93,9 +90,13 @@ fi
 AC_SUBST(AM_RUNTESTFLAGS)
 AC_SUBST(AM_LTLDFLAGS)
 
-AC_HEADER_STDC
+m4_warn([obsolete],
+[The preprocessor macro `STDC_HEADERS' is obsolete.
+  Except in unusual embedded environments, you can safely include all
+  ISO C90 headers unconditionally.])dnl
+
 AC_CHECK_FUNCS(memcpy)
-AC_FUNC_ALLOCA
+AC_CHECK_HEADERS(alloca.h)
 
 AC_CHECK_SIZEOF(double)
 AC_CHECK_SIZEOF(long double)
@@ -122,6 +123,8 @@ AC_C_BIGENDIAN
 
 GCC_AS_CFI_PSEUDO_OP
 
+AC_ARG_VAR([WASM64_MEMORY64], [Used only for the wasm64 target. Set to 1 (default) or 2 for Emscripten's -sMEMORY64 mode])
+
 case "$TARGET" in
   SPARC)
     AC_CACHE_CHECK([assembler and linker support unaligned pc related relocs],
@@ -130,9 +133,7 @@ case "$TARGET" in
        save_LDFLAGS="$LDFLAGS"
        CFLAGS="$CFLAGS -fpic"
        LDFLAGS="$LDFLAGS -shared"
-       AC_TRY_LINK([asm (".text; foo: nop; .data; .align 4; .byte 0; .uaword %r_disp32(foo); .text");],,
-                   [libffi_cv_as_sparc_ua_pcrel=yes],
-                   [libffi_cv_as_sparc_ua_pcrel=no])
+       AC_LINK_IFELSE([AC_LANG_PROGRAM([[asm (".text; foo: nop; .data; .align 4; .byte 0; .uaword %r_disp32(foo); .text");]], [[]])],[libffi_cv_as_sparc_ua_pcrel=yes],[libffi_cv_as_sparc_ua_pcrel=no])
        CFLAGS="$save_CFLAGS"
        LDFLAGS="$save_LDFLAGS"])
     if test "x$libffi_cv_as_sparc_ua_pcrel" = xyes; then
@@ -144,9 +145,7 @@ case "$TARGET" in
        libffi_cv_as_register_pseudo_op, [
        libffi_cv_as_register_pseudo_op=unknown
        # Check if we have .register
-       AC_TRY_COMPILE(,[asm (".register %g2, #scratch");],
-                      [libffi_cv_as_register_pseudo_op=yes],
-                      [libffi_cv_as_register_pseudo_op=no])
+       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[asm (".register %g2, #scratch");]])],[libffi_cv_as_register_pseudo_op=yes],[libffi_cv_as_register_pseudo_op=no])
     ])
     if test "x$libffi_cv_as_register_pseudo_op" = xyes; then
        AC_DEFINE(HAVE_AS_REGISTER_PSEUDO_OP, 1,
@@ -175,7 +174,7 @@ case "$TARGET" in
        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
+           if $GREP -q brasl conftest.s; then
                libffi_cv_as_s390_zarch=yes
            fi
        fi
@@ -185,38 +184,52 @@ case "$TARGET" in
                  [Define if the compiler uses zarch features.])
     fi
     ;;
+  wasm64)
+    if test -z "$WASM64_MEMORY64"; then
+      WASM64_MEMORY64=1
+    fi
+    CFLAGS="$CFLAGS -sMEMORY64=$WASM64_MEMORY64"
+    ;;
 esac
 
 AC_CACHE_CHECK([whether compiler supports pointer authentication],
    libffi_cv_as_ptrauth, [
    libffi_cv_as_ptrauth=unknown
-   AC_TRY_COMPILE(,[
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
 #ifdef __clang__
 # if __has_feature(ptrauth_calls)
-#  define HAVE_PTRAUTH 1
+#  define HAVE_ARM64E_PTRAUTH 1
 # endif
 #endif
 
-#ifndef HAVE_PTRAUTH
+#ifndef HAVE_ARM64E_PTRAUTH
 # error Pointer authentication not supported
 #endif
-                  ],
-                  [libffi_cv_as_ptrauth=yes],
-                  [libffi_cv_as_ptrauth=no])
+                  ]])],[libffi_cv_as_ptrauth=yes],[libffi_cv_as_ptrauth=no])
 ])
 if test "x$libffi_cv_as_ptrauth" = xyes; then
-    AC_DEFINE(HAVE_PTRAUTH, 1,
+    AC_DEFINE(HAVE_ARM64E_PTRAUTH, 1,
              [Define if your compiler supports pointer authentication.])
 fi
 
-# On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC.
+# On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC;
+# if EMUTRAMP is active too ffi could try mapping without PROT_EXEC,
+# but the kernel needs to recognize the trampoline generated by ffi.
+# Otherwise fallback to double mmap trick.
 AC_ARG_ENABLE(pax_emutramp,
-  [  --enable-pax_emutramp       enable pax emulated trampolines, for we can't use PROT_EXEC],
+  [  --enable-pax_emutramp       enable pax emulated trampolines (experimental)],
   if test "$enable_pax_emutramp" = "yes"; then
+    AC_MSG_WARN([EMUTRAMP is experimental only.  Use --enable-pax_emutramp=experimental to enforce.])
+  elif test "$enable_pax_emutramp" = "experimental"; then
     AC_DEFINE(FFI_MMAP_EXEC_EMUTRAMP_PAX, 1,
-      [Define this if you want to enable pax emulated trampolines])
+      [Define this if you want to enable pax emulated trampolines (experimental)])
   fi)
 
+LT_SYS_SYMBOL_USCORE
+if test "x$sys_symbol_underscore" = xyes; then
+    AC_DEFINE(SYMBOL_UNDERSCORE, 1, [Define if symbols are underscored.])
+fi
+
 FFI_EXEC_TRAMPOLINE_TABLE=0
 case "$target" in
      *arm*-apple-* | aarch64-apple-*)
@@ -225,7 +238,7 @@ case "$target" in
                  [Cannot use PROT_EXEC on this target, so, we revert to
                    alternative means])
      ;;
-     *-apple-* | *-*-freebsd* | *-*-kfreebsd* | *-*-openbsd* | *-pc-solaris* | *-linux-android*)
+     *-apple-* | *-*-dragonfly* | *-*-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])
@@ -266,12 +279,14 @@ EOF
 fi
 
 if test "x$GCC" = "xyes"; then
+  AX_CHECK_COMPILE_FLAG(-fno-lto, libffi_cv_no_lto=-fno-lto)
+
   AC_CACHE_CHECK([whether .eh_frame section should be read-only],
       libffi_cv_ro_eh_frame, [
        libffi_cv_ro_eh_frame=yes
        echo 'extern void foo (void); void bar (void) { foo (); foo (); }' > conftest.c
-       if $CC $CFLAGS -c -fpic -fexceptions -fno-lto -o conftest.o conftest.c > /dev/null 2>&1; then
-           if $READELF -WS conftest.o | grep -q -n 'eh_frame .* WA'; then
+       if $CC $CFLAGS -c -fpic -fexceptions $libffi_cv_no_lto -o conftest.o conftest.c > /dev/null 2>&1; then
+           if $READELF -WS conftest.o 2>/dev/null | $GREP -q -n 'eh_frame .* WA'; then
                libffi_cv_ro_eh_frame=no
            fi
        fi
@@ -292,7 +307,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 egrep '(\.hidden|\.private_extern).*foo' conftest.s >/dev/null; then
+           if $EGREP '(\.hidden|\.private_extern).*foo|foo.*,hidden' conftest.s >/dev/null; then
                libffi_cv_hidden_visibility_attribute=yes
            fi
        fi
@@ -304,12 +319,11 @@ if test "x$GCC" = "xyes"; then
   fi
 fi
 
-# See if makeinfo has been installed and is modern enough
-# that we can use it.
-ACX_CHECK_PROG_VER([MAKEINFO], [makeinfo], [--version],
-                   [GNU texinfo.* \([0-9][0-9.]*\)],
-                   [4.[4-9]*|4.[1-9][0-9]*|[5-9]*|[1-9][0-9]*])
-AM_CONDITIONAL(BUILD_DOCS, test $gcc_cv_prog_makeinfo_modern = "yes")
+AC_ARG_ENABLE(docs,
+              AS_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
@@ -365,13 +379,20 @@ AC_ARG_ENABLE(raw-api,
   fi)
 
 AC_ARG_ENABLE(exec-static-tramp,
-[  --enable-exec-static-tramp  enable use of static exec trampolines])
+[  --disable-exec-static-tramp  disable use of static exec trampolines (enabled by default)])
 
-if test "$enable_exec_static_tramp" = yes; then
+if test "$enable_exec_static_tramp" != no; then
 case "$target" in
-     *-cygwin*)
+     *-cygwin* | *-msys*)
+       # Only define static trampolines if we are using the cygwin runtime.
+       # Will this need to be changed for mingw?
+       if test "x$GCC" = "xyes"; then
+         AC_DEFINE(FFI_EXEC_STATIC_TRAMP, 1,
+                   [Define this if you want statically defined trampolines])
+       fi
      ;;
-     *arm*-*-linux-* | aarch64*-*-linux-* | i*86-*-linux-* | x86_64-*-linux-*)
+     *arm*-*-linux-* | aarch64*-*-linux-* | i*86-*-linux-* | x86_64-*-linux-* \
+     | loongarch*-*-linux-* | s390x*-linux-* | powerpc*-linux-*)
        AC_DEFINE(FFI_EXEC_STATIC_TRAMP, 1,
                  [Define this if you want statically defined trampolines])
      ;;
@@ -384,51 +405,57 @@ AC_ARG_ENABLE(purify-safety,
     AC_DEFINE(USING_PURIFY, 1, [Define this if you are using Purify and want to suppress spurious messages.])
   fi)
 
-GCC_WITH_TOOLEXECLIBDIR
-
-if test -n "$with_cross_host" &&
-   test x"$with_cross_host" != x"no"; then
-  toolexecdir='$(exec_prefix)/$(target_alias)'
-  case ${with_toolexeclibdir} in
-    no)
-      toolexeclibdir='$(toolexecdir)/lib'
-      ;;
-    *)
-      toolexeclibdir=${with_toolexeclibdir}
-      ;;
-  esac
+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
+  else
+    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
+  AC_SUBST(toolexecdir)
 else
-  toolexecdir='$(libdir)/gcc-lib/$(target_alias)'
-  toolexeclibdir='$(libdir)'
+  toolexeclibdir='${libdir}'
 fi
-multi_os_directory=`$CC -print-multi-os-directory`
-case $multi_os_directory in
-  .) ;; # Avoid trailing /.
-  *) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;;
-esac
-AC_SUBST(toolexecdir)
 AC_SUBST(toolexeclibdir)
 
-if test "${multilib}" = "yes"; then
-  multilib_arg="--enable-multilib"
-else
-  multilib_arg=
-fi
+# Conditionalize the makefile for this target machine.
+tmake_file_=
+for f in ${tmake_file}; do
+  if test -f ${srcdir}/src/$TARGETDIR/$f; then
+     tmake_file_="${tmake_file_} \$(srcdir)/src/$TARGETDIR/$f"
+  fi
+done
+tmake_file="${tmake_file_}"
+AC_SUBST(tmake_file)
 
 # Check linker support.
 LIBFFI_ENABLE_SYMVERS
 
-# Determine what GCC version number to use in filesystem paths.
-GCC_BASE_VER
-
 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_FILES(include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile libffi.pc)
-
-AC_CONFIG_LINKS(include/ffitarget.h:src/$TARGETDIR/ffitarget.h)
+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
index 9d73f18ee8cb0bfce30457e87661b675db48f6dd..4e10c3edb773a10a66bfbd3b33bfe1d037e8138d 100644 (file)
@@ -6,7 +6,7 @@
 # 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* )
+  aarch64*-*-cygwin* | aarch64*-*-msys* | aarch64*-*-mingw* | aarch64*-*-win* )
        TARGET=ARM_WIN64; TARGETDIR=aarch64
        if test "${ax_cv_c_compiler_vendor}" = "microsoft"; then
          MSVC=1
@@ -30,7 +30,7 @@ case "${host}" in
        SOURCES="ffi.c arcompact.S"
        ;;
 
-  arm*-*-cygwin* | arm*-*-mingw* | arm*-*-win* )
+  arm*-*-cygwin* | arm*-*-msys* | arm*-*-mingw* | arm*-*-win* )
        TARGET=ARM_WIN32; TARGETDIR=arm
        if test "${ax_cv_c_compiler_vendor}" = "microsoft"; then
          MSVC=1
@@ -73,6 +73,7 @@ case "${host}" in
        ;;
   hppa*64-*-hpux*)
        TARGET=PA64_HPUX; TARGETDIR=pa
+       SOURCES="ffi64.c hpux64.S"
        ;;
   hppa*-*-hpux*)
        TARGET=PA_HPUX; TARGETDIR=pa
@@ -83,8 +84,8 @@ case "${host}" in
        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* )
+  i?86-*-cygwin* | i?86-*-msys* | i?86-*-mingw* | i?86-*-win* | i?86-*-os2* | i?86-*-interix* \
+  | x86_64-*-cygwin* | x86_64-*-msys* | x86_64-*-mingw* | x86_64-*-win* )
        TARGETDIR=x86
        if test $ac_cv_sizeof_size_t = 4; then
          TARGET=X86_WIN32
@@ -184,11 +185,6 @@ case "${host}" in
        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"
@@ -204,7 +200,7 @@ case "${host}" in
   powerpc-*-eabi*)
        TARGET=POWERPC; TARGETDIR=powerpc
        ;;
-  powerpc-*-beos*)
+  powerpc-*-beos* | powerpc-*-haiku*)
        TARGET=POWERPC; TARGETDIR=powerpc
        ;;
   powerpc-*-darwin* | powerpc64-*-darwin*)
@@ -212,6 +208,8 @@ case "${host}" in
        ;;
   powerpc-*-aix* | rs6000-*-aix*)
        TARGET=POWERPC_AIX; TARGETDIR=powerpc
+       # Create AIX-style "FAT" libraries.
+       tmake_file="t-aix"
        ;;
   powerpc-*-freebsd* | powerpc-*-openbsd* | powerpc-*-netbsd*)
        TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
@@ -262,6 +260,16 @@ case "${host}" in
        SOURCES="ffi.c elfbsd.S"
        ;;
 
+  wasm32-*-*)
+       TARGET=wasm32; TARGETDIR=wasm
+       SOURCES="ffi.c"
+       ;;
+
+  wasm64-*-*)
+       TARGET=wasm64; TARGETDIR=wasm
+       SOURCES="ffi.c"
+       ;;
+
   xtensa*-*)
        TARGET=XTENSA; TARGETDIR=xtensa
        SOURCES="ffi.c sysv.S"
index 7fd3625d992b50e713721f8bae60bb9b397e99dd..165c2fb1f873ecd536af909138f50128d9875203 100644 (file)
@@ -18,7 +18,7 @@
 This manual is for libffi, a portable foreign function interface
 library.
 
-Copyright @copyright{} 2008--2019, 2021 Anthony Green and Red Hat, Inc.
+Copyright @copyright{} 2008--2025 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
@@ -91,10 +91,10 @@ sometimes called the @dfn{ABI} or @dfn{Application Binary Interface}.
 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.  @samp{Libffi} can be used in such programs to
+a given function.  @code{libffi} can be used in such programs to
 provide a bridge from the interpreter program to compiled code.
 
-The @samp{libffi} library provides a portable, high level programming
+The @code{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.
@@ -102,9 +102,9 @@ time.
 @acronym{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 @samp{libffi} library really only provides the lowest, machine
+The @code{libffi} library really only provides the lowest, machine
 dependent layer of a fully featured foreign function interface.  A
-layer must exist above @samp{libffi} that handles type conversions for
+layer must exist above @code{libffi} that handles type conversions for
 values passed between the two languages.
 @cindex FFI
 @cindex Foreign Function Interface
@@ -127,7 +127,7 @@ values passed between the two languages.
 @node The Basics
 @section The Basics
 
-@samp{Libffi} assumes that you have a pointer to the function you wish
+@code{libffi} assumes that you have a pointer to the function you wish
 to call and that you know the number and types of arguments to pass
 it, as well as the return type of the function.
 
@@ -213,22 +213,20 @@ 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
+In most situations, @code{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
+@code{libffi}.  @code{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
+with a return type of @code{char}, @code{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.
+then @var{avalues} is ignored.
 
 Note that while the return value must be register-sized, arguments
 should exactly match their declared type.  For example, if an argument
@@ -238,6 +236,29 @@ object declared as @code{short}; but if the return type is
 a larger type -- usually @code{ffi_arg}.
 @end defun
 
+@findex ffi_get_version
+@defun {const char *} ffi_get_version (void)
+Returns the library version as a string.  This string is also
+available at build time as the macro @code{FFI_VERSION_STRING}.
+@end defun
+
+@findex ffi_get_version_number
+@defun {unsigned long} ffi_get_version_number (void)
+Returns the library version as an unsigned long value where
+version ``x.y.z'' is represented as the number x*10000+y*100+z.
+This number is also available at build time as the macro
+@code{FFI_VERSION_NUMBER}.
+@end defun
+
+@findex ffi_get_default_abi
+@defun {unsigned int} ffi_get_default_abi (void)
+Return the value of @code{FFI_DEFAULT_ABI}.
+@end defun
+
+@findex ffi_get_closure_size
+@defun {size_t} ffi_get_closure_size (void)
+Return @code{sizeof(ffi_closure)}.
+@end defun
 
 @node Simple Example
 @section Simple Example
@@ -265,14 +286,14 @@ int main()
                       &ffi_type_sint, args) == FFI_OK)
     @{
       s = "Hello World!";
-      ffi_call(&cif, puts, &rc, values);
+      ffi_call(&cif, (void(*)())puts, &rc, values);
       /* rc now holds the result of the call to puts */
 
       /* values holds a pointer to the function's arg, so to
          call puts() again all we need to do is change the
          value of s */
       s = "This is cool!";
-      ffi_call(&cif, puts, &rc, values);
+      ffi_call(&cif, (void(*)())puts, &rc, values);
     @}
 
   return 0;
@@ -412,8 +433,8 @@ when passing to @code{ffi_prep_cif}.
 @node Structures
 @subsection Structures
 
-@samp{libffi} is perfectly happy passing structures back and forth.
-You must first describe the structure to @samp{libffi} by creating a
+@code{libffi} is perfectly happy passing structures back and forth.
+You must first describe the structure to @code{libffi} by creating a
 new @code{ffi_type} object for it.
 
 @tindex ffi_type
@@ -433,7 +454,7 @@ For a structure, this should be set to @code{FFI_TYPE_STRUCT}.
 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
+Note that @code{libffi} has no special support for bit-fields.  You
 must manage these manually.
 @end table
 @end deftp
@@ -510,7 +531,7 @@ valid here.
 
 @subsubsection Arrays
 
-@samp{libffi} does not have direct support for arrays or unions.
+@code{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
@@ -537,7 +558,7 @@ 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
+@code{libffi} if you use it as an argument or return type.  This may
 be confusing.
 
 @subsubsection Unions
@@ -629,7 +650,7 @@ Here is the corresponding code to describe this struct to
 
       tm_type.size = tm_type.alignment = 0;
       tm_type.type = FFI_TYPE_STRUCT;
-      tm_type.elements = &tm_type_elements;
+      tm_type.elements = tm_type_elements;
 
       for (i = 0; i < 9; i++)
           tm_type_elements[i] = &ffi_type_sint;
@@ -646,7 +667,7 @@ Here is the corresponding code to describe this struct to
 @node Complex
 @subsection Complex Types
 
-@samp{libffi} supports the complex types defined by the C99
+@code{libffi} supports the complex types defined by the C99
 standard (@code{_Complex float}, @code{_Complex double} and
 @code{_Complex long double} with the built-in type descriptors
 @code{ffi_type_complex_float}, @code{ffi_type_complex_double} and
@@ -654,7 +675,7 @@ standard (@code{_Complex float}, @code{_Complex double} and
 
 Custom complex types like @code{_Complex int} can also be used.
 An @code{ffi_type} object has to be defined to describe the
-complex type to @samp{libffi}.
+complex type to @code{libffi}.
 
 @tindex ffi_type
 @deftp {Data type} ffi_type
@@ -821,7 +842,6 @@ Free memory allocated using @code{ffi_closure_alloc}.  The argument is
 the writable address that was returned.
 @end defun
 
-
 Once you have allocated the memory for a closure, you must construct a
 @code{ffi_cif} describing the function call.  Finally you can prepare
 the closure function:
@@ -977,7 +997,7 @@ type is @code{long double}.
 Note that memory allocated by @code{ffi_closure_alloc} and freed by
 @code{ffi_closure_free} does not come from the same general pool of
 memory that @code{malloc} and @code{free} use.  To accomodate security
-settings, @samp{libffi} may aquire memory, for example, by mapping
+settings, @code{libffi} may aquire memory, for example, by mapping
 temporary files into multiple places in the address space (once to
 write out the closure, a second to execute it).  The search follows
 this list, using the first that works:
index 6261b21fec9cec94d82b82887c90ba608b01fbb8..fc180c12dd52e882ebe6e16a07019915530aacd0 100644 (file)
@@ -1,4 +1,4 @@
-@set UPDATED 31 August 2022
-@set UPDATED-MONTH August 2022
-@set EDITION 3.4.2
-@set VERSION 3.4.2
+@set UPDATED 2 August 2025
+@set UPDATED-MONTH August 2025
+@set EDITION 3.5.2
+@set VERSION 3.5.2
index 9921b0d99d8c464e12be3cf5351f84282dc19544..f6e9152846aa9e74754d4292ce990e09696050b2 100755 (executable)
@@ -11,19 +11,8 @@ class Platform(object):
     pass
 
 
-class simulator_platform(Platform):
-    arch = 'i386'
-    triple = 'i386-apple-darwin11'
-
-    prefix = "#ifdef __i386__\n\n"
-    suffix = "\n\n#endif"
-    src_dir = 'x86'
-    src_files = ['sysv.S', 'ffi.c', 'internal.h']
-
-
-class simulator64_platform(Platform):
+class x86_64_platform(Platform):
     arch = 'x86_64'
-    triple = 'x86_64-apple-darwin13'
 
     prefix = "#ifdef __x86_64__\n\n"
     suffix = "\n\n#endif"
@@ -31,101 +20,117 @@ class simulator64_platform(Platform):
     src_files = ['unix64.S', 'ffi64.c', 'ffiw64.c', 'win64.S', 'internal64.h', 'asmnames.h']
 
 
-class device_platform(Platform):
-    arch = 'armv7'
-    triple = 'arm-apple-darwin11'
+class arm64_platform(Platform):
+    arch = 'arm64'
 
-    prefix = "#ifdef __arm__\n\n"
+    prefix = "#ifdef __arm64__\n\n"
     suffix = "\n\n#endif"
-    src_dir = 'arm'
+    src_dir = 'aarch64'
     src_files = ['sysv.S', 'ffi.c', 'internal.h']
 
 
-class device64_platform(Platform):
-    arch = 'arm64'
-    triple = 'aarch64-apple-darwin13'
+class armv7_platform(Platform):
+    arch = 'armv7'
 
-    prefix = "#ifdef __arm64__\n\n"
+    prefix = "#ifdef __arm__\n\n"
     suffix = "\n\n#endif"
-    src_dir = 'aarch64'
+    src_dir = 'arm'
     src_files = ['sysv.S', 'ffi.c', 'internal.h']
 
 
-class ios_simulator_platform(simulator_platform):
+class ios_simulator_x86_64_platform(x86_64_platform):
+    target = 'x86_64-apple-ios-simulator'
     directory = 'darwin_ios'
     sdk = 'iphonesimulator'
     version_min = '-miphoneos-version-min=7.0'
 
 
-class ios_simulator64_platform(simulator64_platform):
+class ios_simulator_arm64_platform(arm64_platform):
+    target = 'arm64-apple-ios-simulator'
     directory = 'darwin_ios'
     sdk = 'iphonesimulator'
     version_min = '-miphoneos-version-min=7.0'
 
 
-class ios_device_platform(device_platform):
+class ios_device_armv7_platform(armv7_platform):
+    target = 'armv7-apple-ios'
     directory = 'darwin_ios'
     sdk = 'iphoneos'
     version_min = '-miphoneos-version-min=7.0'
 
 
-class ios_device64_platform(device64_platform):
+class ios_device_arm64_platform(arm64_platform):
+    target = 'arm64-apple-ios'
     directory = 'darwin_ios'
     sdk = 'iphoneos'
     version_min = '-miphoneos-version-min=7.0'
 
 
-class desktop32_platform(Platform):
+class desktop_x86_64_platform(x86_64_platform):
+    target = 'x86_64-apple-macos'
     directory = 'darwin_osx'
     sdk = 'macosx'
-    arch = 'i386'
-    triple = 'i386-apple-darwin10'
     version_min = '-mmacosx-version-min=10.6'
-    src_dir = 'x86'
-    src_files = ['sysv.S', 'ffi.c', 'internal.h']
-
-    prefix = "#ifdef __i386__\n\n"
-    suffix = "\n\n#endif"
 
 
-class desktop64_platform(Platform):
+class desktop_arm64_platform(arm64_platform):
+    target = 'arm64-apple-macos'
     directory = 'darwin_osx'
     sdk = 'macosx'
-    arch = 'x86_64'
-    triple = 'x86_64-apple-darwin10'
-    version_min = '-mmacosx-version-min=10.6'
+    version_min = '-mmacosx-version-min=11.0'
 
-    prefix = "#ifdef __x86_64__\n\n"
-    suffix = "\n\n#endif"
-    src_dir = 'x86'
-    src_files = ['unix64.S', 'ffi64.c', 'ffiw64.c', 'win64.S', 'internal64.h', 'asmnames.h']
+
+class tvos_simulator_x86_64_platform(x86_64_platform):
+    target = 'x86_64-apple-tvos-simulator'
+    directory = 'darwin_tvos'
+    sdk = 'appletvsimulator'
+    version_min = '-mtvos-version-min=9.0'
 
 
-class tvos_simulator64_platform(simulator64_platform):
+class tvos_simulator_arm64_platform(arm64_platform):
+    target = 'arm64-apple-tvos-simulator'
     directory = 'darwin_tvos'
     sdk = 'appletvsimulator'
     version_min = '-mtvos-version-min=9.0'
 
 
-class tvos_device64_platform(device64_platform):
+class tvos_device_arm64_platform(arm64_platform):
+    target = 'arm64-apple-tvos'
     directory = 'darwin_tvos'
     sdk = 'appletvos'
     version_min = '-mtvos-version-min=9.0'
 
 
-class watchos_simulator_platform(simulator_platform):
+class watchos_simulator_x86_64_platform(x86_64_platform):
+    target = 'x86_64-apple-watchos-simulator'
     directory = 'darwin_watchos'
     sdk = 'watchsimulator'
     version_min = '-mwatchos-version-min=4.0'
 
 
-class watchos_device_platform(device_platform):
+class watchos_simulator_arm64_platform(arm64_platform):
+    target = 'arm64-apple-watchos-simulator'
+    directory = 'darwin_watchos'
+    sdk = 'watchsimulator'
+    version_min = '-mwatchos-version-min=4.0'
+
+
+class watchos_device_armv7k_platform(armv7_platform):
+    target = 'armv7k-apple-watchos'
     directory = 'darwin_watchos'
     sdk = 'watchos'
     arch = 'armv7k'
     version_min = '-mwatchos-version-min=4.0'
 
 
+class watchos_device_arm64_32_platform(arm64_platform):
+    target = 'arm64_32-apple-watchos'
+    directory = 'darwin_watchos'
+    sdk = 'watchos'
+    arch = 'arm64_32'
+    version_min = '-mwatchos-version-min=4.0'
+
+
 def mkdir_p(path):
     try:
         os.makedirs(path)
@@ -175,18 +180,26 @@ def copy_src_platform_files(platform):
 
 def build_target(platform, platform_headers):
     def xcrun_cmd(cmd):
-        return 'xcrun -sdk %s %s -arch %s' % (platform.sdk, cmd, platform.arch)
+        return 'xcrun -sdk %s %s -target %s' % (platform.sdk, cmd, platform.target)
 
     tag='%s-%s' % (platform.sdk, platform.arch)
     build_dir = 'build_%s' % tag
     mkdir_p(build_dir)
     env = dict(CC=xcrun_cmd('clang'),
                LD=xcrun_cmd('ld'),
-               CFLAGS='%s -fembed-bitcode' % (platform.version_min))
+               CFLAGS='%s' % (platform.version_min))
     working_dir = os.getcwd()
     try:
         os.chdir(build_dir)
-        subprocess.check_call(['../configure', '-host', platform.triple], env=env)
+        subprocess.check_call(
+            [
+                "../configure",
+                f"--host={platform.target}",
+            ] + (
+                [] if platform.sdk == "macosx" else [f"--build={os.uname().machine}-apple-darwin"]
+            ),
+            env=env
+        )
     finally:
         os.chdir(working_dir)
 
@@ -212,34 +225,42 @@ def generate_source_and_headers(
     copy_files('include', 'darwin_common/include', pattern='*.h')
 
     if generate_ios:
-        copy_src_platform_files(ios_simulator_platform)
-        copy_src_platform_files(ios_simulator64_platform)
-        copy_src_platform_files(ios_device_platform)
-        copy_src_platform_files(ios_device64_platform)
+        copy_src_platform_files(ios_simulator_x86_64_platform)
+        copy_src_platform_files(ios_simulator_arm64_platform)
+        copy_src_platform_files(ios_device_armv7_platform)
+        copy_src_platform_files(ios_device_arm64_platform)
     if generate_osx:
-        copy_src_platform_files(desktop64_platform)
+        copy_src_platform_files(desktop_x86_64_platform)
+        copy_src_platform_files(desktop_arm64_platform)
     if generate_tvos:
-        copy_src_platform_files(tvos_simulator64_platform)
-        copy_src_platform_files(tvos_device64_platform)
+        copy_src_platform_files(tvos_simulator_x86_64_platform)
+        copy_src_platform_files(tvos_simulator_arm64_platform)
+        copy_src_platform_files(tvos_device_arm64_platform)
     if generate_watchos:
-        copy_src_platform_files(watchos_simulator_platform)
-        copy_src_platform_files(watchos_device_platform)
+        copy_src_platform_files(watchos_simulator_x86_64_platform)
+        copy_src_platform_files(watchos_simulator_arm64_platform)
+        copy_src_platform_files(watchos_device_armv7k_platform)
+        copy_src_platform_files(watchos_device_arm64_32_platform)
 
     platform_headers = collections.defaultdict(set)
 
     if generate_ios:
-        build_target(ios_simulator_platform, platform_headers)
-        build_target(ios_simulator64_platform, platform_headers)
-        build_target(ios_device_platform, platform_headers)
-        build_target(ios_device64_platform, platform_headers)
+        build_target(ios_simulator_x86_64_platform, platform_headers)
+        build_target(ios_simulator_arm64_platform, platform_headers)
+        build_target(ios_device_armv7_platform, platform_headers)
+        build_target(ios_device_arm64_platform, platform_headers)
     if generate_osx:
-        build_target(desktop64_platform, platform_headers)
+        build_target(desktop_x86_64_platform, platform_headers)
+        build_target(desktop_arm64_platform, platform_headers)
     if generate_tvos:
-        build_target(tvos_simulator64_platform, platform_headers)
-        build_target(tvos_device64_platform, platform_headers)
+        build_target(tvos_simulator_x86_64_platform, platform_headers)
+        build_target(tvos_simulator_arm64_platform, platform_headers)
+        build_target(tvos_device_arm64_platform, platform_headers)
     if generate_watchos:
-        build_target(watchos_simulator_platform, platform_headers)
-        build_target(watchos_device_platform, platform_headers)
+        build_target(watchos_simulator_x86_64_platform, platform_headers)
+        build_target(watchos_simulator_arm64_platform, platform_headers)
+        build_target(watchos_device_armv7k_platform, platform_headers)
+        build_target(watchos_device_arm64_32_platform, platform_headers)
 
     mkdir_p('darwin_common/include')
     for header_name, tag_tuples in platform_headers.items():
index d7d1641f00cbf920ecd89994ced339d3fcb04924..5f0d4066f4a97a95fc67c2c866664d46bf2d128d 100644 (file)
@@ -6,8 +6,4 @@ DISTCLEANFILES=ffitarget.h
 noinst_HEADERS=ffi_common.h ffi_cfi.h tramp.h
 EXTRA_DIST=ffi.h.in
 
-# Where generated headers like ffitarget.h get installed.
-gcc_version   := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
-toollibffidir := $(libdir)/gcc/$(target_alias)/$(gcc_version)/include
-
-toollibffi_HEADERS = ffi.h ffitarget.h
+nodist_include_HEADERS = ffi.h ffitarget.h
index d16f307e64bebd72558a094d5df649e3947dd94d..6ce7ac55ec780c3ba1e42a681bf9b562301efce1 100644 (file)
@@ -1,6 +1,6 @@
 /* -----------------------------------------------------------------*-C-*-
    libffi @VERSION@
-     - Copyright (c) 2011, 2014, 2019, 2021 Anthony Green
+     - Copyright (c) 2011, 2014, 2019, 2021, 2022, 2024, 2025 Anthony Green
      - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.
 
    Permission is hereby granted, free of charge, to any person
@@ -56,6 +56,31 @@ extern "C" {
 
 /* ---- System configuration information --------------------------------- */
 
+/* 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
+#if @HAVE_LONG_DOUBLE@
+#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
+
 #include <ffitarget.h>
 
 #ifndef LIBFFI_ASM
@@ -115,13 +140,11 @@ typedef struct _ffi_type
    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 _MSC_VER && !defined(FFI_STATIC_BUILD)
 # if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */
 #  define FFI_API __declspec(dllexport)
-# elif !defined FFI_BUILDING  /* Importing libffi.DLL */
+# else  /* Importing libffi.DLL */
 #  define FFI_API __declspec(dllimport)
-# else                        /* Building/linking static library */
-#  define FFI_API
 # endif
 #else
 # define FFI_API
@@ -197,21 +220,12 @@ 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;
-
-#if @HAVE_LONG_DOUBLE@
 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 @HAVE_LONG_DOUBLE@
 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 */
 
@@ -300,6 +314,24 @@ void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) __a
 FFI_API
 size_t ffi_java_raw_size (ffi_cif *cif) __attribute__((deprecated));
 
+/* ---- Version API ------------------------------------------------------ */
+
+#define FFI_VERSION_STRING "@FFI_VERSION_STRING@"
+#define FFI_VERSION_NUMBER @FFI_VERSION_NUMBER@
+
+#ifndef LIBFFI_ASM
+/* Return a version string. */
+FFI_API const char *ffi_get_version (void);
+
+/* Return the version as an unsigned long value: (x * 10000 + y * 100 + z) */
+FFI_API unsigned long ffi_get_version_number (void);
+#endif
+
+/* ---- Internals API ---------------------------------------------------- */
+
+FFI_API unsigned int ffi_get_default_abi (void);
+FFI_API size_t ffi_get_closure_size (void);
+
 /* ---- Definitions for closures ----------------------------------------- */
 
 #if FFI_CLOSURES
@@ -320,6 +352,9 @@ typedef struct {
   ffi_cif   *cif;
   void     (*fun)(ffi_cif*,void*,void**,void*);
   void      *user_data;
+#if defined(_MSC_VER) && defined(_M_IX86)
+  void      *padding;
+#endif
 } ffi_closure
 #ifdef __GNUC__
     __attribute__((aligned (8)))
@@ -335,14 +370,6 @@ typedef struct {
 FFI_API void *ffi_closure_alloc (size_t size, void **code);
 FFI_API void ffi_closure_free (void *);
 
-#if defined(PA_LINUX) || defined(PA_HPUX)
-#define FFI_CLOSURE_PTR(X) ((void *)((unsigned int)(X) | 2))
-#define FFI_RESTORE_PTR(X) ((void *)((unsigned int)(X) & ~3))
-#else
-#define FFI_CLOSURE_PTR(X) (X)
-#define FFI_RESTORE_PTR(X) (X)
-#endif
-
 FFI_API ffi_status
 ffi_prep_closure (ffi_closure*,
                  ffi_cif *,
@@ -360,7 +387,7 @@ ffi_prep_closure_loc (ffi_closure*,
                      ffi_cif *,
                      void (*fun)(ffi_cif*,void*,void**,void*),
                      void *user_data,
-                     void*codeloc);
+                     void *codeloc);
 
 #ifdef __sgi
 # pragma pack 8
@@ -378,7 +405,7 @@ typedef struct {
 
   /* 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;
@@ -446,7 +473,7 @@ ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
 
 #endif /* FFI_CLOSURES */
 
-#if FFI_GO_CLOSURES
+#ifdef FFI_GO_CLOSURES
 
 typedef struct {
   void      *tramp;
@@ -489,38 +516,19 @@ FFI_API
 ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
                                   size_t *offsets);
 
-/* Useful for eliminating compiler warnings.  */
+/* Convert between closure and function pointers.  */
+#if defined(PA_LINUX) || defined(PA_HPUX)
+#define FFI_FN(f) ((void (*)(void))((unsigned int)(f) | 2))
+#define FFI_CL(f) ((void *)((unsigned int)(f) & ~3))
+#else
 #define FFI_FN(f) ((void (*)(void))f)
+#define FFI_CL(f) ((void *)(f))
+#endif
 
 /* ---- 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
-#if @HAVE_LONG_DOUBLE@
-#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
index 2beb165c9a16f730cb37092a464077ee93e9113a..8565663244c0f8ba79c9dc644dca45c69d990649 100644 (file)
 # define cfi_remember_state            .cfi_remember_state
 # define cfi_restore_state             .cfi_restore_state
 # define cfi_window_save               .cfi_window_save
-# define cfi_negate_ra_state           .cfi_negate_ra_state
 # 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__
+# define cfi_window_save               .cfi_window_save
 
 #else
 
 # define cfi_remember_state
 # define cfi_restore_state
 # define cfi_window_save
-# define cfi_negate_ra_state
 # define cfi_personality(enc, exp)
 # define cfi_lsda(enc, exp)
 # define cfi_escape(...)
+# define cfi_window_save
 
 #endif /* HAVE_AS_CFI_PSEUDO_OP */
 #endif /* FFI_CFI_H */
index 2bd31b03d0f9d1252d637c57d81185a3049174b4..e4ed2287e580a51fec5262554aa40ff4d0f6038b 100644 (file)
@@ -49,8 +49,10 @@ extern "C" {
 #  endif
 # endif
 # define MAYBE_UNUSED __attribute__((__unused__))
+# define NORETURN __attribute__((__noreturn__))
 #else
 # define MAYBE_UNUSED
+# define NORETURN
 # if HAVE_ALLOCA_H
 #  include <alloca.h>
 # else
@@ -81,10 +83,27 @@ char *alloca ();
 #include <stdio.h>
 #endif
 
+#ifndef __SANITIZE_ADDRESS__
+# ifdef __clang__
+#  if __has_feature(address_sanitizer)
+#   define FFI_ASAN
+#  endif
+# endif
+#endif
+#ifdef __SANITIZE_ADDRESS__
+#define FFI_ASAN
+#endif
+
+#ifdef FFI_ASAN
+#define FFI_ASAN_NO_SANITIZE __attribute__((no_sanitize_address))
+#else
+#define FFI_ASAN_NO_SANITIZE
+#endif
+
 #ifdef FFI_DEBUG
-void ffi_assert(char *expr, char *file, int line);
+NORETURN void ffi_assert(const char *expr, const char *file, int line);
 void ffi_stop_here(void);
-void ffi_type_test(ffi_type *a, char *file, int line);
+void ffi_type_test(ffi_type *a, const char *file, int line);
 
 #define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__))
 #define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l)))
@@ -128,6 +147,10 @@ void *ffi_data_to_code_pointer (void *data) FFI_HIDDEN;
    static trampoline. */
 int ffi_tramp_is_present (void *closure) FFI_HIDDEN;
 
+/* Return a file descriptor of a temporary zero-sized file in a
+   writable and executable filesystem. */
+int open_temp_exec_file(void) FFI_HIDDEN;
+
 /* Extended cif, used in callback from assembly routine */
 typedef struct
 {
index de8778ae40fb9c88398f1f96e978333699a8d141..cc135ba8e2915cdaacf364d95bfd4f0222494ca5 100644 (file)
@@ -23,7 +23,6 @@ LIBFFI_BASE_8.0 {
        ffi_type_longdouble;
        ffi_type_pointer;
 
-       /* Exported functions.  */
        ffi_call;
        ffi_prep_cif;
        ffi_prep_cif_var;
@@ -33,7 +32,10 @@ LIBFFI_BASE_8.0 {
        ffi_raw_to_ptrarray;
        ffi_raw_size;
 
+#if !FFI_NATIVE_RAW_API
        ffi_java_raw_call;
+#endif
+
        ffi_java_ptrarray_to_raw;
        ffi_java_raw_to_ptrarray;
        ffi_java_raw_size;
@@ -43,6 +45,19 @@ LIBFFI_BASE_8.0 {
        *;
 };
 
+/* ----------------------------------------------------------------------
+   Symbols **added in libffi 3.5.0**.
+   Give them a fresh namespace so that package managers notice when
+   code requires a newer libffi than 3.4.x.
+   -------------------------------------------------------------------- */
+LIBFFI_BASE_8.1 {
+  global:
+    ffi_get_version;
+    ffi_get_version_number;
+    ffi_get_default_abi;
+    ffi_get_closure_size;
+} LIBFFI_BASE_8.0;
+
 #ifdef FFI_TARGET_HAS_COMPLEX_TYPE
 LIBFFI_COMPLEX_8.0 {
   global:
@@ -62,8 +77,10 @@ LIBFFI_CLOSURE_8.0 {
        ffi_prep_closure_loc;
        ffi_prep_raw_closure;
        ffi_prep_raw_closure_loc;
+#if !FFI_NATIVE_RAW_API
        ffi_prep_java_raw_closure;
        ffi_prep_java_raw_closure_loc;
+#endif
 } LIBFFI_BASE_8.0;
 #endif
 
index 607fee5585d9c7afec826675689a56abad43966d..37c2bc9035edb65e95ca9b28977c8085205d31e6 100644 (file)
@@ -5,7 +5,7 @@
 #
 # Here are a set of rules to help you update your library version
 # information:
-# 
+#
 # 1. Start with version information of `0:0:0' for each libtool library.
 #
 # 2. Update the version information only immediately before a public
@@ -26,4 +26,4 @@
 #    release, then set age to 0.
 #
 # CURRENT:REVISION:AGE
-9:0:1
+10:0:2
index b394c18fc56778ea63761ca4c8264ec970a81a52..94c643b70ab67849da10d0a6344942c6e314f641 100644 (file)
@@ -28,7 +28,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #include <ffi_common.h>
 #include "internal.h"
 #ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
 #include <windows.h> /* FlushInstructionCache */
 #endif
 #include <tramp.h>
@@ -64,7 +63,7 @@ struct call_context
 #if FFI_EXEC_TRAMPOLINE_TABLE
 
 #ifdef __MACH__
-#ifdef HAVE_PTRAUTH
+#ifdef HAVE_ARM64E_PTRAUTH
 #include <ptrauth.h>
 #endif
 #include <mach/vm_param.h>
@@ -249,13 +248,18 @@ is_vfp_type (const ffi_type *ty)
    state.
 
    The terse state variable names match the names used in the AARCH64
-   PCS. */
+   PCS.
+
+   The struct area is allocated downwards from the top of the argument
+   area.  It is used to hold copies of structures passed by value that are
+   bigger than 16 bytes.  */
 
 struct arg_state
 {
   unsigned ngrn;                /* Next general-purpose register number. */
   unsigned nsrn;                /* Next vector register number. */
   size_t nsaa;                  /* Next stack offset. */
+  size_t next_struct_area;     /* Place to allocate big structs. */
 
 #if defined (__APPLE__)
   unsigned allocating_variadic;
@@ -264,11 +268,12 @@ struct arg_state
 
 /* Initialize a procedure call argument marshalling state.  */
 static void
-arg_init (struct arg_state *state)
+arg_init (struct arg_state *state, size_t size)
 {
   state->ngrn = 0;
   state->nsrn = 0;
   state->nsaa = 0;
+  state->next_struct_area = size;
 #if defined (__APPLE__)
   state->allocating_variadic = 0;
 #endif
@@ -290,37 +295,83 @@ allocate_to_stack (struct arg_state *state, void *stack,
   if (alignment < 8)
     alignment = 8;
 #endif
-    
+
   nsaa = FFI_ALIGN (nsaa, alignment);
   state->nsaa = nsaa + size;
 
   return (char *)stack + nsaa;
 }
 
+/* Allocate and copy a structure that is passed by value on the stack and
+   return a pointer to it.  */
+static void *
+allocate_and_copy_struct_to_stack (struct arg_state *state, void *stack,
+                                  size_t alignment, size_t size, void *value)
+{
+  size_t dest = state->next_struct_area - size;
+
+  /* Round down to the natural alignment of the value.  */
+  dest = FFI_ALIGN_DOWN (dest, alignment);
+  state->next_struct_area = dest;
+
+  return memcpy ((char *) stack + dest, value, size);
+}
+
 static ffi_arg
 extend_integer_type (void *source, int type)
 {
   switch (type)
     {
     case FFI_TYPE_UINT8:
-      return *(UINT8 *) source;
+      {
+        UINT8 u8;
+        memcpy (&u8, source, sizeof (u8));
+        return u8;
+      }
     case FFI_TYPE_SINT8:
-      return *(SINT8 *) source;
+      {
+        SINT8 s8;
+        memcpy (&s8, source, sizeof (s8));
+        return s8;
+      }
     case FFI_TYPE_UINT16:
-      return *(UINT16 *) source;
+      {
+        UINT16 u16;
+        memcpy (&u16, source, sizeof (u16));
+        return u16;
+      }
     case FFI_TYPE_SINT16:
-      return *(SINT16 *) source;
+      {
+        SINT16 s16;
+        memcpy (&s16, source, sizeof (s16));
+        return s16;
+      }
     case FFI_TYPE_UINT32:
-      return *(UINT32 *) source;
+      {
+        UINT32 u32;
+        memcpy (&u32, source, sizeof (u32));
+        return u32;
+      }
     case FFI_TYPE_INT:
     case FFI_TYPE_SINT32:
-      return *(SINT32 *) source;
+      {
+        SINT32 s32;
+        memcpy (&s32, source, sizeof (s32));
+        return s32;
+      }
     case FFI_TYPE_UINT64:
     case FFI_TYPE_SINT64:
-      return *(UINT64 *) source;
-      break;
+      {
+        UINT64 u64;
+        memcpy (&u64, source, sizeof (u64));
+        return u64;
+      }
     case FFI_TYPE_POINTER:
-      return *(uintptr_t *) source;
+      {
+        uintptr_t uptr;
+        memcpy (&uptr, source, sizeof (uptr));
+        return uptr;
+      }
     default:
       abort();
     }
@@ -335,51 +386,64 @@ extend_hfa_type (void *dest, void *src, int h)
   ssize_t f = h - AARCH64_RET_S4;
   void *x0;
 
+#define BTI_J "hint #36"
   asm volatile (
        "adr    %0, 0f\n"
 "      add     %0, %0, %1\n"
 "      br      %0\n"
-"0:    ldp     s16, s17, [%3]\n"       /* S4 */
+"0:    "BTI_J"\n"                      /* S4 */
+"      ldp     s16, s17, [%3]\n"
 "      ldp     s18, s19, [%3, #8]\n"
 "      b       4f\n"
-"      ldp     s16, s17, [%3]\n"       /* S3 */
+"      "BTI_J"\n"                      /* S3 */
+"      ldp     s16, s17, [%3]\n"
 "      ldr     s18, [%3, #8]\n"
 "      b       3f\n"
-"      ldp     s16, s17, [%3]\n"       /* S2 */
+"      "BTI_J"\n"                      /* S2 */
+"      ldp     s16, s17, [%3]\n"
 "      b       2f\n"
 "      nop\n"
-"      ldr     s16, [%3]\n"            /* S1 */
+"      "BTI_J"\n"                      /* S1 */
+"      ldr     s16, [%3]\n"
 "      b       1f\n"
 "      nop\n"
-"      ldp     d16, d17, [%3]\n"       /* D4 */
+"      "BTI_J"\n"                      /* D4 */
+"      ldp     d16, d17, [%3]\n"
 "      ldp     d18, d19, [%3, #16]\n"
 "      b       4f\n"
-"      ldp     d16, d17, [%3]\n"       /* D3 */
+"      "BTI_J"\n"                      /* D3 */
+"      ldp     d16, d17, [%3]\n"
 "      ldr     d18, [%3, #16]\n"
 "      b       3f\n"
-"      ldp     d16, d17, [%3]\n"       /* D2 */
+"      "BTI_J"\n"                      /* D2 */
+"      ldp     d16, d17, [%3]\n"
 "      b       2f\n"
 "      nop\n"
-"      ldr     d16, [%3]\n"            /* D1 */
+"      "BTI_J"\n"                      /* D1 */
+"      ldr     d16, [%3]\n"
 "      b       1f\n"
 "      nop\n"
-"      ldp     q16, q17, [%3]\n"       /* Q4 */
+"      "BTI_J"\n"                      /* Q4 */
+"      ldp     q16, q17, [%3]\n"
 "      ldp     q18, q19, [%3, #32]\n"
 "      b       4f\n"
-"      ldp     q16, q17, [%3]\n"       /* Q3 */
+"      "BTI_J"\n"                      /* Q3 */
+"      ldp     q16, q17, [%3]\n"
 "      ldr     q18, [%3, #32]\n"
 "      b       3f\n"
-"      ldp     q16, q17, [%3]\n"       /* Q2 */
+"      "BTI_J"\n"                      /* Q2 */
+"      ldp     q16, q17, [%3]\n"
 "      b       2f\n"
 "      nop\n"
-"      ldr     q16, [%3]\n"            /* Q1 */
+"      "BTI_J"\n"                      /* Q1 */
+"      ldr     q16, [%3]\n"
 "      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)
+    : "r"(f * 16), "r"(dest), "r"(src)
     : "memory", "v16", "v17", "v18", "v19");
 }
 #endif
@@ -581,7 +645,10 @@ extern void ffi_call_SYSV (struct call_context *context, void *frame,
                           void *closure) FFI_HIDDEN;
 
 /* Call a function with the provided arguments and capture the return
-   value.  */
+   value.
+   n.b. ffi_call_SYSV will steal the alloca'd `stack` variable here for use
+   _as its own stack_ - so we need to compile this function without ASAN */
+FFI_ASAN_NO_SANITIZE
 static void
 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
              void **avalue, void *closure)
@@ -618,20 +685,21 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
   else if (flags & AARCH64_RET_NEED_COPY)
     rsize = 16;
 
-  /* Allocate consectutive stack for everything we'll need.
+  /* Allocate consecutive stack for everything we'll need.
      The frame uses 40 bytes for: lr, fp, rvalue, flags, sp */
   context = alloca (sizeof(struct call_context) + stack_bytes + 40 + rsize);
   stack = context + 1;
   frame = (void*)((uintptr_t)stack + (uintptr_t)stack_bytes);
   rvalue = (rsize ? (void*)((uintptr_t)frame + 40) : orig_rvalue);
 
-  arg_init (&state);
+  arg_init (&state, stack_bytes);
   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;
+      void *dest;
 
       t = ty->type;
       switch (t)
@@ -679,8 +747,6 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
        case FFI_TYPE_STRUCT:
        case FFI_TYPE_COMPLEX:
          {
-           void *dest;
-
            h = is_vfp_type (ty);
            if (h)
              {
@@ -713,9 +779,12 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
            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
+                  bytes, then the argument is copied to memory, and
                   the argument is replaced by a pointer to the copy.  */
-               a = &avalue[i];
+               dest = allocate_and_copy_struct_to_stack (&state, stack,
+                                                         ty->alignment, s,
+                                                         avalue[i]);
+               a = &dest;
                t = FFI_TYPE_POINTER;
                s = sizeof (void *);
                goto do_pointer;
@@ -803,21 +872,21 @@ ffi_prep_closure_loc (ffi_closure *closure,
     return FFI_BAD_ABI;
 
   void (*start)(void);
-  
+
   if (cif->flags & AARCH64_FLAG_ARG_V)
     start = ffi_closure_SYSV_V;
   else
     start = ffi_closure_SYSV;
 
 #if FFI_EXEC_TRAMPOLINE_TABLE
-#ifdef __MACH__
-#ifdef HAVE_PTRAUTH
+# ifdef __MACH__
+#  ifdef HAVE_ARM64E_PTRAUTH
   codeloc = ptrauth_auth_data(codeloc, ptrauth_key_function_pointer, 0);
-#endif
+#  endif
   void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
   config[0] = closure;
   config[1] = start;
-#endif
+# endif
 #else
   static const unsigned char trampoline[16] = {
     0x90, 0x00, 0x00, 0x58,    /* ldr  x16, tramp+16   */
@@ -826,7 +895,7 @@ ffi_prep_closure_loc (ffi_closure *closure,
   };
   char *tramp = closure->tramp;
 
-#if defined(FFI_EXEC_STATIC_TRAMP)
+# if defined(FFI_EXEC_STATIC_TRAMP)
   if (ffi_tramp_is_present(closure))
     {
       /* Initialize the static trampoline's parameters. */
@@ -837,25 +906,27 @@ ffi_prep_closure_loc (ffi_closure *closure,
       ffi_tramp_set_parms (closure->ftramp, start, closure);
       goto out;
     }
-#endif
+# endif
 
   /* Initialize the dynamic trampoline. */
   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 _WIN32
+# ifdef _WIN32
   // Not using dlmalloc.c for Windows ARM64 builds
   // so calling ffi_data_to_code_pointer() isn't necessary
   unsigned char *tramp_code = tramp;
-  #else
+else
   unsigned char *tramp_code = ffi_data_to_code_pointer (tramp);
-  #endif
+endif
   ffi_clear_cache (tramp_code, tramp_code + FFI_TRAMPOLINE_SIZE);
+# if defined(FFI_EXEC_STATIC_TRAMP)
 out:
+# endif
 #endif
 
   closure->cif = cif;
@@ -918,7 +989,7 @@ ffi_closure_SYSV_inner (ffi_cif *cif,
   int i, h, nargs, flags, isvariadic = 0;
   struct arg_state state;
 
-  arg_init (&state);
+  arg_init (&state, cif->bytes);
 
   flags = cif->flags;
   if (flags & AARCH64_FLAG_VARARG)
@@ -967,7 +1038,7 @@ ffi_closure_SYSV_inner (ffi_cif *cif,
                     {
                       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
@@ -1005,9 +1076,18 @@ ffi_closure_SYSV_inner (ffi_cif *cif,
             {
               /* Replace Composite type of size greater than 16 with a
                   pointer.  */
+#ifdef __ILP32__
+             UINT64 avalue_tmp;
+             memcpy (&avalue_tmp,
+                  allocate_int_to_reg_or_stack (context, &state,
+                                               stack, sizeof (void *)),
+                  sizeof (UINT64));
+             avalue[i] = (void *)(UINT32)avalue_tmp;
+#else
               avalue[i] = *(void **)
               allocate_int_to_reg_or_stack (context, &state, stack,
                                          sizeof (void *));
+#endif
             }
           else
             {
index d5622e133625cac90c334476b41d7b6b1aee6f88..2ab95644a311d259e11d1910e7ac777559787c82 100644 (file)
@@ -83,8 +83,8 @@ typedef enum ffi_abi
 
 #if defined (__APPLE__)
 #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs
-#elif !defined(_WIN32)
-/* iOS and Windows reserve x18 for the system.  Disable Go closures until
+#elif !defined(_WIN32) && !defined(__ANDROID__)
+/* iOS, Windows and Android reserve x18 for the system.  Disable Go closures until
    a new static chain is chosen.  */
 #define FFI_GO_CLOSURES 1
 #endif
index b5d102b4add2c5948a9309b23f79977e52458d8a..591b9f5c087eb104a4b794b64850b2483f2aa9e3 100644 (file)
@@ -81,20 +81,66 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 /* Helpers for writing assembly compatible with arm ptr auth */
 #ifdef LIBFFI_ASM
 
-#ifdef HAVE_PTRAUTH
-#define SIGN_LR pacibsp
-#define SIGN_LR_WITH_REG(x) pacib lr, x
-#define AUTH_LR_AND_RET retab
-#define AUTH_LR_WITH_REG(x) autib lr, x
-#define BRANCH_AND_LINK_TO_REG blraaz
-#define BRANCH_TO_REG braaz
-#else
-#define SIGN_LR
-#define SIGN_LR_WITH_REG(x)
-#define AUTH_LR_AND_RET ret
-#define AUTH_LR_WITH_REG(x)
-#define BRANCH_AND_LINK_TO_REG blr
-#define BRANCH_TO_REG br
-#endif
-
-#endif
+  #if defined(HAVE_ARM64E_PTRAUTH)
+  /* ARM64E ABI For Darwin */
+  #define SIGN_LR pacibsp
+  #define SIGN_LR_WITH_REG(x) pacib lr, x
+  #define AUTH_LR_AND_RET retab
+  #define AUTH_LR_WITH_REG(x) autib lr, x
+  #define BRANCH_AND_LINK_TO_REG blraaz
+  #define SIGN_LR_LINUX_ONLY
+  #define BRANCH_TO_REG braaz
+  #define PAC_CFI_WINDOW_SAVE
+  #define GNU_PROPERTY_AARCH64_POINTER_AUTH 0
+  /* Linux PAC Support */
+  #elif defined(__ARM_FEATURE_PAC_DEFAULT)
+    #define GNU_PROPERTY_AARCH64_POINTER_AUTH (1 << 1)
+    #define PAC_CFI_WINDOW_SAVE cfi_window_save
+    #define TMP_REG x9
+    #define BRANCH_TO_REG br
+    #define BRANCH_AND_LINK_TO_REG blr
+       #define SIGN_LR_LINUX_ONLY SIGN_LR
+    /* Which key to sign with? */
+    #if (__ARM_FEATURE_PAC_DEFAULT & 1) == 1
+      /* Signed with A-key */
+      #define SIGN_LR            hint #25  /* paciasp */
+      #define AUTH_LR            hint #29  /* autiasp */
+    #else
+      /* Signed with B-key */
+      #define SIGN_LR            hint #27  /* pacibsp */
+      #define AUTH_LR            hint #31  /* autibsp */
+    #endif /* __ARM_FEATURE_PAC_DEFAULT */
+    #define AUTH_LR_WITH_REG(x) _auth_lr_with_reg x
+.macro _auth_lr_with_reg modifier
+    mov TMP_REG, sp
+    mov sp, \modifier
+    AUTH_LR
+    mov sp, TMP_REG
+.endm
+  #define SIGN_LR_WITH_REG(x) _sign_lr_with_reg x
+.macro _sign_lr_with_reg modifier
+    mov TMP_REG, sp
+    mov sp, \modifier
+    SIGN_LR
+    mov sp, TMP_REG
+.endm
+  #define AUTH_LR_AND_RET _auth_lr_and_ret modifier
+.macro _auth_lr_and_ret modifier
+    AUTH_LR
+    ret
+.endm
+  #undef TMP_REG
+
+  /* No Pointer Auth */
+  #else
+    #define SIGN_LR
+    #define SIGN_LR_WITH_REG(x)
+    #define AUTH_LR_AND_RET ret
+    #define AUTH_LR_WITH_REG(x)
+    #define BRANCH_AND_LINK_TO_REG blr
+    #define SIGN_LR_LINUX_ONLY
+    #define BRANCH_TO_REG br
+    #define PAC_CFI_WINDOW_SAVE
+    #define GNU_PROPERTY_AARCH64_POINTER_AUTH 0
+  #endif /* HAVE_ARM64E_PTRAUTH */
+#endif /* LIBFFI_ASM */
index eeaf3f85140f4877e2c28d043c11491bdadb0782..81d33f2ef0a5fb7da93fc9e5ded5661a1dd3337a 100644 (file)
@@ -40,6 +40,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #endif
 #endif
 
+#ifdef __APPLE__
+# define L(X)     CONCAT1(L, X)
+#else
+# define L(X)     CONCAT1(.L, X)
+#endif
+
 #ifdef __AARCH64EB__
 # define BE(X) X
 #else
@@ -58,6 +64,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 #define PTR_SIZE       8
 #endif
 
+#define BTI_C hint #34
+#define BTI_J hint #36
+/*
+ * The ELF Notes section needs to indicate if BTI is supported, as the first ELF loaded that doesn't
+ * declare this support disables it for memory region containing the loaded library.
+ */
+# define GNU_PROPERTY_AARCH64_BTI (1 << 0)         /* Has Branch Target Identification */
        .text
        .align 4
 
@@ -76,29 +89,30 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
    x5 closure
 */
 
-       cfi_startproc
 CNAME(ffi_call_SYSV):
-       /* Sign the lr with x1 since that is where it will be stored */
+       cfi_startproc
+       BTI_C
+       PAC_CFI_WINDOW_SAVE
+       /* Sign the lr with x1 since that is the CFA which is the modifer used in auth instructions */
        SIGN_LR_WITH_REG(x1)
 
-       /* Use a stack frame allocated by our caller.  */
-#if defined(HAVE_PTRAUTH) && defined(__APPLE__)
+#if defined(HAVE_ARM64E_PTRAUTH) && defined(__APPLE__)
        /* darwin's libunwind assumes that the cfa is the sp and that's the data
         * used to sign the lr.  In order to allow unwinding through this
         * function it is necessary to point the cfa at the signing register.
         */
        cfi_def_cfa(x1, 0);
-#else
-       cfi_def_cfa(x1, 40);
 #endif
+       /* Use a stack frame allocated by our caller.  */
        stp     x29, x30, [x1]
+       cfi_def_cfa_register(x1)
+       cfi_rel_offset (x29, 0)
+       cfi_rel_offset (x30, 8)
        mov     x9, sp
        str     x9, [x1, #32]
        mov     x29, x1
-       mov     sp, x0
        cfi_def_cfa_register(x29)
-       cfi_rel_offset (x29, 0)
-       cfi_rel_offset (x30, 8)
+       mov     sp, x0
 
        mov     x9, x2                  /* save fn */
        mov     x8, x3                  /* install structure return */
@@ -138,78 +152,142 @@ CNAME(ffi_call_SYSV):
        /* Save the return value as directed.  */
        adr     x5, 0f
        and     w4, w4, #AARCH64_RET_MASK
-       add     x5, x5, x4, lsl #3
+       add     x5, x5, x4, lsl #4
        br      x5
 
-       /* Note that each table entry is 2 insns, and thus 8 bytes.
+       /* Note that each table entry is 4 insns, and thus 16 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:     b 99f                           /* VOID */
+0:     BTI_J                           /* VOID */
+       b 99f
+       nop 
        nop
-1:     str     x0, [x3]                /* INT64 */
+1:     BTI_J                           /* INT64 */
+       str     x0, [x3]
        b 99f
-2:     stp     x0, x1, [x3]            /* INT128 */
+       nop
+2:     BTI_J                           /* INT128 */
+       stp     x0, x1, [x3]
        b 99f
+       nop
 3:     brk     #1000                   /* UNUSED */
        b 99f
+       nop
+       nop
 4:     brk     #1000                   /* UNUSED */
        b 99f
+       nop
+       nop
 5:     brk     #1000                   /* UNUSED */
        b 99f
+       nop
+       nop
 6:     brk     #1000                   /* UNUSED */
        b 99f
+       nop
+       nop
 7:     brk     #1000                   /* UNUSED */
        b 99f
-8:     st4     { v0.s, v1.s, v2.s, v3.s }[0], [x3]     /* S4 */
+       nop
+       nop
+8:     BTI_J                           /* S4 */
+       st4     { v0.s, v1.s, v2.s, v3.s }[0], [x3]
        b 99f
-9:     st3     { v0.s, v1.s, v2.s }[0], [x3]   /* S3 */
+       nop
+9:     BTI_J                           /* S3 */
+       st3     { v0.s, v1.s, v2.s }[0], [x3]
        b 99f
-10:    stp     s0, s1, [x3]            /* S2 */
+       nop
+10:    BTI_J                           /* S2 */
+       stp     s0, s1, [x3]
        b 99f
-11:    str     s0, [x3]                /* S1 */
+       nop
+11:    BTI_J
+       str     s0, [x3]                /* S1 */
        b 99f
-12:    st4     { v0.d, v1.d, v2.d, v3.d }[0], [x3]     /* D4 */
+       nop
+12:    BTI_J                           /* D4 */
+       st4     { v0.d, v1.d, v2.d, v3.d }[0], [x3]
        b 99f
-13:    st3     { v0.d, v1.d, v2.d }[0], [x3]   /* D3 */
+       nop
+13:    BTI_J                           /* D3 */
+       st3     { v0.d, v1.d, v2.d }[0], [x3]
        b 99f
-14:    stp     d0, d1, [x3]            /* D2 */
+       nop
+14:    BTI_J                           /* D2 */
+       stp     d0, d1, [x3]
        b 99f
-15:    str     d0, [x3]                /* D1 */
+       nop
+15:    BTI_J                           /* D1 */
+       str     d0, [x3]
        b 99f
-16:    str     q3, [x3, #48]           /* Q4 */
        nop
-17:    str     q2, [x3, #32]           /* Q3 */
+16:    BTI_J                           /* Q4 */
+       str     q3, [x3, #48]
+       nop
        nop
-18:    stp     q0, q1, [x3]            /* Q2 */
+17:    BTI_J                           /* Q3 */
+       str     q2, [x3, #32]
+       nop
+       nop
+18:    BTI_J                           /* Q2 */
+       stp     q0, q1, [x3]
        b 99f
-19:    str     q0, [x3]                /* Q1 */
+       nop
+19:    BTI_J                           /* Q1 */
+       str     q0, [x3]
        b 99f
-20:    uxtb    w0, w0                  /* UINT8 */
+       nop
+20:    BTI_J                           /* UINT8 */
+       uxtb    w0, w0
        str     x0, [x3]
+       nop
 21:    b 99f                           /* reserved */
        nop
-22:    uxth    w0, w0                  /* UINT16 */
+       nop
+       nop
+22:    BTI_J                           /* UINT16 */
+       uxth    w0, w0
        str     x0, [x3]
+       nop
 23:    b 99f                           /* reserved */
        nop
-24:    mov     w0, w0                  /* UINT32 */
+       nop
+       nop
+24:    BTI_J                           /* UINT32 */
+       mov     w0, w0
        str     x0, [x3]
+       nop
 25:    b 99f                           /* reserved */
        nop
-26:    sxtb    x0, w0                  /* SINT8 */
+       nop
+       nop
+26:    BTI_J                           /* SINT8 */
+       sxtb    x0, w0
        str     x0, [x3]
+       nop
 27:    b 99f                           /* reserved */
        nop
-28:    sxth    x0, w0                  /* SINT16 */
+       nop
+       nop
+28:    BTI_J                           /* SINT16 */
+       sxth    x0, w0
        str     x0, [x3]
+       nop
 29:    b 99f                           /* reserved */
        nop
-30:    sxtw    x0, w0                  /* SINT32 */
+       nop
+       nop
+30:    BTI_J                           /* SINT32 */
+       sxtw    x0, w0
        str     x0, [x3]
+       nop
 31:    b 99f                           /* reserved */
        nop
+       nop
+       nop
 
        /* Return now that result has been populated. */
 99:
@@ -246,7 +324,9 @@ CNAME(ffi_call_SYSV):
        .align 4
 CNAME(ffi_closure_SYSV_V):
        cfi_startproc
+       BTI_C
        SIGN_LR
+       PAC_CFI_WINDOW_SAVE
        stp     x29, x30, [sp, #-ffi_closure_SYSV_FS]!
        cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
        cfi_rel_offset (x29, 0)
@@ -268,9 +348,11 @@ CNAME(ffi_closure_SYSV_V):
 #endif
 
        .align  4
-       cfi_startproc
 CNAME(ffi_closure_SYSV):
+       cfi_startproc
+       BTI_C
        SIGN_LR
+       PAC_CFI_WINDOW_SAVE
        stp     x29, x30, [sp, #-ffi_closure_SYSV_FS]!
        cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
        cfi_rel_offset (x29, 0)
@@ -288,7 +370,7 @@ CNAME(ffi_closure_SYSV):
        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 */
 #ifdef FFI_GO_CLOSURES
-.Ldo_closure:
+L(do_closure):
 #endif
        add     x3, sp, #16                             /* load context */
        add     x4, sp, #ffi_closure_SYSV_FS            /* load stack */
@@ -299,73 +381,135 @@ CNAME(ffi_closure_SYSV):
        /* Load the return value as directed.  */
        adr     x1, 0f
        and     w0, w0, #AARCH64_RET_MASK
-       add     x1, x1, x0, lsl #3
+       add     x1, x1, x0, lsl #4
        add     x3, sp, #16+CALL_CONTEXT_SIZE
        br      x1
 
-       /* Note that each table entry is 2 insns, and thus 8 bytes.  */
+       /* Note that each table entry is 4 insns, and thus 16 bytes.  */
        .align  4
-0:     b       99f                     /* VOID */
+0:     BTI_J                           /* VOID */
+       b       99f
        nop
-1:     ldr     x0, [x3]                /* INT64 */
+       nop
+1:     BTI_J                           /* INT64 */
+       ldr     x0, [x3]
        b       99f
-2:     ldp     x0, x1, [x3]            /* INT128 */
+       nop
+2:     BTI_J                           /* INT128 */
+       ldp     x0, x1, [x3]
        b       99f
+       nop
 3:     brk     #1000                   /* UNUSED */
        nop
+       nop
+       nop
 4:     brk     #1000                   /* UNUSED */
        nop
+       nop
+       nop
 5:     brk     #1000                   /* UNUSED */
        nop
+       nop
+       nop
 6:     brk     #1000                   /* UNUSED */
        nop
+       nop
+       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 */
+8:     BTI_J                           /* S4 */
+       ldr     s3, [x3, #12]
+       nop
+       nop
+9:     BTI_J                           /* S3 */
+       ldr     s2, [x3, #8]
+       nop
+       nop
+10:    BTI_J                           /* S2 */
+       ldp     s0, s1, [x3]
        b       99f
-11:    ldr     s0, [x3]                /* S1 */
+       nop
+11:    BTI_J                           /* S1 */
+       ldr     s0, [x3]
        b       99f
-12:    ldr     d3, [x3, #24]           /* D4 */
        nop
-13:    ldr     d2, [x3, #16]           /* D3 */
+12:    BTI_J                           /* D4 */
+       ldr     d3, [x3, #24]
+       nop
+       nop
+13:    BTI_J                           /* D3 */
+       ldr     d2, [x3, #16]
        nop
-14:    ldp     d0, d1, [x3]            /* D2 */
+       nop
+14:    BTI_J                           /* D2 */
+       ldp     d0, d1, [x3]
        b       99f
-15:    ldr     d0, [x3]                /* D1 */
+       nop
+15:    BTI_J                           /* D1 */
+       ldr     d0, [x3]
        b       99f
-16:    ldr     q3, [x3, #48]           /* Q4 */
        nop
-17:    ldr     q2, [x3, #32]           /* Q3 */
+16:    BTI_J                           /* Q4 */
+       ldr     q3, [x3, #48]
+       nop
+       nop
+17:    BTI_J                           /* Q3 */
+       ldr     q2, [x3, #32]
        nop
-18:    ldp     q0, q1, [x3]            /* Q2 */
+       nop
+18:    BTI_J                           /* Q2 */
+       ldp     q0, q1, [x3]
        b       99f
-19:    ldr     q0, [x3]                /* Q1 */
+       nop
+19:    BTI_J                           /* Q1 */
+       ldr     q0, [x3]
        b       99f
-20:    ldrb    w0, [x3, #BE(7)]        /* UINT8 */
+       nop
+20:    BTI_J                           /* UINT8 */
+       ldrb    w0, [x3, #BE(7)]
        b       99f
+       nop
 21:    brk     #1000                   /* reserved */
        nop
-22:    ldrh    w0, [x3, #BE(6)]        /* UINT16 */
+       nop
+       nop
+22:    BTI_J                           /* UINT16 */
+       ldrh    w0, [x3, #BE(6)]
        b       99f
+       nop
 23:    brk     #1000                   /* reserved */
        nop
-24:    ldr     w0, [x3, #BE(4)]        /* UINT32 */
+       nop
+       nop
+24:    BTI_J                           /* UINT32 */
+       ldr     w0, [x3, #BE(4)]
        b       99f
+       nop
 25:    brk     #1000                   /* reserved */
        nop
-26:    ldrsb   x0, [x3, #BE(7)]        /* SINT8 */
+       nop
+       nop
+26:    BTI_J                           /* SINT8 */
+       ldrsb   x0, [x3, #BE(7)]
        b       99f
+       nop
 27:    brk     #1000                   /* reserved */
        nop
-28:    ldrsh   x0, [x3, #BE(6)]        /* SINT16 */
+       nop
+       nop
+28:    BTI_J                           /* SINT16 */
+       ldrsh   x0, [x3, #BE(6)]
        b       99f
+       nop
 29:    brk     #1000                   /* reserved */
        nop
-30:    ldrsw   x0, [x3, #BE(4)]        /* SINT32 */
+       nop
+       nop
+30:    BTI_J                           /* SINT32 */
+       ldrsw   x0, [x3, #BE(4)]
+       nop
        nop
 31:                                    /* reserved */
 99:    ldp     x29, x30, [sp], #ffi_closure_SYSV_FS
@@ -385,6 +529,7 @@ CNAME(ffi_closure_SYSV):
 #if defined(FFI_EXEC_STATIC_TRAMP)
        .align 4
 CNAME(ffi_closure_SYSV_V_alt):
+       BTI_C
        /* See the comments above trampoline_code_table. */
        ldr     x17, [sp, #8]                   /* Load closure in x17 */
        add     sp, sp, #16                     /* Restore the stack */
@@ -399,6 +544,7 @@ CNAME(ffi_closure_SYSV_V_alt):
 
        .align 4
 CNAME(ffi_closure_SYSV_alt):
+       BTI_C
        /* See the comments above trampoline_code_table. */
        ldr     x17, [sp, #8]                   /* Load closure in x17 */
        add     sp, sp, #16                     /* Restore the stack */
@@ -479,6 +625,7 @@ CNAME(ffi_closure_trampoline_table_page):
        .align 4
 CNAME(ffi_go_closure_SYSV_V):
        cfi_startproc
+       BTI_C
        stp     x29, x30, [sp, #-ffi_closure_SYSV_FS]!
        cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
        cfi_rel_offset (x29, 0)
@@ -500,8 +647,11 @@ CNAME(ffi_go_closure_SYSV_V):
 #endif
 
        .align  4
-       cfi_startproc
 CNAME(ffi_go_closure_SYSV):
+       cfi_startproc
+       BTI_C
+       SIGN_LR_LINUX_ONLY
+       PAC_CFI_WINDOW_SAVE
        stp     x29, x30, [sp, #-ffi_closure_SYSV_FS]!
        cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
        cfi_rel_offset (x29, 0)
@@ -518,7 +668,7 @@ CNAME(ffi_go_closure_SYSV):
        /* 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
+       b       L(do_closure)
        cfi_endproc
 
        .globl  CNAME(ffi_go_closure_SYSV)
@@ -533,5 +683,17 @@ CNAME(ffi_go_closure_SYSV):
 
 #if defined __ELF__ && defined __linux__
        .section .note.GNU-stack,"",%progbits
+
+       .pushsection .note.gnu.property, "a";
+       .balign 8;
+       .long 4;
+       .long 0x10;
+       .long 0x5;
+       .asciz "GNU";
+       .long 0xc0000000; /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+       .long 4;
+       .long GNU_PROPERTY_AARCH64_BTI | GNU_PROPERTY_AARCH64_POINTER_AUTH;
+       .long 0;
+       .popsection;
 #endif
 
index 03715fde49f7a1ff02c82be3b09362cf0b871e17..e74934110202b483d5414b51756350ec0d8bfea9 100644 (file)
 #define ENTRY(x) .globl CNAME(x)` .type CNAME(x),%function` CNAME(x):
 #endif
 
+#if __SIZEOF_POINTER__ == 8
+#define PTRS 8
+#define FLTS 8
+#define LARG ldl
+#define SARG stl
+#define ADDPTR addl
+#define MOVPTR movl
+#else
+#define PTRS 4
+#define FLTS 4
+#define LARG ld
+#define SARG st
+#define ADDPTR add
+#define MOVPTR mov
+#endif
+
+#define FRAME_LEN (8 * PTRS + 16)
+
 .text
 
-        /* R0:   ffi_prep_args */
-        /* R1:   &ecif */
-        /* R2:   cif->bytes */
-        /* R3:   fig->flags */
-        /* R4:   ecif.rvalue */
-        /* R5:   fn */
-ENTRY(ffi_call_ARCompact)
+ENTRY(ffi_call_asm)
+        .cfi_startproc
+
         /* Save registers.  */
-        st.a       fp, [sp, -4]        /* fp + 20, fp */
-        push_s     blink               /* fp + 16, blink */
-        st.a       r4, [sp, -4]        /* fp + 12, ecif.rvalue */
-        push_s     r3                  /* fp +  8, fig->flags */
-        st.a       r5, [sp, -4]        /* fp +  4, fn */
-        push_s     r2                  /* fp +  0, cif->bytes */
-        mov        fp, sp
-
-        /* Make room for all of the new args.  */
-        sub        sp, sp, r2
-
-        /* Place all of the ffi_prep_args in position.  */
-        /* ffi_prep_args(char *stack, extended_cif *ecif) */
-        /* R1 already set.  */
-
-        /* And call.  */
-        jl_s.d     [r0]
-        mov_s      r0, sp
-
-        ld.ab      r12, [fp, 4]        /* cif->bytes */
-        ld.ab      r11, [fp, 4]        /* fn */
-
-        /* Move first 8 parameters in registers...  */
-        ld_s       r0, [sp]
-        ld_s       r1, [sp, 4]
-        ld_s       r2, [sp, 8]
-        ld_s       r3, [sp, 12]
-        ld         r4, [sp, 16]
-        ld         r5, [sp, 20]
-        ld         r6, [sp, 24]
-        ld         r7, [sp, 28]
-
-        /* ...and adjust the stack.  */
-        min        r12, r12, 32
+        .cfi_def_cfa r1, FRAME_LEN
+        SARG    fp, [r1, FRAME_LEN - 2*PTRS]
+        .cfi_offset fp, -2*PTRS
+        SARG    blink, [r1, FRAME_LEN - 1*PTRS]
+        .cfi_offset blink, -1*PTRS
+        ADDPTR  fp, r1, FRAME_LEN
+        MOVPTR  sp, r0
+        .cfi_def_cfa fp, 0
+
+        /* Load arguments.  */
+        MOVPTR  r11, r2      /* fn */
+        MOVPTR  r12, r3      /* closure */
+
+        /* Save arguments.  */
+        LARG    r0, [fp, -FRAME_LEN+0*PTRS]
+        LARG    r1, [fp, -FRAME_LEN+1*PTRS]
+        LARG    r2, [fp, -FRAME_LEN+2*PTRS]
+        LARG    r3, [fp, -FRAME_LEN+3*PTRS]
+        LARG    r4, [fp, -FRAME_LEN+4*PTRS]
+        LARG    r5, [fp, -FRAME_LEN+5*PTRS]
+        LARG    r6, [fp, -FRAME_LEN+6*PTRS]
+        LARG    r7, [fp, -FRAME_LEN+7*PTRS]
 
         /* Call the function.  */
-        jl.d       [r11]
-        add        sp, sp, r12 
-
-        mov        sp, fp        
-        pop_s      r3        /* fig->flags, return type */
-        pop_s      r2        /* ecif.rvalue, pointer for return value */
-
-        /* If the return value pointer is NULL, assume no return value.  */
-        breq.d     r2, 0, epilogue
-        pop_s      blink
-
-        /* Return INT.  */
-        brne       r3, FFI_TYPE_INT, return_double
-        b.d        epilogue
-        st_s       r0, [r2]        
-
-return_double:
-        brne       r3, FFI_TYPE_DOUBLE, epilogue
-        st_s       r0, [r2]        
-        st_s       r1, [r2,4]
-
-epilogue:
-        j_s.d      [blink]
-        ld.ab      fp, [sp, 4]
-
-ENTRY(ffi_closure_ARCompact)
-        st.a       r0, [sp, -32]
-        st_s       r1, [sp, 4]
-        st_s       r2, [sp, 8]
-        st_s       r3, [sp, 12]
-        st         r4, [sp, 16]
-        st         r5, [sp, 20]
-        st         r6, [sp, 24]
-        st         r7, [sp, 28]
-
-        /* pointer to arguments */
-        mov_s      r2, sp
-
-        /* return value goes here */
-        sub        sp, sp, 8
-        mov_s      r1, sp
-
-        push_s     blink
+        jl         [r11] 
+
+        /* Save return value (r0/r1)  */
+        SARG    r0, [fp, -FRAME_LEN+0*PTRS]
+        SARG    r1, [fp, -FRAME_LEN+1*PTRS]
+
+        /* Restore and return.  */
+        add     sp, fp, -FRAME_LEN
+        .cfi_def_cfa sp, FRAME_LEN
+        LARG    blink, [fp, -1*PTRS]
+        .cfi_restore blink
+        LARG    fp, [fp, -2*PTRS]
+        .cfi_restore fp
+        j_s     [blink]
+        .cfi_endproc
+        .size   ffi_call_asm, .-ffi_call_asm
+
+/*
+  ffi_closure_asm. Expects address of the passed-in ffi_closure in r8.
+  void ffi_closure_inner (ffi_cif *cif,
+                         void (*fun) (ffi_cif *, void *, void **, void *),
+                         void *user_data,
+                         size_t *stackargs, struct call_context *regargs)
+*/
+
+ENTRY(ffi_closure_asm)
+        .cfi_startproc
+
+        ADDPTR  sp, sp, -FRAME_LEN
+        .cfi_def_cfa_offset FRAME_LEN
+
+        /* Make a frame.  */
+        SARG    fp, [sp, FRAME_LEN-2*PTRS]
+        .cfi_offset fp, -2*PTRS
+        SARG    blink, [sp, FRAME_LEN-1*PTRS]
+        .cfi_offset blink, -1*PTRS
+        ADDPTR  fp, sp, FRAME_LEN
+
+        /* Save arguments.  */
+        SARG    r0, [sp, 0*PTRS]
+        SARG    r1, [sp, 1*PTRS]
+        SARG    r2, [sp, 2*PTRS]
+        SARG    r3, [sp, 3*PTRS]
+        SARG    r4, [sp, 4*PTRS]
+        SARG    r5, [sp, 5*PTRS]
+        SARG    r6, [sp, 6*PTRS]
+        SARG    r7, [sp, 7*PTRS]
+
+        /* Enter C.  */
+        LARG    r0, [r8, FFI_TRAMPOLINE_SIZE+0*PTRS]
+        LARG    r1, [r8, FFI_TRAMPOLINE_SIZE+1*PTRS]
+        LARG    r2, [r8, FFI_TRAMPOLINE_SIZE+2*PTRS]
+        ADDPTR  r3, sp, FRAME_LEN
+        MOVPTR  r4, sp
+
+        /* Call the C code.  */
+        bl      ffi_closure_inner
         
-        bl.d       ffi_closure_inner_ARCompact
-        mov_s      r0, r8                /* codeloc, set by trampoline */
-
-        pop_s      blink
-
-        /* set return value to r1:r0 */
-        pop_s      r0
-        pop_s      r1
-        j_s.d      [blink]
-        add_s      sp, sp, 32
+        /* Return values.  */
+        LARG    r0, [sp, 0*PTRS]
+        LARG    r1, [sp, 1*PTRS]
+
+        /* Restore and return.  */
+        LARG    blink, [sp, FRAME_LEN-1*PTRS]
+        .cfi_restore blink
+        LARG    fp, [sp, FRAME_LEN-2*PTRS]
+        .cfi_restore fp
+        ADDPTR  sp, sp, FRAME_LEN
+        .cfi_def_cfa_offset 0
+        j_s     [blink]
+        .cfi_endproc
+        .size ffi_closure_asm, .-ffi_closure_asm
+
+/*
+  ffi_go_closure_asm.  Expects address of the passed-in ffi_go_closure in r12.
+  void ffi_closure_inner (ffi_cif *cif,
+                         void (*fun) (ffi_cif *, void *, void **, void *),
+                         void *user_data,
+                         size_t *stackargs, struct call_context *regargs)
+*/
+
+ENTRY(ffi_go_closure_asm)
+        .cfi_startproc
+
+        ADDPTR  sp, sp, -FRAME_LEN
+        .cfi_def_cfa_offset FRAME_LEN
+
+        /* make a frame */
+        SARG    fp, [sp, FRAME_LEN-2*PTRS]
+        .cfi_offset fp, -2*PTRS
+        SARG    blink, [sp, FRAME_LEN-1*PTRS]
+        .cfi_offset blink, -1*PTRS
+        ADDPTR  fp, sp, FRAME_LEN
+
+        /* save arguments */
+        SARG    r0, [sp, 0*PTRS]
+        SARG    r1, [sp, 1*PTRS]
+        SARG    r2, [sp, 2*PTRS]
+        SARG    r3, [sp, 3*PTRS]
+        SARG    r4, [sp, 4*PTRS]
+        SARG    r5, [sp, 5*PTRS]
+        SARG    r6, [sp, 6*PTRS]
+        SARG    r7, [sp, 7*PTRS]
+
+        /* enter C */
+        LARG    r0, [r12, 1*PTRS]
+        LARG    r1, [r12, 2*PTRS]
+        MOVPTR  r2, r12
+        ADDPTR  r3, sp, FRAME_LEN
+        MOVPTR  r4, sp
+
+        bl      ffi_closure_inner
+
+        /* Return values. */
+        LARG    r0, [sp, 0*PTRS]
+        LARG    r1, [sp, 1*PTRS]
+
+
+        LARG    blink, [sp, FRAME_LEN-1*PTRS]
+        .cfi_restore blink
+        LARG    fp, [sp, FRAME_LEN-2*PTRS]
+        .cfi_restore fp
+        ADDPTR  sp, sp, FRAME_LEN
+        .cfi_def_cfa_offset 0
+        j_s     [blink]
+        .cfi_endproc
+        .size ffi_go_closure_asm, .-ffi_go_closure_asm
index 4d10b21a5d95d9a7a4ec1fa2991d2dd2680d8b97..0632319139bb535c0627526848be8acf6974b4d7 100644 (file)
 
 #include <sys/cachectl.h>
 
+#define NARGREG 8
+#define STKALIGN 4
+#define MAXCOPYARG (2 * sizeof(double))
+
+typedef struct call_context
+{
+  size_t r[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;
+  void *struct_stack;
+} call_builder;
+
+/* integer (not pointer) less than ABI XLEN */
+/* FFI_TYPE_INT does not appear to be used */
+#if defined(__ARC64_ARCH64__)
+#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
+
 /* for little endian ARC, the code is in fact stored as mixed endian for
    performance reasons */
 #if __BIG_ENDIAN__
 #define CODE_ENDIAN(x) ( (((uint32_t) (x)) << 16) | (((uint32_t) (x)) >> 16))
 #endif
 
-/* ffi_prep_args is called by the assembly routine once stack
-   space has been allocated for the function's arguments.  */
-
-void
-ffi_prep_args (char *stack, extended_cif * ecif)
-{
-  unsigned int i;
-  void **p_argv;
-  char *argp;
-  ffi_type **p_arg;
-
-  argp = stack;
-
-  if (ecif->cif->rtype->type == 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++)
-    {
-      size_t z;
-      int alignment;
-
-      /* align alignment to 4 */
-      alignment = (((*p_arg)->alignment - 1) | 3) + 1;
-
-      /* Align if necessary.  */
-      if ((alignment - 1) & (unsigned) argp)
-       argp = (char *) FFI_ALIGN (argp, alignment);
-
-      z = (*p_arg)->size;
-      if (z < sizeof (int))
-       {
-         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);
-             break;
-
-           default:
-             FFI_ASSERT (0);
-           }
-       }
-      else if (z == sizeof (int))
-       {
-         *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
-       }
-      else
-       {
-         if ((*p_arg)->type == FFI_TYPE_STRUCT)
-           {
-             memcpy (argp, *p_argv, z);
-           }
-         else
-           {
-             /* Double or long long 64bit.  */
-             memcpy (argp, *p_argv, z);
-           }
-       }
-      p_argv++;
-      argp += z;
-    }
-
-  return;
-}
-
 /* Perform machine dependent cif processing.  */
 ffi_status
 ffi_prep_cif_machdep (ffi_cif * cif)
@@ -157,85 +97,251 @@ ffi_prep_cif_machdep (ffi_cif * cif)
   return FFI_OK;
 }
 
-extern void ffi_call_ARCompact (void (*)(char *, extended_cif *),
-                               extended_cif *, unsigned, unsigned,
-                               unsigned *, void (*fn) (void));
+/* 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 defined(__ARC64_ARCH64__)
+    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;
+    default: FFI_ASSERT(0); break;
+  }
+
+  if (cb->used_integer == NARGREG) {
+    *cb->used_stack++ = value;
+  } else {
+    cb->aregs->r[cb->used_integer++] = value;
+  }
+}
 
-void
-ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue)
-{
-  extended_cif ecif;
+/* 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 (defined(__ARC64_ARCH64__) || defined(__ARC64_ARCH32__))
+  if (type->size > 2 * __SIZEOF_POINTER__) {
+    if (var) {
+      marshal_atom(cb, FFI_TYPE_POINTER, &data);
+    } else {
+      /* copy to stack and pass by reference */
+      data = memcpy (cb->struct_stack, data, type->size);
+      cb->struct_stack = (size_t *) FFI_ALIGN ((char *) cb->struct_stack + type->size, __SIZEOF_POINTER__);
+      marshal_atom(cb, FFI_TYPE_POINTER, &data);
+    }
+  }
+#else
+  if (type->type == FFI_TYPE_STRUCT) {
+    if (var) {
+      if (type->size > 0)
+        marshal_atom(cb, FFI_TYPE_POINTER, data);
+    } else {
+      int i;
+      
+      for (i = 0; i < type->size; i += sizeof(size_t)) {
+        marshal_atom(cb, FFI_TYPE_POINTER, data);
+        data += sizeof(size_t);
+      }
+    }
+  }
+#endif
+  else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) {
+    marshal_atom(cb, type->type, data);
+  } else {
+      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);
+  }
+}
 
-  ecif.cif = cif;
-  ecif.avalue = avalue;
+static void unmarshal_atom(call_builder *cb, int type, void *data) {
+  size_t value;
+
+  if (cb->used_integer == NARGREG) {
+    value = *cb->used_stack++;
+  } else {
+    value = cb->aregs->r[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 defined(__ARC64_ARCH64__)
+    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;
+  }
+}
 
-  /* 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;
+/* 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];
 
-  switch (cif->abi)
-    {
-    case FFI_ARCOMPACT:
-      ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes,
-                         cif->flags, ecif.rvalue, fn);
-      break;
+#if defined(__ARC64_ARCH64__)
+  void *pointer;
 
-    default:
-      FFI_ASSERT (0);
-      break;
+  if (type->size > 2 * __SIZEOF_POINTER__) {
+        /* pass by reference */
+        unmarshal_atom(cb, FFI_TYPE_POINTER, (char*)&pointer);
+        return pointer;
+    }
+#elif defined(__ARC64_ARCH32__)
+  if (type->type == FFI_TYPE_STRUCT) {
+    if (type->size > 2 * __SIZEOF_POINTER__) {
+      unmarshal_atom(cb, FFI_TYPE_POINTER, &realign[0]);
+      memcpy(data, (const void*)realign[0], type->size);
+      return data;
+    } else {
+      int i;
+      void *pdata = data;
+
+      for (i = 0; i < type->size; i += sizeof(size_t)) {
+        unmarshal_atom(cb, FFI_TYPE_POINTER, pdata);
+        pdata += sizeof(size_t);
+      }
+      return data;
     }
+  }
+#else
+  if (type->type == FFI_TYPE_STRUCT) {
+
+      if (var) {
+        int i;
+        void *pdata = data;
+
+        for (i = 0; i < type->size; i += sizeof(size_t)) {
+          unmarshal_atom(cb, FFI_TYPE_POINTER, pdata);
+          pdata += sizeof(size_t);
+        }
+        return data;
+      } else {
+        if (type->size > 0)
+          unmarshal_atom(cb, FFI_TYPE_POINTER, &realign[0]);
+        memcpy(data, (const void*)realign[0], type->size);
+        return data;
+      }
+  }
+#endif
+  else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) {
+    unmarshal_atom(cb, type->type, data);
+    return data;
+  } else {
+      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(ffi_type *type, int var) {
+  if (type->type == FFI_TYPE_STRUCT)
+         return 1;
+  
+  return type->size > 2 * __SIZEOF_POINTER__;
 }
 
-int
-ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue,
-                            ffi_arg * args)
+/* 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)
 {
-  void **arg_area, **p_argv;
-  ffi_cif *cif = closure->cif;
-  char *argp = (char *) args;
-  ffi_type **p_argt;
-  int i;
+  int return_by_ref = passed_by_ref(cif->rtype, 0);
 
-  arg_area = (void **) alloca (cif->nargs * sizeof (void *));
+  /* Allocate space for stack arg parameters.  */
+  size_t arg_bytes = FFI_ALIGN(2 * sizeof(size_t) * cif->nargs, STKALIGN);
+  /* Allocate space for copies of big structures.  */
+  size_t struct_bytes = FFI_ALIGN(cif->bytes, 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 +*/ struct_bytes + sizeof(call_context);
+  size_t alloc_base = (size_t)alloca(alloc_size);
 
-  /* handle hidden argument */
-  if (cif->flags == FFI_TYPE_STRUCT)
-    {
-      rvalue = *(void **) argp;
-      argp += 4;
-    }
+  // if (rval_bytes)
+  //   rvalue = (void*)(alloc_base + arg_bytes);
 
-  p_argv = arg_area;
+  call_builder cb;
+  cb.used_integer = 0;
+  cb.aregs = (call_context*)(alloc_base + arg_bytes /*+ rval_bytes*/ + struct_bytes);
+  cb.used_stack = (void*)alloc_base;
+  cb.struct_stack = (void *)(alloc_base + arg_bytes /*+ rval_bytes*/);
 
-  for (i = 0, p_argt = cif->arg_types; i < cif->nargs;
-       i++, p_argt++, p_argv++)
-    {
-      size_t z;
-      int alignment;
+  // if (cif->rtype->type == FFI_TYPE_STRUCT)
+  //   marshal(&cb, &ffi_type_pointer, 0, &rvalue);
+
+  if (return_by_ref)
+         marshal(&cb, &ffi_type_pointer, 0, &rvalue);
 
-      /* align alignment to 4 */
-      alignment = (((*p_argt)->alignment - 1) | 3) + 1;
+  int i;
+  for (i = 0; i < cif->nargs; i++)
+    marshal(&cb, cif->arg_types[i], 0, avalue[i]);
 
-      /* Align if necessary.  */
-      if ((alignment - 1) & (unsigned) argp)
-       argp = (char *) FFI_ALIGN (argp, alignment);
+  ffi_call_asm ((void *) alloc_base, cb.aregs, fn, closure);
 
-      z = (*p_argt)->size;
-      *p_argv = (void *) argp;
-      argp += z;
+  cb.used_integer = 0;
+  if (!return_by_ref && rvalue)
+    {
+           if (IS_INT(cif->rtype->type)
+               && cif->rtype->size < sizeof (ffi_arg))
+           {
+        /* Integer types smaller than ffi_arg need to be extended.  */
+           switch (cif->rtype->type) {
+             case FFI_TYPE_SINT8:
+             case FFI_TYPE_SINT16:
+             case FFI_TYPE_SINT32:
+                     unmarshal_atom (&cb, (sizeof (ffi_arg) > 4
+                          ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32),
+                                                 rvalue);
+                     break;
+             case FFI_TYPE_UINT8:
+             case FFI_TYPE_UINT16:
+             case FFI_TYPE_UINT32:
+                     unmarshal_atom (&cb, (sizeof (ffi_arg) > 4
+                                                 ? FFI_TYPE_UINT64 : FFI_TYPE_UINT32),
+                                                 rvalue);
+                     break;
+             }
+           }
+           else
+             unmarshal(&cb, cif->rtype, 0, rvalue);
     }
+}
 
-  (closure->fun) (cif, rvalue, arg_area, closure->user_data);
+void
+ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
+{
+  ffi_call_int(cif, fn, rvalue, avalue, NULL);
+}
 
-  return cif->flags;
+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_ARCompact (void);
+extern void ffi_closure_asm(void) FFI_HIDDEN;
 
 ffi_status
 ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif,
@@ -244,14 +350,30 @@ ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif,
 {
   uint32_t *tramp = (uint32_t *) & (closure->tramp[0]);
 
+#if defined(__ARC64_ARCH64__)
+  size_t address_ffi_closure = (size_t) ffi_closure_asm;
+#endif
+
   switch (cif->abi)
     {
+#if defined(__ARC64_ARCH64__)
+    case FFI_ARC64:
+      FFI_ASSERT (tramp == codeloc);
+      tramp[0] = CODE_ENDIAN (0x580a1fc0);     /* movl r8, pcl  */
+      tramp[1] = CODE_ENDIAN (0x5c0b1f80);     /* movhl r12, limm */
+      tramp[2] = CODE_ENDIAN ((uint32_t)(address_ffi_closure >> 32));
+      tramp[3] = CODE_ENDIAN (0x5c051f8c);     /* orl r12, r12, limm */
+      tramp[4] = CODE_ENDIAN ((uint32_t)(address_ffi_closure & 0xffffffff));
+      tramp[5] = CODE_ENDIAN (0x20200300);     /* j [r12] */
+      break;
+#else
     case FFI_ARCOMPACT:
       FFI_ASSERT (tramp == codeloc);
       tramp[0] = CODE_ENDIAN (0x200a1fc0);     /* mov r8, pcl  */
       tramp[1] = CODE_ENDIAN (0x20200f80);     /* j [long imm] */
-      tramp[2] = CODE_ENDIAN (ffi_closure_ARCompact);
+      tramp[2] = CODE_ENDIAN ((uint32_t) ffi_closure_asm);
       break;
+#endif
 
     default:
       return FFI_BAD_ABI;
@@ -264,3 +386,62 @@ ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif,
 
   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->bytes);
+    char *ptr = astorage;
+    void *rvalue;
+    call_builder cb;
+    int i;
+
+    cb.aregs = aregs;
+    cb.used_integer = 0;
+    cb.used_stack = stack;
+    
+    /* handle hidden argument */
+    if (cif->flags == FFI_TYPE_STRUCT)
+      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], 1, ptr);
+      ptr += cif->arg_types[i]->size;
+    }
+
+    fun (cif, rvalue, avalue, user_data);
+
+    if (cif->rtype->type != FFI_TYPE_VOID) {
+        cb.used_integer = 0;
+        marshal(&cb, cif->rtype, 1, rvalue);
+    }
+}
index bf8311bc832c52a64c31784c496c49e820d041d8..5b36902e714a2bdf84a7607db07ceaa1053ae0d6 100644 (file)
@@ -40,14 +40,28 @@ typedef signed long ffi_sarg;
 typedef enum ffi_abi
 {
   FFI_FIRST_ABI = 0,
+#if __SIZEOF_POINTER__ == 8
+  FFI_ARC64,
+#else
   FFI_ARCOMPACT,
+#endif
   FFI_LAST_ABI,
+#if __SIZEOF_POINTER__ == 8
+  FFI_DEFAULT_ABI = FFI_ARC64
+#else
   FFI_DEFAULT_ABI = FFI_ARCOMPACT
+#endif
 } ffi_abi;
 #endif
 
 #define FFI_CLOSURES           1
+#define FFI_GO_CLOSURES 1
+#if __SIZEOF_POINTER__ == 8
+#define FFI_TRAMPOLINE_SIZE    24
+#else
 #define FFI_TRAMPOLINE_SIZE    12
+#endif
+
 #define FFI_NATIVE_RAW_API     0
 
 #endif
index 593ab4d48b8b003f606b1f795284823420656d35..cfd3e9d19ebd4bbb497e2efb8913083a8dfc1394 100644 (file)
@@ -64,6 +64,10 @@ extern unsigned char ffi_arm_trampoline[12] FFI_HIDDEN;
 #include <machine/sysarch.h>
 #endif
 
+#if defined(__QNX__)
+#include <sys/mman.h>
+#endif
+
 /* Forward declares. */
 static int vfp_type_p (const ffi_type *);
 static void layout_vfp_args (ffi_cif *);
@@ -622,7 +626,7 @@ ffi_prep_closure_loc (ffi_closure * closure,
   config[1] = closure_func;
 #else
 
-#if defined(FFI_EXEC_STATIC_TRAMP)
+# if defined(FFI_EXEC_STATIC_TRAMP)
   if (ffi_tramp_is_present(closure))
     {
       /* Initialize the static trampoline's parameters. */
@@ -633,31 +637,33 @@ ffi_prep_closure_loc (ffi_closure * closure,
       ffi_tramp_set_parms (closure->ftramp, closure_func, closure);
       goto out;
     }
-#endif
+# endif
 
   /* Initialize the dynamic trampoline. */
-#ifndef _WIN32
+# ifndef _WIN32
   memcpy(closure->tramp, ffi_arm_trampoline, 8);
-#else
+# 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
+# endif
 
-#if defined (__QNX__)
-  msync(closure->tramp, 8, 0x1000000); /* clear data map */
-  msync(codeloc, 8, 0x1000000);        /* clear insn map */
-#elif defined(_WIN32)
+# if defined(__QNX__)
+  msync (closure->tramp, 8, MS_INVALIDATE_ICACHE);     /* clear data map */
+  msync (codeloc, 8, MS_INVALIDATE_ICACHE);            /* clear insn map */
+# elif defined(_WIN32)
   FlushInstructionCache(GetCurrentProcess(), closure->tramp, FFI_TRAMPOLINE_SIZE);
-#else
+# else
   __clear_cache(closure->tramp, closure->tramp + 8);   /* clear data map */
   __clear_cache(codeloc, codeloc + 8);                 /* clear insn map */
-#endif
-#ifdef _WIN32
+# endif
+# ifdef _WIN32
   *(void(**)(void))(closure->tramp + FFI_TRAMPOLINE_CLOSURE_FUNCTION) = closure_func;
-#else
+# else
   *(void (**)(void))(closure->tramp + 8) = closure_func;
-#endif
+# endif
+# if defined(FFI_EXEC_STATIC_TRAMP)
 out:
+# endif
 #endif
 
   closure->cif = cif;
index fb36213c6805fa5017154328e094daeaf902a0c5..e4272a103c542da193759ed3680e4e2bbb80c6b1 100644 (file)
@@ -142,13 +142,8 @@ ARM_FUNC_START(ffi_call_VFP)
 
        cmp     r3, #3                  @ load only d0 if possible
        ite     le
-#ifdef __clang__
-       vldrle d0, [r0]
-       vldmgt r0, {d0-d7}
-#else
        ldcle   p11, cr0, [r0]          @ vldrle d0, [r0]
        ldcgt   p11, cr0, [r0], {16}    @ vldmgt r0, {d0-d7}
-#endif
        add     r0, r0, #64             @ discard the vfp register args
        /* FALLTHRU */
 ARM_FUNC_END(ffi_call_VFP)
@@ -193,25 +188,13 @@ ARM_FUNC_START(ffi_call_SYSV)
 #endif
 0:
 E(ARM_TYPE_VFP_S)
-#ifdef __clang__
-       vstr s0, [r2]
-#else
        stc     p10, cr0, [r2]          @ vstr s0, [r2]
-#endif
        pop     {fp,pc}
 E(ARM_TYPE_VFP_D)
-#ifdef __clang__
-       vstr d0, [r2]
-#else
        stc     p11, cr0, [r2]          @ vstr d0, [r2]
-#endif
        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]
@@ -320,11 +303,7 @@ ARM_FUNC_START(ffi_closure_VFP)
        add     ip, sp, #16
        sub     sp, sp, #64+32                  @ allocate frame
        cfi_adjust_cfa_offset(64+32)
-#ifdef __clang__
-       vstm sp, {d0-d7}
-#else
        stc     p11, cr0, [sp], {16}            @ vstm sp, {d0-d7}
-#endif
        stmdb   sp!, {ip,lr}
 
        /* See above.  */
@@ -358,25 +337,13 @@ ARM_FUNC_START_LOCAL(ffi_closure_ret)
        cfi_rel_offset(lr, 4)
 0:
 E(ARM_TYPE_VFP_S)
-#ifdef __clang__
-       vldr s0, [r2]
-#else
        ldc     p10, cr0, [r2]                  @ vldr s0, [r2]
-#endif
        b       call_epilogue
 E(ARM_TYPE_VFP_D)
-#ifdef __clang__
-       vldr d0, [r2]
-#else
        ldc     p11, cr0, [r2]                  @ vldr d0, [r2]
-#endif
        b       call_epilogue
 E(ARM_TYPE_VFP_N)
-#ifdef __clang__
-       vldm r2, {d0-d3}
-#else
        ldc     p11, cr0, [r2], {8}             @ vldm r2, {d0-d3}
-#endif
        b       call_epilogue
 E(ARM_TYPE_INT64)
        ldr     r1, [r2, #4]
index f7bead67b54ebc08f99d07505374693f34624916..02cf78fa26c0aaadb4af5265d32489ca3e216014 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   closures.c - Copyright (c) 2019 Anthony Green
+   closures.c - Copyright (c) 2019, 2022 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.
    DEALINGS IN THE SOFTWARE.
    ----------------------------------------------------------------------- */
 
-#if defined __linux__ && !defined _GNU_SOURCE
+#if (defined __linux__ || defined __CYGWIN__) && !defined _GNU_SOURCE
 #define _GNU_SOURCE 1
 #endif
 
+#ifndef __EMSCRIPTEN__
+
 #include <fficonfig.h>
 #include <ffi.h>
 #include <ffi_common.h>
@@ -133,22 +135,26 @@ ffi_tramp_is_present (__attribute__((unused)) void *ptr)
 #  define FFI_MMAP_EXEC_WRIT 1
 #  define HAVE_MNTENT 1
 # endif
-# if defined(_WIN32) || defined(__OS2__)
-/* Windows systems may have Data Execution Protection (DEP) enabled, 
+# if defined(__CYGWIN__) || defined(_WIN32) || defined(__OS2__)
+/* Windows systems may have Data Execution Protection (DEP) enabled,
    which requires the use of VirtualMalloc/VirtualFree to alloc/free
    executable memory. */
 #  define FFI_MMAP_EXEC_WRIT 1
 # endif
 #endif
 
-#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
-# if defined(__linux__) && !defined(__ANDROID__)
+#if FFI_MMAP_EXEC_WRIT && defined(__linux__) && !defined(__ANDROID__)
+# if !defined FFI_MMAP_EXEC_SELINUX
 /* 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.  */
 #  define FFI_MMAP_EXEC_SELINUX 1
-# endif
-#endif
+# endif /* !defined FFI_MMAP_EXEC_SELINUX */
+# if !defined FFI_MMAP_PAX
+/* Also check for PaX MPROTECT */
+#  define FFI_MMAP_PAX 1
+# endif /* !defined FFI_MMAP_PAX */
+#endif /* FFI_MMAP_EXEC_WRIT && defined(__linux__) && !defined(__ANDROID__) */
 
 #if FFI_CLOSURES
 
@@ -158,7 +164,7 @@ ffi_tramp_is_present (__attribute__((unused)) void *ptr)
 
 #include <mach/mach.h>
 #include <pthread.h>
-#ifdef HAVE_PTRAUTH
+#ifdef HAVE_ARM64E_PTRAUTH
 #include <ptrauth.h>
 #endif
 #include <stdio.h>
@@ -217,7 +223,7 @@ ffi_trampoline_table_alloc (void)
   /* Remap the trampoline table on top of the placeholder page */
   trampoline_page = config_page + PAGE_MAX_SIZE;
 
-#ifdef HAVE_PTRAUTH
+#ifdef HAVE_ARM64E_PTRAUTH
   trampoline_page_template = (vm_address_t)(uintptr_t)ptrauth_auth_data((void *)&ffi_closure_trampoline_table_page, ptrauth_key_function_pointer, 0);
 #else
   trampoline_page_template = (vm_address_t)&ffi_closure_trampoline_table_page;
@@ -230,12 +236,24 @@ ffi_trampoline_table_alloc (void)
   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 || !(cur_prot & VM_PROT_EXECUTE))
+  if (kt != KERN_SUCCESS)
     {
       vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2);
       return NULL;
     }
 
+  if (!(cur_prot & VM_PROT_EXECUTE))
+    {
+      /* If VM_PROT_EXECUTE isn't set on the remapped trampoline page, set it */
+      kt = vm_protect (mach_task_self (), trampoline_page, PAGE_MAX_SIZE,
+         FALSE, cur_prot | VM_PROT_EXECUTE);
+      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;
@@ -250,7 +268,7 @@ ffi_trampoline_table_alloc (void)
       ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
       entry->trampoline =
        (void *) (trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
-#ifdef HAVE_PTRAUTH
+#ifdef HAVE_ARM64E_PTRAUTH
       entry->trampoline = ptrauth_sign_unauthenticated(entry->trampoline, ptrauth_key_function_pointer, 0);
 #endif
 
@@ -467,14 +485,18 @@ selinux_enabled_check (void)
 
 #endif /* !FFI_MMAP_EXEC_SELINUX */
 
-/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. */
-#ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX
+/* On PaX enable kernels that have MPROTECT enabled we can't use PROT_EXEC. */
+#if defined FFI_MMAP_PAX
 #include <stdlib.h>
 
-static int emutramp_enabled = -1;
+enum {
+  PAX_MPROTECT = (1 << 0),
+  PAX_EMUTRAMP = (1 << 1),
+};
+static int cached_pax_flags = -1;
 
 static int
-emutramp_enabled_check (void)
+pax_flags_check (void)
 {
   char *buf = NULL;
   size_t len = 0;
@@ -488,9 +510,10 @@ emutramp_enabled_check (void)
   while (getline (&buf, &len, f) != -1)
     if (!strncmp (buf, "PaX:", 4))
       {
-        char emutramp;
-        if (sscanf (buf, "%*s %*c%c", &emutramp) == 1)
-          ret = (emutramp == 'E');
+        if (NULL != strchr (buf + 4, 'M'))
+          ret |= PAX_MPROTECT;
+        if (NULL != strchr (buf + 4, 'E'))
+          ret |= PAX_EMUTRAMP;
         break;
       }
   free (buf);
@@ -498,9 +521,13 @@ emutramp_enabled_check (void)
   return ret;
 }
 
-#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \
-                               : (emutramp_enabled = emutramp_enabled_check ()))
-#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
+#define get_pax_flags() (cached_pax_flags >= 0 ? cached_pax_flags \
+                               : (cached_pax_flags = pax_flags_check ()))
+#define has_pax_flags(flags) ((flags) == ((flags) & get_pax_flags ()))
+#define is_mprotect_enabled() (has_pax_flags (PAX_MPROTECT))
+#define is_emutramp_enabled() (has_pax_flags (PAX_EMUTRAMP))
+
+#endif /* defined FFI_MMAP_PAX */
 
 #elif defined (__CYGWIN__) || defined(__INTERIX)
 
@@ -511,9 +538,10 @@ emutramp_enabled_check (void)
 
 #endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */
 
-#ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX
-#define is_emutramp_enabled() 0
-#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
+#if !defined FFI_MMAP_PAX
+# define is_mprotect_enabled() 0
+# define is_emutramp_enabled() 0
+#endif /* !defined FFI_MMAP_PAX */
 
 /* Declare all functions defined in dlmalloc.c as static.  */
 static void *dlmalloc(size_t);
@@ -571,7 +599,7 @@ open_temp_exec_file_memfd (const char *name)
 
 /* Open a temporary file name, and immediately unlink it.  */
 static int
-open_temp_exec_file_name (char *name, int flags)
+open_temp_exec_file_name (char *name, int flags MAYBE_UNUSED)
 {
   int fd;
 
@@ -737,7 +765,7 @@ open_temp_exec_file_opts_next (void)
 
 /* Return a file descriptor of a temporary zero-sized file in a
    writable and executable filesystem.  */
-static int
+int
 open_temp_exec_file (void)
 {
   int fd;
@@ -767,9 +795,9 @@ open_temp_exec_file (void)
    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)
+allocate_space (int fd, off_t len)
 {
-  static size_t page_size;
+  static long page_size;
 
   /* Obtain system page size. */
   if (!page_size)
@@ -810,7 +838,7 @@ dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
 
   offset = execsize;
 
-  if (allocate_space (execfd, offset, length))
+  if (allocate_space (execfd, length))
     return MFAIL;
 
   flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
@@ -878,13 +906,23 @@ dlmmap (void *start, size_t length, int prot,
       return ptr;
     }
 
-  if (execfd == -1 && is_emutramp_enabled ())
+  /* -1 != execfd hints that we already decided to use dlmmap_locked
+     last time.  */
+  if (execfd == -1 && is_mprotect_enabled ())
     {
-      ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
-      return ptr;
+#ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX
+      if (is_emutramp_enabled ())
+        {
+          /* emutramp requires the kernel recognizing the trampoline pattern
+             generated by ffi_prep_closure_loc; there is no way to test
+             in advance whether this will work, so this is experimental.  */
+          ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
+          return ptr;
+        }
+#endif
+      /* fallback to dlmmap_locked.  */
     }
-
-  if (execfd == -1 && !is_selinux_enabled ())
+  else if (execfd == -1 && !is_selinux_enabled ())
     {
       ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
 
@@ -897,16 +935,11 @@ dlmmap (void *start, size_t length, int prot,
         MREMAP_DUP and prot at this point.  */
     }
 
-  if (execsize == 0 || execfd == -1)
-    {
-      pthread_mutex_lock (&open_temp_exec_file_mutex);
-      ptr = dlmmap_locked (start, length, prot, flags, offset);
-      pthread_mutex_unlock (&open_temp_exec_file_mutex);
+  pthread_mutex_lock (&open_temp_exec_file_mutex);
+  ptr = dlmmap_locked (start, length, prot, flags, offset);
+  pthread_mutex_unlock (&open_temp_exec_file_mutex);
 
-      return ptr;
-    }
-
-  return dlmmap_locked (start, length, prot, flags, offset);
+  return ptr;
 }
 
 /* Release memory at the given address, as well as the corresponding
@@ -962,23 +995,23 @@ ffi_closure_alloc (size_t size, void **code)
   if (!code)
     return NULL;
 
-  ptr = FFI_CLOSURE_PTR (dlmalloc (size));
+  ptr = dlmalloc (size);
 
   if (ptr)
     {
       msegmentptr seg = segment_holding (gm, ptr);
 
-      *code = add_segment_exec_offset (ptr, seg);
+      *code = FFI_FN (add_segment_exec_offset (ptr, seg));
       if (!ffi_tramp_is_supported ())
         return ptr;
 
       ftramp = ffi_tramp_alloc (0);
       if (ftramp == NULL)
       {
-        dlfree (FFI_RESTORE_PTR (ptr));
+        dlfree (ptr);
         return NULL;
       }
-      *code = ffi_tramp_get_addr (ftramp);
+      *code = FFI_FN (ffi_tramp_get_addr (ftramp));
       ((ffi_closure *) ptr)->ftramp = ftramp;
     }
 
@@ -1019,7 +1052,7 @@ ffi_closure_free (void *ptr)
   if (ffi_tramp_is_supported ())
     ffi_tramp_free (((ffi_closure *) ptr)->ftramp);
 
-  dlfree (FFI_RESTORE_PTR (ptr));
+  dlfree (ptr);
 }
 
 int
@@ -1039,16 +1072,20 @@ ffi_tramp_is_present (void *ptr)
 void *
 ffi_closure_alloc (size_t size, void **code)
 {
+  void *c;
+
   if (!code)
     return NULL;
 
-  return *code = FFI_CLOSURE_PTR (malloc (size));
+  c = malloc (size);
+  *code = FFI_FN (c);
+  return c;
 }
 
 void
 ffi_closure_free (void *ptr)
 {
-  free (FFI_RESTORE_PTR (ptr));
+  free (ptr);
 }
 
 void *
@@ -1067,3 +1104,4 @@ ffi_tramp_is_present (__attribute__((unused)) void *ptr)
 #endif /* FFI_CLOSURES */
 
 #endif /* NetBSD with PROT_MPROTECT */
+#endif /* __EMSCRIPTEN__ */
index f3172b1ef6c9a9f04870cc76815984091de95da9..63321dc013cc276d80e4ce425fa359eccb90b7b5 100644 (file)
@@ -38,7 +38,7 @@ void ffi_stop_here(void)
 
 /* This function should only be called via the FFI_ASSERT() macro */
 
-void ffi_assert(char *expr, char *file, int line)
+NORETURN void ffi_assert(const char *expr, const char *file, int line)
 {
   fprintf(stderr, "ASSERTION FAILURE: %s at %s:%d\n", expr, file, line);
   ffi_stop_here();
@@ -47,7 +47,7 @@ void ffi_assert(char *expr, char *file, int line)
 
 /* Perform a sanity check on an ffi_type structure */
 
-void ffi_type_test(ffi_type *a, char *file, int line)
+void ffi_type_test(ffi_type *a, const char *file, int line)
 {
   FFI_ASSERT_AT(a != NULL, file, line);
 
index 1aba657edb51fb8d067985d3a8e707b5cf4adb5c..17193a0db3bb4576b593aa148c559849271f3a2e 100644 (file)
@@ -592,6 +592,11 @@ DEFAULT_MMAP_THRESHOLD       default: 256K
   malloc does support the following options.
 */
 
+/* The system's malloc.h may have conflicting defines. */
+#undef M_TRIM_THRESHOLD
+#undef M_GRANULARITY
+#undef M_MMAP_THRESHOLD
+
 #define M_TRIM_THRESHOLD     (-1)
 #define M_GRANULARITY        (-2)
 #define M_MMAP_THRESHOLD     (-3)
@@ -3383,6 +3388,7 @@ static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
   mchunkptr tnext = chunk_plus_offset(sp, ssize);
   mchunkptr p = tnext;
   int nfences = 0;
+  (void)nfences; // Suppress unused variable warning
 
   /* reset top to new space */
   init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
@@ -4447,7 +4453,7 @@ struct mallinfo dlmallinfo(void) {
 }
 #endif /* NO_MALLINFO */
 
-void dlmalloc_stats() {
+void dlmalloc_stats(void) {
   internal_malloc_stats(gm);
 }
 
index b1d04c3e749b0c6111f32207fad873b64c347a9b..1395f26a88feabe6d9a47bb825af71a1a601bd13 100644 (file)
 /* A 64-bit pointer value.  In LP64 mode, this is effectively a plain
    pointer.  In ILP32 mode, it's a pointer that's been extended to 
    64 bits by "addp4".  */
+#ifdef __hpux
+typedef void *PTR64;
+#else // some other unix
 typedef void *PTR64 __attribute__((mode(DI)));
+#endif
 
 /* Memory image of fp register contents.  This is the implementation
    specific format used by ldf.fill/stf.spill.  All we care about is
@@ -76,14 +80,22 @@ endian_adjust (void *addr, size_t len)
    point types without type conversions.  Type conversion to long double breaks
    the denorm support.  */
 
+#ifdef __hpux
+#define stf_spill(addr, value)
+#else
 #define stf_spill(addr, value) \
   asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
+#endif
 
 /* Load a value from ADDR, which is in the current cpu implementation's
    fp spill format.  As above, this must also be a macro.  */
 
+#ifdef __hpux
+#define ldf_fill(result, addr)
+#else
 #define ldf_fill(result, addr) \
   asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
+#endif
 
 /* Return the size of the C type associated with with TYPE.  Which will
    be one of the FFI_IA64_TYPE_HFA_* values.  */
index e2547e02b3aa1c173bdbc80fc8ef78c00194c34f..04908368c3e26a20f716d14d499f986905168bb7 100644 (file)
 
        .pred.safe_across_calls p1-p5,p16-p63
 .text
+/* HPUX assembler needs to see these symbols, otherwise compilation
+   fails */
+#ifdef __hpux
+      .global memcpy
+      .global ffi_closure_unix_inner
+#endif
 
 /* int ffi_call_unix (struct ia64_args *stack, PTR64 rvalue,
                      void (*fn)(void), int flags);
@@ -104,7 +110,12 @@ ffi_call_unix:
        mov     ar.pfs = loc0
        addl    r18 = @ltoffx(.Lst_table), gp
        ;;
+       /* default assembler on HP-UX does not support LDXMOV */
+#ifdef __hpux
+       ld8     r18 = [r18]
+#else
        ld8.mov r18 = [r18], .Lst_table
+#endif
        mov     b0 = loc1
        ;;
        shladd  r18 = r16, 3, r18
@@ -357,7 +368,11 @@ ffi_closure_unix:
        addl    r18 = @ltoffx(.Lld_table), gp
        mov     ar.pfs = loc0
        ;;
-       ld8.mov r18 = [r18], .Lld_table
+#ifdef __hpux
+       ld8     r18 = [r18]
+#else
+       ld8.mov r18 = [r18], .Lst_table
+#endif
        mov     b0 = loc1
        ;;
        shladd  r18 = r16, 3, r18
@@ -515,8 +530,11 @@ ffi_closure_unix:
        ;;
 
        .endp   ffi_closure_unix
-
+#ifdef __hpux
+       .rodata
+#else
        .section .rodata
+#endif
        .align  8
 .Lst_table:
        data8   @pcrel(.Lst_void)               // FFI_TYPE_VOID
index 01c2e18a395faf6caafad9da149bf24864e03a1d..93c337749f171d599679bbc3b500b9afc6a166e6 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <ffi.h>
 #include <ffi_common.h>
+#include <tramp.h>
 
 #include <stdlib.h>
 #include <stdint.h>
index ab8fc4e48a250a14d8d14f4f3d247a55524b8692..6fab50b115ed240a7889442efe6144b50c24ee7a 100644 (file)
@@ -1,8 +1,9 @@
 /* -----------------------------------------------------------------------
    ffi.c - Copyright (c) 2004  Renesas Technology
            Copyright (c) 2008  Red Hat, Inc.
-   
-   M32R Foreign Function Interface 
+           Copyright (c) 2022  Anthony Green
+
+   M32R Foreign Function Interface
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -63,7 +64,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
       if (((*p_arg)->alignment - 1) & (unsigned) argp)
        argp = (char *) FFI_ALIGN (argp, (*p_arg)->alignment);
 
-      if (avn != 0) 
+      if (avn != 0)
        {
          avn--;
          z = (*p_arg)->size;
@@ -76,19 +77,19 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
                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:
                  z = (*p_arg)->size;
                  if ((*p_arg)->alignment != 1)
@@ -131,7 +132,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
          argp += z;
        }
     }
-  
+
   return;
 }
 
@@ -178,24 +179,40 @@ extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
 {
   extended_cif ecif;
+  ffi_type **arg_types = cif->arg_types;
+  int i, nargs = cif->nargs;
 
   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) && 
+  if ((rvalue == NULL) &&
       (cif->rtype->type == FFI_TYPE_STRUCT))
     {
       ecif.rvalue = alloca (cif->rtype->size);
     }
   else
-    ecif.rvalue = rvalue;    
-  
-  switch (cif->abi) 
+    ecif.rvalue = rvalue;
+
+  /* If we have any large structure arguments, make a copy so we are passing
+     by value.  */
+  for (i = 0; i < nargs; i++)
+    {
+      ffi_type *at = arg_types[i];
+      int size = at->size;
+      if (at->type == FFI_TYPE_STRUCT && size > 4)
+        {
+          char *argcopy = alloca (size);
+          memcpy (argcopy, avalue[i], size);
+          avalue[i] = argcopy;
+        }
+    }
+
+  switch (cif->abi)
     {
     case FFI_SYSV:
-      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
+      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
                    cif->flags, ecif.rvalue, fn);
       if (cif->rtype->type == FFI_TYPE_STRUCT)
        {
index 979ca49f1bd64b7b49c7f757709bc6eacc9e134c..5c8c6bc5d4473d5b299c6da258e7dd0ee3b85b45 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <stdint.h>
 #include <stdlib.h>
+#include <stdio.h>
 
 #ifdef __GNUC__
 #  if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))
@@ -77,22 +78,39 @@ static void ffi_prep_args(char *stack,
 {
   int i;
   void **p_argv;
-  char *argp;
+  char *argp, *argp_f;
   ffi_type **p_arg;
 
+  memset(stack, 0, bytes);
+
 #ifdef FFI_MIPS_N32
+  int soft_float = (ecif->cif->abi == FFI_N32_SOFT_FLOAT
+                   || ecif->cif->abi == FFI_N64_SOFT_FLOAT);
   /* If more than 8 double words are used, the remainder go
      on the stack. We reorder stuff on the stack here to 
      support this easily. */
-  if (bytes > 8 * sizeof(ffi_arg))
-    argp = &stack[bytes - (8 * sizeof(ffi_arg))];
+  /* if ret is _Complex long double, args reg shift2, and a0 should holds pointer to rvalue */
+  if (ecif->cif->rtype->type == FFI_TYPE_COMPLEX && ecif->cif->rtype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
+    {
+      if (bytes + 16 > 8 * sizeof(ffi_arg))
+        argp = &stack[bytes - (8 * sizeof(ffi_arg))];
+      else
+        argp = stack;
+      * (unsigned long *) argp = (unsigned long) ecif->rvalue;
+      argp += 16;
+    }
   else
-    argp = stack;
+    {
+      if (bytes > 8 * sizeof(ffi_arg))
+        argp = &stack[bytes - (8 * sizeof(ffi_arg))];
+      else
+        argp = stack;
+    }
 #else
   argp = stack;
 #endif
 
-  memset(stack, 0, bytes);
+  argp_f = argp;
 
 #ifdef FFI_MIPS_N32
   if ( ecif->cif->rstruct_flag != 0 )
@@ -133,7 +151,7 @@ static void ffi_prep_args(char *stack,
           if (type == FFI_TYPE_POINTER)
             type = (ecif->cif->abi == FFI_N64
                    || ecif->cif->abi == FFI_N64_SOFT_FLOAT)
-             ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+             ? FFI_TYPE_SINT64 : FFI_TYPE_UINT32;
 
        if (i < 8 && (ecif->cif->abi == FFI_N32_SOFT_FLOAT
                      || ecif->cif->abi == FFI_N64_SOFT_FLOAT))
@@ -183,6 +201,25 @@ static void ffi_prep_args(char *stack,
 #endif
                break;
 
+#ifdef FFI_MIPS_N32
+             case FFI_TYPE_COMPLEX:
+               /* expand from 4+4 to 8+8 if pass with fpr reg */
+               /* argp will wind back to stack when we process all of reg args */
+               /* all var_args passed with gpr, should be expand */
+               if(!soft_float
+                   && (*p_arg)->elements[0]->type == FFI_TYPE_FLOAT
+                   && argp>=argp_f
+                   && i < ecif->cif->mips_nfixedargs)
+                 {
+                   *(float *) argp = *(float *)(* p_argv);
+                   argp += z;
+                   char *tmp = (void *) (*p_argv);
+                   *(float *) argp = *(float *)(tmp+4);
+                 }
+               else
+                 memcpy(argp, *p_argv, (*p_arg)->size);
+               break;
+#endif
              /* This can only happen with 64bit slots.  */
              case FFI_TYPE_FLOAT:
                *(float *) argp = *(float *)(* p_argv);
@@ -235,6 +272,24 @@ static void ffi_prep_args(char *stack,
    passed in an integer register". This code traverses structure
    definitions and generates the appropriate flags. */
 
+static int
+calc_n32_struct_flags_element(unsigned *flags, ffi_type *e,
+                             unsigned *loc, unsigned *arg_reg)
+{
+  /* Align this object.  */
+  *loc = FFI_ALIGN(*loc, e->alignment);
+  if (e->type == FFI_TYPE_DOUBLE)
+    {
+      /* Already aligned to FFI_SIZEOF_ARG.  */
+      *arg_reg = *loc / FFI_SIZEOF_ARG;
+      if (*arg_reg > 7)
+       return 1;
+      *flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS));
+    }
+  *loc += e->size;
+  return 0;
+}
+
 static unsigned
 calc_n32_struct_flags(int soft_float, ffi_type *arg,
                      unsigned *loc, unsigned *arg_reg)
@@ -249,19 +304,16 @@ calc_n32_struct_flags(int soft_float, ffi_type *arg,
 
   while ((e = arg->elements[index]))
     {
-      /* Align this object.  */
-      *loc = FFI_ALIGN(*loc, e->alignment);
-      if (e->type == FFI_TYPE_DOUBLE)
+      if (e->type == FFI_TYPE_COMPLEX)
        {
-          /* Already aligned to FFI_SIZEOF_ARG.  */
-          *arg_reg = *loc / FFI_SIZEOF_ARG;
-          if (*arg_reg > 7)
-            break;
-         flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS));
-          *loc += e->size;
+         if (calc_n32_struct_flags_element(&flags, e->elements[0], loc, arg_reg))
+           break;
+         if (calc_n32_struct_flags_element(&flags, e->elements[0], loc, arg_reg))
+           break;
        }
       else
-        *loc += e->size;
+       if (calc_n32_struct_flags_element(&flags, e, loc, arg_reg))
+         break;
       index++;
     }
   /* Next Argument register at alignment of FFI_SIZEOF_ARG.  */
@@ -273,7 +325,7 @@ calc_n32_struct_flags(int soft_float, ffi_type *arg,
 static unsigned
 calc_n32_return_struct_flags(int soft_float, ffi_type *arg)
 {
-  unsigned flags = 0;
+  unsigned flags;
   unsigned small = FFI_TYPE_SMALLSTRUCT;
   ffi_type *e;
 
@@ -292,33 +344,48 @@ calc_n32_return_struct_flags(int soft_float, ffi_type *arg)
 
   e = arg->elements[0];
 
-  if (e->type == FFI_TYPE_DOUBLE)
-    flags = FFI_TYPE_DOUBLE;
-  else if (e->type == FFI_TYPE_FLOAT)
-    flags = FFI_TYPE_FLOAT;
-
-  if (flags && (e = arg->elements[1]))
+  if (e->type == FFI_TYPE_COMPLEX)
     {
-      if (e->type == FFI_TYPE_DOUBLE)
-       flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
-      else if (e->type == FFI_TYPE_FLOAT)
-       flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS;
-      else 
+      int type = e->elements[0]->type;
+
+      if (type != FFI_TYPE_DOUBLE && type != FFI_TYPE_FLOAT)
        return small;
 
-      if (flags && (arg->elements[2]))
+      if (arg->elements[1])
        {
-         /* There are three arguments and the first two are 
-            floats! This must be passed the old way. */
+         /* Two floating point fields with more fields!
+            This must be passed the old way. */
          return small;
        }
-      if (soft_float)
-       flags += FFI_TYPE_STRUCT_SOFT;
+
+      flags = (type << FFI_FLAG_BITS) + type;
     }
   else
-    if (!flags)
-      return small;
+    {
+      if (e->type != FFI_TYPE_DOUBLE && e->type != FFI_TYPE_FLOAT)
+       return small;
+
+      flags = e->type;
 
+      if (arg->elements[1])
+       {
+         e = arg->elements[1];
+         if (e->type != FFI_TYPE_DOUBLE && e->type != FFI_TYPE_FLOAT)
+           return small;
+
+         if (arg->elements[2])
+           {
+             /* There are three arguments and the first two are
+                floats! This must be passed the old way. */
+             return small;
+           }
+
+         flags += e->type << FFI_FLAG_BITS;
+       }
+    }
+
+  if (soft_float)
+    flags += FFI_TYPE_STRUCT_SOFT;
   return flags;
 }
 
@@ -335,7 +402,7 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
    * does not have special handling for floating point args.
    */
 
-  if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32)
+  if (cif->rtype->type != FFI_TYPE_STRUCT && cif->rtype->type != FFI_TYPE_COMPLEX && cif->abi == FFI_O32)
     {
       if (cif->nargs > 0 && cif->nargs == nfixedargs)
        {
@@ -403,7 +470,10 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
         case FFI_TYPE_STRUCT:
         case FFI_TYPE_FLOAT:
         case FFI_TYPE_DOUBLE:
+        case FFI_TYPE_COMPLEX:
           cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
+         if (cif->rtype->type == FFI_TYPE_COMPLEX)
+            cif->flags +=  ((*cif->rtype->elements[0]).type) << (FFI_FLAG_BITS * 4);
           break;
 
         case FFI_TYPE_SINT64:
@@ -421,7 +491,6 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
 #ifdef FFI_MIPS_N32
   /* Set the flags necessary for N32 processing */
   {
-    int type;
     unsigned arg_reg = 0;
     unsigned loc = 0;
     unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
@@ -453,29 +522,14 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
 
     while (count-- > 0 && arg_reg < 8)
       {
-       type = (cif->arg_types)[index]->type;
+       ffi_type *t = cif->arg_types[index];
 
-       // Pass variadic arguments in integer registers even if they're floats
-       if (soft_float || index >= nfixedargs)
-         {
-           switch (type)
-             {
-             case FFI_TYPE_FLOAT:
-               type = FFI_TYPE_UINT32;
-               break;
-             case FFI_TYPE_DOUBLE:
-               type = FFI_TYPE_UINT64;
-               break;
-             default:
-               break;
-             }
-         }
-       switch (type)
+       switch (t->type)
          {
          case FFI_TYPE_FLOAT:
          case FFI_TYPE_DOUBLE:
-           cif->flags +=
-              ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS));
+           if (!soft_float && index < nfixedargs)
+              cif->flags += t->type << (arg_reg * FFI_FLAG_BITS);
            arg_reg++;
            break;
           case FFI_TYPE_LONGDOUBLE:
@@ -491,17 +545,71 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
                cif->flags +=
                  (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
                arg_reg++;
+               if (arg_reg >= 8)
+                 continue;
                cif->flags +=
                  (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
                arg_reg++;
              }
             break;
 
+         case FFI_TYPE_COMPLEX:
+           switch (t->elements[0]->type)
+             {
+             case FFI_TYPE_LONGDOUBLE:
+               arg_reg = FFI_ALIGN(arg_reg, 2);
+               if (soft_float || index >= nfixedargs)
+                 {
+                   arg_reg += 2;
+                 }
+               else
+                 {
+                   cif->flags +=
+                     (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+                   arg_reg++;
+                   if (arg_reg >= 8)
+                       continue;
+                   cif->flags +=
+                     (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+                   arg_reg++;
+                   if (arg_reg >= 8)
+                       continue;
+                 }
+               /* passthrough */
+             case FFI_TYPE_FLOAT:
+               // one fpr can only holds one arg even it is single
+               cif->bytes += 16;
+               /* passthrough */
+             case FFI_TYPE_SINT32:
+             case FFI_TYPE_UINT32:
+             case FFI_TYPE_DOUBLE:
+               if (soft_float || index >= nfixedargs)
+                 {
+                   arg_reg += 2;
+                 }
+               else
+                 {
+                   uint32_t type = t->elements[0]->type != FFI_TYPE_LONGDOUBLE? t->elements[0]->type: FFI_TYPE_DOUBLE;
+                   cif->flags +=
+                     (type << (arg_reg * FFI_FLAG_BITS));
+                   arg_reg++;
+                   if (arg_reg >= 8)
+                       continue;
+                   cif->flags +=
+                     (type << (arg_reg * FFI_FLAG_BITS));
+                   arg_reg++;
+                 }
+               break;
+             default:
+               arg_reg += 2;
+               break;
+             }
+           break;
+
          case FFI_TYPE_STRUCT:
             loc = arg_reg * FFI_SIZEOF_ARG;
            cif->flags += calc_n32_struct_flags(soft_float || index >= nfixedargs,
-                                               (cif->arg_types)[index],
-                                               &loc, &arg_reg);
+                                               t, &loc, &arg_reg);
            break;
 
          default:
@@ -541,7 +649,7 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
        if (cif->abi == FFI_N32_SOFT_FLOAT || cif->abi == FFI_N32)
          cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8);
        else
-         cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
+         cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 8);
        break;
 
       case FFI_TYPE_FLOAT:
@@ -553,7 +661,7 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
        /* else fall through */
       case FFI_TYPE_DOUBLE:
        if (soft_float)
-         cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
+         cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 8);
        else
          cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
        break;
@@ -563,8 +671,9 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
           two doubles.  */
        if (soft_float)
          {
-           cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
-           cif->flags += FFI_TYPE_SMALLSTRUCT2 << (4 + (FFI_FLAG_BITS * 8));
+           /* if ret is long double, the ret is given by v0 and a0, no idea why
+            * Let's us VOID | VOID | LONGDOUBLE for it*/
+           cif->flags += FFI_TYPE_LONGDOUBLE << (FFI_FLAG_BITS * 8);
          }
        else
          {
@@ -574,13 +683,52 @@ static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
                                              << (4 + (FFI_FLAG_BITS * 8));
          }
        break;
+      case FFI_TYPE_COMPLEX:
+       {
+         int type = cif->rtype->elements[0]->type;
+
+         cif->flags += (FFI_TYPE_COMPLEX << (FFI_FLAG_BITS * 8));
+         if (soft_float || (type != FFI_TYPE_FLOAT && type != FFI_TYPE_DOUBLE && type != FFI_TYPE_LONGDOUBLE))
+           {
+             switch (type)
+               {
+               case FFI_TYPE_DOUBLE:
+               case FFI_TYPE_SINT64:
+               case FFI_TYPE_UINT64:
+               case FFI_TYPE_INT:
+                 type = FFI_TYPE_SMALLSTRUCT2;
+                 break;
+               case FFI_TYPE_LONGDOUBLE:
+                 type = FFI_TYPE_LONGDOUBLE;
+                 break;
+               case FFI_TYPE_FLOAT:
+               default:
+                 type = FFI_TYPE_SMALLSTRUCT;
+               }
+             cif->flags += type << (4 + (FFI_FLAG_BITS * 8));
+           }
+         else
+           {
+             //cif->flags += (type + (type << FFI_FLAG_BITS))
+               //          << (4 + (FFI_FLAG_BITS * 8));
+             cif->flags += type << (4 + (FFI_FLAG_BITS * 8));
+           }
+         break;
+       }
+      case FFI_TYPE_UINT32:
+       /* In the N32 or N64 ABI unsigned 32-bit integer should be
+          *sign*-extended.  */
+       cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8);
+       break;
+      case FFI_TYPE_SINT64:
+       cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 8);
+       break;
       default:
-       cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
+       cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
        break;
       }
   }
 #endif
-  
   return FFI_OK;
 }
 
@@ -618,7 +766,7 @@ void ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
   /* value address then we need to make one                    */
   
   if ((rvalue == NULL) && 
-      (cif->rtype->type == FFI_TYPE_STRUCT))
+      (cif->rtype->type == FFI_TYPE_STRUCT || cif->rtype->type == FFI_TYPE_COMPLEX))
     ecif.rvalue = alloca(cif->rtype->size);
   else
     ecif.rvalue = rvalue;
@@ -830,6 +978,11 @@ ffi_closure_mips_inner_O32 (ffi_cif *cif,
       argn = 1;
       seen_int = 1;
     }
+  if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_COMPLEX)
+    {
+      rvalue = fpr;
+      argn = 1;
+    }
 
   i = 0;
   avn = cif->nargs;
@@ -902,6 +1055,9 @@ ffi_closure_mips_inner_O32 (ffi_cif *cif,
     }
   else
     {
+      if (cif->rtype->type == FFI_TYPE_COMPLEX) {
+          __asm__ volatile ("move $v1, %0" : : "r"(cif->rtype->size));
+      }
       return cif->rtype->type;
     }
 }
@@ -991,6 +1147,8 @@ ffi_closure_mips_inner_N32 (ffi_cif *cif,
 #endif
       argn = 1;
     }
+  if (cif->rtype->type == FFI_TYPE_COMPLEX && cif->rtype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
+    argn = 2;
 
   i = 0;
   avn = cif->nargs;
@@ -1015,6 +1173,31 @@ ffi_closure_mips_inner_N32 (ffi_cif *cif,
 #endif
             avaluep[i] = (char *) argp;
         }
+      else if (arg_types[i]->type == FFI_TYPE_COMPLEX && arg_types[i]->elements[0]->type == FFI_TYPE_DOUBLE)
+        {
+          argp = (argn >= 8 || i >= cif->mips_nfixedargs || soft_float) ? ar + argn : fpr + argn;
+          avaluep[i] = (char *) argp;
+        }
+      else if (arg_types[i]->type == FFI_TYPE_COMPLEX && arg_types[i]->elements[0]->type == FFI_TYPE_LONGDOUBLE)
+        {
+         /* align long double */
+         argn += ((argn & 0x1)? 1 : 0);
+          argp = (argn >= 8 || i >= cif->mips_nfixedargs || soft_float) ? ar + argn : fpr + argn;
+          avaluep[i] = (char *) argp;
+        }
+      else if (arg_types[i]->type == FFI_TYPE_COMPLEX && arg_types[i]->elements[0]->type == FFI_TYPE_FLOAT)
+        {
+          if (argn >= 8 || i >= cif->mips_nfixedargs || soft_float)
+            argp = ar + argn;
+         else
+           {
+             argp = fpr + argn;
+             /* the normal args for function holds 8bytes, while here we convert it to ptr */
+             uint32_t *tmp = (uint32_t *)argp;
+             tmp[1] = tmp[2];
+           }
+          avaluep[i] = (char *) argp;
+        }
       else
         {
           unsigned type = arg_types[i]->type;
@@ -1027,10 +1210,10 @@ ffi_closure_mips_inner_N32 (ffi_cif *cif,
           /* The size of a pointer depends on the ABI */
           if (type == FFI_TYPE_POINTER)
             type = (cif->abi == FFI_N64 || cif->abi == FFI_N64_SOFT_FLOAT)
-             ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+             ? FFI_TYPE_SINT64 : FFI_TYPE_UINT32;
 
          if (soft_float && type ==  FFI_TYPE_FLOAT)
-           type = FFI_TYPE_UINT32;
+           type = FFI_TYPE_SINT32;
 
           switch (type)
             {
index fdd5ca90ac432e271d36feea82a21ab540e6617c..cc7250cc1c051b0ec2133df079d947e40f6e44ec 100644 (file)
 #error "Please do not include ffitarget.h directly into your source.  Use ffi.h instead."
 #endif
 
-#ifdef __linux__
-# include <asm/sgidefs.h>
-#elif defined(__rtems__)
+#ifdef __rtems__
 /*
  * Subprogram calling convention - copied from sgidefs.h
  */
 #define _MIPS_SIM_ABI32                1
 #define _MIPS_SIM_NABI32       2
 #define _MIPS_SIM_ABI64                3
-#elif !defined(__OpenBSD__) && !defined(__FreeBSD__)
+#elif !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__linux__)
 # include <sgidefs.h>
 #endif
 
@@ -80,6 +78,7 @@
 #  endif
 #endif
 
+#define FFI_TARGET_HAS_COMPLEX_TYPE 1
 #define FFI_FLAG_BITS 2
 
 /* SGI's strange assembler requires that we multiply by 4 rather 
 #define FFI_TYPE_STRUCT_SMALL  93
 #define FFI_TYPE_STRUCT_SMALL2 109
 
+#define FFI_TYPE_COMPLEX_SMALL    95
+#define FFI_TYPE_COMPLEX_SMALL2   111
+#define FFI_TYPE_COMPLEX_FF       47
+#define FFI_TYPE_COMPLEX_DD       63
+#define FFI_TYPE_COMPLEX_LDLD     79
+
 /* and for n32 soft float, add 16 * 2^4 */
 #define FFI_TYPE_STRUCT_D_SOFT      317
 #define FFI_TYPE_STRUCT_F_SOFT      301
index 23b77fdfde5071c7ed4e0eefc83d35c04b8b0e9c..08cbb956667e3686fefa19a3e477fabb25554f38 100644 (file)
@@ -114,6 +114,16 @@ loadregs:
 
        REG_L   t6, 3*FFI_SIZEOF_ARG($fp)  # load the flags word into t6.
 
+       # when retval is _Complex long double, $f12/$a0, $f13/$a1 will be skipped
+       # no idea why, but gcc does it.
+       SRL     t4, t6, 8*FFI_FLAG_BITS
+       move    t8, t6
+       bne     t4, FFI_TYPE_COMPLEX_LDLD, loadregs1
+
+       SLL     t8, t6, 2*FFI_FLAG_BITS
+
+
+loadregs1:
 #ifdef __mips_soft_float
        REG_L   a0, 0*FFI_SIZEOF_ARG(t9)
        REG_L   a1, 1*FFI_SIZEOF_ARG(t9)
@@ -124,7 +134,7 @@ loadregs:
        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)
+       and     t4, t8, ((1<<FFI_FLAG_BITS)-1)
        REG_L   a0, 0*FFI_SIZEOF_ARG(t9)
        beqz    t4, arg1_next
        bne     t4, FFI_TYPE_FLOAT, arg1_doublep
@@ -134,7 +144,7 @@ arg1_doublep:
        l.d     $f12, 0*FFI_SIZEOF_ARG(t9)
 arg1_next:     
        
-       SRL     t4, t6, 1*FFI_FLAG_BITS
+       SRL     t4, t8, 1*FFI_FLAG_BITS
        and     t4, ((1<<FFI_FLAG_BITS)-1)
        REG_L   a1, 1*FFI_SIZEOF_ARG(t9)
        beqz    t4, arg2_next
@@ -145,7 +155,7 @@ arg2_doublep:
        l.d     $f13, 1*FFI_SIZEOF_ARG(t9)      
 arg2_next:     
        
-       SRL     t4, t6, 2*FFI_FLAG_BITS
+       SRL     t4, t8, 2*FFI_FLAG_BITS
        and     t4, ((1<<FFI_FLAG_BITS)-1)
        REG_L   a2, 2*FFI_SIZEOF_ARG(t9)
        beqz    t4, arg3_next
@@ -156,7 +166,7 @@ arg3_doublep:
        l.d     $f14, 2*FFI_SIZEOF_ARG(t9)      
 arg3_next:     
        
-       SRL     t4, t6, 3*FFI_FLAG_BITS
+       SRL     t4, t8, 3*FFI_FLAG_BITS
        and     t4, ((1<<FFI_FLAG_BITS)-1)
        REG_L   a3, 3*FFI_SIZEOF_ARG(t9)
        beqz    t4, arg4_next
@@ -167,7 +177,7 @@ arg4_doublep:
        l.d     $f15, 3*FFI_SIZEOF_ARG(t9)      
 arg4_next:     
        
-       SRL     t4, t6, 4*FFI_FLAG_BITS
+       SRL     t4, t8, 4*FFI_FLAG_BITS
        and     t4, ((1<<FFI_FLAG_BITS)-1)
        REG_L   a4, 4*FFI_SIZEOF_ARG(t9)
        beqz    t4, arg5_next
@@ -178,7 +188,7 @@ arg5_doublep:
        l.d     $f16, 4*FFI_SIZEOF_ARG(t9)      
 arg5_next:     
        
-       SRL     t4, t6, 5*FFI_FLAG_BITS
+       SRL     t4, t8, 5*FFI_FLAG_BITS
        and     t4, ((1<<FFI_FLAG_BITS)-1)
        REG_L   a5, 5*FFI_SIZEOF_ARG(t9)
        beqz    t4, arg6_next
@@ -189,7 +199,7 @@ arg6_doublep:
        l.d     $f17, 5*FFI_SIZEOF_ARG(t9)      
 arg6_next:     
        
-       SRL     t4, t6, 6*FFI_FLAG_BITS
+       SRL     t4, t8, 6*FFI_FLAG_BITS
        and     t4, ((1<<FFI_FLAG_BITS)-1)
        REG_L   a6, 6*FFI_SIZEOF_ARG(t9)
        beqz    t4, arg7_next
@@ -200,7 +210,7 @@ arg7_doublep:
        l.d     $f18, 6*FFI_SIZEOF_ARG(t9)      
 arg7_next:     
        
-       SRL     t4, t6, 7*FFI_FLAG_BITS
+       SRL     t4, t8, 7*FFI_FLAG_BITS
        and     t4, ((1<<FFI_FLAG_BITS)-1)
        REG_L   a7, 7*FFI_SIZEOF_ARG(t9)
        beqz    t4, arg8_next
@@ -212,7 +222,7 @@ arg8_doublep:
 arg8_next:     
 #endif
 
-callit:                
+callit:
        # Load the function pointer
        REG_L   t9, 5*FFI_SIZEOF_ARG($fp)
 
@@ -226,12 +236,54 @@ callit:
        # Shift the return type flag over
        SRL     t6, 8*FFI_FLAG_BITS
 
-       beq     t6, FFI_TYPE_SINT32, retint     
-       bne     t6, FFI_TYPE_INT, retfloat
-retint:
+       bne     t6, FFI_TYPE_UINT64, retsint32
+
+retuint64:
        jal     t9
        REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
-       REG_S   v0, 0(t4)
+       sd      v0, 0(t4)
+       b       epilogue
+
+retsint32:
+       bne     t6, FFI_TYPE_SINT32, retuint16
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       sll     v0, v0, 0
+       sd      v0, 0(t4)
+       b       epilogue
+
+retuint16:
+       bne     t6, FFI_TYPE_UINT16, retsint16
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       andi    v0, v0, 0xffff
+       sd      v0, 0(t4)
+       b       epilogue
+
+retsint16:
+       bne     t6, FFI_TYPE_SINT16, retuint8
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       dsll    v0, v0, 48
+       dsra    v0, v0, 48
+       sd      v0, 0(t4)
+       b       epilogue
+
+retuint8:
+       bne     t6, FFI_TYPE_UINT8, retsint8
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       andi    v0, v0, 0xff
+       sd      v0, 0(t4)
+       b       epilogue
+
+retsint8:
+       bne     t6, FFI_TYPE_SINT8, retfloat
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       sd      v0, 0(t4)
+       dsll    v0, v0, 56
+       dsra    v0, v0, 56
        b       epilogue
 
 retfloat:
@@ -249,7 +301,7 @@ retdouble:
        s.d     $f0, 0(t4)
        b       epilogue
 
-retstruct_d:   
+retstruct_d:
        bne     t6, FFI_TYPE_STRUCT_D, retstruct_f
        jal     t9
        REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
@@ -263,16 +315,37 @@ retstruct_f:
        s.s     $f0, 0(t4)
        b       epilogue
        
-retstruct_d_d: 
-       bne     t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
+retstruct_d_d:
+       bne     t6, FFI_TYPE_STRUCT_DD, retcomplex_d_d
        jal     t9
        REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
        s.d     $f0, 0(t4)
        s.d     $f2, 8(t4)
        b       epilogue
+
+retcomplex_d_d:
+       bne     t6, FFI_TYPE_COMPLEX_DD, retcomplex_ld_ld
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       s.d     $f0, 0(t4)
+       s.d     $f2, 8(t4)
+       b       epilogue
+
+retcomplex_ld_ld:
+       bne     t6, FFI_TYPE_COMPLEX_LDLD, retstruct_f_f
+       jal     t9
+       b       epilogue
        
-retstruct_f_f: 
-       bne     t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
+retstruct_f_f:
+       bne     t6, FFI_TYPE_STRUCT_FF, retcomplex_f_f
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       s.s     $f0, 0(t4)
+       s.s     $f2, 4(t4)
+       b       epilogue
+
+retcomplex_f_f:
+       bne     t6, FFI_TYPE_COMPLEX_FF, retstruct_d_f
        jal     t9
        REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
        s.s     $f0, 0(t4)
@@ -315,7 +388,7 @@ retstruct_d_d_soft:
        jal     t9
        REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
        sd      v0, 0(t4)
-       sd      v1, 8(t4)
+       sd      a0, 8(t4) # not typo, it is a0, I have no idea, gcc does do it
        b       epilogue
        
 retstruct_f_f_soft:    
@@ -339,7 +412,7 @@ retstruct_f_d_soft:
        jal     t9
        REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
        sw      v0, 0(t4)
-       sd      v1, 8(t4)
+       sd      a0, 8(t4) # not typo, it is a0, I have no idea, gcc does do it
        b       epilogue
        
 retstruct_small:       
@@ -350,14 +423,37 @@ retstruct_small:
        b       epilogue
        
 retstruct_small2:      
-       bne     t6, FFI_TYPE_STRUCT_SMALL2, retstruct
+       bne     t6, FFI_TYPE_STRUCT_SMALL2, retlongdouble_soft
        jal     t9
        REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
        REG_S   v0, 0(t4)
        REG_S   v1, 8(t4)
        b       epilogue
        
-retstruct:     
+retlongdouble_soft:
+       bne     t6, FFI_TYPE_LONGDOUBLE, retcomplex_small
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       REG_S   v0, 0(t4)
+       REG_S   a0, 8(t4) # not typo, it is a0, I have no idea, gcc does do it
+       b       epilogue
+
+retcomplex_small:
+       bne     t6, FFI_TYPE_COMPLEX_SMALL, retcomplex_small2
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       REG_S   v0, 0(t4)
+       b       epilogue
+
+retcomplex_small2:
+       bne     t6, FFI_TYPE_COMPLEX_SMALL2, retstruct
+       jal     t9
+       REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
+       REG_S   v0, 0(t4)
+       REG_S   v1, 8(t4)
+       b       epilogue
+
+retstruct:
 noretval:      
        jal     t9
        
@@ -403,7 +499,7 @@ epilogue:
         */
 
 #define SIZEOF_FRAME2  (20 * FFI_SIZEOF_ARG)
-       
+
 #define A7_OFF2                (19 * FFI_SIZEOF_ARG)
 #define A6_OFF2                (18 * FFI_SIZEOF_ARG)
 #define A5_OFF2                (17 * FFI_SIZEOF_ARG)
@@ -451,8 +547,13 @@ ffi_go_closure_N32:
 
        # Call ffi_closure_mips_inner_N32 to do the real work.
        LA      t9, ffi_closure_mips_inner_N32
+#if _MIPS_SIM==_ABIN32
+       lw      a0, 4($15)   # cif
+       lw      a1, 8($15) # fun
+#else
        REG_L   a0, 8($15)   # cif
        REG_L   a1, 16($15) # fun
+#endif
        move    a2, t7                     # userdata=closure
        ADDU    a3, $sp, V0_OFF2           # rvalue
        ADDU    a4, $sp, A0_OFF2           # ar
@@ -485,10 +586,17 @@ ffi_closure_N32:
 
        # Call ffi_closure_mips_inner_N32 to do the real work.
        LA      t9, ffi_closure_mips_inner_N32
+#if _MIPS_SIM==_ABIN32
+       lw      a0, 20($12)   # cif
+       lw      a1, 24($12)   # fun
+       lw      a2, 28($12) # user_data
+#else
        REG_L   a0, 56($12)   # cif
        REG_L   a1, 64($12)   # fun
        REG_L   a2, 72($12) # user_data
+#endif
        ADDU    a3, $sp, V0_OFF2
+       # FIXME: a4 does work, while if ret is _Complex long double, it will overwrite Fn_OFF2
        ADDU    a4, $sp, A0_OFF2
        ADDU    a5, $sp, F12_OFF2
 
@@ -512,14 +620,35 @@ $do_closure:
 
        jalr    t9
 
+cls_retuint64:
        # Return flags are in v0
-       bne     v0, FFI_TYPE_SINT32, cls_retint
+       bne     v0, FFI_TYPE_UINT64, cls_retsint32
+       ld      v0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retsint32:
+       bne     v0, FFI_TYPE_SINT32, cls_retsint16
        lw      v0, V0_OFF2($sp)
        b       cls_epilogue
 
-cls_retint:
-       bne     v0, FFI_TYPE_INT, cls_retfloat
-       REG_L   v0, V0_OFF2($sp)
+cls_retsint16:
+       bne     v0, FFI_TYPE_SINT16, cls_retuint16
+       lh      v0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retuint16:
+       bne     v0, FFI_TYPE_UINT16, cls_retsint8
+       lhu     v0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retsint8:
+       bne     v0, FFI_TYPE_SINT8, cls_retuint8
+       lb      v0, V0_OFF2($sp)
+       b       cls_epilogue
+
+cls_retuint8:
+       bne     v0, FFI_TYPE_UINT8, cls_retfloat
+       lbu     v0, V0_OFF2($sp)
        b       cls_epilogue
 
 cls_retfloat:
@@ -544,17 +673,29 @@ cls_retstruct_f:
        b       cls_epilogue
        
 cls_retstruct_d_d:     
-       bne     v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f
+       bne     v0, FFI_TYPE_STRUCT_DD, cls_retcomplex_d_d
+       l.d     $f0, V0_OFF2($sp)
+       l.d     $f2, V1_OFF2($sp)
+       b       cls_epilogue
+
+cls_retcomplex_d_d:
+       bne     v0, FFI_TYPE_COMPLEX_DD, cls_retcomplex_f_f
        l.d     $f0, V0_OFF2($sp)
        l.d     $f2, V1_OFF2($sp)
        b       cls_epilogue
        
-cls_retstruct_f_f:     
-       bne     v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f
+cls_retstruct_f_f:
+       bne     v0, FFI_TYPE_STRUCT_FF, cls_retcomplex_f_f
        l.s     $f0, V0_OFF2($sp)
        l.s     $f2, V1_OFF2($sp)
        b       cls_epilogue
        
+cls_retcomplex_f_f:
+       bne     v0, FFI_TYPE_COMPLEX_FF, cls_retstruct_d_f
+       l.s     $f0, V0_OFF2($sp)
+       l.s     $f2, (V0_OFF2+4)($sp)
+       b       cls_epilogue
+
 cls_retstruct_d_f:     
        bne     v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d
        l.d     $f0, V0_OFF2($sp)
@@ -562,12 +703,31 @@ cls_retstruct_d_f:
        b       cls_epilogue
        
 cls_retstruct_f_d:     
-       bne     v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
+       bne     v0, FFI_TYPE_STRUCT_FD, cls_retcomplex_ld_ld
        l.s     $f0, V0_OFF2($sp)
        l.d     $f2, V1_OFF2($sp)
        b       cls_epilogue
+#else
+cls_longdouble_soft:
+       bne     v0, FFI_TYPE_LONGDOUBLE, cls_retcomplex_ld_ld
+       REG_L   v0, V0_OFF2($sp)
+       REG_L   a0, V1_OFF2($sp) # not typo, it is a0, I have no idea, gcc does do it
+       b       cls_epilogue
 #endif
-       
+
+cls_retcomplex_ld_ld:
+       bne     v0, FFI_TYPE_COMPLEX_LDLD, cls_retstruct_small2
+       REG_L   t8, A0_OFF2($sp)
+       REG_L   t9, 16($sp)
+       REG_S   t9, 0(t8)
+       REG_L   t9, 24($sp)
+       REG_S   t9, 8(t8)
+       REG_L   t9, 32($sp)
+       REG_S   t9, 16(t8)
+       REG_L   t9, 40($sp)
+       REG_S   t9, 24(t8)
+       b       cls_epilogue
+
 cls_retstruct_small2:  
        REG_L   v0, V0_OFF2($sp)
        REG_L   v1, V1_OFF2($sp)
@@ -661,3 +821,7 @@ cls_epilogue:
 #endif /* __GNUC__ */  
        
 #endif
+
+#if defined __ELF__ && defined __linux__
+       .section .note.GNU-stack,"",%progbits
+#endif
index 799139b2968b10e43788590a49c86d5adb065673..03ceed5dc4524cd1ee0529f43d7e11ccf83ba55d 100644 (file)
@@ -133,6 +133,7 @@ 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:       
@@ -146,7 +147,8 @@ call_it:
        REG_L   t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
        beqz    t1, noretval
 
-       bne     t2, FFI_TYPE_INT, retlonglong
+       and     t1, t2, ((1<<4)-1)
+       bne     t1, FFI_TYPE_INT, retlonglong
        jalr    t9
        REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
        REG_S   v0, 0(t0)
@@ -154,7 +156,7 @@ call_it:
 
 retlonglong:
        # Really any 64-bit int, signed or not.
-       bne     t2, FFI_TYPE_UINT64, retfloat
+       bne     t1, FFI_TYPE_UINT64, retfloat
        jalr    t9
        REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
        REG_S   v1, 4(t0)
@@ -162,7 +164,7 @@ retlonglong:
        b       epilogue
 
 retfloat:
-       bne     t2, FFI_TYPE_FLOAT, retdouble
+       bne     t1, FFI_TYPE_FLOAT, retdouble
        jalr    t9
        REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
 #ifndef __mips_soft_float
@@ -173,7 +175,7 @@ retfloat:
        b       epilogue
 
 retdouble:     
-       bne     t2, FFI_TYPE_DOUBLE, noretval
+       bne     t1, FFI_TYPE_DOUBLE, retcomplex
        jalr    t9
        REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
 #ifndef __mips_soft_float
@@ -184,6 +186,48 @@ retdouble:
 #endif
        b       epilogue
        
+retcomplex:
+       # mask out the complex elements type.
+       # the struct of flags (bits):
+       # 0-1: arg0
+       # 2-3: arg1
+       # 4-7: return type
+       # 8-11: rtype elements type: for complex
+       # Note here: t2 is flags>>4
+       bne     t1, FFI_TYPE_COMPLEX, noretval
+       jalr    t9
+       REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+       REG_L   t1, A3_OFF($fp)         # load the flags word
+       SRL     t1, t1, 8
+       li      t3, 3
+       beq     t1, t3, 3f # double
+       li      t3, 2
+       beq     t1, t3, 2f # float
+       # FIXME: long double
+       slti    t3, t1, 5
+       beqz    t3, 5f     # (u)int8/16/32/64
+2:
+#ifndef __mips_soft_float
+       s.s     $f0, 0(t0)
+       s.s     $f2, 4(t0)
+#else
+       # FIXME: do nothing can pass all of the testsuite
+#endif
+       b       epilogue
+3:
+#ifndef __mips_soft_float
+       s.d     $f0, 0(t0)
+       s.d     $f2, 8(t0)
+#else
+       # FIXME: do nothing can pass all of the testsuite
+#endif
+       b       epilogue
+
+5:
+       REG_S   v1, 4(t0)
+       REG_S   v0, 0(t0)
+       b       epilogue
+
 noretval:      
        jalr    t9
        
@@ -378,6 +422,19 @@ $do_closure:
        li      $9, FFI_TYPE_DOUBLE
        l.d     $f0, V0_OFF2($fp)
        beq     $8, $9, closure_done
+
+       li      $9, FFI_TYPE_COMPLEX
+       bne     $8, $9, 1f
+
+       li      $9, 8
+       l.s     $f0, V0_OFF2($fp)
+       l.s     $f2, V1_OFF2($fp)
+       beq     $3, $9, closure_done
+
+       li      $9, 16
+       l.d     $f0, V0_OFF2($fp)
+       l.d     $f2, (V0_OFF2+8)($fp)
+       beq     $3, $9, closure_done
 #endif
 1:     
        REG_L   $3, V1_OFF2($fp)
@@ -502,3 +559,7 @@ $LASFDE2:
 $LEFDE2:
 
 #endif
+
+#if defined __ELF__ && defined __linux__
+       .section .note.GNU-stack,"",%progbits
+#endif
index 16d2bb37c8eaa19bec89b15cbbcc8ca061050f51..99bcf4077ce8905c957b29bf5df7658e9968ba11 100644 (file)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (C) 2012, 2013, 2018  Anthony Green
-   
-   Moxie Foreign Function Interface 
+   ffi.c - Copyright (C) 2012, 2013, 2018, 2021, 2022  Anthony Green
+
+   Moxie Foreign Function Interface
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -54,14 +54,14 @@ void *ffi_prep_args(char *stack, extended_cif *ecif)
        i--, p_arg++)
     {
       size_t z;
-      
+
       z = (*p_arg)->size;
 
       if ((*p_arg)->type == FFI_TYPE_STRUCT)
        {
          z = sizeof(void*);
          *(void **) argp = *p_argv;
-       } 
+       }
       else if (z < sizeof(int))
        {
          z = sizeof(int);
@@ -70,19 +70,19 @@ void *ffi_prep_args(char *stack, extended_cif *ecif)
            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;
-                 
+
            default:
              FFI_ASSERT(0);
            }
@@ -116,26 +116,28 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
   return FFI_OK;
 }
 
-extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
-                         extended_cif *, 
-                         unsigned, unsigned, 
-                         unsigned *, 
+extern void ffi_call_EABI(void *(*)(char *, extended_cif *),
+                         extended_cif *,
+                         unsigned, unsigned,
+                         unsigned *,
                          void (*fn)(void));
 
-void ffi_call(ffi_cif *cif, 
-             void (*fn)(void), 
-             void *rvalue, 
+void ffi_call(ffi_cif *cif,
+             void (*fn)(void),
+             void *rvalue,
              void **avalue)
 {
   extended_cif ecif;
+  ffi_type **arg_types = cif->arg_types;
+  int i, nargs = cif->nargs;
 
   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) && 
+  if ((rvalue == NULL) &&
       (cif->rtype->type == FFI_TYPE_STRUCT))
     {
       ecif.rvalue = alloca(cif->rtype->size);
@@ -143,10 +145,24 @@ void ffi_call(ffi_cif *cif,
   else
     ecif.rvalue = rvalue;
 
-  switch (cif->abi) 
+  /* If we have any large structure arguments, make a copy so we are passing
+     by value.  */
+  for (i = 0; i < nargs; i++)
+    {
+      ffi_type *at = arg_types[i];
+      int size = at->size;
+      if (at->type == FFI_TYPE_STRUCT) /*  && size > 4) All struct args?? */
+        {
+          char *argcopy = alloca (size);
+          memcpy (argcopy, avalue[i], size);
+          avalue[i] = argcopy;
+        }
+    }
+
+  switch (cif->abi)
     {
     case FFI_EABI:
-      ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
+      ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes,
                    cif->flags, ecif.rvalue, fn);
       break;
     default:
@@ -172,7 +188,7 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
   void *struct_rvalue = (void *) arg1;
 
   /* 6 words reserved for register args + 3 words from jsr */
-  char *stack_args = frame_pointer + 9*4; 
+  char *stack_args = frame_pointer + 9*4;
 
   /* Lay the register arguments down in a continuous chunk of memory.  */
   unsigned register_args[6] =
@@ -211,7 +227,16 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
          avalue[i] = ptr;
          break;
        case FFI_TYPE_STRUCT:
-         avalue[i] = *(void**)ptr;
+          {
+            if (arg_types[i]->size > 4)
+              {
+                void *copy = alloca(arg_types[i]->size);
+                memcpy(copy, *(void**)ptr, arg_types[i]->size);
+                avalue[i] = copy;
+              }
+            else
+              avalue[i] = *(void**)ptr;
+          }
          break;
        default:
          /* This is an 8-byte value.  */
index 2bad938a29f75ccfc61f680ba0686c247254159a..7a6d28c2c12e39bc3f5ee034f6fd83b6d08ed9a8 100644 (file)
@@ -37,7 +37,7 @@ void* ffi_prep_args(char *stack, extended_cif *ecif)
   ffi_type **arg;
   int count = 0;
   int nfixedargs;
-  
+
   nfixedargs = ecif->cif->nfixedargs;
   arg = ecif->cif->arg_types;
   void **argv = ecif->avalue;
@@ -47,7 +47,7 @@ void* ffi_prep_args(char *stack, extended_cif *ecif)
       *(void **) stack = ecif->rvalue;
       stack += 4;
       count = 4;
-    } 
+    }
   for(i=0; i<ecif->cif->nargs; i++)
   {
 
@@ -55,12 +55,12 @@ void* ffi_prep_args(char *stack, extended_cif *ecif)
     if ((nfixedargs == 0) && (count < 24))
       {
         count = 24;
-        stack = stacktemp + 24;        
+        stack = stacktemp + 24;
       }
     nfixedargs--;
 
     s = 4;
-    switch((*arg)->type) 
+    switch((*arg)->type)
       {
       case FFI_TYPE_STRUCT:
         *(void **)stack = *argv;
@@ -94,7 +94,7 @@ void* ffi_prep_args(char *stack, extended_cif *ecif)
           {
             stack += 4;
             count += 4;
-          }  
+          }
         s = (*arg)->size;
         memcpy(stack, *argv, s);
         break;
@@ -110,7 +110,7 @@ void* ffi_prep_args(char *stack, extended_cif *ecif)
 
 extern void ffi_call_SYSV(unsigned,
                           extended_cif *,
-                          void *(*)(int *, extended_cif *),
+                          void *(*)(char *, extended_cif *),
                           unsigned *,
                           void (*fn)(void),
                           unsigned);
@@ -133,6 +133,19 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
         size += 4;
       else
         size += 8;
+
+      /* If we have any large structure arguments, make a copy so we are passing
+         by value.  */
+      {
+        ffi_type *at = cif->arg_types[i];
+        int size = at->size;
+        if (at->type == FFI_TYPE_STRUCT) /* && size > 4) All struct args? */
+          {
+            char *argcopy = alloca (size);
+            memcpy (argcopy, avalue[i], size);
+            avalue[i] = argcopy;
+          }
+      }
     }
 
   /* for variadic functions more space is needed on the stack */
@@ -148,7 +161,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   ecif.avalue = avalue;
   ecif.rvalue = rvalue;
 
-  switch (cif->abi) 
+  switch (cif->abi)
   {
     case FFI_SYSV:
       ffi_call_SYSV(size, &ecif, ffi_prep_args, rvalue, fn, cif->flags);
@@ -160,14 +173,14 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
 }
 
 
-void ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5, 
+void ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5,
                       unsigned long r6, unsigned long r7, unsigned long r8)
 {
   register int *sp __asm__ ("r17");
   register int *r13 __asm__ ("r13");
 
   ffi_closure* closure = (ffi_closure*) r13;
-  char *stack_args = sp;
+  char *stack_args = (char*) sp;
 
   /* Lay the register arguments down in a continuous chunk of memory.  */
   unsigned register_args[6] =
@@ -186,7 +199,7 @@ void ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5,
 
   /* preserve struct type return pointer passing */
 
-  if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) 
+  if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
   {
     ptr += 4;
     count = 4;
@@ -256,7 +269,7 @@ void ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5,
       long long rvalue;
       (closure->fun) (cif, &rvalue, avalue, closure->user_data);
       if (cif->rtype)
-        asm ("l.ori r12, %0, 0x0\n l.lwz r11, 0(r12)\n l.lwz r12, 4(r12)" : : "r" (&rvalue));      
+        asm ("l.ori r12, %0, 0x0\n l.lwz r11, 0(r12)\n l.lwz r12, 4(r12)" : : "r" (&rvalue));
     }
 }
 
@@ -303,11 +316,11 @@ ffi_prep_closure_loc (ffi_closure* closure,
 ffi_status ffi_prep_cif_machdep (ffi_cif *cif)
 {
   cif->flags = 0;
-       
+
   /* structures are returned as pointers */
   if (cif->rtype->type == FFI_TYPE_STRUCT)
     cif->flags = FFI_TYPE_STRUCT;
-  else 
+  else
   if (cif->rtype->size > 4)
     cif->flags = FFI_TYPE_UINT64;
 
@@ -325,4 +338,4 @@ ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
   status = ffi_prep_cif_machdep (cif);
   cif->nfixedargs = nfixedargs;
   return status;
-} 
+}
index 95e669473e1ecda58a1d5f50e05b7b132b414b5c..f6012397e767354c7ffb013a3179fd661cf3f95a 100644 (file)
@@ -56,27 +56,12 @@ static inline int ffi_struct_type(ffi_type *t)
   size_t sz = t->size;
 
   /* Small structure results are passed in registers,
-     larger ones are passed by pointer.  Note that
-     small structures of size 2, 4 and 8 differ from
-     the corresponding integer types in that they have
-     different alignment requirements.  */
-
-  if (sz <= 1)
-    return FFI_TYPE_UINT8;
-  else if (sz == 2)
-    return FFI_TYPE_SMALL_STRUCT2;
-  else if (sz == 3)
-    return FFI_TYPE_SMALL_STRUCT3;
-  else if (sz == 4)
-    return FFI_TYPE_SMALL_STRUCT4;
-  else if (sz == 5)
-    return FFI_TYPE_SMALL_STRUCT5;
-  else if (sz == 6)
-    return FFI_TYPE_SMALL_STRUCT6;
-  else if (sz == 7)
-    return FFI_TYPE_SMALL_STRUCT7;
-  else if (sz <= 8)
-    return FFI_TYPE_SMALL_STRUCT8;
+     larger ones are passed by pointer.  Note that small
+     structures differ from the corresponding integer
+     types in that they have different alignment requirements.  */
+
+  if (sz <= 8)
+    return -sz;
   else
     return FFI_TYPE_STRUCT; /* else, we pass it by pointer.  */
 }
@@ -376,10 +361,26 @@ extern void ffi_call_pa32(void (*)(UINT32 *, extended_cif *, unsigned),
 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
 {
   extended_cif ecif;
+  size_t i, nargs = cif->nargs;
+  ffi_type **arg_types = cif->arg_types;
 
   ecif.cif = cif;
   ecif.avalue = avalue;
 
+  /* If we have any large structure arguments, make a copy so we are passing
+     by value.  */
+  for (i = 0; i < nargs; i++)
+    {
+      ffi_type *at = arg_types[i];
+      int size = at->size;
+      if (at->type == FFI_TYPE_STRUCT && size > 8)
+       {
+         char *argcopy = alloca (size);
+         memcpy (argcopy, avalue[i], size);
+         avalue[i] = argcopy;
+       }
+    }
+
   /* If the return value is a struct and we don't have a return
      value address then we need to make one.  */
 
@@ -429,7 +430,6 @@ ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
   int i, avn;
   unsigned int slot = FIRST_ARG_SLOT;
   register UINT32 r28 asm("r28");
-  ffi_closure *c = (ffi_closure *)FFI_RESTORE_PTR (closure);
 
   cif = closure->cif;
 
@@ -532,7 +532,7 @@ ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
     }
 
   /* Invoke the closure.  */
-  (c->fun) (cif, rvalue, avalue, c->user_data);
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
 
   debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", u.ret[0],
        u.ret[1]);
@@ -541,16 +541,16 @@ ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
   switch (cif->flags)
     {
     case FFI_TYPE_UINT8:
-      *(stack - FIRST_ARG_SLOT) = (UINT8)(u.ret[0] >> 24);
+      *(stack - FIRST_ARG_SLOT) = (UINT8)u.ret[0];
       break;
     case FFI_TYPE_SINT8:
-      *(stack - FIRST_ARG_SLOT) = (SINT8)(u.ret[0] >> 24);
+      *(stack - FIRST_ARG_SLOT) = (SINT8)u.ret[0];
       break;
     case FFI_TYPE_UINT16:
-      *(stack - FIRST_ARG_SLOT) = (UINT16)(u.ret[0] >> 16);
+      *(stack - FIRST_ARG_SLOT) = (UINT16)u.ret[0];
       break;
     case FFI_TYPE_SINT16:
-      *(stack - FIRST_ARG_SLOT) = (SINT16)(u.ret[0] >> 16);
+      *(stack - FIRST_ARG_SLOT) = (SINT16)u.ret[0];
       break;
     case FFI_TYPE_INT:
     case FFI_TYPE_SINT32:
@@ -575,6 +575,7 @@ ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
       /* Don't need a return value, done by caller.  */
       break;
 
+    case FFI_TYPE_SMALL_STRUCT1:
     case FFI_TYPE_SMALL_STRUCT2:
     case FFI_TYPE_SMALL_STRUCT3:
     case FFI_TYPE_SMALL_STRUCT4:
@@ -633,8 +634,6 @@ ffi_prep_closure_loc (ffi_closure* closure,
                      void *user_data,
                      void *codeloc)
 {
-  ffi_closure *c = (ffi_closure *)FFI_RESTORE_PTR (closure);
-
   /* The layout of a function descriptor.  A function pointer with the PLABEL
      bit set points to a function descriptor.  */
   struct pa32_fd
@@ -660,14 +659,14 @@ ffi_prep_closure_loc (ffi_closure* closure,
   fd = (struct pa32_fd *)((UINT32)ffi_closure_pa32 & ~3);
 
   /* Setup trampoline.  */
-  tramp = (struct ffi_pa32_trampoline_struct *)c->tramp;
+  tramp = (struct ffi_pa32_trampoline_struct *)closure->tramp;
   tramp->code_pointer = fd->code_pointer;
   tramp->fake_gp = (UINT32)codeloc & ~3;
   tramp->real_gp = fd->gp;
 
-  c->cif  = cif;
-  c->user_data = user_data;
-  c->fun  = fun;
+  closure->cif  = cif;
+  closure->user_data = user_data;
+  closure->fun  = fun;
 
   return FFI_OK;
 }
diff --git a/libffi/src/pa/ffi64.c b/libffi/src/pa/ffi64.c
new file mode 100644 (file)
index 0000000..08807c8
--- /dev/null
@@ -0,0 +1,614 @@
+/* -----------------------------------------------------------------------
+   ffi64.c - (c) 2022 John David Anglin <dave.anglin@bell.net>
+           
+   HPPA Foreign Function Interface
+   PA 64-Bit ABI support 
+
+   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 <stdio.h>
+
+#define ROUND_UP(v, a)  (((size_t)(v) + (a) - 1) & ~((a) - 1))
+
+#define FIRST_ARG_SLOT  0
+#define DEBUG_LEVEL   0
+
+#define fldw(addr, fpreg) \
+  __asm__ volatile ("fldw 4(%0), %%" #fpreg "R" : : "r"(addr) : #fpreg)
+#define fstw(fpreg, addr) \
+  __asm__ volatile ("fstw %%" #fpreg "R, 4(%0)" : : "r"(addr))
+#define fldd(addr, fpreg) \
+  __asm__ volatile ("fldd 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg)
+#define fstd(fpreg, addr) \
+  __asm__ volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr))
+
+#define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0)
+
+static inline int ffi_struct_type(ffi_type *t)
+{
+  int sz = t->size;
+
+  /* Small structure results are returned in registers 28 and 29,
+     larger ones are in a buffer allocated by the callee.  The
+     address of the buffer is passed in r28.  The buffer is supposed
+     to be aligned on a 16-byte boundary.   Register return values are
+     padded on the right.  The pad bits on the right are undefined.  */
+
+  if (sz <= 16)
+    return -sz;
+  else
+    return FFI_TYPE_STRUCT;
+}
+
+/* PA has a downward growing stack, which looks like this.  Stack
+   arguments are offset from the argument ponter (AP) in r29.
+
+   Offset
+       [ Fixed args ]
+   AP-64                arg word 0 (r26, fr4)
+   AP-56                arg word 1 (r25, fr5)
+   AP-48                arg word 2 (r24, fr6)
+   AP-40                arg word 3 (r23, fr7)
+   AP-32                arg word 4 (r22, fr8)
+   AP-24                arg word 5 (r21, fr9)
+   AP-16                arg word 6 (r20, fr10)
+   AP-8                        arg word 7 (r19, fr11)
+       [ Variable args; AP = SP-16 if there are no variable args ]
+   AP                  stack arg 0
+   AP+8                        stack arg 1
+   ...
+       [ Frame marker ]
+   SP-16                RP
+   SP-8                 previous SP
+
+   The first eight argument words on the stack are reserved for use by
+   the callee.  Instead, the general and floating registers replace
+   the first four argument slots.  Non FP arguments are passed solely
+   in the general registers.  Single and double FP arguments are passed
+   in both general and floating registers when using libffi.
+
+   The registers are allocated in the same manner as stack slots.
+   This allows the callee to save its arguments on the stack if
+   necessary:
+
+   arg word 0 -> gr26 or fr4L or fr4R
+   arg word 1 -> gr25 or fr5L or fr5R
+   arg word 2 -> gr24 or fr6L or fr6R
+   arg word 3 -> gr23 or fr7L or fr7R
+   ...
+
+   Single Single-precision floating-point parameters, when passed in
+   floating-point registers, are passed in the right halves of the
+   floating point registers; the left halves are unused.
+
+   Quad-precision floating-point parameters within the first 64 bytes of
+   the parameter list are always passed in general registers.
+
+   The rest of the arguments are passed on the stack starting at AP.
+
+   This means we can have holes either in the register allocation,
+   or in the stack.  */
+
+/* ffi_prep_args is called by the assembly routine once stack space
+   has been allocated for the function's arguments
+
+   The following code will put everything into the stack frame
+   (which was allocated by the asm routine), and on return
+   the asm routine will load the arguments that should be
+   passed by register into the appropriate registers
+
+   NOTE: We load floating point args in this function... that means we
+   assume gcc will not mess with fp regs in here.  */
+
+void ffi_prep_args_pa64(UINT64 *stack, extended_cif *ecif, unsigned bytes)
+{
+  register unsigned int i;
+  register ffi_type **p_arg;
+  register void **p_argv;
+  unsigned int slot = FIRST_ARG_SLOT;
+  size_t len;
+
+  debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack,
+       ecif, bytes);
+
+  p_arg = ecif->cif->arg_types;
+  p_argv = ecif->avalue;
+
+  for (i = 0; i < ecif->cif->nargs; i++)
+    {
+      int type = (*p_arg)->type;
+
+      len = (*p_arg)->size;
+
+      switch (type)
+       {
+       case FFI_TYPE_SINT8:
+         *(SINT64 *)(stack + slot) = *(SINT8 *)(*p_argv);
+         break;
+
+       case FFI_TYPE_UINT8:
+         *(UINT64 *)(stack + slot) = *(UINT8 *)(*p_argv);
+         break;
+
+       case FFI_TYPE_SINT16:
+         *(SINT64 *)(stack + slot) = *(SINT16 *)(*p_argv);
+         break;
+
+       case FFI_TYPE_UINT16:
+         *(UINT64 *)(stack + slot) = *(UINT16 *)(*p_argv);
+         break;
+
+       case FFI_TYPE_SINT32:
+         *(SINT64 *)(stack + slot) = *(SINT32 *)(*p_argv);
+         break;
+
+       case FFI_TYPE_UINT32:
+         *(UINT64 *)(stack + slot) = *(UINT32 *)(*p_argv);
+         break;
+
+       case FFI_TYPE_UINT64:
+       case FFI_TYPE_SINT64:
+       case FFI_TYPE_POINTER:
+         debug(3, "Storing UINT64 %lu in slot %u\n", *(UINT64 *)(*p_argv),
+               slot);
+         *(UINT64 *)(stack + slot) = *(UINT64 *)(*p_argv);
+         break;
+
+       case FFI_TYPE_FLOAT:
+         /* First 8 args go in fr4L - fr11L.  */
+         debug(3, "Storing UINT32(float) in slot %u\n", slot);
+         *(UINT64 *)(stack + slot) = *(UINT32 *)(*p_argv);
+         switch (slot - FIRST_ARG_SLOT)
+           {
+           /* First 4 args go in fr4L - fr7L.  */
+           case 0: fldw(stack + slot, fr4); break;
+           case 1: fldw(stack + slot, fr5); break;
+           case 2: fldw(stack + slot, fr6); break;
+           case 3: fldw(stack + slot, fr7); break;
+           case 4: fldw(stack + slot, fr8); break;
+           case 5: fldw(stack + slot, fr9); break;
+           case 6: fldw(stack + slot, fr10); break;
+           case 7: fldw(stack + slot, fr11); break;
+           }
+         break;
+
+       case FFI_TYPE_DOUBLE:
+         debug(3, "Storing UINT64(double) at slot %u\n", slot);
+         *(UINT64 *)(stack + slot) = *(UINT64 *)(*p_argv);
+         switch (slot - FIRST_ARG_SLOT)
+           {
+           /* First 8 args go in fr4 to fr11.  */
+           case 0: fldd(stack + slot, fr4); break;
+           case 1: fldd(stack + slot, fr5); break;
+           case 2: fldd(stack + slot, fr6); break;
+           case 3: fldd(stack + slot, fr7); break;
+           case 4: fldd(stack + slot, fr8); break;
+           case 5: fldd(stack + slot, fr9); break;
+           case 6: fldd(stack + slot, fr10); break;
+           case 7: fldd(stack + slot, fr11); break;
+           }
+         break;
+
+#ifdef PA64_HPUX
+       case FFI_TYPE_LONGDOUBLE:
+         /* Align slot to a 16-byte boundary.  */
+         slot += (slot & 1);
+         *(UINT64 *)(stack + slot) = *(UINT64 *)(*p_argv);
+         *(UINT64 *)(stack + slot + 1) = *(UINT64 *)(*p_argv + 8);
+         break;
+#endif
+
+       case FFI_TYPE_STRUCT:
+         /* Structs larger than 8 bytes are aligned on a 16-byte boundary. */
+         if (len > 8)
+           slot += (slot & 1);
+         memcpy((char *)(stack + slot), (char *)*p_argv, len);
+         break;
+
+       default:
+         FFI_ASSERT(0);
+       }
+
+      slot += ROUND_UP (len, 8) >> 3;
+      p_arg++;
+      p_argv++;
+    }
+
+  FFI_ASSERT(slot * 8 <= bytes);
+
+  return;
+}
+
+static void ffi_size_stack_pa64(ffi_cif *cif)
+{
+  ffi_type **ptr;
+  int i;
+  int z = 0; /* # stack slots */
+
+  for (ptr = cif->arg_types, i = 0; i < cif->nargs; ptr++, i++)
+    {
+      int type = (*ptr)->type;
+      int size = (*ptr)->size;
+
+      switch (type)
+       {
+#ifdef PA64_HPUX
+       case FFI_TYPE_LONGDOUBLE:
+         z += 2 + (z & 1);
+         break;
+#endif
+
+       case FFI_TYPE_STRUCT:
+         if (size > 8)
+           z += (z & 1);
+         z += ROUND_UP (size, 8) >> 3;
+         break;
+
+       default: /* 64-bit values */
+         z++;
+       }
+    }
+
+  /* We need a minimum of 8 argument slots.  Stack must be 16-byte
+     aligned.  */
+  if (z <= 8)
+    z = 8;
+  else
+    z += (z & 1);
+
+  /* Add 16 bytes for frame marker.  */
+  cif->bytes = z * 8 + 64;
+  debug(3, "Calculated stack size is %u bytes\n", cif->bytes);
+}
+
+/* Perform machine dependent cif processing.  */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+  /* Set the return type flag for jump table.  */
+  switch (cif->rtype->type)
+    {
+    case FFI_TYPE_COMPLEX:
+    case FFI_TYPE_STRUCT:
+      /* For the return type we have to check the size of the structures.
+        If the size is smaller or equal 8 bytes, the result is given back
+        in one register. If the size is smaller or equal 16 bytes than we
+        return the result in two registers. If the size is bigger than
+        16 bytes, the return is in a buffer allocated by the caller.  */
+      cif->flags = ffi_struct_type(cif->rtype);
+      break;
+
+    default:
+      cif->flags = (unsigned) cif->rtype->type;
+      break;
+    }
+
+  /* Lucky us, because of the unique PA ABI we get to do our
+     own stack sizing.  */
+  switch (cif->abi)
+    {
+    case FFI_PA64:
+      ffi_size_stack_pa64(cif);
+      break;
+
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+
+  return FFI_OK;
+}
+
+extern void ffi_call_pa64(void (*)(UINT64 *, extended_cif *, unsigned),
+                         extended_cif *, unsigned, unsigned, unsigned *,
+                         void (*fn)(void));
+
+void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+  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
+         || cif->rtype->type == FFI_TYPE_COMPLEX)
+      && cif->rtype->size > 16)
+    ecif.rvalue = alloca(ROUND_UP (cif->rtype->size, 16));
+  else
+    ecif.rvalue = rvalue;
+
+
+  switch (cif->abi)
+    {
+    case FFI_PA64:
+      debug(3, "Calling ffi_call_pa64: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn);
+      ffi_call_pa64(ffi_prep_args_pa64, &ecif, cif->bytes,
+                    cif->flags, ecif.rvalue, fn);
+      break;
+
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+}
+
+#if FFI_CLOSURES
+/* This is more-or-less an inverse of ffi_call -- we have arguments on
+   the stack, and we need to fill them into a cif structure and invoke
+   the user function. This really ought to be in asm to make sure
+   the compiler doesn't do things we don't expect.  */
+ffi_status ffi_closure_inner_pa64(ffi_closure *closure, UINT64 *stack)
+{
+  ffi_cif *cif;
+  void **avalue;
+  void *rvalue;
+  /* Functions can return up to 128-bits in registers.  Return address
+     must be double word aligned.  */
+  union { long double rld; UINT64 ret[2]; } u;
+  ffi_type **p_arg;
+  char *tmp;
+  int i, avn;
+  unsigned int slot = FIRST_ARG_SLOT;
+  register UINT64 r28 asm("r28");
+
+  cif = closure->cif;
+
+  /* If returning via structure, callee will write to our pointer.  */
+  if (cif->flags == FFI_TYPE_STRUCT)
+    rvalue = (void *)r28;
+  else
+    rvalue = &u;
+
+  avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG);
+  avn = cif->nargs;
+  p_arg = cif->arg_types;
+
+  for (i = 0; i < avn; i++)
+    {
+      int type = (*p_arg)->type;
+
+      switch (type)
+       {
+       case FFI_TYPE_SINT8:
+       case FFI_TYPE_UINT8:
+         avalue[i] = (void *)(stack + slot) + 7;
+         break;
+
+       case FFI_TYPE_SINT16:
+       case FFI_TYPE_UINT16:
+         avalue[i] = (void *)(stack + slot) + 6;
+         break;
+
+       case FFI_TYPE_SINT32:
+       case FFI_TYPE_UINT32:
+         avalue[i] = (void *)(stack + slot) + 4;
+         break;
+
+       case FFI_TYPE_POINTER:
+       case FFI_TYPE_SINT64:
+       case FFI_TYPE_UINT64:
+         avalue[i] = (void *)(stack + slot);
+         break;
+
+       case FFI_TYPE_FLOAT:
+         /* The closure call is indirect.  In Linux, floating point
+            arguments in indirect calls with a prototype are passed
+            in the floating point registers instead of the general
+            registers.  So, we need to replace what was previously
+            stored in the current slot with the value in the
+            corresponding floating point register.  */
+         switch (slot + FIRST_ARG_SLOT)
+           {
+           case 0: fstw(fr4, (void *)(stack + slot)); break;
+           case 1: fstw(fr5, (void *)(stack + slot)); break;
+           case 2: fstw(fr6, (void *)(stack + slot)); break;
+           case 3: fstw(fr7, (void *)(stack + slot)); break;
+           case 4: fstw(fr8, (void *)(stack + slot)); break;
+           case 5: fstw(fr9, (void *)(stack + slot)); break;
+           case 6: fstw(fr10, (void *)(stack + slot)); break;
+           case 7: fstw(fr11, (void *)(stack + slot)); break;
+           }
+         avalue[i] = (void *)(stack + slot) + 4;
+         break;
+
+       case FFI_TYPE_DOUBLE:
+         /* See previous comment for FFI_TYPE_FLOAT.  */
+         switch (slot + FIRST_ARG_SLOT)
+           {
+           case 0: fstd(fr4, (void *)(stack + slot)); break;
+           case 1: fstd(fr5, (void *)(stack + slot)); break;
+           case 2: fstd(fr6, (void *)(stack + slot)); break;
+           case 3: fstd(fr7, (void *)(stack + slot)); break;
+           case 4: fstd(fr8, (void *)(stack + slot)); break;
+           case 5: fstd(fr9, (void *)(stack + slot)); break;
+           case 6: fstd(fr10, (void *)(stack + slot)); break;
+           case 7: fstd(fr11, (void *)(stack + slot)); break;
+           }
+         avalue[i] = (void *)(stack + slot);
+         break;
+
+#ifdef PA64_HPUX
+       case FFI_TYPE_LONGDOUBLE:
+         /* Long doubles are treated like a big structure.  */
+         slot += (slot & 1);
+         avalue[i] = (void *)(stack + slot);
+         break;
+#endif
+
+       case FFI_TYPE_STRUCT:
+         /* All structs are passed in registers.  Structs larger
+            than 8 bytes are aligned on a 16-byte boundary.  */
+         if((*p_arg)->size > 8)
+           slot += (slot & 1);
+         avalue[i] = (void *) (stack + slot);
+         break;
+
+       default:
+         FFI_ASSERT(0);
+       }
+
+      slot += (ROUND_UP ((*p_arg)->size, 8) >> 3);
+      p_arg++;
+    }
+
+  /* Invoke the closure.  */
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+  debug(3, "after calling function, ret[0] = %16lx, ret[1] = %16lx\n", u.ret[0],
+       u.ret[1]);
+
+  /* Store the result using the lower 2 bytes of the flags.  */
+  switch (cif->flags)
+    {
+    case FFI_TYPE_UINT8:
+      *(stack + FIRST_ARG_SLOT) = (UINT8)u.ret[0];
+      break;
+    case FFI_TYPE_SINT8:
+      *(stack + FIRST_ARG_SLOT) = (SINT8)u.ret[0];
+      break;
+    case FFI_TYPE_UINT16:
+      *(stack + FIRST_ARG_SLOT) = (UINT16)u.ret[0];
+      break;
+    case FFI_TYPE_SINT16:
+      *(stack + FIRST_ARG_SLOT) = (SINT16)u.ret[0];
+      break;
+    case FFI_TYPE_INT:
+    case FFI_TYPE_SINT32:
+      *(stack + FIRST_ARG_SLOT) = (SINT32)u.ret[0];
+      break;
+    case FFI_TYPE_UINT32:
+      *(stack - FIRST_ARG_SLOT) = (UINT32)u.ret[0];
+      break;
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_UINT64:
+    case FFI_TYPE_POINTER:
+      *(stack - FIRST_ARG_SLOT) = u.ret[0];
+      break;
+
+    case FFI_TYPE_LONGDOUBLE:
+      *(stack + FIRST_ARG_SLOT) = u.ret[0];
+      *(stack + FIRST_ARG_SLOT + 1) = u.ret[1];
+      break;
+
+    case FFI_TYPE_DOUBLE:
+      fldd(rvalue, fr4);
+      break;
+
+    case FFI_TYPE_FLOAT:
+      /* Adjust for address adjustment in fldw macro.  */
+      fldw(rvalue - 4, fr4);
+      break;
+
+    case FFI_TYPE_STRUCT:
+      /* Don't need a return value, done by caller.  */
+      break;
+
+    case -1:
+    case -2:
+    case -3:
+    case -4:
+    case -5:
+    case -6:
+    case -7:
+    case -8:
+    case -9:
+    case -10:
+    case -11:
+    case -12:
+    case -13:
+    case -14:
+    case -15:
+    case -16:
+      tmp = (void*)(stack + FIRST_ARG_SLOT);
+      memcpy((void*)tmp, &u, cif->rtype->size);
+      break;
+
+    case FFI_TYPE_VOID:
+      break;
+
+    default:
+      debug(0, "assert with cif->flags: %d\n",cif->flags);
+      FFI_ASSERT(0);
+      break;
+    }
+  return FFI_OK;
+}
+
+/* Fill in a closure to refer to the specified fun and user_data.
+   cif specifies the argument and result types for fun.
+   The cif must already be prep'ed.  */
+
+extern void ffi_closure_pa64(void);
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+                     ffi_cif* cif,
+                     void (*fun)(ffi_cif*,void*,void**,void*),
+                     void *user_data,
+                     void *codeloc)
+{
+  /* The layout of a function descriptor.  */
+  struct pa64_fd
+  {
+    UINT64 tmp1;
+    UINT64 tmp2;
+    UINT64 code_pointer;
+    UINT64 gp;
+  };
+
+  struct ffi_pa64_trampoline_struct
+  {
+    UINT64 real_gp;             /* Real gp value.  */
+    UINT64 tmp2;
+    UINT64 code_pointer;        /* Pointer to ffi_closure_unix.  */
+    UINT64 fake_gp;             /* Pointer to closure, installed as gp.  */
+  };
+
+  struct ffi_pa64_trampoline_struct *tramp;
+  struct pa64_fd *fd;
+
+  if (cif->abi != FFI_PA64)
+    return FFI_BAD_ABI;
+
+  /* Get function descriptor address for ffi_closure_pa64.  */
+  fd = (struct pa64_fd *)((UINT64)ffi_closure_pa64);
+
+  /* Setup trampoline.  */
+  tramp = (struct ffi_pa64_trampoline_struct *)closure->tramp;
+  tramp->code_pointer = fd->code_pointer;
+  tramp->fake_gp = (UINT64)codeloc;
+  tramp->real_gp = fd->gp;
+
+  closure->cif  = cif;
+  closure->user_data = user_data;
+  closure->fun  = fun;
+
+  return FFI_OK;
+}
+#endif
index df1209eb16700e0284d114ed134bca2fa0afdecd..dae854a695bb30e6e87ebaee47e462f29c128e63 100644 (file)
@@ -54,7 +54,6 @@ typedef enum ffi_abi {
 #endif
 
 #ifdef PA64_HPUX
-#error "PA64_HPUX FFI is not yet implemented"
   FFI_PA64,
   FFI_LAST_ABI,
   FFI_DEFAULT_ABI = FFI_PA64
@@ -68,13 +67,28 @@ typedef enum ffi_abi {
 
 #define FFI_CLOSURES 1
 #define FFI_NATIVE_RAW_API 0
+#if defined(PA64_HPUX)
+#define FFI_TRAMPOLINE_SIZE 32
+#else
 #define FFI_TRAMPOLINE_SIZE 12
+#endif
+
+#define FFI_TYPE_SMALL_STRUCT1 -1
+#define FFI_TYPE_SMALL_STRUCT2 -2
+#define FFI_TYPE_SMALL_STRUCT3 -3
+#define FFI_TYPE_SMALL_STRUCT4 -4
+#define FFI_TYPE_SMALL_STRUCT5 -5
+#define FFI_TYPE_SMALL_STRUCT6 -6
+#define FFI_TYPE_SMALL_STRUCT7 -7
+#define FFI_TYPE_SMALL_STRUCT8 -8
+
+/* linux.S and hpux32.S expect FFI_TYPE_COMPLEX is the last generic type.  */
+#define FFI_PA_TYPE_LAST FFI_TYPE_COMPLEX
+
+/* If new generic types are added, the jump tables in linux.S and hpux32.S
+   likely need updating.  */
+#if FFI_TYPE_LAST != FFI_PA_TYPE_LAST
+# error "You likely have broken jump tables"
+#endif
 
-#define FFI_TYPE_SMALL_STRUCT2 -1
-#define FFI_TYPE_SMALL_STRUCT3 -2
-#define FFI_TYPE_SMALL_STRUCT4 -3
-#define FFI_TYPE_SMALL_STRUCT5 -4
-#define FFI_TYPE_SMALL_STRUCT6 -5
-#define FFI_TYPE_SMALL_STRUCT7 -6
-#define FFI_TYPE_SMALL_STRUCT8 -7
 #endif
index d0e5f695297bb837f3a360e5af27b0c4010da508..1629c0356b439d9ddc6ad8a9d874d9aa4b17aa1d 100644 (file)
@@ -109,52 +109,104 @@ L$CFI13
 
        /* Prepare to store the result; we need to recover flags and rvalue.  */
        ldw     -48(%r3), %r21          ; r21 <- flags
-       ldw     -52(%r3), %r20          ; r20 <- rvalue
 
-       /* Store the result according to the return type.  The most
-          likely types should come first.  */
+       /* Adjust flags range from [-8, 15] to  [0, 23].  */
+       addi    8, %r21, %r21
 
-L$checkint
-       comib,<>,n FFI_TYPE_INT, %r21, L$checkint8
-       b       L$done
-       stw     %ret0, 0(%r20)
+       blr     %r21, %r0
+       ldw     -52(%r3), %r20          ; r20 <- rvalue
 
-L$checkint8
-       comib,<>,n FFI_TYPE_UINT8, %r21, L$checkint16
+       /* Giant jump table */
+       /* 8-byte small struct */
+       b,n     L$smst8
+       nop
+       /* 7-byte small struct */
+       b,n     L$smst7
+       nop
+       /* 6-byte small struct */
+       b,n     L$smst6
+       nop
+       /* 5-byte small struct */
+       b,n     L$smst5
+       nop
+       /* 4-byte small struct */
+       b,n     L$smst4
+       nop
+       /* 3-byte small struct */
+       b,n     L$smst3
+       nop
+       /* 2-byte small struct */
+       b,n     L$smst2
+       nop
+       /* 1-byte small struct */
        b       L$done
        stb     %ret0, 0(%r20)
-
-L$checkint16
-       comib,<>,n FFI_TYPE_UINT16, %r21, L$checkdbl
+       /* void */
+       b,n     L$done
+       nop
+       /* int */
        b       L$done
-       sth     %ret0, 0(%r20)
-
-L$checkdbl
-       comib,<>,n FFI_TYPE_DOUBLE, %r21, L$checkfloat
+       stw     %ret0, 0(%r20)
+       /* float */
+       b       L$done
+       fstw    %fr4L,0(%r20)
+       /* double */
        b       L$done
        fstd    %fr4,0(%r20)
-
-L$checkfloat
-       comib,<>,n FFI_TYPE_FLOAT, %r21, L$checkll
+       /* long double */
+       b,n     L$done
+       nop
+       /* unsigned int8 */
        b       L$done
-       fstw    %fr4L,0(%r20)
+       stw     %ret0, 0(%r20)
+       /* signed int8 */
+       b       L$done
+       stw     %ret0, 0(%r20)
+       /* unsigned int16 */
+       b       L$done
+       stw     %ret0, 0(%r20)
+       /* signed int16 */
+       b       L$done
+       stw     %ret0, 0(%r20)
+       /* unsigned int32 */
+       b       L$done
+       stw     %ret0, 0(%r20)
+       /* signed int32 */
+       b       L$done
+       stw     %ret0, 0(%r20)
+       /* unsigned int64 */
+       b,n     L$uint64
+       nop
+       /* signed int64 */
+       b,n     L$sint64
+       nop
+       /* large struct */
+       b,n     L$done
+       nop
+       /* pointer */
+       b       L$done
+       stw     %ret0, 0(%r20)
+       /* complex */
+       b,n     L$done
+       nop
+
+       /* Store the result according to the return type.  The most
+          likely types should come first.  */
 
-L$checkll
-       comib,<>,n FFI_TYPE_UINT64, %r21, L$checksmst2
+L$uint64
+L$sint64
        stw     %ret0, 0(%r20)
        b       L$done
        stw     %ret1, 4(%r20)
 
-L$checksmst2
-       comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, L$checksmst3
+L$smst2
        /* 2-byte structs are returned in ret0 as ????xxyy.  */
        extru   %ret0, 23, 8, %r22
        stbs,ma %r22, 1(%r20)
        b       L$done
        stb     %ret0, 0(%r20)
 
-L$checksmst3
-       comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, L$checksmst4
+L$smst3
        /* 3-byte structs are returned in ret0 as ??xxyyzz.  */
        extru   %ret0, 15, 8, %r22
        stbs,ma %r22, 1(%r20)
@@ -163,8 +215,7 @@ L$checksmst3
        b       L$done
        stb     %ret0, 0(%r20)
 
-L$checksmst4
-       comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, L$checksmst5
+L$smst4
        /* 4-byte structs are returned in ret0 as wwxxyyzz.  */
        extru   %ret0, 7, 8, %r22
        stbs,ma %r22, 1(%r20)
@@ -175,8 +226,7 @@ L$checksmst4
        b       L$done
        stb     %ret0, 0(%r20)
 
-L$checksmst5
-       comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, L$checksmst6
+L$smst5
        /* 5 byte values are returned right justified:
              ret0     ret1
           5: ??????aa bbccddee */
@@ -190,8 +240,7 @@ L$checksmst5
        b       L$done
        stb     %ret1, 0(%r20)
 
-L$checksmst6
-       comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, L$checksmst7
+L$smst6
        /* 6 byte values are returned right justified:
              ret0     ret1
           6: ????aabb ccddeeff */
@@ -207,8 +256,7 @@ L$checksmst6
        b       L$done
        stb     %ret1, 0(%r20)
 
-L$checksmst7
-       comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, L$checksmst8
+L$smst7
        /* 7 byte values are returned right justified:
              ret0     ret1
           7: ??aabbcc ddeeffgg */
@@ -226,8 +274,7 @@ L$checksmst7
        b       L$done
        stb     %ret1, 0(%r20)
 
-L$checksmst8
-       comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, L$done
+L$smst8
        /* 8 byte values are returned right justified:
              ret0     ret1
           8: aabbccdd eeffgghh */
diff --git a/libffi/src/pa/hpux64.S b/libffi/src/pa/hpux64.S
new file mode 100644 (file)
index 0000000..6a82b57
--- /dev/null
@@ -0,0 +1,681 @@
+/* -----------------------------------------------------------------------
+   hpux64.S - (c) 2005-2022 John David Anglin <dave.anglin@bell.net>
+
+   HPUX PA 64-Bit Foreign Function Interface
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+       .LEVEL 2.0w
+       .text
+       .align  4
+
+       /* void ffi_call_pa64(void (*)(char *, extended_cif *),
+                              extended_cif *ecif,
+                              unsigned bytes,
+                              unsigned flags,
+                              unsigned *rvalue,
+                              void (*fn)());
+        */
+
+       .export ffi_call_pa64,code
+       .import ffi_prep_args_pa64,code
+
+       .align  4
+
+L$FB1
+ffi_call_pa64
+       .proc
+       .callinfo       FRAME=48,CALLS,SAVE_RP,ENTRY_GR=4
+       .entry
+       std     %rp, -16(%sp)
+       copy    %r3, %r1
+L$CFI11
+       copy    %sp, %r3
+L$CFI12
+       std,ma  %r1, 48(%sp)
+
+       /* Setup the stack for calling prep_args...
+          We want the stack to look like this:
+
+          [ Previous stack                            ] <- %r3
+
+          [ 48-byte register save area                ]
+
+          [ Stack space for call arguments            ] <- %r4
+
+          [ 16-byte rame marker                       ]
+
+          [ 128-byte stack for calling prep_args      ] <- %sp
+        */
+
+       std     %r4, 8(%r3)             ; save r4
+L$CFI13
+       std     %r23, 16(%r3)           ; save flags we need it later
+       std     %r22, 24(%r3)           ; save rvalue
+       std     %r21, 32(%r3)           ; save fn pointer
+
+       copy    %sp, %r4
+       copy    %r4, %r26               ; argument stack pointer
+       addl    %r24, %sp, %sp          ; allocate argument space
+
+       ldo     112(%sp), %r29          ; arg pointer for prep args
+
+       /* Call prep_args:
+          %arg0(stack) -- set up above to point to call arguments
+          %arg1(ecif) -- same as incoming param
+          %arg2(bytes) -- same as incoming param */
+       bl      ffi_prep_args_pa64,%r2
+       ldo     128(%sp), %sp
+       ldo     -128(%sp), %sp
+
+       /* Load the arguments that should be passed in registers
+          The fp args were loaded by the prep_args function.  */
+       ldd     0(%r4), %r26
+       ldd     8(%r4), %r25
+       ldd     16(%r4), %r24
+       ldd     24(%r4), %r23
+       ldd     32(%r4), %r22
+       ldd     40(%r4), %r21
+       ldd     48(%r4), %r20
+       ldd     56(%r4), %r19
+
+       ldd     24(%r3), %ret0          ; %ret0 <- rvalue
+
+       ldd     32(%r3), %r1            ; %r1 <- function pointer
+       ldd     16(%r1), %rp            ; fn address
+       ldd     24(%r1), %dp            ; New gp
+       bve,l   (%rp), %r2              ; Call the user function
+       ldo     64(%r4), %r29           ; Argument pointer
+
+       /* Prepare to store the result; recover flags and rvalue.  */
+       ldd     16(%r3), %r21           ; r21 <- flags
+       extrd,s %r21, 63, 32, %r21      ; sign extend flags for blr
+
+       /* Adjust flags range from [-16, 15] to  [0, 31].  */
+       addi    16, %r21, %r21
+
+       blr     %r21, %r0
+       ldd     24(%r3), %r20           ; r20 <- rvalue
+
+       /* Giant jump table */
+       /* 16-byte small struct */
+       b,n     L$smst16
+       nop
+       /* 15-byte small struct */
+       b,n     L$smst15
+       nop
+       /* 14-byte small struct */
+       b,n     L$smst14
+       nop
+       /* 13-byte small struct */
+       b,n     L$smst13
+       nop
+       /* 12-byte small struct */
+       b,n     L$smst12
+       nop
+       /* 11-byte small struct */
+       b,n     L$smst11
+       nop
+       /* 10-byte small struct */
+       b,n     L$smst10
+       nop
+       /* 9-byte small struct */
+       b,n     L$smst9
+       nop
+       /* 8-byte small struct */
+       b,n     L$smst8
+       nop
+       /* 7-byte small struct */
+       b,n     L$smst7
+       nop
+       /* 6-byte small struct */
+       b,n     L$smst6
+       nop
+       /* 5-byte small struct */
+       b,n     L$smst5
+       nop
+       /* 4-byte small struct */
+       b,n     L$smst4
+       nop
+       /* 3-byte small struct */
+       b,n     L$smst3
+       nop
+       /* 2-byte small struct */
+       b,n     L$smst2
+       nop
+       /* 1-byte small struct */
+       b,n     L$smst1
+       nop
+       /* void */
+       b,n     L$done
+       nop
+       /* int */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* float */
+       b       L$done
+       fstw    %fr4R, 0(%r20)
+       /* double */
+       b       L$done
+       fstd    %fr4, 0(%r20)
+       /* long double */
+       b,n     L$longdouble
+       nop
+       /* unsigned int8 */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* signed int8 */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* unsigned int16 */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* signed int16 */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* unsigned int32 */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* signed int32 */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* unsigned int64 */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* signed int64 */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* large struct */
+       b,n     L$done
+       nop
+       /* pointer */
+       b       L$done
+       std     %ret0, 0(%r20)
+       /* complex */
+       b,n     L$done
+       nop
+
+L$longdouble
+       std     %ret0, 0(%r20)
+       b       L$done
+       std     %ret1, 8(%r20)
+
+       /* We need to copy byte-by-byte the exact number bytes
+          in the struct to avoid clobbering other data.  */
+L$smst1
+       extrd,u %ret0, 7, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst2
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst3
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst4
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst5
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst6
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst7
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst8
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       b       L$done
+       stb     %ret0, 0(%r20)
+
+L$smst9
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       stb,ma  %ret0, 1(%r20)
+       extrd,u %ret1, 7, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst10
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       stb,ma  %ret0, 1(%r20)
+       extrd,u %ret1, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 15, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst11
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       stb,ma  %ret0, 1(%r20)
+       extrd,u %ret1, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 23, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst12
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       stb,ma  %ret0, 1(%r20)
+       extrd,u %ret1, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 31, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst13
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       stb,ma  %ret0, 1(%r20)
+       extrd,u %ret1, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 39, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst14
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       stb,ma  %ret0, 1(%r20)
+       extrd,u %ret1, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 47, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst15
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       stb,ma  %ret0, 1(%r20)
+       extrd,u %ret1, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 55, 8, %r22
+       b       L$done
+       stb     %r22, 0(%r20)
+
+L$smst16
+       extrd,u %ret0, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret0, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       stb,ma  %ret0, 1(%r20)
+       extrd,u %ret1, 7, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 15, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 23, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 31, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 39, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 47, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       extrd,u %ret1, 55, 8, %r22
+       stb,ma  %r22, 1(%r20)
+       stb     %ret1, 0(%r20)
+
+L$done
+       /* all done, restore registers and return */
+       copy    %r4, %sp
+       ldd     8(%r3), %r4
+       ldd     -16(%r3), %rp
+       bve     (%rp)
+       ldd,mb  -48(%sp), %r3
+       .exit
+       .procend
+L$FE1
+       .size   ffi_call_pa64, .-ffi_call_pa64
+
+       /* void ffi_closure_pa64(void);
+          Called with closure argument in %r21 */
+
+       .export ffi_closure_pa64,code
+       .import ffi_closure_inner_pa64,code
+       .align 4
+L$FB2
+ffi_closure_pa64
+       .proc
+       .callinfo FRAME=128,CALLS,SAVE_RP,ENTRY_GR=3
+       .entry
+
+       std     %rp, -16(%sp)
+       copy    %r3, %r1
+L$CFI21
+       copy    %sp, %r3
+L$CFI22
+       std,ma  %r1, 128(%sp)
+L$CFI23
+
+       /* Put arguments onto the stack and call ffi_closure_inner.  */
+       std     %r26, -64(%r29)
+       std     %r25, -56(%r29)
+       std     %r24, -48(%r29)
+       std     %r23, -40(%r29)
+       std     %r22, -32(%r29)
+       std     %r21, -24(%r29)
+       std     %r20, -16(%r29)
+       std     %r19, -8(%r29)
+
+       /* Load and save start of argument stack.  */
+       ldo     -64(%r29), %r25
+       std     %r25, 8(%r3)
+
+       /* Setup arg pointer.  */
+       ldo     -16(%sp), %ret1
+
+       /* Retrieve closure pointer and real gp.  */
+       copy    %dp, %r26
+       bl      ffi_closure_inner_pa64, %r2
+       ldd     0(%dp), %dp
+
+       /* Retrieve start of argument stack.  */
+       ldd     8(%r3), %r1
+
+       /* Restore r3 and op stack.  */
+       ldd,mb  -128(%sp), %r3
+
+       /* Load return address.  */
+       ldd     -16(%sp), %rp
+
+       /* Load return values from first and second stack slots.  */
+       ldd     0(%r1), %ret0
+       bve     (%rp)
+       ldd     8(%r1), %ret1
+
+       .exit
+       .procend
+       .end
+L$FE2:
+       .size   ffi_closure_pa64, .-ffi_closure_pa64
+
+       .section        .eh_frame,"aw",@progbits
+L$frame1:
+       .word   L$ECIE1-L$SCIE1 ;# Length of Common Information Entry
+L$SCIE1:
+       .word   0x0     ;# CIE Identifier Tag
+       .byte   0x3     ;# CIE Version
+       .stringz ""     ;# CIE Augmentation
+       .uleb128 0x1    ;# CIE Code Alignment Factor
+       .sleb128 8      ;# CIE Data Alignment Factor
+       .byte   0x2     ;# CIE RA Column
+       .byte   0xc     ;# DW_CFA_def_cfa
+       .uleb128 0x1e
+       .uleb128 0x0
+       .align 8
+L$ECIE1:
+L$SFDE1:
+       .word   L$EFDE1-L$ASFDE1        ;# FDE Length
+L$ASFDE1:
+       .word   L$ASFDE1-L$frame1       ;# FDE CIE offset
+       .dword  L$FB1   ;# FDE initial location
+       .dword  L$FE1-L$FB1     ;# FDE address range
+
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI11-L$FB1
+       .byte   0x9     ;# DW_CFA_register: r3 in r1
+       .uleb128 0x3
+       .uleb128 0x1
+       .byte   0x11    ;# DW_CFA_offset_extended_sf: r2 at cfa-16
+       .uleb128 0x2
+       .sleb128 -2
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI12-L$CFI11
+       .byte   0xd     ;# DW_CFA_def_cfa_register: r3
+       .uleb128 0x3
+
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI13-L$CFI12
+       .byte   0x83    ;# DW_CFA_offset: r3 at cfa+0
+       .uleb128 0
+       .byte   0x84    ;# DW_CFA_offset: r4 at cfa+8
+       .uleb128 1
+
+       .align 8
+L$EFDE1:
+
+L$SFDE2:
+       .word   L$EFDE2-L$ASFDE2        ;# FDE Length
+L$ASFDE2:
+       .word   L$ASFDE2-L$frame1       ;# FDE CIE offset
+       .dword   L$FB2  ;# FDE initial location
+       .dword   L$FE2-L$FB2     ;# FDE address range
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI21-L$FB2
+       .byte   0x9     ;# DW_CFA_register: r3 in r1
+       .uleb128 0x3
+       .uleb128 0x1
+       .byte   0x11    ;# DW_CFA_offset_extended_sf: r2 at cfa-16
+       .uleb128 0x2
+       .sleb128 -2
+
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI22-L$CFI21
+       .byte   0xd     ;# DW_CFA_def_cfa_register: r3
+       .uleb128 0x3
+
+       .byte   0x4     ;# DW_CFA_advance_loc4
+       .word   L$CFI23-L$CFI22
+       .byte   0x83    ;# DW_CFA_offset: r3 at cfa+0
+       .uleb128 0
+
+       .align 8
+L$EFDE2:
index 33ef0b137a4118bcfce9bc1e4b1dc4335cb4f027..fdd43324769d5f9b20a3dc4b8b4d76ef2079492f 100644 (file)
@@ -103,51 +103,103 @@ ffi_call_pa32:
 
        /* Prepare to store the result; we need to recover flags and rvalue.  */
        ldw -48(%r3), %r21                      /* r21 <- flags */
-       ldw -52(%r3), %r20                      /* r20 <- rvalue */
 
-       /* Store the result according to the return type.  */
+       /* Adjust flags range from [-8, 15] to  [0, 23].  */
+       addi 8, %r21, %r21
 
-.Lcheckint:
-       comib,<>,n FFI_TYPE_INT, %r21, .Lcheckint8
-       b       .Ldone
-       stw     %ret0, 0(%r20)
+       blr %r21, %r0
+       ldw -52(%r3), %r20                      /* r20 <- rvalue */
 
-.Lcheckint8:
-       comib,<>,n FFI_TYPE_UINT8, %r21, .Lcheckint16
+       /* Giant jump table */
+       /* 8-byte small struct */
+       b,n     .Lsmst8
+       nop
+       /* 7-byte small struct */
+       b,n     .Lsmst7
+       nop
+       /* 6-byte small struct */
+       b,n     .Lsmst6
+       nop
+       /* 5-byte small struct */
+       b,n     .Lsmst5
+       nop
+       /* 4-byte small struct */
+       b,n     .Lsmst4
+       nop
+       /* 3-byte small struct */
+       b,n     .Lsmst3
+       nop
+       /* 2-byte small struct */
+       b,n     .Lsmst2
+       nop
+       /* 1-byte small struct */
        b       .Ldone
        stb     %ret0, 0(%r20)
-
-.Lcheckint16:
-       comib,<>,n FFI_TYPE_UINT16, %r21, .Lcheckdbl
+       /* void */
+       b,n     .Ldone
+       nop
+       /* int */
        b       .Ldone
-       sth     %ret0, 0(%r20)
-
-.Lcheckdbl:
-       comib,<>,n FFI_TYPE_DOUBLE, %r21, .Lcheckfloat
+       stw     %ret0, 0(%r20)
+       /* float */
+       b       .Ldone
+       fstw    %fr4L,0(%r20)
+       /* double */
        b       .Ldone
        fstd    %fr4,0(%r20)
-
-.Lcheckfloat:
-       comib,<>,n FFI_TYPE_FLOAT, %r21, .Lcheckll
+       /* long double */
        b       .Ldone
-       fstw    %fr4L,0(%r20)
+       fstd    %fr4,0(%r20)
+       /* unsigned int8 */
+       b       .Ldone
+       stw     %ret0, 0(%r20)
+       /* sint8 */
+       b       .Ldone
+       stw     %ret0, 0(%r20)
+       /* unsigned int16 */
+       b       .Ldone
+       stw     %ret0, 0(%r20)
+       /* sint16 */
+       b       .Ldone
+       stw     %ret0, 0(%r20)
+       /* unsigned int32 */
+       b       .Ldone
+       stw     %ret0, 0(%r20)
+       /* sint32 */
+       b       .Ldone
+       stw     %ret0, 0(%r20)
+       /* unsigned int64 */
+       b,n     .Luint64
+       nop
+       /* signed int64 */
+       b,n     .Lsint64
+       nop
+       /* large struct */
+       b,n     .Ldone
+       nop
+       /* pointer */
+       b       .Ldone
+       stw     %ret0, 0(%r20)
+       /* complex */
+       b,n     .Ldone
+       nop
+
+       /* Store the result according to the return type.  */
 
-.Lcheckll:
-       comib,<>,n FFI_TYPE_UINT64, %r21, .Lchecksmst2
+.Luint64:
+.Lsint64:
        stw     %ret0, 0(%r20)
        b       .Ldone
        stw     %ret1, 4(%r20)
 
-.Lchecksmst2:
-       comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, .Lchecksmst3
+.Lsmst2:
        /* 2-byte structs are returned in ret0 as ????xxyy.  */
        extru   %ret0, 23, 8, %r22
        stbs,ma %r22, 1(%r20)
        b       .Ldone
        stb     %ret0, 0(%r20)
 
-.Lchecksmst3:
-       comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, .Lchecksmst4
+.Lsmst3:
        /* 3-byte structs are returned in ret0 as ??xxyyzz.  */
        extru   %ret0, 15, 8, %r22
        stbs,ma %r22, 1(%r20)
@@ -156,8 +208,7 @@ ffi_call_pa32:
        b       .Ldone
        stb     %ret0, 0(%r20)
 
-.Lchecksmst4:
-       comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, .Lchecksmst5
+.Lsmst4:
        /* 4-byte structs are returned in ret0 as wwxxyyzz.  */
        extru   %ret0, 7, 8, %r22
        stbs,ma %r22, 1(%r20)
@@ -168,8 +219,7 @@ ffi_call_pa32:
        b       .Ldone
        stb     %ret0, 0(%r20)
 
-.Lchecksmst5:
-       comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, .Lchecksmst6
+.Lsmst5:
        /* 5 byte values are returned right justified:
              ret0     ret1
           5: ??????aa bbccddee */
@@ -183,8 +233,7 @@ ffi_call_pa32:
        b       .Ldone
        stb     %ret1, 0(%r20)
 
-.Lchecksmst6:
-       comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, .Lchecksmst7
+.Lsmst6:
        /* 6 byte values are returned right justified:
              ret0     ret1
           6: ????aabb ccddeeff */
@@ -200,8 +249,7 @@ ffi_call_pa32:
        b       .Ldone
        stb     %ret1, 0(%r20)
 
-.Lchecksmst7:
-       comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, .Lchecksmst8
+.Lsmst7:
        /* 7 byte values are returned right justified:
              ret0     ret1
           7: ??aabbcc ddeeffgg */
@@ -219,8 +267,7 @@ ffi_call_pa32:
        b       .Ldone
        stb     %ret1, 0(%r20)
 
-.Lchecksmst8:
-       comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, .Ldone
+.Lsmst8:
        /* 8 byte values are returned right justified:
              ret0     ret1
           8: aabbccdd eeffgghh */
@@ -378,3 +425,7 @@ ffi_closure_pa32:
 
        .align 4
 .LEFDE2:
+
+#if defined(__ELF__) && defined(__linux__)
+.section .note.GNU-stack,"",%progbits
+#endif
index a19bcbbfc52ffd1fda52820e8664745cba00e769..3601cc4ab1e2aa8b15771ebb7c403ee05674eb18 100644 (file)
@@ -31,6 +31,8 @@
 #include "ffi.h"
 #include "ffi_common.h"
 #include "ffi_powerpc.h"
+#include "internal.h"
+#include <tramp.h>
 
 #if HAVE_LONG_DOUBLE_VARIANT
 /* Adjust ffi_type_longdouble.  */
@@ -173,3 +175,20 @@ ffi_prep_go_closure (ffi_go_closure *closure,
   closure->fun = fun;
   return FFI_OK;
 }
+
+#ifdef FFI_EXEC_STATIC_TRAMP
+void *
+ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
+{
+  extern void *trampoline_code_table;
+  *tramp_size = PPC_TRAMP_SIZE;
+  *map_size = PPC_TRAMP_MAP_SIZE;
+#if defined (_CALL_AIX) || _CALL_ELF == 1
+  /* The caller wants the entry point address of the trampoline code,
+     not the address of the function descriptor.  */
+  return *(void **)trampoline_code_table;
+#else
+  return &trampoline_code_table;
+#endif
+}
+#endif
index 64bb94dfae7e3d9a15aca95ce64282122bfcfa6a..afb6750a5bbfb5cb44208b42bbe5b0871bc79ee5 100644 (file)
@@ -623,38 +623,50 @@ darwin_adjust_aggregate_sizes (ffi_type *s)
 }
 
 /* Adjust the size of S to be correct for AIX.
-   Word-align double unless it is the first member of a structure.  */
+   Word-align double unless it is the first member of a structure recursively.
+   Return non-zero if we found a recursive first member aggregate of interest. */
 
-static void
-aix_adjust_aggregate_sizes (ffi_type *s)
+static int
+aix_adjust_aggregate_sizes (ffi_type *s, int outer_most_type_or_first_member)
 {
-  int i;
+  int i, nested_first_member=0, final_align, rc=0;
 
   if (s->type != FFI_TYPE_STRUCT)
-    return;
+    return 0;
 
   s->size = 0;
   for (i = 0; s->elements[i] != NULL; i++)
     {
-      ffi_type *p;
+      ffi_type p;
       int align;
-      
-      p = s->elements[i];
-      aix_adjust_aggregate_sizes (p);
-      align = p->alignment;
-      if (i != 0 && p->type == FFI_TYPE_DOUBLE)
-       align = 4;
-      s->size = FFI_ALIGN(s->size, align) + p->size;
+
+      /* nested aggregates layout differently on AIX, so take a copy of the type */
+      p = *(s->elements[i]);
+      if (i == 0)
+        nested_first_member = aix_adjust_aggregate_sizes(&p, outer_most_type_or_first_member);
+      else
+        aix_adjust_aggregate_sizes(&p, 0);
+      align = p.alignment;
+      if (i != 0 && p.type == FFI_TYPE_DOUBLE)
+        align = 4;
+      s->size = FFI_ALIGN(s->size, align) + p.size;
     }
-  
-  s->size = FFI_ALIGN(s->size, s->alignment);
-  
-  if (s->elements[0]->type == FFI_TYPE_UINT64
-      || s->elements[0]->type == FFI_TYPE_SINT64
-      || s->elements[0]->type == FFI_TYPE_DOUBLE
-      || s->elements[0]->alignment == 8)
-    s->alignment = s->alignment > 8 ? s->alignment : 8;
-  /* Do not add additional tail padding.  */
+
+  final_align=s->alignment;
+  if ((s->elements[0]->type == FFI_TYPE_UINT64
+          || s->elements[0]->type == FFI_TYPE_SINT64
+          || s->elements[0]->type == FFI_TYPE_DOUBLE
+          || s->elements[0]->alignment == 8 || nested_first_member)) {
+      final_align = s->alignment > 8 ? s->alignment : 8;
+      rc=1;
+      /* still use the adjusted alignment to calculate tail padding, but don't adjust the types alignment if
+         we aren't in the recursive first position */
+      if (outer_most_type_or_first_member)
+        s->alignment=final_align;
+  }
+
+  s->size = FFI_ALIGN(s->size, final_align);
+  return rc;
 }
 
 /* Perform machine dependent cif processing.  */
@@ -682,9 +694,9 @@ ffi_prep_cif_machdep (ffi_cif *cif)
 
   if (cif->abi == FFI_AIX)
     {
-      aix_adjust_aggregate_sizes (cif->rtype);
+      aix_adjust_aggregate_sizes (cif->rtype, 1);
       for (i = 0; i < cif->nargs; i++)
-       aix_adjust_aggregate_sizes (cif->arg_types[i]);
+       aix_adjust_aggregate_sizes (cif->arg_types[i], 1);
     }
 
   /* Space for the frame pointer, callee's LR, CR, etc, and for
index 3454dacd3d641654929152271535f68493bf55be..90100a4d8b8b5f6f43c81500cbdfe65283be00ac 100644 (file)
@@ -29,6 +29,7 @@
    ----------------------------------------------------------------------- */
 
 #include "ffi.h"
+#include <tramp.h>
 
 #ifdef POWERPC64
 #include "ffi_common.h"
@@ -820,32 +821,38 @@ ffi_prep_closure_loc_linux64 (ffi_closure *closure,
                              void *user_data,
                              void *codeloc)
 {
-#if _CALL_ELF == 2
-  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
-
   if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
     return FFI_BAD_ABI;
 
-  tramp[0] = 0xe96c0018;       /* 0:   ld      11,2f-0b(12)    */
-  tramp[1] = 0xe98c0010;       /*      ld      12,1f-0b(12)    */
-  tramp[2] = 0x7d8903a6;       /*      mtctr   12              */
-  tramp[3] = 0x4e800420;       /*      bctr                    */
+#ifdef FFI_EXEC_STATIC_TRAMP
+  if (ffi_tramp_is_present(closure))
+    {
+      /* Initialize the static trampoline's parameters. */
+      void (*dest)(void) = ffi_closure_LINUX64;
+      ffi_tramp_set_parms (closure->ftramp, dest, closure);
+    }
+  else
+#endif
+    {
+#if _CALL_ELF == 2
+      unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+      tramp[0] = 0xe96c0018;   /* 0:   ld      11,2f-0b(12)    */
+      tramp[1] = 0xe98c0010;   /*      ld      12,1f-0b(12)    */
+      tramp[2] = 0x7d8903a6;   /*      mtctr   12              */
+      tramp[3] = 0x4e800420;   /*      bctr                    */
                                /* 1:   .quad   function_addr   */
                                /* 2:   .quad   context         */
-  *(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
-  *(void **) &tramp[6] = codeloc;
-  flush_icache ((char *) tramp, (char *) codeloc, 4 * 4);
+      *(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
+      *(void **) &tramp[6] = codeloc;
+      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 OPD.  */
-  memcpy (&tramp[0], (void **) ffi_closure_LINUX64, sizeof (void *));
-  tramp[1] = codeloc;
-  memcpy (&tramp[2], (void **) ffi_closure_LINUX64 + 1, sizeof (void *));
+      /* Copy function address and TOC from ffi_closure_LINUX64 OPD.  */
+      void **tramp = (void **) &closure->tramp[0];
+      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;
   closure->fun = fun;
index 4078e7511629dd25eb18c74a800ba82db3c43340..5d7c5c82365899336c41345b06fffd6cedcfe0d9 100644 (file)
@@ -29,6 +29,7 @@
    ----------------------------------------------------------------------- */
 
 #include "ffi.h"
+#include <tramp.h>
 
 #ifndef POWERPC64
 #include "ffi_common.h"
@@ -636,25 +637,34 @@ ffi_prep_closure_loc_sysv (ffi_closure *closure,
                           void *user_data,
                           void *codeloc)
 {
-  unsigned int *tramp;
-
   if (cif->abi < FFI_SYSV || cif->abi >= FFI_LAST_ABI)
     return FFI_BAD_ABI;
 
-  tramp = (unsigned int *) &closure->tramp[0];
-  tramp[0] = 0x7c0802a6;  /*   mflr    r0 */
-  tramp[1] = 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, 8 * 4);
+#ifdef FFI_EXEC_STATIC_TRAMP
+  if (ffi_tramp_is_present(closure))
+    {
+      /* Initialize the static trampoline's parameters. */
+      void (*dest)(void) = ffi_closure_SYSV;
+      ffi_tramp_set_parms (closure->ftramp, dest, closure);
+    }
+  else
+#endif
+    {
+      unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+      tramp[0] = 0x7c0802a6;  /*   mflr    r0 */
+      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, 8 * 4);
+    }
 
   closure->cif = cif;
   closure->fun = fun;
diff --git a/libffi/src/powerpc/internal.h b/libffi/src/powerpc/internal.h
new file mode 100644 (file)
index 0000000..b3db5f0
--- /dev/null
@@ -0,0 +1,10 @@
+#ifdef FFI_EXEC_STATIC_TRAMP
+/* For the trampoline code table mapping, a mapping size of 64K is chosen.  */
+#define PPC_TRAMP_MAP_SHIFT    16
+#define PPC_TRAMP_MAP_SIZE     (1 << PPC_TRAMP_MAP_SHIFT)
+# ifdef __PCREL__
+#  define PPC_TRAMP_SIZE       24
+# else
+#  define PPC_TRAMP_SIZE       40
+# endif /* __PCREL__ */
+#endif /* FFI_EXEC_STATIC_TRAMP */
index 199981db3307c23fc1a57d37e4e5fa01a78351d7..d9e5cff64fd07fe21bde27aa05226127ef57a31f 100644 (file)
@@ -27,6 +27,7 @@
 #define LIBFFI_ASM
 #include <fficonfig.h>
 #include <ffi.h>
+#include "internal.h"
 
        .file   "linux64_closure.S"
 
@@ -559,7 +560,53 @@ ffi_go_closure_linux64:
        .size   .ffi_go_closure_linux64,.-.ffi_go_closure_linux64
 #  endif
 # endif
+
+#ifdef FFI_EXEC_STATIC_TRAMP
+       .text
+       .align PPC_TRAMP_MAP_SHIFT
+       FFI_HIDDEN (trampoline_code_table)
+       .globl  trampoline_code_table
+# if _CALL_ELF == 2
+       .type   trampoline_code_table,@function
+trampoline_code_table:
+       .localentry trampoline_code_table,.-trampoline_code_table
+# else
+       .section        ".opd","aw"
+       .align  3
+trampoline_code_table:
+       .quad   .L.trampoline_code_table,.TOC.@tocbase,0
+       .type   trampoline_code_table,@function
+       .text
+.L.trampoline_code_table:
+# endif
+       .rept   PPC_TRAMP_MAP_SIZE / PPC_TRAMP_SIZE
+#ifdef __PCREL__
+       pla     %r2,PPC_TRAMP_MAP_SIZE
+       ld      %r11,0(%r2)
+       ld      %r12,8(%r2)
+       mtctr   %r12
+       bctr
+#else
+       mflr    %r0
+       bcl     20,31,$+4
+       mflr    %r11
+       addis   %r11,%r11,PPC_TRAMP_MAP_SIZE@ha
+       mtlr    %r0
+       ld      %r12,(PPC_TRAMP_MAP_SIZE+0)@l(%r11)
+       mtctr   %r12
+       ld      %r11,(PPC_TRAMP_MAP_SIZE-8)@l(%r11)
+       bctr
+       nop
+#endif
+       .endr
+       .align PPC_TRAMP_MAP_SHIFT
+#if _CALL_ELF == 2
+       .size   trampoline_code_table,.-trampoline_code_table
+#else
+       .size   trampoline_code_table,.-.L.trampoline_code_table
 #endif
+#endif /* FFI_EXEC_STATIC_TRAMP */
+#endif /* POWERPC64 */
 
 #if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
        .section        .note.GNU-stack,"",@progbits
index b6d209de8635c59f06767ac7f1da083816ceea76..d3556ebadbab98053e50806930ab2e873922bcc6 100644 (file)
@@ -27,6 +27,7 @@
 #define LIBFFI_ASM
 #include <fficonfig.h>
 #include <ffi.h>
+#include "internal.h"
 #include <powerpc/asm.h>
 
        .file   "ppc_closure.S"
@@ -391,6 +392,29 @@ ENTRY(ffi_go_closure_sysv)
        .cfi_endproc
 END(ffi_go_closure_sysv)
 
+#ifdef FFI_EXEC_STATIC_TRAMP
+       .text
+       .align PPC_TRAMP_MAP_SHIFT
+       FFI_HIDDEN (trampoline_code_table)
+       .globl  trampoline_code_table
+       .type   trampoline_code_table,@function
+trampoline_code_table:
+       .rept   PPC_TRAMP_MAP_SIZE / PPC_TRAMP_SIZE
+       mflr    %r0
+       bcl     20,31,$+4
+       mflr    %r11
+       addis   %r11,%r11,PPC_TRAMP_MAP_SIZE@ha
+       mtlr    %r0
+       lwz     %r0,(PPC_TRAMP_MAP_SIZE-4)@l(%r11)
+       mtctr   %r0
+       lwz     %r11,(PPC_TRAMP_MAP_SIZE-8)@l(%r11)
+       bctr
+       nop
+       .endr
+       .size   trampoline_code_table,.-trampoline_code_table
+       .align PPC_TRAMP_MAP_SHIFT
+#endif /* FFI_EXEC_STATIC_TRAMP */
+
 #if defined __ELF__ && defined __linux__
        .section        .note.GNU-stack,"",@progbits
 #endif
diff --git a/libffi/src/powerpc/t-aix b/libffi/src/powerpc/t-aix
new file mode 100644 (file)
index 0000000..e7be1ca
--- /dev/null
@@ -0,0 +1,5 @@
+# This file is needed by GCC in order to correctly build AIX FAT
+# library for libffi.
+# However, it has no sense to include this code here, as it depends
+# on GCC multilib architecture.
+# Thus, this file is a simple stub replaced in GCC repository.
index c1832b10302fa355ecf9d5d2b749946492b88246..47c9259470c5eef70d2a11352f532e923ff4cf53 100644 (file)
@@ -1,6 +1,7 @@
 /* -----------------------------------------------------------------------
-   prep_cif.c - Copyright (c) 2011, 2012, 2021  Anthony Green
+   prep_cif.c - Copyright (c) 2011, 2012, 2021, 2025  Anthony Green
                 Copyright (c) 1996, 1998, 2007  Red Hat, Inc.
+                Copyright (c) 2022 Oracle and/or its affiliates.
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -157,9 +158,6 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
 #endif
 #ifdef XTENSA
       && (cif->rtype->size > 16)
-#endif
-#ifdef NIOS2
-      && (cif->rtype->size > 8)
 #endif
      )
     bytes = STACK_ARG_SIZE(sizeof(void*));
@@ -233,14 +231,14 @@ ffi_status ffi_prep_cif_var(ffi_cif *cif,
 {
   ffi_status rc;
   size_t int_size = ffi_type_sint.size;
-  int i;
+  unsigned int i;
 
   rc = ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
 
   if (rc != FFI_OK)
     return rc;
 
-  for (i = 1; i < ntotalargs; i++)
+  for (i = nfixedargs; i < ntotalargs; i++)
     {
       ffi_type *arg_type = atypes[i];
       if (arg_type == &ffi_type_float
index c910858896ae60d38da2b992c4790932767a5e20..b455b12ae75ca516f5b2d5ad4aecf85c0448589b 100644 (file)
@@ -61,6 +61,7 @@ typedef struct call_builder
     int used_integer;
     int used_float;
     size_t *used_stack;
+    void *struct_stack;
 } call_builder;
 
 /* integer (not pointer) less than ABI XLEN */
@@ -227,7 +228,9 @@ static void marshal(call_builder *cb, ffi_type *type, int var, void *data) {
 #endif
 
     if (type->size > 2 * __SIZEOF_POINTER__) {
-        /* pass by reference */
+        /* copy to stack and pass by reference */
+        data = memcpy (cb->struct_stack, data, type->size);
+        cb->struct_stack = (size_t *) FFI_ALIGN ((char *) cb->struct_stack + type->size, __SIZEOF_POINTER__);
         marshal_atom(cb, FFI_TYPE_POINTER, &data);
     } else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) {
         marshal_atom(cb, type->type, data);
@@ -335,10 +338,12 @@ ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
        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);
+    /* Allocate space for copies of big structures.  */
+    size_t struct_bytes = FFI_ALIGN (cif->bytes, 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);
+    size_t alloc_size = arg_bytes + rval_bytes + struct_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
@@ -358,8 +363,9 @@ ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
 
     call_builder cb;
     cb.used_float = cb.used_integer = 0;
-    cb.aregs = (call_context*)(alloc_base + arg_bytes + rval_bytes);
+    cb.aregs = (call_context*)(alloc_base + arg_bytes + rval_bytes + struct_bytes);
     cb.used_stack = (void*)alloc_base;
+    cb.struct_stack = (void *) (alloc_base + arg_bytes + rval_bytes);
 
     int return_by_ref = passed_by_ref(&cb, cif->rtype, 0);
     if (return_by_ref)
@@ -373,7 +379,32 @@ ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
 
     cb.used_float = cb.used_integer = 0;
     if (!return_by_ref && rvalue)
-        unmarshal(&cb, cif->rtype, 0, rvalue);
+      {
+       if (IS_INT(cif->rtype->type)
+           && cif->rtype->size < sizeof (ffi_arg))
+         {
+           /* Integer types smaller than ffi_arg need to be extended.  */
+           switch (cif->rtype->type)
+             {
+             case FFI_TYPE_SINT8:
+             case FFI_TYPE_SINT16:
+             case FFI_TYPE_SINT32:
+               unmarshal_atom (&cb, (sizeof (ffi_arg) > 4
+                                     ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32),
+                               rvalue);
+               break;
+             case FFI_TYPE_UINT8:
+             case FFI_TYPE_UINT16:
+             case FFI_TYPE_UINT32:
+               unmarshal_atom (&cb, (sizeof (ffi_arg) > 4
+                                     ? FFI_TYPE_UINT64 : FFI_TYPE_UINT32),
+                               rvalue);
+               break;
+             }
+         }
+       else
+         unmarshal(&cb, cif->rtype, 0, rvalue);
+      }
 }
 
 void
@@ -417,7 +448,9 @@ ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void (*fun)(
     closure->fun = fun;
     closure->user_data = user_data;
 
+#if !defined(__FreeBSD__)
     __builtin___clear_cache(codeloc, codeloc + FFI_TRAMPOLINE_SIZE);
+#endif
 
     return FFI_OK;
 }
index 4035b6e366e6655ea263dfcf8df6a678455d1293..b197cd5fa609ca962802fbb4dcb663f16ff9c78a 100644 (file)
@@ -32,6 +32,7 @@
 #include <ffi_common.h>
 #include <stdint.h>
 #include "internal.h"
+#include <tramp.h>
 
 /*====================== End of Includes =============================*/
 
@@ -720,16 +721,30 @@ ffi_prep_closure_loc (ffi_closure *closure,
 #endif
     0x07f1                     /* br %r1 */
   };
-
+  void (*dest)(void);
   unsigned long *tramp = (unsigned long *)&closure->tramp;
 
   if (cif->abi != FFI_SYSV)
     return FFI_BAD_ABI;
 
+
+#if defined(FFI_EXEC_STATIC_TRAMP)
+  if (ffi_tramp_is_present(closure))
+    {
+      /* Initialize the static trampoline's parameters. */
+      dest = ffi_closure_SYSV;
+      ffi_tramp_set_parms (closure->ftramp, dest, closure);
+      goto out;
+    }
+#endif
+
   memcpy (tramp, template, sizeof(template));
   tramp[2] = (unsigned long)codeloc;
   tramp[3] = (unsigned long)&ffi_closure_SYSV;
 
+#if defined(FFI_EXEC_STATIC_TRAMP)
+out:
+#endif
   closure->cif = cif;
   closure->fun = fun;
   closure->user_data = user_data;
@@ -754,3 +769,15 @@ ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
 
   return FFI_OK;
 }
+
+#if defined(FFI_EXEC_STATIC_TRAMP)
+void *
+ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
+{
+  extern void *trampoline_code_table;
+
+  *tramp_size = FFI390_TRAMP_SIZE;
+  *map_size = FFI390_TRAMP_MAP_SIZE;
+  return &trampoline_code_table;
+}
+#endif
\ No newline at end of file
index b8755786f9e4f5e0d9a2d9d52ffb40a22aaae5d0..eba8e86d439cf6b654029590be19e6993bcc3541 100644 (file)
@@ -9,3 +9,14 @@
 #define FFI390_RET_IN_MEM      8
 
 #define FFI390_RET_STRUCT      (FFI390_RET_VOID | FFI390_RET_IN_MEM)
+
+
+#if defined(FFI_EXEC_STATIC_TRAMP)
+/*
+ * For the trampoline code table mapping, a mapping size of 4K is chosen.
+ */
+#define FFI390_TRAMP_MAP_SHIFT 12
+#define FFI390_TRAMP_MAP_SIZE  (1 << FFI390_TRAMP_MAP_SHIFT)
+#define FFI390_TRAMP_SIZE      16
+
+#endif
index c4b5006aed07454aba41870f4bc2bb1bac65a88e..d603218e6e200d82c71c2a57f108d9f9525d5f84 100644 (file)
@@ -28,6 +28,7 @@
 #define LIBFFI_ASM
 #include <fficonfig.h>
 #include <ffi.h>
+#include "internal.h"
 
        .text
 
@@ -318,6 +319,43 @@ ffi_closure_SYSV:
        br      %r14
        .cfi_endproc
        .size    ffi_closure_SYSV,.-ffi_closure_SYSV
+
+
+#if defined(FFI_EXEC_STATIC_TRAMP)
+/*
+ * Below is the definition of the trampoline code table. Each element in
+ * the code table is a trampoline.
+ */
+/*
+ * The trampoline uses the volatile register r0 and r1. As the registers are
+ * marked volatile in the ABI, the original values are not saved.
+ *
+ * The trampoline has two parameters - target code to jump to and data for
+ * the target code. The trampoline extracts the parameters from its parameter
+ * block (see tramp_table_map()). The trampoline saves the data address in r0.
+ * Finally, it jumps to the target code.
+ */
+
+       .align  FFI390_TRAMP_MAP_SIZE
+trampoline_code_table:
+       .rept   FFI390_TRAMP_MAP_SIZE / FFI390_TRAMP_SIZE
+       basr %r1,0              # load next instruction address to r1
+       lmg %r0,%r1,4094(%r1)   # load parameter block
+                                                       #               r0 -> data
+                                                       #               r1 -> code
+       br %r1                  # jump to r1/code
+       .balign 8
+       .endr
+
+       .globl trampoline_code_table
+       FFI_HIDDEN(trampoline_code_table)
+#ifdef __ELF__
+       .type   trampoline_code_table, @function
+       .size   trampoline_code_table,.- trampoline_code_table
+#endif
+       .align  FFI390_TRAMP_MAP_SIZE
+#endif /* FFI_EXEC_STATIC_TRAMP */
+
 #endif /* !s390x */
 
 #if defined __ELF__ && defined __linux__
index 9e04061a4283c997a74c87d54c2bd2c0b5acd1ec..7a9dc3283b5717ee66dcf9338c7951cf64363211 100644 (file)
@@ -382,13 +382,19 @@ ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
          *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:
+         *argp++ = *(UINT64 *)a;
+         break;
+       case FFI_TYPE_FLOAT:
+         flags |= SPARC_FLAG_FP_ARGS;
+         *argp++ = *(UINT32 *)a;
+         break;
        case FFI_TYPE_DOUBLE:
+         flags |= SPARC_FLAG_FP_ARGS;
          *argp++ = *(UINT64 *)a;
          break;
 
@@ -421,12 +427,28 @@ ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
             void **avalue, void *closure)
 {
   size_t bytes = cif->bytes;
+  size_t i, nargs = cif->nargs;
+  ffi_type **arg_types = cif->arg_types;
 
   FFI_ASSERT (cif->abi == FFI_V9);
 
   if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM))
     bytes += FFI_ALIGN (cif->rtype->size, 16);
 
+  /* If we have any large structure arguments, make a copy so we are passing
+     by value.  */
+  for (i = 0; i < nargs; i++)
+    {
+      ffi_type *at = arg_types[i];
+      int size = at->size;
+      if (at->type == FFI_TYPE_STRUCT && size > 4)
+        {
+          char *argcopy = alloca (size);
+          memcpy (argcopy, avalue[i], size);
+          avalue[i] = argcopy;
+        }
+    }  
+  
   ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure);
 }
 
index 265aeaa3cdf8d8a77c27c7d00a33b84e8f227cf2..76a9dfe75c2c3b407a8b168d249f1b1be1ecf8ba 100644 (file)
@@ -1,5 +1,6 @@
 /* -----------------------------------------------------------------------
    tramp.c - Copyright (c) 2020 Madhavan T. Venkataraman
+             Copyright (c) 2022 Anthony Green
 
    API and support functions for managing statically defined closure
    trampolines.
 
 /* -------------------------- Headers and Definitions ---------------------*/
 /*
- * Add support for other OSes later. For now, it is just Linux.
+ * Add support for other OSes later. For now, it is just Linux and Cygwin.
  */
 
-#if defined __linux__
+#if defined (__linux__) || defined (__CYGWIN__)
 #ifdef __linux__
 #define _GNU_SOURCE 1
 #endif
+
+#include <ffi.h>
+#include <ffi_common.h>
+
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <linux/limits.h>
 #include <linux/types.h>
 #endif
-#endif /* __linux__ */
+#ifdef __CYGWIN__
+#include <limits.h>
+#endif
+#endif
 
 /*
  * Each architecture defines static code for a trampoline code table. The
@@ -191,7 +199,7 @@ static struct tramp_globals tramp_globals;
  */
 static int tramp_table_alloc (void);
 
-#if defined __linux__
+#if defined (__linux__) || defined (__CYGWIN__)
 
 static int
 ffi_tramp_get_libffi (void)
@@ -201,6 +209,11 @@ ffi_tramp_get_libffi (void)
   unsigned long start, end, offset, inode;
   uintptr_t addr = (uintptr_t) tramp_globals.text;
   int nfields, found;
+  int open_flags = O_RDONLY;
+
+#ifdef O_CLOEXEC
+  open_flags |= O_CLOEXEC;
+#endif
 
   snprintf (file, PATH_MAX, "/proc/%d/maps", getpid());
   fp = fopen (file, "r");
@@ -228,7 +241,7 @@ ffi_tramp_get_libffi (void)
   if (!found)
     return 0;
 
-  tramp_globals.fd = open (file, O_RDONLY);
+  tramp_globals.fd = open (file, open_flags);
   if (tramp_globals.fd == -1)
     return 0;
 
@@ -245,30 +258,24 @@ ffi_tramp_get_libffi (void)
   return 1;
 }
 
-#endif /* __linux__ */
+#endif /* defined (__linux__) || defined (__CYGWIN__) */
 
-#if defined __linux__
-
-#if defined HAVE_MKSTEMP
+#if defined (__linux__) || defined (__CYGWIN__)
 
 static int
 ffi_tramp_get_temp_file (void)
 {
-  char template[12] = "/tmp/XXXXXX";
   ssize_t count;
 
   tramp_globals.offset = 0;
-  tramp_globals.fd = mkstemp (template);
-  if (tramp_globals.fd == -1)
-    return 0;
+  tramp_globals.fd = open_temp_exec_file ();
 
-  unlink (template);
   /*
    * Write the trampoline code table into the temporary file and allocate a
    * trampoline table to make sure that the temporary file can be mapped.
    */
   count = write(tramp_globals.fd, tramp_globals.text, tramp_globals.map_size);
-  if (count == tramp_globals.map_size && tramp_table_alloc ())
+  if (count >=0 && (size_t)count == tramp_globals.map_size && tramp_table_alloc ())
     return 1;
 
   close (tramp_globals.fd);
@@ -276,29 +283,11 @@ ffi_tramp_get_temp_file (void)
   return 0;
 }
 
-#else /* !defined HAVE_MKSTEMP */
-
-/*
- * TODO:
- * src/closures.c contains code for finding temp file that has EXEC
- * permissions. May be, some of that code can be shared with static
- * trampolines.
- */
-static int
-ffi_tramp_get_temp_file (void)
-{
-  tramp_globals.offset = 0;
-  tramp_globals.fd = -1;
-  return 0;
-}
-
-#endif /* defined HAVE_MKSTEMP */
-
-#endif /* __linux__ */
+#endif /* defined (__linux__) || defined (__CYGWIN__) */
 
 /* ------------------------ OS-specific Initialization ----------------------*/
 
-#if defined __linux__
+#if defined (__linux__) || defined (__CYGWIN__)
 
 static int
 ffi_tramp_init_os (void)
@@ -308,11 +297,11 @@ ffi_tramp_init_os (void)
   return ffi_tramp_get_temp_file ();
 }
 
-#endif /* __linux__ */
+#endif /* defined (__linux__) || defined (__CYGWIN__) */
 
 /* --------------------------- OS-specific Locking -------------------------*/
 
-#if defined __linux__
+#if defined (__linux__) || defined (__CYGWIN__)
 
 static pthread_mutex_t tramp_globals_mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -323,12 +312,12 @@ ffi_tramp_lock(void)
 }
 
 static void
-ffi_tramp_unlock()
+ffi_tramp_unlock(void)
 {
   pthread_mutex_unlock (&tramp_globals_mutex);
 }
 
-#endif /* __linux__ */
+#endif /* defined (__linux__) || defined (__CYGWIN__) */
 
 /* ------------------------ OS-specific Memory Mapping ----------------------*/
 
@@ -347,7 +336,7 @@ ffi_tramp_unlock()
  * sizeof (struct tramp_parm) cannot exceed the size of a parameter block.
  */
 
-#if defined __linux__
+#if defined (__linux__) || defined (__CYGWIN__)
 
 static int
 tramp_table_map (struct tramp_table *table)
@@ -384,7 +373,7 @@ tramp_table_unmap (struct tramp_table *table)
   (void) munmap (table->parm_table, tramp_globals.map_size);
 }
 
-#endif /* __linux__ */
+#endif /* defined (__linux__) || defined (__CYGWIN__) */
 
 /* ------------------------ Trampoline Initialization ----------------------*/
 
@@ -394,6 +383,8 @@ tramp_table_unmap (struct tramp_table *table)
 static int
 ffi_tramp_init (void)
 {
+  long page_size;
+
   if (tramp_globals.status == TRAMP_GLOBALS_PASSED)
     return 1;
 
@@ -416,7 +407,8 @@ ffi_tramp_init (void)
     &tramp_globals.map_size);
   tramp_globals.ntramp = tramp_globals.map_size / tramp_globals.size;
 
-  if (sysconf (_SC_PAGESIZE) > tramp_globals.map_size)
+  page_size = sysconf (_SC_PAGESIZE);
+  if (page_size >= 0 && (size_t)page_size > tramp_globals.map_size)
     return 0;
 
   if (ffi_tramp_init_os ())
index 9ec27f6cf37676d83bfb489bbe1bb7c7c7363378..8b2dec98eafafb28ac48d590d15569162694f6ae 100644 (file)
@@ -1,6 +1,6 @@
 /* -----------------------------------------------------------------------
-   types.c - Copyright (c) 1996, 1998  Red Hat, Inc.
-   
+   types.c - Copyright (c) 1996, 1998, 2024, 2025  Red Hat, Inc.
+
    Predefined ffi_types needed by libffi.
 
    Permission is hereby granted, free of charge, to any person obtaining
 #include <ffi.h>
 #include <ffi_common.h>
 
+/* Return a version string. */
+const char *ffi_get_version (void)
+{
+  return FFI_VERSION_STRING;
+}
+
+/* Return the version as an unsigned long value: (x * 10000 + y * 100 + z) */
+unsigned long ffi_get_version_number (void)
+{
+  return FFI_VERSION_NUMBER;
+}
+
+unsigned int ffi_get_default_abi (void)
+{
+  return FFI_DEFAULT_ABI;
+}
+
+size_t ffi_get_closure_size (void)
+{
+  return sizeof(ffi_closure);
+}
+
 /* Type definitions */
 
 #define FFI_TYPEDEF(name, type, id, maybe_const)\
@@ -87,7 +109,7 @@ FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE, const);
 #endif
 
 #ifdef __alpha__
-/* Even if we're not configured to default to 128-bit long double, 
+/* Even if we're not configured to default to 128-bit long double,
    maintain binary compatibility, as -mlong-double-128 can be used
    at any time.  */
 /* Validate the hard-coded number below.  */
@@ -95,14 +117,12 @@ FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE, const);
 #  error FFI_TYPE_LONGDOUBLE out of date
 # endif
 const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL };
-#elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+#else
 FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE, FFI_LDBL_CONST);
 #endif
 
 #ifdef FFI_TARGET_HAS_COMPLEX_TYPE
 FFI_COMPLEX_TYPEDEF(float, float, const);
 FFI_COMPLEX_TYPEDEF(double, double, const);
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
 FFI_COMPLEX_TYPEDEF(longdouble, long double, FFI_LDBL_CONST);
 #endif
-#endif
diff --git a/libffi/src/wasm/ffi.c b/libffi/src/wasm/ffi.c
new file mode 100644 (file)
index 0000000..486ffa7
--- /dev/null
@@ -0,0 +1,798 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 2018-2023  Hood Chatham, Brion Vibber, Kleis Auke Wolthuizen, and others.
+
+   wasm32/emscripten 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>
+
+#include <emscripten/emscripten.h>
+
+#ifdef DEBUG_F
+#define LOG_DEBUG(args...)  \
+  console.warn(`====LIBFFI(line __LINE__)`, args)
+#else
+#define LOG_DEBUG(args...) 0
+#endif
+
+#define EM_JS_MACROS(ret, name, args, body...) EM_JS(ret, name, args, body)
+
+EM_JS_DEPS(libffi, "$getWasmTableEntry,$setWasmTableEntry,$getEmptyTableSlot,$convertJsFunctionToWasm");
+
+#define DEREF_U8(addr, offset) HEAPU8[addr + offset]
+#define DEREF_S8(addr, offset) HEAP8[addr + offset]
+#define DEREF_U16(addr, offset) HEAPU16[(addr >> 1) + offset]
+#define DEREF_S16(addr, offset) HEAP16[(addr >> 1) + offset]
+#define DEREF_U32(addr, offset) HEAPU32[(addr >> 2) + offset]
+#define DEREF_S32(addr, offset) HEAP32[(addr >> 2) + offset]
+
+#define DEREF_F32(addr, offset) HEAPF32[(addr >> 2) + offset]
+#define DEREF_F64(addr, offset) HEAPF64[(addr >> 3) + offset]
+#define DEREF_U64(addr, offset) HEAPU64[(addr >> 3) + offset]
+
+#define CHECK_FIELD_OFFSET(struct, field, offset)                                  \
+  _Static_assert(                                                                  \
+    offsetof(struct, field) == offset,                                             \
+    "Memory layout of '" #struct "' has changed: '" #field "' is in an unexpected location");
+
+#if __SIZEOF_POINTER__ == 4
+
+#define FFI_EMSCRIPTEN_ABI FFI_WASM32_EMSCRIPTEN
+#define PTR_SIG 'i'
+
+#define DEC_PTR(p) p
+#define ENC_PTR(p) p
+
+#define DEREF_PTR(addr, offset) DEREF_U32(addr, offset)
+#define DEREF_PTR_NUMBER(addr, offset) DEREF_PTR(addr, offset)
+
+CHECK_FIELD_OFFSET(ffi_cif, abi, 4*0);
+CHECK_FIELD_OFFSET(ffi_cif, nargs, 4*1);
+CHECK_FIELD_OFFSET(ffi_cif, arg_types, 4*2);
+CHECK_FIELD_OFFSET(ffi_cif, rtype, 4*3);
+CHECK_FIELD_OFFSET(ffi_cif, flags, 4*5);
+CHECK_FIELD_OFFSET(ffi_cif, nfixedargs, 4*6);
+
+#define CIF__ABI(addr) DEREF_U32(addr, 0)
+#define CIF__NARGS(addr) DEREF_U32(addr, 1)
+#define CIF__ARGTYPES(addr) DEREF_U32(addr, 2)
+#define CIF__RTYPE(addr) DEREF_U32(addr, 3)
+#define CIF__FLAGS(addr) DEREF_U32(addr, 5)
+#define CIF__NFIXEDARGS(addr) DEREF_U32(addr, 6)
+
+CHECK_FIELD_OFFSET(ffi_type, size, 0);
+CHECK_FIELD_OFFSET(ffi_type, alignment, 4);
+CHECK_FIELD_OFFSET(ffi_type, type, 6);
+CHECK_FIELD_OFFSET(ffi_type, elements, 8);
+
+#define FFI_TYPE__SIZE(addr) DEREF_U32(addr, 0)
+#define FFI_TYPE__ALIGN(addr) DEREF_U16(addr + 4, 0)
+#define FFI_TYPE__TYPEID(addr) DEREF_U16(addr + 6, 0)
+#define FFI_TYPE__ELEMENTS(addr) DEREF_U32(addr + 8, 0)
+
+#elif __SIZEOF_POINTER__ == 8
+
+#define FFI_EMSCRIPTEN_ABI FFI_WASM64_EMSCRIPTEN
+#define PTR_SIG 'j'
+
+// DEC_PTR casts a pointer value (comming from Wasm) represented as BigInt (i64) to Number (i53).
+// This should be used for a pointer that is expected to be within the i53 range. If the pointer
+// value is outside the Number's range, the value will become NaN.
+#define DEC_PTR(p) bigintToI53Checked(p)
+// ENC_PTR casts a pointer value represented as Number to BigInt (i64)
+#define ENC_PTR(p) BigInt(p)
+
+#define DEREF_PTR(addr, offset) DEREF_U64(addr, offset)
+#define DEREF_PTR_NUMBER(addr, offset) DEC_PTR(DEREF_PTR(addr, offset))
+
+CHECK_FIELD_OFFSET(ffi_cif, abi, 0);
+CHECK_FIELD_OFFSET(ffi_cif, nargs, 4);
+CHECK_FIELD_OFFSET(ffi_cif, arg_types, 8);
+CHECK_FIELD_OFFSET(ffi_cif, rtype, 16);
+CHECK_FIELD_OFFSET(ffi_cif, flags, 28);
+CHECK_FIELD_OFFSET(ffi_cif, nfixedargs, 32);
+
+#define CIF__ABI(addr) DEREF_U32(addr, 0)
+#define CIF__NARGS(addr) DEREF_U32(addr + 4,  0)
+#define CIF__ARGTYPES(addr) DEREF_U64(addr + 8,  0)
+#define CIF__RTYPE(addr) DEREF_U64(addr + 16, 0)
+#define CIF__FLAGS(addr) DEREF_U32(addr + 28, 0)
+#define CIF__NFIXEDARGS(addr) DEREF_U32(addr + 32, 0)
+
+CHECK_FIELD_OFFSET(ffi_type, size, 0);
+CHECK_FIELD_OFFSET(ffi_type, alignment, 8);
+CHECK_FIELD_OFFSET(ffi_type, type, 10);
+CHECK_FIELD_OFFSET(ffi_type, elements, 16);
+
+#define FFI_TYPE__SIZE(addr) DEREF_U64(addr, 0)
+#define FFI_TYPE__ALIGN(addr) DEREF_U16(addr + 8, 0)
+#define FFI_TYPE__TYPEID(addr) DEREF_U16(addr + 10, 0)
+#define FFI_TYPE__ELEMENTS(addr) DEREF_U64(addr + 16, 0)
+
+#else
+#error "Unknown pointer size"
+#endif
+
+#define ALIGN_ADDRESS(addr, align) (addr &= (~((align) - 1)))
+#define STACK_ALLOC(stack, size, align) ((stack -= (size)), ALIGN_ADDRESS(stack, align))
+
+// Most wasm runtimes support at most 1000 Js trampoline args.
+#define MAX_ARGS 1000
+
+#include <stddef.h>
+
+#define VARARGS_FLAG 1
+
+#define FFI_OK_MACRO 0
+_Static_assert(FFI_OK_MACRO == FFI_OK, "FFI_OK must be 0");
+
+#define FFI_BAD_TYPEDEF_MACRO 1
+_Static_assert(FFI_BAD_TYPEDEF_MACRO == FFI_BAD_TYPEDEF, "FFI_BAD_TYPEDEF must be 1");
+
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+  if (cif->abi != FFI_EMSCRIPTEN_ABI)
+    return FFI_BAD_ABI;
+  // This is called after ffi_prep_cif_machdep_var so we need to avoid
+  // overwriting cif->nfixedargs.
+  if (!(cif->flags & VARARGS_FLAG))
+    cif->nfixedargs = cif->nargs;
+  if (cif->nargs > MAX_ARGS)
+    return FFI_BAD_TYPEDEF;
+  if (cif->rtype->type == FFI_TYPE_COMPLEX)
+    return FFI_BAD_TYPEDEF;
+  // If they put the COMPLEX type into a struct we won't notice, but whatever.
+  for (int i = 0; i < cif->nargs; i++)
+    if (cif->arg_types[i]->type == FFI_TYPE_COMPLEX)
+      return FFI_BAD_TYPEDEF;
+  return FFI_OK;
+}
+
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs)
+{
+  cif->flags |= VARARGS_FLAG;
+  cif->nfixedargs = nfixedargs;
+  // The varargs takes up one extra argument
+  if (cif->nfixedargs + 1 > MAX_ARGS)
+    return FFI_BAD_TYPEDEF;
+  return FFI_OK;
+}
+
+/**
+ * A Javascript helper function. This takes an argument typ which is a wasm
+ * pointer to an ffi_type object. It returns a pair a type and a type id.
+ *
+ *    - If it is not a struct, return its type and its typeid field.
+ *    - If it is a struct of size >= 2, return the type and its typeid (which
+ *      will be FFI_TYPE_STRUCT)
+ *    - If it is a struct of size 0, return FFI_TYPE_VOID (????? this is broken)
+ *    - If it is a struct of size 1, replace it with the single field and apply
+ *      the same logic again to that.
+ *
+ * By always unboxing structs up front, we can avoid messy casework later.
+ */
+EM_JS_MACROS(
+void,
+unbox_small_structs, (ffi_type type_ptr), {
+  type_ptr = DEC_PTR(type_ptr);
+  var type_id = FFI_TYPE__TYPEID(type_ptr);
+  while (type_id === FFI_TYPE_STRUCT) {
+    // Don't unbox single element structs if they are bigger than 16 bytes. This
+    // is a work around for the fact that Python will give incorrect values for
+    // the size of the field in these cases: it says that the struct has pointer
+    // size and alignment and are of type pointer, even though it is more
+    // accurately a struct and has a larger size. Keeping it as a struct here
+    // will let us get the ABI right (which is in fact that the true argument is
+    // a pointer to the stack... so maybe Python issn't so wrong??)
+    //
+    // See the Python comment here:
+    // https://github.com/python/cpython/blob/a16a9f978f42b8a09297c1efbf33877f6388c403/Modules/_ctypes/stgdict.c#L718-L779
+    if (DEC_PTR(FFI_TYPE__SIZE(type_ptr)) > 16) {
+      break;
+    }
+    var elements = DEC_PTR(FFI_TYPE__ELEMENTS(type_ptr));
+    var first_element = DEREF_PTR_NUMBER(elements, 0);
+    if (first_element === 0) {
+      type_id = FFI_TYPE_VOID;
+      break;
+    } else if (DEREF_PTR_NUMBER(elements, 1) === 0) {
+      type_ptr = first_element;
+      type_id = FFI_TYPE__TYPEID(first_element);
+    } else {
+      break;
+    }
+  }
+  return [type_ptr, type_id];
+})
+
+EM_JS_MACROS(
+void,
+ffi_call_js, (ffi_cif *cif, ffi_fp fn, void *rvalue, void **avalue),
+{
+  cif = DEC_PTR(cif);
+  fn = DEC_PTR(fn);
+  rvalue = DEC_PTR(rvalue);
+  avalue = DEC_PTR(avalue);
+  var abi = CIF__ABI(cif);
+  var nargs = CIF__NARGS(cif);
+  var nfixedargs = CIF__NFIXEDARGS(cif);
+  var arg_types_ptr = DEC_PTR(CIF__ARGTYPES(cif));
+  var flags = CIF__FLAGS(cif);
+  var rtype_unboxed = unbox_small_structs(CIF__RTYPE(cif));
+  var rtype_ptr = rtype_unboxed[0];
+  var rtype_id = rtype_unboxed[1];
+  var orig_stack_ptr = stackSave();
+  var cur_stack_ptr = orig_stack_ptr;
+
+  var args = [];
+  // Does our onwards call return by argument or normally? We return by argument
+  // no matter what.
+  var ret_by_arg = false;
+
+  if (rtype_id === FFI_TYPE_COMPLEX) {
+    throw new Error('complex ret marshalling nyi');
+  }
+  if (rtype_id < 0 || rtype_id > FFI_TYPE_LAST) {
+    throw new Error('Unexpected rtype ' + rtype_id);
+  }
+  // If the return type is a struct with multiple entries or a long double, the
+  // function takes an extra first argument which is a pointer to return value.
+  // Conveniently, we've already received a pointer to return value, so we can
+  // just use this. We also mark a flag that we don't need to convert the return
+  // value of the dynamic call back to C.
+  if (rtype_id === FFI_TYPE_LONGDOUBLE || rtype_id === FFI_TYPE_STRUCT) {
+    args.push(ENC_PTR(rvalue));
+    ret_by_arg = true;
+  }
+
+  // Accumulate a Javascript list of arguments for the Javascript wrapper for
+  // the wasm function. The Javascript wrapper does a type conversion from
+  // Javascript to C automatically, here we manually do the inverse conversion
+  // from C to Javascript.
+  for (var i = 0; i < nfixedargs; i++) {
+    var arg_ptr = DEREF_PTR_NUMBER(avalue, i);
+    var arg_unboxed = unbox_small_structs(DEREF_PTR(arg_types_ptr, i));
+    var arg_type_ptr = arg_unboxed[0];
+    var arg_type_id = arg_unboxed[1];
+
+    // It's okay here to always use unsigned integers as long as the size is 32
+    // or 64 bits. Smaller sizes get extended to 32 bits differently according
+    // to whether they are signed or unsigned.
+    switch (arg_type_id) {
+    case FFI_TYPE_INT:
+    case FFI_TYPE_SINT32:
+    case FFI_TYPE_UINT32:
+      args.push(DEREF_U32(arg_ptr, 0));
+      break;
+    case FFI_TYPE_FLOAT:
+      args.push(DEREF_F32(arg_ptr, 0));
+      break;
+    case FFI_TYPE_DOUBLE:
+      args.push(DEREF_F64(arg_ptr, 0));
+      break;
+    case FFI_TYPE_UINT8:
+      args.push(DEREF_U8(arg_ptr, 0));
+      break;
+    case FFI_TYPE_SINT8:
+      args.push(DEREF_S8(arg_ptr, 0));
+      break;
+    case FFI_TYPE_UINT16:
+      args.push(DEREF_U16(arg_ptr, 0));
+      break;
+    case FFI_TYPE_SINT16:
+      args.push(DEREF_S16(arg_ptr, 0));
+      break;
+    case FFI_TYPE_UINT64:
+    case FFI_TYPE_SINT64:
+      args.push(DEREF_U64(arg_ptr, 0));
+      break;
+    case FFI_TYPE_LONGDOUBLE:
+      // long double is passed as a pair of BigInts.
+      args.push(DEREF_U64(arg_ptr, 0));
+      args.push(DEREF_U64(arg_ptr, 1));
+      break;
+    case FFI_TYPE_STRUCT:
+      // Nontrivial structs are passed by pointer.
+      // Have to copy the struct onto the stack though because C ABI says it's
+      // call by value.
+      var size = DEC_PTR(FFI_TYPE__SIZE(arg_type_ptr));
+      var align = FFI_TYPE__ALIGN(arg_type_ptr);
+      STACK_ALLOC(cur_stack_ptr, size, align);
+      HEAP8.subarray(cur_stack_ptr, cur_stack_ptr+size).set(HEAP8.subarray(arg_ptr, arg_ptr + size));
+      args.push(ENC_PTR(cur_stack_ptr));
+      break;
+    case FFI_TYPE_POINTER:
+      args.push(DEREF_PTR(arg_ptr, 0));
+      break;
+    case FFI_TYPE_COMPLEX:
+      throw new Error('complex marshalling nyi');
+    default:
+      throw new Error('Unexpected type ' + arg_type_id);
+    }
+  }
+
+  // Wasm functions can't directly manipulate the callstack, so varargs
+  // arguments have to go on a separate stack. A varags function takes one extra
+  // argument which is a pointer to where on the separate stack the args are
+  // located. Because stacks are allocated backwards, we have to loop over the
+  // varargs backwards.
+  //
+  // We don't have any way of knowing how many args were actually passed, so we
+  // just always copy extra nonsense past the end. The ownwards call will know
+  // not to look at it.
+  if (flags & VARARGS_FLAG) {
+    var struct_arg_info = [];
+    for (var i = nargs - 1;  i >= nfixedargs; i--) {
+      var arg_ptr = DEREF_PTR_NUMBER(avalue, i);
+      var arg_unboxed = unbox_small_structs(DEREF_PTR(arg_types_ptr, i));
+      var arg_type_ptr = arg_unboxed[0];
+      var arg_type_id = arg_unboxed[1];
+      switch (arg_type_id) {
+      case FFI_TYPE_UINT8:
+      case FFI_TYPE_SINT8:
+        STACK_ALLOC(cur_stack_ptr, 1, 1);
+        DEREF_U8(cur_stack_ptr, 0) = DEREF_U8(arg_ptr, 0);
+        break;
+      case FFI_TYPE_UINT16:
+      case FFI_TYPE_SINT16:
+        STACK_ALLOC(cur_stack_ptr, 2, 2);
+        DEREF_U16(cur_stack_ptr, 0) = DEREF_U16(arg_ptr, 0);
+        break;
+      case FFI_TYPE_INT:
+      case FFI_TYPE_UINT32:
+      case FFI_TYPE_SINT32:
+      case FFI_TYPE_FLOAT:
+        STACK_ALLOC(cur_stack_ptr, 4, 4);
+        DEREF_U32(cur_stack_ptr, 0) = DEREF_U32(arg_ptr, 0);
+        break;
+      case FFI_TYPE_DOUBLE:
+      case FFI_TYPE_UINT64:
+      case FFI_TYPE_SINT64:
+        STACK_ALLOC(cur_stack_ptr, 8, 8);
+        DEREF_U32(cur_stack_ptr, 0) = DEREF_U32(arg_ptr, 0);
+        DEREF_U32(cur_stack_ptr, 1) = DEREF_U32(arg_ptr, 1);
+        break;
+      case FFI_TYPE_LONGDOUBLE:
+        STACK_ALLOC(cur_stack_ptr, 16, 8);
+        DEREF_U32(cur_stack_ptr, 0) = DEREF_U32(arg_ptr, 0);
+        DEREF_U32(cur_stack_ptr, 1) = DEREF_U32(arg_ptr, 1);
+        DEREF_U32(cur_stack_ptr, 2) = DEREF_U32(arg_ptr, 2);
+        DEREF_U32(cur_stack_ptr, 3) = DEREF_U32(arg_ptr, 3);
+        break;
+      case FFI_TYPE_STRUCT:
+        // Again, struct must be passed by pointer.
+        // But ABI is by value, so have to copy struct onto stack.
+        // Currently arguments are going onto stack so we can't put it there now. Come back for this.
+        STACK_ALLOC(cur_stack_ptr, __SIZEOF_POINTER__, __SIZEOF_POINTER__);
+        struct_arg_info.push([cur_stack_ptr, arg_ptr, DEC_PTR(FFI_TYPE__SIZE(arg_type_ptr)), FFI_TYPE__ALIGN(arg_type_ptr)]);
+        break;
+      case FFI_TYPE_POINTER:
+        STACK_ALLOC(cur_stack_ptr, __SIZEOF_POINTER__, __SIZEOF_POINTER__);
+        DEREF_PTR(cur_stack_ptr, 0) = DEREF_PTR(arg_ptr, 0);
+        break;
+      case FFI_TYPE_COMPLEX:
+        throw new Error('complex arg marshalling nyi');
+      default:
+        throw new Error('Unexpected argtype ' + arg_type_id);
+      }
+    }
+    // extra normal argument which is the pointer to the varargs.
+    args.push(ENC_PTR(cur_stack_ptr));
+    // Now allocate variable struct args on stack too.
+    for (var i = 0; i < struct_arg_info.length; i++) {
+      var struct_info = struct_arg_info[i];
+      var arg_target = struct_info[0];
+      var arg_ptr = struct_info[1];
+      var size = struct_info[2];
+      var align = struct_info[3];
+      STACK_ALLOC(cur_stack_ptr, size, align);
+      HEAP8.subarray(cur_stack_ptr, cur_stack_ptr+size).set(HEAP8.subarray(arg_ptr, arg_ptr + size));
+      DEREF_PTR(arg_target, 0) = ENC_PTR(cur_stack_ptr);
+    }
+  }
+  stackRestore(cur_stack_ptr);
+  stackAlloc(0); // stackAlloc enforces alignment invariants on the stack pointer
+  LOG_DEBUG("CALL_FUNC_PTR", "fn:", fn, "args:", args);
+  var result = getWasmTableEntry(fn).apply(null, args);
+  // Put the stack pointer back (we moved it if there were any struct args or we
+  // made a varargs call)
+  stackRestore(orig_stack_ptr);
+
+  // We need to return by argument. If return value was a nontrivial struct or
+  // long double, the onwards call already put the return value in rvalue
+  if (ret_by_arg) {
+    return;
+  }
+
+  // Otherwise the result was automatically converted from C into Javascript and
+  // we need to manually convert it back to C.
+  switch (rtype_id) {
+  case FFI_TYPE_VOID:
+    break;
+  case FFI_TYPE_INT:
+  case FFI_TYPE_UINT32:
+  case FFI_TYPE_SINT32:
+    DEREF_U32(rvalue, 0) = result;
+    break;
+  case FFI_TYPE_FLOAT:
+    DEREF_F32(rvalue, 0) = result;
+    break;
+  case FFI_TYPE_DOUBLE:
+    DEREF_F64(rvalue, 0) = result;
+    break;
+  case FFI_TYPE_UINT8:
+  case FFI_TYPE_SINT8:
+    DEREF_U8(rvalue, 0) = result;
+    break;
+  case FFI_TYPE_UINT16:
+  case FFI_TYPE_SINT16:
+    DEREF_U16(rvalue, 0) = result;
+    break;
+  case FFI_TYPE_UINT64:
+  case FFI_TYPE_SINT64:
+    DEREF_U64(rvalue, 0) = result;
+    break;
+  case FFI_TYPE_POINTER:
+    DEREF_PTR(rvalue, 0) = result;
+    break;
+  case FFI_TYPE_COMPLEX:
+    throw new Error('complex ret marshalling nyi');
+  default:
+    throw new Error('Unexpected rtype ' + rtype_id);
+  }
+});
+
+void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) {
+  ffi_call_js(cif, fn, rvalue, avalue);
+}
+
+#if __SIZEOF_POINTER__ == 4
+
+CHECK_FIELD_OFFSET(ffi_closure, ftramp, 4*0);
+CHECK_FIELD_OFFSET(ffi_closure, cif, 4*1);
+CHECK_FIELD_OFFSET(ffi_closure, fun, 4*2);
+CHECK_FIELD_OFFSET(ffi_closure, user_data, 4*3);
+
+#define CLOSURE__wrapper(addr) DEREF_U32(addr, 0)
+#define CLOSURE__cif(addr) DEREF_U32(addr, 1)
+#define CLOSURE__fun(addr) DEREF_U32(addr, 2)
+#define CLOSURE__user_data(addr) DEREF_U32(addr, 3)
+
+#elif __SIZEOF_POINTER__ == 8
+
+CHECK_FIELD_OFFSET(ffi_closure, ftramp, 0);
+CHECK_FIELD_OFFSET(ffi_closure, cif, 8);
+CHECK_FIELD_OFFSET(ffi_closure, fun, 16);
+CHECK_FIELD_OFFSET(ffi_closure, user_data, 24);
+
+#define CLOSURE__wrapper(addr) DEREF_U64(addr, 0)
+#define CLOSURE__cif(addr) DEREF_U64(addr, 1)
+#define CLOSURE__fun(addr) DEREF_U64(addr, 2)
+#define CLOSURE__user_data(addr) DEREF_U64(addr, 3)
+
+#else
+#error "Unknown pointer size"
+#endif
+
+EM_JS_MACROS(void *, ffi_closure_alloc_js, (size_t size, void **code), {
+  size = DEC_PTR(size);
+  code = DEC_PTR(code);
+  var closure = _malloc(size);
+  var index = getEmptyTableSlot();
+  DEREF_PTR(code, 0) = ENC_PTR(index);
+  CLOSURE__wrapper(closure) = ENC_PTR(index);
+  return ENC_PTR(closure);
+})
+
+void * __attribute__ ((visibility ("default")))
+ffi_closure_alloc(size_t size, void **code) {
+  return ffi_closure_alloc_js(size, code);
+}
+
+EM_JS_MACROS(void, ffi_closure_free_js, (void *closure), {
+  closure = DEC_PTR(closure);
+  var index = DEC_PTR(CLOSURE__wrapper(closure));
+  freeTableIndexes.push(index);
+  _free(closure);
+})
+
+void __attribute__ ((visibility ("default")))
+ffi_closure_free(void *closure) {
+  return ffi_closure_free_js(closure);
+}
+
+EM_JS_MACROS(
+ffi_status,
+ffi_prep_closure_loc_js,
+(ffi_closure *closure, ffi_cif *cif, void *fun, void *user_data, void *codeloc),
+{
+  closure = DEC_PTR(closure);
+  cif = DEC_PTR(cif);
+  fun = DEC_PTR(fun);
+  user_data = DEC_PTR(user_data);
+  codeloc = DEC_PTR(codeloc);
+  var abi = CIF__ABI(cif);
+  var nargs = CIF__NARGS(cif);
+  var nfixedargs = CIF__NFIXEDARGS(cif);
+  var arg_types_ptr = DEC_PTR(CIF__ARGTYPES(cif));
+  var rtype_unboxed = unbox_small_structs(CIF__RTYPE(cif));
+  var rtype_ptr = rtype_unboxed[0];
+  var rtype_id = rtype_unboxed[1];
+
+  // First construct the signature of the javascript trampoline we are going to create.
+  // Important: this is the signature for calling us, the onward call always has sig viiii.
+  var sig;
+  var ret_by_arg = false;
+  switch (rtype_id) {
+  case FFI_TYPE_VOID:
+    sig = 'v';
+    break;
+  case FFI_TYPE_STRUCT:
+  case FFI_TYPE_LONGDOUBLE:
+    // Return via a first pointer argument.
+    sig = 'v' + PTR_SIG;
+    ret_by_arg = true;
+    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:
+    sig = 'i';
+    break;
+  case FFI_TYPE_FLOAT:
+    sig = 'f';
+    break;
+  case FFI_TYPE_DOUBLE:
+    sig = 'd';
+    break;
+  case FFI_TYPE_UINT64:
+  case FFI_TYPE_SINT64:
+    sig = 'j';
+    break;
+  case FFI_TYPE_POINTER:
+    sig = PTR_SIG;
+    break;
+  case FFI_TYPE_COMPLEX:
+    throw new Error('complex ret marshalling nyi');
+  default:
+    throw new Error('Unexpected rtype ' + rtype_id);
+  }
+  var unboxed_arg_type_id_list = [];
+  var unboxed_arg_type_info_list = [];
+  for (var i = 0; i < nargs; i++) {
+    var arg_unboxed = unbox_small_structs(DEREF_PTR(arg_types_ptr, i));
+    var arg_type_ptr = arg_unboxed[0];
+    var arg_type_id = arg_unboxed[1];
+    unboxed_arg_type_id_list.push(arg_type_id);
+    unboxed_arg_type_info_list.push([DEC_PTR(FFI_TYPE__SIZE(arg_type_ptr)), FFI_TYPE__ALIGN(arg_type_ptr)]);
+  }
+  for (var i = 0; i < nfixedargs; i++) {
+    switch (unboxed_arg_type_id_list[i]) {
+    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:
+      sig += 'i';
+      break;
+    case FFI_TYPE_FLOAT:
+      sig += 'f';
+      break;
+    case FFI_TYPE_DOUBLE:
+      sig += 'd';
+      break;
+    case FFI_TYPE_LONGDOUBLE:
+      sig += 'jj';
+      break;
+    case FFI_TYPE_UINT64:
+    case FFI_TYPE_SINT64:
+      sig += 'j';
+      break;
+    case FFI_TYPE_STRUCT:
+    case FFI_TYPE_POINTER:
+      sig += PTR_SIG;
+      break;
+    case FFI_TYPE_COMPLEX:
+      throw new Error('complex marshalling nyi');
+    default:
+      throw new Error('Unexpected argtype ' + arg_type_id);
+    }
+  }
+  if (nfixedargs < nargs) {
+    // extra pointer to varargs stack
+    sig += PTR_SIG;
+  }
+  LOG_DEBUG("CREATE_CLOSURE", "sig:", sig);
+  function trampoline() {
+    var args = Array.prototype.slice.call(arguments);
+    var size = 0;
+    var orig_stack_ptr = stackSave();
+    var cur_ptr = orig_stack_ptr;
+    var ret_ptr;
+    var jsarg_idx = 0;
+    // Should we return by argument or not? The onwards call returns by argument
+    // no matter what. (Warning: ret_by_arg means the opposite in ffi_call)
+    if (ret_by_arg) {
+      ret_ptr = args[jsarg_idx++];
+    } else {
+      // We might return 4 bytes or 8 bytes, allocate 8 just in case.
+      STACK_ALLOC(cur_ptr, 8, 8);
+      ret_ptr = cur_ptr;
+    }
+    cur_ptr -= __SIZEOF_POINTER__ * nargs;
+    var args_ptr = cur_ptr;
+    var carg_idx = 0;
+    // Here we either have the actual argument, or a pair of BigInts for long
+    // double, or a pointer to struct. We have to store into args_ptr[i] a
+    // pointer to the ith argument. If the argument is a struct, just store the
+    // pointer. Otherwise allocate stack space and copy the js argument onto the
+    // stack.
+    for (; carg_idx < nfixedargs; carg_idx++) {
+      // jsarg_idx might start out as 0 or 1 depending on ret_by_arg
+      // it advances an extra time for long double
+      var cur_arg = args[jsarg_idx++];
+      var arg_type_info = unboxed_arg_type_info_list[carg_idx];
+      var arg_size = arg_type_info[0];
+      var arg_align = arg_type_info[1];
+      var arg_type_id = unboxed_arg_type_id_list[carg_idx];
+      switch (arg_type_id) {
+      case FFI_TYPE_UINT8:
+      case FFI_TYPE_SINT8:
+        // Bad things happen if we don't align to 4 here
+        STACK_ALLOC(cur_ptr, 1, 4);
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+        DEREF_U8(cur_ptr, 0) = cur_arg;
+        break;
+      case FFI_TYPE_UINT16:
+      case FFI_TYPE_SINT16:
+        // Bad things happen if we don't align to 4 here
+        STACK_ALLOC(cur_ptr, 2, 4);
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+        DEREF_U16(cur_ptr, 0) = cur_arg;
+        break;
+      case FFI_TYPE_INT:
+      case FFI_TYPE_UINT32:
+      case FFI_TYPE_SINT32:
+        STACK_ALLOC(cur_ptr, 4, 4);
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+        DEREF_U32(cur_ptr, 0) = cur_arg;
+        break;
+      case FFI_TYPE_STRUCT:
+        // cur_arg is already a pointer to struct
+        // copy it onto stack to pass by value
+        STACK_ALLOC(cur_ptr, arg_size, arg_align);
+        HEAP8.subarray(cur_ptr, cur_ptr + arg_size).set(HEAP8.subarray(DEC_PTR(cur_arg), DEC_PTR(cur_arg) + arg_size));
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+        break;
+      case FFI_TYPE_FLOAT:
+        STACK_ALLOC(cur_ptr, 4, 4);
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+        DEREF_F32(cur_ptr, 0) = cur_arg;
+        break;
+      case FFI_TYPE_DOUBLE:
+        STACK_ALLOC(cur_ptr, 8, 8);
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+        DEREF_F64(cur_ptr, 0) = cur_arg;
+        break;
+      case FFI_TYPE_UINT64:
+      case FFI_TYPE_SINT64:
+        STACK_ALLOC(cur_ptr, 8, 8);
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+        DEREF_U64(cur_ptr, 0) = cur_arg;
+        break;
+      case FFI_TYPE_LONGDOUBLE:
+        STACK_ALLOC(cur_ptr, 16, 8);
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+        DEREF_U64(cur_ptr, 0) = cur_arg;
+        cur_arg = args[jsarg_idx++];
+        DEREF_U64(cur_ptr, 1) = cur_arg;
+        break;
+      case FFI_TYPE_POINTER:
+        STACK_ALLOC(cur_ptr, __SIZEOF_POINTER__, __SIZEOF_POINTER__);
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+        DEREF_PTR(cur_ptr, 0) = cur_arg;
+        break;
+      }
+    }
+    // If its a varargs call, last js argument is a pointer to the varargs.
+    var varargs = DEC_PTR(args[args.length - 1]);
+    // We have no way of knowing how many varargs were actually provided, this
+    // fills the rest of the stack space allocated with nonsense. The onward
+    // call will know to ignore the nonsense.
+
+    // We either have a pointer to the argument if the argument is not a struct
+    // or a pointer to pointer to struct. We need to store a pointer to the
+    // argument into args_ptr[i]
+    for (; carg_idx < nargs; carg_idx++) {
+      var arg_type_id = unboxed_arg_type_id_list[carg_idx];
+      var arg_type_info = unboxed_arg_type_info_list[carg_idx];
+      var arg_size = arg_type_info[0];
+      var arg_align = arg_type_info[1];
+      if (arg_type_id === FFI_TYPE_STRUCT) {
+        // In this case varargs is a pointer to pointer to struct so we need to
+        // deref once
+        var struct_ptr = DEREF_PTR_NUMBER(varargs, 0);
+        STACK_ALLOC(cur_ptr, arg_size, arg_align);
+        HEAP8.subarray(cur_ptr, cur_ptr + arg_size).set(HEAP8.subarray(struct_ptr, struct_ptr + arg_size));
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(cur_ptr);
+      } else {
+        DEREF_PTR(args_ptr, carg_idx) = ENC_PTR(varargs);
+      }
+      varargs += __SIZEOF_POINTER__;
+    }
+    stackRestore(cur_ptr);
+    stackAlloc(0); // stackAlloc enforces alignment invariants on the stack pointer
+    LOG_DEBUG("CALL_CLOSURE", "closure:", closure, "fptr", CLOSURE__fun(closure), "cif", CLOSURE__cif(closure));
+    getWasmTableEntry(CLOSURE__fun(closure))(
+        CLOSURE__cif(closure), ENC_PTR(ret_ptr), ENC_PTR(args_ptr),
+        CLOSURE__user_data(closure)
+    );
+    stackRestore(orig_stack_ptr);
+
+    // If we aren't supposed to return by argument, figure out what to return.
+    if (!ret_by_arg) {
+      switch (sig[0]) {
+      case 'i':
+        return DEREF_U32(ret_ptr, 0);
+      case 'j':
+        return DEREF_U64(ret_ptr, 0);
+      case 'd':
+        return DEREF_F64(ret_ptr, 0);
+      case 'f':
+        return DEREF_F32(ret_ptr, 0);
+      }
+    }
+  }
+  try {
+    var wasm_trampoline = convertJsFunctionToWasm(trampoline, sig);
+  } catch(e) {
+    return FFI_BAD_TYPEDEF_MACRO;
+  }
+  setWasmTableEntry(codeloc, wasm_trampoline);
+  CLOSURE__cif(closure) = ENC_PTR(cif);
+  CLOSURE__fun(closure) = ENC_PTR(fun);
+  CLOSURE__user_data(closure) = ENC_PTR(user_data);
+  return FFI_OK_MACRO;
+})
+
+// EM_JS does not correctly handle function pointer arguments, so we need a
+// helper
+ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif,
+                                void (*fun)(ffi_cif *, void *, void **, void *),
+                                void *user_data, void *codeloc) {
+  if (cif->abi != FFI_EMSCRIPTEN_ABI)
+    return FFI_BAD_ABI;
+  return ffi_prep_closure_loc_js(closure, cif, (void *)fun, user_data,
+                                     codeloc);
+}
diff --git a/libffi/src/wasm/ffitarget.h b/libffi/src/wasm/ffitarget.h
new file mode 100644 (file)
index 0000000..10041c0
--- /dev/null
@@ -0,0 +1,79 @@
+/* -----------------------------------------------------------------*-C-*-
+   ffitarget.h - Copyright (c) 2018-2023  Hood Chatham, Brion Vibber, Kleis Auke Wolthuizen, and others.
+
+   Target configuration macros for wasm32.
+
+   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
+
+/* ---- Generic type definitions ----------------------------------------- */
+
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+// TODO: https://github.com/emscripten-core/emscripten/issues/9868
+typedef void (*ffi_fp)(void);
+
+typedef enum ffi_abi {
+  FFI_FIRST_ABI = 0,
+#if __SIZEOF_POINTER__ == 4
+  FFI_WASM32, // "raw", no structures, varargs, or closures (not implemented!)
+  FFI_WASM32_EMSCRIPTEN, // structures, varargs, and split 64-bit params
+#elif __SIZEOF_POINTER__ == 8
+  FFI_WASM64,
+  FFI_WASM64_EMSCRIPTEN,
+#else
+#error "Unknown pointer size"
+#endif
+  FFI_LAST_ABI,
+#if __SIZEOF_POINTER__ == 4
+#ifdef __EMSCRIPTEN__
+  FFI_DEFAULT_ABI = FFI_WASM32_EMSCRIPTEN
+#else
+  FFI_DEFAULT_ABI = FFI_WASM32
+#endif
+#elif __SIZEOF_POINTER__ == 8
+#ifdef __EMSCRIPTEN__
+  FFI_DEFAULT_ABI = FFI_WASM64_EMSCRIPTEN
+#else
+  FFI_DEFAULT_ABI = FFI_WASM64
+#endif
+#else
+#error "Unknown pointer size"
+#endif
+} ffi_abi;
+
+#define FFI_CLOSURES 1
+// #define FFI_GO_CLOSURES 0
+#define FFI_TRAMPOLINE_SIZE 4
+// #define FFI_NATIVE_RAW_API 0
+#define FFI_TARGET_SPECIFIC_VARIADIC 1
+#define FFI_EXTRA_CIF_FIELDS  unsigned int nfixedargs
+
+#endif
index 24431c170ba539c7af5d7eff03a92614ca87286e..6862533f282a296ad7283430b4a99117df98512f 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 2017  Anthony Green
+   ffi.c - Copyright (c) 2017, 2022  Anthony Green
            Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008  Red Hat, Inc.
            Copyright (c) 2002  Ranjit Mathew
            Copyright (c) 2002  Bo Thorsen
@@ -117,35 +117,37 @@ ffi_prep_cif_machdep(ffi_cif *cif)
       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)
-       flags = X86_RET_STRUCT_1B;
-      else if (cif->rtype->size == 2)
-       flags = X86_RET_STRUCT_2B;
-      else if (cif->rtype->size == 4)
-       flags = X86_RET_INT32;
-      else if (cif->rtype->size == 8)
-       flags = X86_RET_INT64;
-      else
+      {
+#if defined(X86_WIN32) || defined(X86_DARWIN)
+        size_t size = cif->rtype->size;
+        if (size == 1)
+          flags = X86_RET_STRUCT_1B;
+        else if (size == 2)
+          flags = X86_RET_STRUCT_2B;
+        else if (size == 4)
+          flags = X86_RET_INT32;
+        else if (size == 8)
+          flags = X86_RET_INT64;
+        else
 #endif
-       {
-       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);
-       }
+          {
+          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;
     case FFI_TYPE_COMPLEX:
       switch (cif->rtype->elements[0]->type)
@@ -182,7 +184,12 @@ ffi_prep_cif_machdep(ffi_cif *cif)
     {
       ffi_type *t = cif->arg_types[i];
 
-      bytes = FFI_ALIGN (bytes, t->alignment);
+#if defined(X86_WIN32)
+      if (cabi == FFI_STDCALL)
+        bytes = FFI_ALIGN (bytes, FFI_SIZEOF_ARG);
+      else
+#endif
+        bytes = FFI_ALIGN (bytes, t->alignment);
       bytes += FFI_ALIGN (t->size, FFI_SIZEOF_ARG);
     }
   cif->bytes = bytes;
@@ -263,6 +270,9 @@ extern void FFI_DECLARE_FASTCALL ffi_call_i386(struct call_frame *, char *) FFI_
 #if defined(_MSC_VER)
 #pragma runtime_checks("s", off)
 #endif
+/* n.b. ffi_call_unix64 will steal the alloca'd `stack` variable here for use
+   _as its own stack_ - so we need to compile this function without ASAN */
+FFI_ASAN_NO_SANITIZE
 static void
 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
              void **avalue, void *closure)
@@ -378,7 +388,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
             cases.  */
          if (t == FFI_TYPE_STRUCT && ty->alignment >= 16)
            align = 16;
-           
+
          if (dir < 0)
            {
              /* ??? These reverse argument ABIs are probably too old
@@ -609,7 +619,9 @@ ffi_prep_closure_loc (ffi_closure* closure,
   tramp[9] = 0xe9;
   *(unsigned *)(tramp + 10) = (unsigned)dest - ((unsigned)codeloc + 14);
 
+#if defined(FFI_EXEC_STATIC_TRAMP)
 out:
+#endif
   closure->cif = cif;
   closure->fun = fun;
   closure->user_data = user_data;
index 438b374e2fbbf89bc97deefe7a2085f2a06c6661..1d1b88e049d5e6792584adc4998584d024bf53bd 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------
-   ffi64.c - Copyright (c) 2011, 2018  Anthony Green
+   ffi64.c - Copyright (c) 2011, 2018, 2022  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>
@@ -557,6 +557,9 @@ ffi_prep_cif_machdep (ffi_cif *cif)
   return FFI_OK;
 }
 
+/* n.b. ffi_call_unix64 will steal the alloca'd `stack` variable here for use
+   _as its own stack_ - so we need to compile this function without ASAN */
+FFI_ASAN_NO_SANITIZE
 static void
 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
              void **avalue, void *closure)
@@ -581,6 +584,9 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
        flags = UNIX64_RET_VOID;
     }
 
+  arg_types = cif->arg_types;
+  avn = cif->nargs;
+
   /* 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;
@@ -595,9 +601,6 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
   if (flags & UNIX64_FLAG_RET_IN_MEM)
     reg_args->gpr[gprcount++] = (unsigned long) rvalue;
 
-  avn = cif->nargs;
-  arg_types = cif->arg_types;
-
   for (i = 0; i < avn; ++i)
     {
       size_t n, size = arg_types[i]->size;
@@ -613,11 +616,12 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
          if (align < 8)
            align = 8;
 
-         /* Pass this argument in memory.  */
-         argp = (void *) FFI_ALIGN (argp, align);
-         memcpy (argp, avalue[i], size);
-         argp += size;
-       }
+          /* Pass this argument in memory.  */
+          argp = (void *) FFI_ALIGN (argp, align);
+          memcpy (argp, avalue[i], size);
+
+          argp += size;
+        }
       else
        {
          /* The argument is passed entirely in registers.  */
@@ -650,7 +654,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
                      break;
                    default:
                      reg_args->gpr[gprcount] = 0;
-                     memcpy (&reg_args->gpr[gprcount], a, size);
+                     memcpy (&reg_args->gpr[gprcount], a, size <= 8 ? size : 8);
                    }
                  gprcount++;
                  break;
@@ -681,6 +685,24 @@ ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);
 void
 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
 {
+  ffi_type **arg_types = cif->arg_types;
+  int i, nargs = cif->nargs;
+  const int max_reg_struct_size = cif->abi == FFI_GNUW64 ? 8 : 16;
+
+  /* If we have any large structure arguments, make a copy so we are passing
+     by value.  */
+  for (i = 0; i < nargs; i++)
+    {
+      ffi_type *at = arg_types[i];
+      int size = at->size;
+      if (at->type == FFI_TYPE_STRUCT && size > max_reg_struct_size)
+        {
+          char *argcopy = alloca (size);
+          memcpy (argcopy, avalue[i], size);
+          avalue[i] = argcopy;
+        }
+    }
+
 #ifndef __ILP32__
   if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
     {
@@ -780,7 +802,9 @@ ffi_prep_closure_loc (ffi_closure* closure,
   memcpy (tramp, trampoline, sizeof(trampoline));
   *(UINT64 *)(tramp + sizeof (trampoline)) = (uintptr_t)dest;
 
+#if defined(FFI_EXEC_STATIC_TRAMP)
 out:
+#endif
   closure->cif = cif;
   closure->fun = fun;
   closure->user_data = user_data;
index f454341a22d1ddab735aa07afcd82bf422195d4e..5a3399d80982b1f63e6a9b34e775fd0dd814ec1b 100644 (file)
@@ -41,6 +41,9 @@
 
 #if defined (X86_64) && defined (__i386__)
 #undef X86_64
+#warning ******************************************************
+#warning ********** X86 IS DEFINED ****************************
+#warning ******************************************************
 #define X86
 #endif
 
@@ -85,9 +88,9 @@ typedef enum ffi_abi {
   FFI_LAST_ABI,
 #ifdef __GNUC__
   FFI_DEFAULT_ABI = FFI_GNUW64
-#else  
+#else
   FFI_DEFAULT_ABI = FFI_WIN64
-#endif  
+#endif
 
 #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
   FFI_FIRST_ABI = 1,
@@ -159,4 +162,3 @@ typedef enum ffi_abi {
 #endif
 
 #endif
-
index 6870d07c92b787c26544ff5e69c8bd4febe3e71c..2be8b99279ab8e92fb1197b4cd04e8609acb848c 100644 (file)
@@ -123,9 +123,25 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
   UINT64 *stack;
   size_t rsize;
   struct win64_call_frame *frame;
+  ffi_type **arg_types = cif->arg_types;
+  int nargs = cif->nargs;
 
   FFI_ASSERT(cif->abi == FFI_GNUW64 || cif->abi == FFI_WIN64);
 
+  /* If we have any large structure arguments, make a copy so we are passing
+     by value.  */
+  for (i = 0; i < nargs; i++)
+    {
+      ffi_type *at = arg_types[i];
+      int size = at->size;
+      if (at->type == FFI_TYPE_STRUCT && size > 8)
+        {
+          char *argcopy = alloca (size);
+          memcpy (argcopy, avalue[i], size);
+          avalue[i] = argcopy;
+        }
+    }
+
   flags = cif->flags;
   rsize = 0;
 
@@ -211,7 +227,7 @@ EFI64(ffi_prep_closure_loc)(ffi_closure* closure,
                      ffi_cif* cif,
                      void (*fun)(ffi_cif*, void*, void**, void*),
                      void *user_data,
-                     void *codeloc)
+                     void *codeloc MAYBE_UNUSED)
 {
   static const unsigned char trampoline[FFI_TRAMPOLINE_SIZE - 8] = {
     /* endbr64 */
@@ -247,7 +263,9 @@ EFI64(ffi_prep_closure_loc)(ffi_closure* closure,
   memcpy (tramp, trampoline, sizeof(trampoline));
   *(UINT64 *)(tramp + sizeof (trampoline)) = (uintptr_t)ffi_closure_win64;
 
+#if defined(FFI_EXEC_STATIC_TRAMP)
 out:
+#endif
   closure->cif = cif;
   closure->fun = fun;
   closure->user_data = user_data;
index 3cafd71ce18fcd9a7b2fdd0719a8600572e8e3fb..cccdf7d7683f0764b81c81cd324d2c7d90590666 100644 (file)
@@ -1,9 +1,9 @@
 /* -----------------------------------------------------------------------
-   sysv.S - Copyright (c) 2017  Anthony Green
+   sysv.S - Copyright (c) 2017, 2022  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 
+
+   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
 #ifndef __x86_64__
 #ifdef _MSC_VER
 
-#define LIBFFI_ASM     
+#define LIBFFI_ASM
 #include <fficonfig.h>
 #include <ffi.h>
 #include <ffi_cfi.h>
-#include "internal.h" 
+#include "internal.h"
 
 #define C2(X, Y)  X ## Y
 #define C1(X, Y)  C2(X, Y)
@@ -89,8 +89,8 @@ L(UW0):
           perspective of the unwind info, it hasn't moved.  */
        mov     ebp, ecx
 L(UW1):
-       // cfi_def_cfa(%ebp, 8)
-       // cfi_rel_offset(%ebp, 0)
+       /* 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 */
@@ -102,7 +102,7 @@ L(UW1):
        mov         ecx, [12+ebp]               /* load return type code */
        mov     [ebp+8], ebx            /* preserve %ebx */
 L(UW2):
-       // cfi_rel_offset(%ebx, 8)
+       /* cfi_rel_offset(%ebx, 8) */
 
        and     ecx, X86_RET_TYPE_MASK
        lea     ebx, [L(store_table) + ecx * 8]
@@ -148,13 +148,13 @@ L(e1):
        mov         esp, ebp
        pop     ebp
 L(UW3):
-       // cfi_remember_state
-       // cfi_def_cfa(%esp, 4)
-       // cfi_restore(%ebx)
-       // cfi_restore(%ebp)
+       /* cfi_remember_state */
+       /* cfi_def_cfa(%esp, 4) */
+       /* cfi_restore(%ebx) */
+       /* cfi_restore(%ebp) */
        ret
 L(UW4):
-       // cfi_restore_state
+       /* cfi_restore_state */
 
 E(L(store_table), X86_RET_STRUCTPOP)
        jmp         L(e1)
@@ -174,7 +174,7 @@ E(L(store_table), X86_RET_UNUSED15)
        int 3
 
 L(UW5):
-       // cfi_endproc
+       /* cfi_endproc */
 ENDF(@ffi_call_i386@8)
 
 /* The inner helper is declared as
@@ -242,10 +242,10 @@ ALIGN 16
 PUBLIC ffi_go_closure_EAX
 ffi_go_closure_EAX PROC C
 L(UW6):
-       // cfi_startproc
+       /* cfi_startproc */
        sub     esp, closure_FS
 L(UW7):
-       // cfi_def_cfa_offset(closure_FS + 4)
+       /* cfi_def_cfa_offset(closure_FS + 4) */
        FFI_CLOSURE_SAVE_REGS
        mov     edx, [eax+4]                    /* copy cif */
        mov     ecx, [eax +8]                   /* copy fun */
@@ -254,17 +254,17 @@ L(UW7):
        mov     [esp+closure_CF+36], eax        /* closure is user_data */
        jmp     L(do_closure_i386)
 L(UW8):
-       // cfi_endproc
+       /* cfi_endproc */
 ENDF(ffi_go_closure_EAX)
 
 ALIGN 16
 PUBLIC ffi_go_closure_ECX
 ffi_go_closure_ECX PROC C
 L(UW9):
-       // cfi_startproc
+       /* cfi_startproc */
        sub     esp, closure_FS
 L(UW10):
-       // cfi_def_cfa_offset(closure_FS + 4)
+       /* cfi_def_cfa_offset(closure_FS + 4) */
        FFI_CLOSURE_SAVE_REGS
        mov     edx, [ecx+4]                    /* copy cif */
        mov     eax, [ecx+8]                    /* copy fun */
@@ -273,7 +273,7 @@ L(UW10):
        mov     [esp+closure_CF+36], ecx        /* closure is user_data */
        jmp     L(do_closure_i386)
 L(UW11):
-       // cfi_endproc
+       /* cfi_endproc */
 ENDF(ffi_go_closure_ECX)
 
 /* The closure entry points are reached from the ffi_closure trampoline.
@@ -283,10 +283,10 @@ ALIGN 16
 PUBLIC ffi_closure_i386
 ffi_closure_i386 PROC C
 L(UW12):
-       // cfi_startproc
+       /* cfi_startproc */
        sub         esp, closure_FS
 L(UW13):
-       // cfi_def_cfa_offset(closure_FS + 4)
+       /* cfi_def_cfa_offset(closure_FS + 4) */
 
        FFI_CLOSURE_SAVE_REGS
        FFI_CLOSURE_COPY_TRAMP_DATA
@@ -331,17 +331,17 @@ E(L(load_table2), X86_RET_VOID)
 L(e2):
        add     esp, closure_FS
 L(UW16):
-       // cfi_adjust_cfa_offset(-closure_FS)
+       /* cfi_adjust_cfa_offset(-closure_FS) */
        ret
 L(UW17):
-       // cfi_adjust_cfa_offset(closure_FS)
+       /* 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)
+       /* cfi_adjust_cfa_offset(-closure_FS) */
        ret     4
 L(UW19):
-       // cfi_adjust_cfa_offset(closure_FS)
+       /* cfi_adjust_cfa_offset(closure_FS) */
 E(L(load_table2), X86_RET_STRUCTARG)
        jmp     L(e2)
 E(L(load_table2), X86_RET_STRUCT_1B)
@@ -358,17 +358,17 @@ E(L(load_table2), X86_RET_UNUSED15)
        int 3
 
 L(UW20):
-       // cfi_endproc
+       /* cfi_endproc */
 ENDF(ffi_closure_i386)
 
 ALIGN 16
 PUBLIC ffi_go_closure_STDCALL
 ffi_go_closure_STDCALL PROC C
 L(UW21):
-       // cfi_startproc
+       /* cfi_startproc */
        sub     esp, closure_FS
 L(UW22):
-       // cfi_def_cfa_offset(closure_FS + 4)
+       /* cfi_def_cfa_offset(closure_FS + 4) */
        FFI_CLOSURE_SAVE_REGS
        mov     edx, [ecx+4]                    /* copy cif */
        mov     eax, [ecx+8]                    /* copy fun */
@@ -377,7 +377,7 @@ L(UW22):
        mov     [esp+closure_CF+36], ecx        /* closure is user_data */
        jmp     L(do_closure_STDCALL)
 L(UW23):
-       // cfi_endproc
+       /* cfi_endproc */
 ENDF(ffi_go_closure_STDCALL)
 
 /* For REGISTER, we have no available parameter registers, and so we
@@ -387,19 +387,19 @@ ALIGN 16
 PUBLIC ffi_closure_REGISTER
 ffi_closure_REGISTER PROC C
 L(UW24):
-       // cfi_startproc
-       // cfi_def_cfa(%esp, 8)
-       // cfi_offset(%eip, -8)
+       /* 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)
+       /* 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
+       /* cfi_endproc */
 ENDF(ffi_closure_REGISTER)
 
 /* For STDCALL (and others), we need to pop N bytes of arguments off
@@ -410,10 +410,10 @@ ALIGN 16
 PUBLIC ffi_closure_STDCALL
 ffi_closure_STDCALL PROC C
 L(UW27):
-       // cfi_startproc
+       /* cfi_startproc */
        sub     esp, closure_FS
 L(UW28):
-       // cfi_def_cfa_offset(closure_FS + 4)
+       /* cfi_def_cfa_offset(closure_FS + 4) */
 
        FFI_CLOSURE_SAVE_REGS
 
@@ -504,7 +504,7 @@ E(L(load_table3), X86_RET_UNUSED15)
        int 3
 
 L(UW31):
-       // cfi_endproc
+       /* cfi_endproc */
 ENDF(ffi_closure_STDCALL)
 
 #if !FFI_NO_RAW_API
@@ -515,13 +515,13 @@ ALIGN 16
 PUBLIC ffi_closure_raw_SYSV
 ffi_closure_raw_SYSV PROC C
 L(UW32):
-       // cfi_startproc
+       /* cfi_startproc */
        sub     esp, raw_closure_S_FS
 L(UW33):
-       // cfi_def_cfa_offset(raw_closure_S_FS + 4)
+       /* 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)
+       /* cfi_rel_offset(%ebx, raw_closure_S_FS-4) */
 
        mov     edx, [eax+FFI_TRAMPOLINE_SIZE+8]        /* load cl->user_data */
        mov     [esp+12], edx
@@ -535,16 +535,16 @@ L(UW34):
 
        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
+/* #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
+/* #endif */
        mov     ebx, [esp+raw_closure_S_FS-4]
 L(UW35):
-       // cfi_restore(%ebx)
+       /* cfi_restore(%ebx) */
        mov     eax, [esp+16]                           /* Optimistic load */
        jmp         dword ptr [ecx]
 
@@ -581,17 +581,17 @@ 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)
+       /* cfi_adjust_cfa_offset(-raw_closure_S_FS) */
        ret
 L(UW37):
-       // cfi_adjust_cfa_offset(raw_closure_S_FS)
+       /* 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)
+       /* cfi_adjust_cfa_offset(-raw_closure_S_FS) */
        ret     4
 L(UW39):
-       // cfi_adjust_cfa_offset(raw_closure_S_FS)
+       /* 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)
@@ -608,7 +608,7 @@ E(L(load_table4), X86_RET_UNUSED15)
        int 3
 
 L(UW40):
-       // cfi_endproc
+       /* cfi_endproc */
 ENDF(ffi_closure_raw_SYSV)
 
 #define raw_closure_T_FS       (16+16+8)
@@ -617,26 +617,26 @@ ALIGN 16
 PUBLIC ffi_closure_raw_THISCALL
 ffi_closure_raw_THISCALL PROC C
 L(UW41):
-       // cfi_startproc
+       /* 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)
+       /* cfi_def_cfa_offset(0) */
+       /* cfi_register(%eip, %edx) */
        push    ecx
 L(UW43):
-       // cfi_adjust_cfa_offset(4)
+       /* cfi_adjust_cfa_offset(4) */
        push    edx
 L(UW44):
-       // cfi_adjust_cfa_offset(4)
-       // cfi_rel_offset(%eip, 0)
+       /* 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)
+       /* 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)
+       /* cfi_rel_offset(%ebx, raw_closure_T_FS-4) */
 
        mov     edx, [eax+FFI_TRAMPOLINE_SIZE+8]        /* load cl->user_data */
        mov     [esp+12], edx
@@ -650,16 +650,16 @@ L(UW46):
 
        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
+/* #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
+/*#endif */
        mov     ebx, [esp+raw_closure_T_FS-4]
 L(UW47):
-       // cfi_restore(%ebx)
+       /* cfi_restore(%ebx) */
        mov     eax, [esp+16]                           /* Optimistic load */
        jmp         DWORD PTR [ecx]
 
@@ -696,18 +696,18 @@ 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)
+       /* 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)
+       /* 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)
+       /* cfi_adjust_cfa_offset(-raw_closure_T_FS) */
        ret     8
 L(UW51):
-       // cfi_adjust_cfa_offset(raw_closure_T_FS)
+       /* 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)
@@ -724,7 +724,7 @@ E(L(load_table5), X86_RET_UNUSED15)
        int 3
 
 L(UW52):
-       // cfi_endproc
+       /* cfi_endproc */
 ENDF(ffi_closure_raw_THISCALL)
 
 #endif /* !FFI_NO_RAW_API */
@@ -743,20 +743,23 @@ ENDF(ffi_closure_raw_THISCALL)
 # 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
+#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__ */
+#endif
+
 
 #if 0
 /* Sadly, OSX cctools-as doesn't understand .cfi directives at all.  */
@@ -992,4 +995,4 @@ L(EFDE9):
 #endif
 #endif
 
-END
\ No newline at end of file
+END
index ca6fe0cb4cfabb26f19f56b9654af9ecd1a75cf4..d9c5bd4c720db1b2feda988dd5b1854331c163ad 100644 (file)
    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__))
+#ifdef __CET__
+/* Double slot size to 16 byte to add 4 bytes of ENDBR64.  */
+# define E(BASE, X)    .balign 8; .org BASE + X * 16
+#elif defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
 # define E(BASE, X)    .balign 8
 #else
-# ifdef __CET__
-#  define E(BASE, X)   .balign 8; .org BASE + X * 16
-# else
-#  define E(BASE, X)   .balign 8; .org BASE + X * 8
-# endif
+# define E(BASE, X)    .balign 8; .org BASE + X * 8
 #endif
 
 /* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
@@ -505,11 +504,19 @@ C(ffi_closure_unix64_alt):
  * - restore the stack pointer to what it was when the trampoline was invoked.
  */
 #ifdef ENDBR_PRESENT
-#define X86_DATA_OFFSET                4077
-#define X86_CODE_OFFSET                4073
+# define X86_DATA_OFFSET       4077
+# ifdef __ILP32__
+#  define X86_CODE_OFFSET      4069
+# else
+#  define X86_CODE_OFFSET      4073
+# endif
 #else
-#define X86_DATA_OFFSET                4081
-#define X86_CODE_OFFSET                4077
+# define X86_DATA_OFFSET       4081
+# ifdef __ILP32__
+#  define X86_CODE_OFFSET      4073
+# else
+#  define X86_CODE_OFFSET      4077
+# endif
 #endif
 
        .align  UNIX64_TRAMP_MAP_SIZE
@@ -521,9 +528,17 @@ C(trampoline_code_table):
        _CET_ENDBR
        subq    $16, %rsp                       /* Make space on the stack */
        movq    %r10, (%rsp)                    /* Save %r10 on stack */
+#ifdef __ILP32__
+       movl    X86_DATA_OFFSET(%rip), %r10d    /* Copy data into %r10 */
+#else
        movq    X86_DATA_OFFSET(%rip), %r10     /* Copy data into %r10 */
+#endif
        movq    %r10, 8(%rsp)                   /* Save data on stack */
+#ifdef __ILP32__
+       movl    X86_CODE_OFFSET(%rip), %r10d    /* Copy code into %r10 */
+#else
        movq    X86_CODE_OFFSET(%rip), %r10     /* Copy code into %r10 */
+#endif
        jmp     *%r10                           /* Jump to code */
        .align  8
        .endr
index 9a0575ff90d44ef74fee170e1bc4b3800b75eedf..82b42a16d25307af9202a1350b189ded5a500639 100644 (file)
@@ -86,11 +86,16 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
       break;
   }
 
-  /* 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 = FFI_ALIGN(cif->bytes, 16);
-
+  /* Round up stack size needed for arguments.
+     Allocate FFI_REGISTER_ARGS_SPACE bytes when there are only arguments
+     passed in registers, round space reserved for arguments passed on stack
+     up to ABI-specified alignment.  */
+  if (cif->bytes < FFI_REGISTER_NARGS * 4)
+    cif->bytes = FFI_REGISTER_ARGS_SPACE;
+  else
+    cif->bytes = FFI_REGISTER_ARGS_SPACE +
+           FFI_ALIGN(cif->bytes - FFI_REGISTER_NARGS * 4,
+                     XTENSA_STACK_ALIGNMENT);
   return FFI_OK;
 }
 
@@ -232,6 +237,9 @@ ffi_prep_closure_loc (ffi_closure* closure,
                       void *user_data,
                       void *codeloc)
 {
+  if (cif->abi != FFI_SYSV)
+    return FFI_BAD_ABI;
+
   /* copye trampoline to stack and patch 'ffi_closure_SYSV' pointer */
   memcpy(closure->tramp, ffi_trampoline, FFI_TRAMPOLINE_SIZE);
   *(unsigned int*)(&closure->tramp[8]) = (unsigned int)ffi_closure_SYSV;
@@ -277,15 +285,15 @@ ffi_closure_SYSV_inner(ffi_closure *closure, void **values, void *rvalue)
     if (arg_types[i]->alignment == 8 && (areg & 1) != 0)
       areg++;
 
-    // skip the entry 16,a1 framework, add 16 bytes (4 registers)
+    // skip the entry a1, * framework, see ffi_trampoline
     if (areg == FFI_REGISTER_NARGS)
-      areg += 4;
+      areg = (FFI_REGISTER_ARGS_SPACE + 32) / 4;
 
     if (arg_types[i]->type == FFI_TYPE_STRUCT)
     {
       int numregs = ((arg_types[i]->size + 3) & ~3) / 4;
       if (areg < FFI_REGISTER_NARGS && areg + numregs > FFI_REGISTER_NARGS)
-        areg = FFI_REGISTER_NARGS + 4;
+        areg = (FFI_REGISTER_ARGS_SPACE + 32) / 4;
     }
 
     avalue[i] = &values[areg];
index 0ba728bc948c8abe34c288b327ed9c2b41de5b9b..4231ed374ebe47333904f4729ac765e24e409403 100644 (file)
@@ -43,6 +43,10 @@ typedef enum ffi_abi {
 #endif
 
 #define FFI_REGISTER_NARGS     6
+#define XTENSA_STACK_ALIGNMENT 16
+#define FFI_REGISTER_ARGS_SPACE ((FFI_REGISTER_NARGS * 4 + \
+                                 XTENSA_STACK_ALIGNMENT - 1) & \
+                                 -XTENSA_STACK_ALIGNMENT)
 
 /* ---- Definitions for closures ----------------------------------------- */
 
index e9421796fd868ea6898552114d714e8e37867392..70e83ac2283e2e5206bc0eaa41a24888af5ec126 100644 (file)
@@ -43,6 +43,9 @@
 #error "xtensa/sysv.S out of sync with ffi.h"
 #endif
 
+#define FFI_REGISTER_ARGS_OFFSET ((XTENSA_STACK_ALIGNMENT - \
+                                  FFI_REGISTER_NARGS * 4) & \
+                                  (XTENSA_STACK_ALIGNMENT - 1))
 
 /* ffi_call_SYSV (rvalue, rbytes, flags, (*fnaddr)(), bytes, ecif)
       void *rvalue;            a2
@@ -62,28 +65,28 @@ ENTRY(ffi_call_SYSV)
        mov     a7, a1              # fp
        movsp   a1, a11             # set new sp = old_sp - bytes
 
+       # align ffi_prep_args stack argument so that arguments
+       # passed on stack if any start on 16-byte aligned boundary
+
+       addi    a11, a11, FFI_REGISTER_ARGS_OFFSET
+
        movi    a8, ffi_prep_args
        callx8  a8                  # ffi_prep_args(ecif, stack)
 
-       # prepare to move stack pointer back up to 6 arguments
-       # note that 'bytes' is already aligned
-
-       movi    a10, 6*4 
-       sub     a11, a6, a10
-       movgez  a6, a10, a11
-       add     a6, a1, a6
+       # prepare to move stack pointer back
+       # to point to arguments passed on stack
 
+       addi    a6, a1, FFI_REGISTER_ARGS_SPACE
        
        # we can pass up to 6 arguments in registers
        # for simplicity, just load 6 arguments
-       # (the stack size is at least 32 bytes, so no risk to cross boundaries)
 
-       l32i    a10, a1, 0
-       l32i    a11, a1, 4
-       l32i    a12, a1, 8
-       l32i    a13, a1, 12
-       l32i    a14, a1, 16
-       l32i    a15, a1, 20
+       l32i    a10, a1, FFI_REGISTER_ARGS_OFFSET + 0
+       l32i    a11, a1, FFI_REGISTER_ARGS_OFFSET + 4
+       l32i    a12, a1, FFI_REGISTER_ARGS_OFFSET + 8
+       l32i    a13, a1, FFI_REGISTER_ARGS_OFFSET + 12
+       l32i    a14, a1, FFI_REGISTER_ARGS_OFFSET + 16
+       l32i    a15, a1, FFI_REGISTER_ARGS_OFFSET + 20
 
        # move stack pointer
 
@@ -167,7 +170,7 @@ END(ffi_call_SYSV)
 
 ENTRY(ffi_cacheflush)
 
-       entry   a1, 16
+       entry   a1, 32
 
 1:     
 #if XCHAL_DCACHE_SIZE
@@ -187,7 +190,14 @@ END(ffi_cacheflush)
 
 ENTRY(ffi_trampoline)
 
-       entry   a1, 16 + (FFI_REGISTER_NARGS * 4) + (4 * 4)   # [ 0]
+       /* 32 bytes for spill + spill overflow area of a frame that uses
+          call8,
+          FFI_REGISTER_NARGS * 4 bytes for arguments passed in registers,
+          aligned up to 4 to maintain 16 byte stack alignment,
+          4 * 4 bytes for the result.
+          This size must be in sync with ffi_closure_SYSV_inner logic.
+        */
+       entry   a1, 32 + FFI_REGISTER_ARGS_SPACE + (4 * 4)   # [ 0]
        j       2f                                # [ 3]
        .align  4                                 # [ 6]
 1:     .long   0                                 # [ 8]
index 1e4b35a34117defde95a90ae614032339f550910..2e422b9a44e8e0040e6946eb6b200f0c598f2182 100644 (file)
@@ -6,121 +6,84 @@ EXTRA_DEJAGNU_SITE_CONFIG=../local.exp
 
 CLEANFILES = *.exe core* *.log *.sum
 
-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_2.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/closure_fn0.c libffi.closures/huge_struct.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/nested_struct12.c \
-libffi.closures/nested_struct13.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 \
-libffi.closures/single_entry_structs1.c \
-libffi.closures/single_entry_structs2.c \
-libffi.closures/single_entry_structs3.c
+EXTRA_DIST = config/default.exp emscripten/build.sh emscripten/conftest.py \
+       emscripten/node-tests.sh emscripten/test.html emscripten/test_libffi.py \
+       emscripten/build-tests.sh lib/libffi.exp lib/target-libpath.exp \
+       lib/wrapper.exp libffi.bhaible/Makefile libffi.bhaible/README \
+       libffi.bhaible/alignof.h libffi.bhaible/bhaible.exp libffi.bhaible/test-call.c \
+       libffi.bhaible/test-callback.c libffi.bhaible/testcases.c libffi.call/align_mixed.c \
+       libffi.call/align_stdcall.c libffi.call/bpo_38748.c libffi.call/call.exp \
+       libffi.call/err_bad_typedef.c libffi.call/ffitest.h libffi.call/float.c \
+       libffi.call/float1.c libffi.call/float2.c libffi.call/float3.c \
+       libffi.call/float4.c libffi.call/float_va.c libffi.call/many.c \
+       libffi.call/many2.c libffi.call/many_double.c libffi.call/many_mixed.c \
+       libffi.call/negint.c libffi.call/offsets.c libffi.call/overread.c \
+       libffi.call/pr1172638.c libffi.call/promotion.c libffi.call/pyobjc_tc.c libffi.call/return_dbl.c \
+       libffi.call/return_dbl1.c libffi.call/return_dbl2.c libffi.call/return_fl.c \
+       libffi.call/return_fl1.c libffi.call/return_fl2.c libffi.call/return_fl3.c \
+       libffi.call/return_ldl.c libffi.call/return_ll.c libffi.call/return_ll1.c \
+       libffi.call/return_sc.c libffi.call/return_sl.c libffi.call/return_uc.c \
+       libffi.call/return_ul.c libffi.call/s55.c libffi.call/strlen.c \
+       libffi.call/strlen2.c libffi.call/strlen3.c libffi.call/strlen4.c \
+       libffi.call/struct1.c libffi.call/struct10.c libffi.call/struct2.c \
+       libffi.call/struct3.c libffi.call/struct4.c libffi.call/struct5.c \
+       libffi.call/struct6.c libffi.call/struct7.c libffi.call/struct8.c \
+       libffi.call/struct9.c libffi.call/struct_by_value_2.c libffi.call/struct_by_value_3.c \
+       libffi.call/struct_by_value_3f.c libffi.call/struct_by_value_4.c libffi.call/struct_by_value_4f.c \
+       libffi.call/struct_by_value_big.c libffi.call/struct_by_value_small.c libffi.call/struct_return_2H.c \
+       libffi.call/struct_int_float.c libffi.call/longjmp.c \
+       libffi.call/struct_return_8H.c libffi.call/uninitialized.c libffi.call/va_1.c \
+       libffi.call/va_2.c libffi.call/va_3.c libffi.call/va_struct1.c \
+       libffi.call/va_struct2.c libffi.call/va_struct3.c libffi.call/callback.c \
+       libffi.call/callback2.c libffi.call/callback3.c libffi.call/callback4.c libffi.call/x32.c \
+       libffi.closures/closure.exp libffi.closures/closure_fn0.c libffi.closures/closure_fn1.c \
+       libffi.closures/closure_fn2.c libffi.closures/closure_fn3.c libffi.closures/closure_fn4.c \
+       libffi.closures/closure_fn5.c libffi.closures/closure_fn6.c libffi.closures/closure_loc_fn0.c \
+       libffi.closures/closure_simple.c libffi.closures/cls_12byte.c libffi.closures/cls_16byte.c \
+       libffi.closures/cls_18byte.c libffi.closures/cls_19byte.c libffi.closures/cls_1_1byte.c \
+       libffi.closures/cls_20byte.c libffi.closures/cls_20byte1.c libffi.closures/cls_24byte.c \
+       libffi.closures/cls_2byte.c libffi.closures/cls_3_1byte.c libffi.closures/cls_3byte1.c \
+       libffi.closures/cls_3byte2.c libffi.closures/cls_3float.c libffi.closures/cls_4_1byte.c \
+       libffi.closures/cls_4byte.c libffi.closures/cls_5_1_byte.c libffi.closures/cls_5byte.c \
+       libffi.closures/cls_64byte.c libffi.closures/cls_6_1_byte.c libffi.closures/cls_6byte.c \
+       libffi.closures/cls_7_1_byte.c libffi.closures/cls_7byte.c libffi.closures/cls_8byte.c \
+       libffi.closures/cls_9byte1.c libffi.closures/cls_9byte2.c libffi.closures/cls_align_double.c \
+       libffi.closures/cls_align_float.c libffi.closures/cls_align_longdouble.c libffi.closures/cls_align_longdouble_split.c \
+       libffi.closures/cls_align_longdouble_split2.c libffi.closures/cls_align_pointer.c libffi.closures/cls_align_sint16.c \
+       libffi.closures/cls_align_sint32.c libffi.closures/cls_align_sint64.c libffi.closures/cls_align_uint16.c \
+       libffi.closures/cls_align_uint32.c libffi.closures/cls_align_uint64.c libffi.closures/cls_dbls_struct.c \
+       libffi.closures/cls_double.c libffi.closures/cls_double_va.c libffi.closures/cls_float.c \
+       libffi.closures/cls_longdouble.c libffi.closures/cls_longdouble_va.c libffi.closures/cls_many_mixed_args.c \
+       libffi.closures/cls_many_mixed_float_double.c libffi.closures/cls_multi_schar.c libffi.closures/cls_multi_sshort.c \
+       libffi.closures/cls_multi_sshortchar.c libffi.closures/cls_multi_uchar.c libffi.closures/cls_multi_ushort.c \
+       libffi.closures/cls_multi_ushortchar.c libffi.closures/cls_pointer.c libffi.closures/cls_pointer_stack.c \
+       libffi.closures/cls_schar.c libffi.closures/cls_sint.c libffi.closures/cls_sshort.c \
+       libffi.closures/cls_struct_va1.c libffi.closures/cls_uchar.c libffi.closures/cls_uint.c \
+       libffi.closures/cls_uint_va.c libffi.closures/cls_ulong_va.c libffi.closures/cls_ulonglong.c \
+       libffi.closures/cls_ushort.c libffi.closures/err_bad_abi.c libffi.closures/ffitest.h \
+       libffi.closures/huge_struct.c libffi.closures/nested_struct.c libffi.closures/nested_struct1.c \
+       libffi.closures/nested_struct10.c libffi.closures/nested_struct11.c libffi.closures/nested_struct12.c \
+       libffi.closures/nested_struct13.c libffi.closures/nested_struct2.c libffi.closures/nested_struct3.c \
+       libffi.closures/nested_struct4.c libffi.closures/nested_struct5.c libffi.closures/nested_struct6.c \
+       libffi.closures/nested_struct7.c libffi.closures/nested_struct8.c libffi.closures/nested_struct9.c \
+       libffi.closures/problem1.c libffi.closures/single_entry_structs1.c libffi.closures/single_entry_structs2.c \
+       libffi.closures/single_entry_structs3.c libffi.closures/stret_large.c libffi.closures/stret_large2.c \
+       libffi.closures/stret_medium.c libffi.closures/stret_medium2.c libffi.closures/testclosure.c \
+       libffi.closures/unwindtest.cc libffi.closures/unwindtest_ffi_call.cc libffi.complex/cls_align_complex.inc \
+       libffi.complex/cls_align_complex_double.c libffi.complex/cls_align_complex_float.c libffi.complex/cls_align_complex_longdouble.c \
+       libffi.complex/cls_complex.inc libffi.complex/cls_complex_double.c libffi.complex/cls_complex_float.c \
+       libffi.complex/cls_complex_longdouble.c libffi.complex/cls_complex_struct.inc libffi.complex/cls_complex_struct_double.c \
+       libffi.complex/cls_complex_struct_float.c libffi.complex/cls_complex_struct_longdouble.c libffi.complex/cls_complex_va.inc \
+       libffi.complex/cls_complex_va_double.c libffi.complex/cls_complex_va_float.c libffi.complex/cls_complex_va_longdouble.c \
+       libffi.complex/complex.exp libffi.complex/complex.inc libffi.complex/complex_defs_double.inc \
+       libffi.complex/complex_defs_float.inc libffi.complex/complex_defs_longdouble.inc libffi.complex/complex_double.c \
+       libffi.complex/complex_float.c libffi.complex/complex_int.c libffi.complex/complex_longdouble.c \
+       libffi.complex/ffitest.h libffi.complex/many_complex.inc libffi.complex/many_complex_double.c \
+       libffi.complex/many_complex_float.c libffi.complex/many_complex_longdouble.c libffi.complex/return_complex.inc \
+       libffi.complex/return_complex1.inc libffi.complex/return_complex1_double.c libffi.complex/return_complex1_float.c \
+       libffi.complex/return_complex1_longdouble.c libffi.complex/return_complex2.inc libffi.complex/return_complex2_double.c \
+       libffi.complex/return_complex2_float.c libffi.complex/return_complex2_longdouble.c libffi.complex/return_complex_double.c \
+       libffi.complex/return_complex_float.c libffi.complex/return_complex_longdouble.c libffi.go/aa-direct.c \
+       libffi.go/closure1.c libffi.go/ffitest.h libffi.go/go.exp \
+       libffi.go/static-chain.h Makefile.am Makefile.in \
+       libffi.threads/ffitest.h libffi.threads/threads.exp libffi.threads/tsan.c
diff --git a/libffi/testsuite/emscripten/build-tests.sh b/libffi/testsuite/emscripten/build-tests.sh
new file mode 100755 (executable)
index 0000000..2f1dd8d
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+if ! [ -x "$(command -v emcc)" ]; then
+  echo "Error: emcc could not be found." >&2
+  exit 1
+fi
+
+set -e
+
+cd "$1"
+shift
+
+export CFLAGS="-fPIC -O2 -I../../target/include $EXTRA_CFLAGS"
+export CXXFLAGS="$CFLAGS -sNO_DISABLE_EXCEPTION_CATCHING $EXTRA_CXXFLAGS"
+export LDFLAGS=" \
+    -L../../target/lib/ -lffi \
+    -sEXPORT_ALL \
+    -sMODULARIZE \
+    -sMAIN_MODULE \
+    -sNO_DISABLE_EXCEPTION_CATCHING \
+    -sWASM_BIGINT \
+    $EXTRA_LD_FLAGS \
+"
+
+# Rename main functions to test__filename so we can link them together
+ls *c | sed 's!\(.*\)\.c!sed -i "s/main/test__\1/g" \0!g' | bash
+
+# Compile
+ls *.c | sed 's/\(.*\)\.c/emcc $CFLAGS -c \1.c -o \1.o /g' | bash
+ls *.cc | sed 's/\(.*\)\.cc/em++ $CXXFLAGS -c \1.cc -o \1.o /g' | bash
+
+# Link
+em++ $LDFLAGS *.o -o test.js
+cp ../emscripten/test.html .
diff --git a/libffi/testsuite/emscripten/build.sh b/libffi/testsuite/emscripten/build.sh
new file mode 100755 (executable)
index 0000000..a332c1d
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+if ! [ -x "$(command -v emcc)" ]; then
+  echo "Error: emcc could not be found." >&2
+  exit 1
+fi
+
+set -e
+
+SOURCE_DIR=$PWD
+
+# Working directories
+TARGET=$SOURCE_DIR/target
+mkdir -p "$TARGET"
+
+# Define default arguments
+DEBUG=false
+
+# Parse arguments
+while [ $# -gt 0 ]; do
+  case $1 in
+    --debug) DEBUG=true ;;
+    *) echo "ERROR: Unknown parameter: $1" >&2; exit 1 ;;
+  esac
+  shift
+done
+
+# Common compiler flags
+export CFLAGS="-O3 -fPIC"
+if [ "$DEBUG" = "true" ]; then export CFLAGS+=" -DDEBUG_F"; fi
+export CXXFLAGS="$CFLAGS"
+
+# Build paths
+export CPATH="$TARGET/include"
+export PKG_CONFIG_PATH="$TARGET/lib/pkgconfig"
+export EM_PKG_CONFIG_PATH="$PKG_CONFIG_PATH"
+
+# Specific variables for cross-compilation
+export CHOST="${TARGET_HOST}-unknown-linux" # wasm32-unknown-emscripten
+
+autoreconf -fiv
+emconfigure ./configure --host=$CHOST --prefix="$TARGET" --enable-static --disable-shared --disable-dependency-tracking \
+  --disable-builddir --disable-multi-os-directory --disable-raw-api --disable-docs ${EXTRA_CONFIGURE_FLAGS}
+make install
+cp fficonfig.h target/include/
+cp include/ffi_common.h target/include/
diff --git a/libffi/testsuite/emscripten/conftest.py b/libffi/testsuite/emscripten/conftest.py
new file mode 100644 (file)
index 0000000..b2e36dd
--- /dev/null
@@ -0,0 +1,86 @@
+from pathlib import Path
+from pytest import fixture
+from pytest_pyodide.server import spawn_web_server
+from pytest_pyodide import runner
+
+import logging
+
+TEST_PATH = Path(__file__).parents[1].resolve()
+
+
+class BaseRunner(runner._BrowserBaseRunner):
+    def __init__(
+        self,
+        *args,
+        test_dir,
+        **kwargs,
+    ):
+        self.test_dir = test_dir
+        super().__init__(
+            *args,
+            **kwargs,
+            load_pyodide=False,
+        )
+
+    def prepare_driver(self):
+        self.base_url = (
+            f"http://{self.server_hostname}:{self.server_port}/{self.test_dir}/"
+        )
+        self.goto(f"{self.base_url}/test.html")
+
+    def javascript_setup(self):
+        self.run_js("globalThis.TestModule = await globalThis.Module();")
+
+
+class FirefoxRunner(BaseRunner, runner.SeleniumFirefoxRunner):
+    pass
+
+
+class ChromeRunner(BaseRunner, runner.SeleniumChromeRunner):
+    pass
+
+
+# TODO: Figure out how to get NodeRunner to work.
+
+RUNNER_DICT = {x.browser: x for x in [FirefoxRunner, ChromeRunner]}
+
+
+@fixture(params=list(RUNNER_DICT), scope="class")
+def selenium_class_scope(request, web_server_main):
+    server_hostname, server_port, server_log = web_server_main
+    assert request.param in RUNNER_DICT
+
+    logger = logging.getLogger('selenium')
+    logger.setLevel(logging.DEBUG)
+
+    cls = RUNNER_DICT[request.param]
+    selenium = cls(
+        test_dir=request.cls.TEST_BUILD_DIR,
+        server_port=server_port,
+        server_hostname=server_hostname,
+        server_log=server_log,
+    )
+    request.cls.call_number = 0
+    try:
+        yield selenium
+    finally:
+        print(selenium.logs)
+        selenium.driver.quit()
+
+
+@fixture(scope="function")
+def selenium(selenium_class_scope, request):
+    selenium = selenium_class_scope
+    request.cls.call_number += 1
+    # Refresh page every 50 calls to prevent firefox out of memory errors
+    if request.cls.call_number % 50 == 0:
+        selenium.driver.refresh()
+        selenium.javascript_setup()
+    selenium.clean_logs()
+    yield selenium
+
+
+@fixture(scope="session")
+def web_server_main(request):
+    with spawn_web_server(TEST_PATH) as output:
+        yield output
diff --git a/libffi/testsuite/emscripten/node-tests.sh b/libffi/testsuite/emscripten/node-tests.sh
new file mode 100755 (executable)
index 0000000..2710947
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+if ! [ -x "$(command -v emcc)" ]; then
+  echo "Error: emcc could not be found." >&2
+  exit 1
+fi
+
+# Common compiler flags
+export CFLAGS="-fPIC $EXTRA_CFLAGS"
+export CXXFLAGS="$CFLAGS -sNO_DISABLE_EXCEPTION_CATCHING $EXTRA_CXXFLAGS"
+export LDFLAGS="-sEXPORTED_FUNCTIONS=_main,_malloc,_free -sALLOW_TABLE_GROWTH -sASSERTIONS -sNO_DISABLE_EXCEPTION_CATCHING -sWASM_BIGINT -Wno-main"
+
+# Specific variables for cross-compilation
+export CHOST="${TARGET_HOST}-unknown-linux" # wasm32-unknown-emscripten
+
+autoreconf -fiv
+emconfigure ./configure --prefix="$(pwd)/target" --host=$CHOST --enable-static --disable-shared \
+  --disable-builddir --disable-multi-os-directory --disable-raw-api --disable-docs ${EXTRA_CONFIGURE_FLAGS} ||
+  (cat config.log && exit 1)
+make
+
+EMMAKEN_JUST_CONFIGURE=1 emmake make check \
+  RUNTESTFLAGS="LDFLAGS_FOR_TARGET='$LDFLAGS $EXTRA_TEST_LDFLAGS'" || (cat testsuite/libffi.log && exit 1)
diff --git a/libffi/testsuite/emscripten/test.html b/libffi/testsuite/emscripten/test.html
new file mode 100644 (file)
index 0000000..7701503
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <script src="test.js"></script>
+  </head>
+  <body></body>
+</html>
diff --git a/libffi/testsuite/emscripten/test_libffi.py b/libffi/testsuite/emscripten/test_libffi.py
new file mode 100644 (file)
index 0000000..059d535
--- /dev/null
@@ -0,0 +1,51 @@
+import subprocess
+import pathlib
+import pytest
+
+TEST_PATH = pathlib.Path(__file__).parents[1].resolve()
+
+xfails = {}
+
+
+def libffi_tests(self, selenium, libffi_test):
+    if libffi_test in xfails:
+        pytest.xfail(f'known failure with code "{xfails[libffi_test]}"')
+    res = selenium.run_js(
+        """
+        window.TestModule = await Module();
+        """
+    )
+    selenium.run_js(
+        f"""
+        try {{
+            TestModule._test__{libffi_test}();
+        }} catch(e){{
+            if(e.name !== "ExitStatus"){{
+                throw e;
+            }}
+            if(e.status !== 0){{
+                throw new Error(`Terminated with nonzero status code ${{e.status}}: ` + e.message);
+            }}
+        }}
+        """
+    )
+
+
+class TestCall:
+    TEST_BUILD_DIR = "libffi.call.test"
+    test_call = libffi_tests
+
+
+class TestClosures:
+    TEST_BUILD_DIR = "libffi.closures.test"
+    test_closures = libffi_tests
+
+
+def pytest_generate_tests(metafunc):
+    test_build_dir = metafunc.cls.TEST_BUILD_DIR
+    test_names = [x.stem for x in (TEST_PATH / test_build_dir).glob("*.o")]
+    metafunc.parametrize("libffi_test", test_names)
+
+
+if __name__ == "__main__":
+    subprocess.call(["build-tests.sh", "libffi.call"])
index c1ae32d987d075835c0ff8355cb1077305d0a555..81eff7752d1cfdd0077564d83f91cf05a41fa181 100644 (file)
@@ -1,4 +1,4 @@
-#   Copyright (C) 2003, 2005, 2008, 2009, 2010, 2011, 2014, 2019 Free Software Foundation, Inc.
+#   Copyright (C) 2003, 2005, 2008, 2009, 2010, 2011, 2014, 2019, 2022, 2025 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
 # <http://www.gnu.org/licenses/>.
 
 proc load_gcc_lib { filename } {
-    global srcdir loaded_libs
-    load_file $srcdir/../../gcc/testsuite/lib/$filename
-    set loaded_libs($filename) ""
+    global srcdir
+    load_file $srcdir/lib/$filename
 }
 
 load_lib dg.exp
 load_lib libgloss.exp
-load_gcc_lib target-supports.exp
-load_gcc_lib target-supports-dg.exp
 load_gcc_lib target-libpath.exp
 load_gcc_lib wrapper.exp
 
@@ -41,14 +38,14 @@ 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
+        # 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}]
+        set selected [check_effective_target_${arg}]
     } else {
-       error "unknown effective target keyword `$arg'" 
+        error "unknown effective target keyword `$arg'"
     }
     verbose "is-effective-target: $arg $selected" 2
     return $selected
@@ -56,9 +53,9 @@ proc is-effective-target { arg } {
 
 proc is-effective-target-keyword { arg } {
     if { [info procs check_effective_target_${arg}] != [list] } {
-       return 1
+        return 1
     } else {
-       return 0
+        return 0
     }
 }
 
@@ -90,93 +87,93 @@ if { [info procs saved-dg-process-target] == [list] } {
 
     # 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
+        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
+        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
+        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]
+        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
@@ -184,24 +181,24 @@ if { [info procs saved-dg-process-target] == [list] } {
     # "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]
+        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]
     }
 }
 
@@ -220,42 +217,49 @@ proc libffi-dg-test-1 { target_compile prog do_what extra_tool_flags } {
     upvar 2 dg-output-text output_match
 
     if { [llength $output_match] > 1 } {
-       regsub -all "\n" [lindex $output_match 1] "\r?\n" x
-       set output_match [lreplace $output_match 1 1 $x]
+        regsub -all "\n" [lindex $output_match 1] "\r?\n" x
+        set output_match [lreplace $output_match 1 1 $x]
+    }
+
+    if { [ istarget "wasm32-*-*" ] } {
+        # emscripten will get confused if told to build as .exe
+        set exec_suffix ""
+    } else {
+        set exec_suffix ".exe"
     }
 
     # Set up the compiler flags, based on what we're going to do.
 
     set options [list]
     switch $do_what {
-       "compile" {
-           set compile_type "assembly"
-           set output_file "[file rootname [file tail $prog]].s"
-       }
-       "link" {
-           set compile_type "executable"
-           set output_file "[file rootname [file tail $prog]].exe"
-           # The following line is needed for targets like the i960 where
-           # the default output file is b.out.  Sigh.
-       }
-       "run" {
-           set compile_type "executable"
-           # FIXME: "./" is to cope with "." not being in $PATH.
-           # Should this be handled elsewhere?
-           # YES.
-           set output_file "./[file rootname [file tail $prog]].exe"
-           # This is the only place where we care if an executable was
-           # created or not.  If it was, dg.exp will try to run it.
-           remote_file build delete $output_file;
-       }
-       default {
-           perror "$do_what: not a valid dg-do keyword"
-           return ""
-       }
+        "compile" {
+            set compile_type "assembly"
+            set output_file "[file rootname [file tail $prog]].s"
+        }
+        "link" {
+            set compile_type "executable"
+            set output_file "[file rootname [file tail $prog]]$exec_suffix"
+            # The following line is needed for targets like the i960 where
+            # the default output file is b.out.  Sigh.
+        }
+        "run" {
+            set compile_type "executable"
+            # FIXME: "./" is to cope with "." not being in $PATH.
+            # Should this be handled elsewhere?
+            # YES.
+            set output_file "./[file rootname [file tail $prog]]$exec_suffix"
+            # This is the only place where we care if an executable was
+            # created or not.  If it was, dg.exp will try to run it.
+            remote_file build delete $output_file;
+        }
+        default {
+            perror "$do_what: not a valid dg-do keyword"
+            return ""
+        }
     }
 
     if { $extra_tool_flags != "" } {
-       lappend options "additional_flags=$extra_tool_flags"
+        lappend options "additional_flags=$extra_tool_flags"
     }
 
     set comp_output [libffi_target_compile "$prog" "$output_file" "$compile_type" $options];
@@ -272,6 +276,10 @@ proc libffi-dg-test { 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
+    # We get this from sparc64 linux systems
+    regsub -all "(^|\n)\[^\n\]*warning: .* has a LOAD segment with RWX permissions" $text "" text
+    # Ignore Emscripten INFO messages
+    regsub -all "(^|\n)(cache|shared):INFO:\[^\n\]*" $text "" text
     return $text
 }
 
@@ -280,7 +288,6 @@ proc libffi-init { args } {
     global srcdir
     global blddirffi
     global objdir
-    global blddircxx
     global TOOL_OPTIONS
     global tool
     global libffi_include
@@ -289,17 +296,17 @@ proc libffi-init { args } {
     global ld_library_path
     global compiler_vendor
 
-    set blddirffi [lookfor_file [get_multilibs] libffi]
-    verbose "libffi $blddirffi"
-    set blddircxx [lookfor_file [get_multilibs] libstdc++-v3]
-    verbose "libstdc++ $blddircxx"
+    if ![info exists blddirffi] {
+        set blddirffi [pwd]/..
+    }
 
-    set compiler_vendor "gnu"
+    verbose "libffi $blddirffi"
 
+    # Which compiler are we building with?
     if { [string match $compiler_vendor "gnu"] } {
         set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a]
         if {$gccdir != ""} {
-           set gccdir [file dirname $gccdir]
+            set gccdir [file dirname $gccdir]
         }
         verbose "gccdir $gccdir"
 
@@ -308,24 +315,22 @@ proc libffi-init { args } {
 
         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}"
-               }
-           }
+            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}"
+                }
+            }
         }
     }
 
     # add the library path for libffi.
     append ld_library_path ":${blddirffi}/.libs"
-    # add the library path for libstdc++ as well.
-    append ld_library_path ":${blddircxx}/src/.libs"
 
     verbose "ld_library_path: $ld_library_path"
 
@@ -336,14 +341,8 @@ proc libffi-init { args } {
     set libffi_dir  "${blddirffi}/.libs"
     verbose "libffi_dir $libffi_dir"
     if { $libffi_dir != "" } {
-       set libffi_dir [file dirname ${libffi_dir}]
-        if [istarget *-*-darwin*] {
-            set libffi_link_flags "-B${libffi_dir}/.libs"
-           lappend libffi_link_flags "-B${blddircxx}/src/.libs"
-       } else {
-           set libffi_link_flags "-L${libffi_dir}/.libs"
-           lappend libffi_link_flags "-L${blddircxx}/src/.libs"
-       }
+        set libffi_dir [file dirname ${libffi_dir}]
+        set libffi_link_flags "-L ../.libs"
     }
 
     set_ld_library_path_env_vars
@@ -354,8 +353,8 @@ proc libffi_exit { } {
     global gluefile;
 
     if [info exists gluefile] {
-       file_on_build delete $gluefile;
-       unset gluefile;
+        file_on_build delete $gluefile;
+        unset gluefile;
     }
 }
 
@@ -370,60 +369,74 @@ proc libffi_target_compile { source dest type options } {
     global compiler_vendor
 
     if { [target_info needs_status_wrapper]!="" && [info exists gluefile] } {
-       lappend options "libs=${gluefile}"
-       lappend options "ldflags=$wrap_flags"
-    }
-
-    if { $blddirffi != "" } {
-       # If '--with-build-sysroot=[...]' was specified, use it for build-tree
-       # testing.
-       global SYSROOT_CFLAGS_FOR_TARGET
-       lappend options "additional_flags=${SYSROOT_CFLAGS_FOR_TARGET}"
+        lappend options "libs=${gluefile}"
+        lappend options "ldflags=$wrap_flags"
     }
 
     # TOOL_OPTIONS must come first, so that it doesn't override testcase
     # specific options.
     if [info exists TOOL_OPTIONS] {
-       lappend  options "additional_flags=$TOOL_OPTIONS"
+        lappend  options "additional_flags=$TOOL_OPTIONS"
     }
 
     # search for ffi_mips.h in srcdir, too
-    lappend options "additional_flags=-I${libffi_include} -I${srcdir}/../include  -I${libffi_include}/.."
-    lappend options "additional_flags=${libffi_link_flags}"
-
-    # Darwin needs a stack execution allowed flag.
+    # lappend options "additional_flags=-I${libffi_include} -I${srcdir}/../include  -I${libffi_include}/.."
+    lappend options "additional_flags=-I ../include -I ${srcdir}/../include  -I .."
+    if { [string match $type "executable"] } {
+
+        lappend options "additional_flags=${libffi_link_flags}"
+
+        # Darwin needs a stack execution allowed flag.
+        if { [istarget "*-*-darwin9*"] || [istarget "*-*-darwin1*"]
+             || [istarget "*-*-darwin2*"] } {
+            # lappend options "additional_flags=-Wl,-allow_stack_execute"
+            lappend options "additional_flags=-Wno-unused-command-line-argument"
+            lappend options "additional_flags=-Wl,-search_paths_first"
+        }
 
-    if { [istarget "*-*-darwin9*"] || [istarget "*-*-darwin1*"]
-        || [istarget "x86_64-*-darwin2*"] } {
-       lappend options "additional_flags=-Wl,-allow_stack_execute"
-       lappend options "additional_flags=-Wl,-search_paths_first"
-    }
+        # If you're building the compiler with --prefix set to a place
+        # where it's not yet installed, then the linker won't be able to
+        # find the libgcc used by libffi.dylib.  We could pass the
+        # -dylib_file option, but that's complicated, and it's much easier
+        # to just make the linker find libgcc using -L options.
+        if { [string match "*-*-darwin*" $target_triplet] } {
+            lappend options "libs= -shared-libgcc"
+        }
 
-    # If you're building the compiler with --prefix set to a place
-    # where it's not yet installed, then the linker won't be able to
-    # find the libgcc used by libffi.dylib.  We could pass the
-    # -dylib_file option, but that's complicated, and it's much easier
-    # to just make the linker find libgcc using -L options.
-    if { [string match "*-*-darwin*" $target_triplet] } {
-       lappend options "libs= -shared-libgcc"
-    }
+        if { [string match "*-*-openbsd*" $target_triplet] } {
+            lappend options "libs= -lpthread"
+        }
 
-    if { [string match "*-*-openbsd*" $target_triplet] } {
-       lappend options "libs= -lpthread"
-    }
+        lappend options "libs= -lffi"
 
-    lappend options "libs= -lffi"
+        if { [string match "aarch64*-*-linux*" $target_triplet] } {
+            if { ! [string match "*android*" $target_triplet] } {
+                lappend options "libs= -lpthread"
+            }
+        }
 
-    if { [string match "aarch64*-*-linux*" $target_triplet] } {
-       lappend options "libs= -lpthread"
-    }
+        # this may be required for g++, but just confused clang.
+        if { [string match "*.cc" $source] } {
+            lappend options "c++"
+            if { [string match "*-*-darwin*" $target_triplet] } {
+                if { [string match $compiler_vendor "gnu"] } {
+                    lappend options "libs= -lc++"
+                }
+            } elseif { [string match "*android*" $target_triplet] } {
+                lappend options "libs= -lc++"
+            }
+        }
 
-    if { [string match "*.cc" $source] } {
-       lappend options "ldflags=-shared-libgcc -lstdc++"
+        if { [string match "arc*-*-linux*" $target_triplet] } {
+            lappend options "libs= -lpthread"
+        }
     }
 
-    if { [string match "arc*-*-linux*" $target_triplet] } {
-       lappend options "libs= -lpthread"
+    # emscripten emits this warning while building the feature test
+    # which causes it to be seen as unsupported.
+    if { [string match "wasm32-*" $target_triplet] } {
+        lappend options "additional_flags=-Wno-unused-command-line-argument"
+        lappend options "libs= -lpthread"
     }
 
     verbose "options: $options"
@@ -441,10 +454,12 @@ proc libffi_feature_test { test } {
     puts $f "#else"
     puts $f "# error Failed $test"
     puts $f "#endif"
+    puts $f "int main() {return 0;}"
     close $f
 
-    set lines [libffi_target_compile $src /dev/null assembly ""]
+    set lines [libffi_target_compile $src $src.i preprocess ""]
     file delete $src
+    file delete $src.i
 
     return [string match "" $lines]
 }
@@ -457,10 +472,10 @@ proc libffi_feature_test { test } {
 proc search_for { file pattern } {
     set fd [open $file r]
     while { [gets $fd cur_line]>=0 } {
-       if [string match "*$pattern*" $cur_line] then {
-           close $fd
-           return 1
-       }
+        if [string match "*$pattern*" $cur_line] then {
+            close $fd
+            return 1
+        }
     }
     close $fd
     return 0
@@ -472,27 +487,27 @@ proc libffi-dg-runtest { testcases default-extra-flags } {
     global runtests
 
     foreach test $testcases {
-       # If we're only testing specific files and this isn't one of
-       # them, skip it.
-       if ![runtest_file_p $runtests $test] {
-           continue
-       }
-
-       # Look for a loop within the source code - if we don't find one,
-       # don't pass -funroll[-all]-loops.
-       global torture_with_loops torture_without_loops
-       if [expr [search_for $test "for*("]+[search_for $test "while*("]] {
-           set option_list $torture_with_loops
-       } else {
-           set option_list $torture_without_loops
-       }
-
-       set nshort [file tail [file dirname $test]]/[file tail $test]
-
-       foreach flags $option_list {
-           verbose "Testing $nshort, $flags" 1
-           dg-test $test $flags ${default-extra-flags}
-       }
+        # If we're only testing specific files and this isn't one of
+        # them, skip it.
+        if ![runtest_file_p $runtests $test] {
+            continue
+        }
+
+        # Look for a loop within the source code - if we don't find one,
+        # don't pass -funroll[-all]-loops.
+        global torture_with_loops torture_without_loops
+        if [expr [search_for $test "for*("]+[search_for $test "while*("]] {
+            set option_list $torture_with_loops
+        } else {
+            set option_list $torture_without_loops
+        }
+
+        set nshort [file tail [file dirname $test]]/[file tail $test]
+
+        foreach flags $option_list {
+            verbose "Testing $nshort, $flags" 1
+            dg-test $test $flags ${default-extra-flags}
+        }
     }
 }
 
@@ -501,31 +516,31 @@ proc run-many-tests { testcases extra_flags } {
     global has_gccbug
     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" }
+        "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"
-        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 -fno-diagnostics-color"
+            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 ""
-        if [info exists env(LIBFFI_TEST_OPTIMIZATION)] {
-         set optimizations [ list $env(LIBFFI_TEST_OPTIMIZATION) ]
-        } else { 
-          set optimizations { "" }
+        default {
+            # Assume we are using the vendor compiler.
+            set common ""
+            if [info exists env(LIBFFI_TEST_OPTIMIZATION)] {
+                set optimizations [ list $env(LIBFFI_TEST_OPTIMIZATION) ]
+            } else {
+                set optimizations { "" }
+            }
         }
-      }
     }
 
     info exists env(LD_LIBRARY_PATH)
@@ -540,7 +555,7 @@ proc run-many-tests { testcases extra_flags } {
                 "-DABI_NUM=FFI_FASTCALL -DABI_ATTR=__FASTCALL__"
             }
         } elseif { [istarget "x86_64-*-*"] \
-                  && [libffi_feature_test "#if !defined __ILP32__  \
+                       && [libffi_feature_test "#if !defined __ILP32__  \
                                                && !defined __i386__"] } {
             set targetabis {
                 ""
@@ -560,22 +575,22 @@ proc run-many-tests { testcases extra_flags } {
         foreach opt $optimizations {
             foreach abi $abis {
                 set options [concat $common $opt $abi]
-               set has_gccbug false;
-               if { [string match $compiler_vendor "gnu"] \
-                        && [string match "*MSABI*" $abi] \
-                        && ( ( [string match "*DGTEST=57 *" $common] \
-                                   && [string match "*call.c*" $testname] ) \
-                                 || ( [string match "*DGTEST=54 *" $common] \
-                                          && [string match "*callback*" $testname] ) \
-                                 || [string match "*DGTEST=55 *" $common] \
-                                 || [string match "*DGTEST=56 *" $common] ) } then {
-                   if [libffi_feature_test "#if (__GNUC__ < 9) || ((__GNUC__ == 9) && (__GNUC_MINOR__ < 3))"] {
-                       set has_gccbug true;
-                   }
-               }
-               verbose "Testing $testname, $options" 1
-               verbose "has_gccbug = $has_gccbug" 1
-               dg-test $test $options ""
+                set has_gccbug false;
+                if { [string match $compiler_vendor "gnu"] \
+                         && [string match "*MSABI*" $abi] \
+                         && ( ( [string match "*DGTEST=57 *" $common] \
+                                    && [string match "*call.c*" $testname] ) \
+                                  || ( [string match "*DGTEST=54 *" $common] \
+                                           && [string match "*callback*" $testname] ) \
+                                  || [string match "*DGTEST=55 *" $common] \
+                                  || [string match "*DGTEST=56 *" $common] ) } then {
+                    if [libffi_feature_test "#if (__GNUC__ < 9) || ((__GNUC__ == 9) && (__GNUC_MINOR__ < 3))"] {
+                        set has_gccbug true;
+                    }
+                }
+                verbose "Testing $testname, $options" 1
+                verbose "has_gccbug = $has_gccbug" 1
+                dg-test $test $options ""
             }
         }
     }
@@ -587,8 +602,8 @@ proc dg-xfail-if { args } {
     set args [lreplace $args 0 0]
     set selector "target [join [lindex $args 1]]"
     if { [dg-process-target $selector] == "S" } {
-       global compiler_conditional_xfail_data
-       set compiler_conditional_xfail_data $args
+        global compiler_conditional_xfail_data
+        set compiler_conditional_xfail_data $args
     }
 }
 
@@ -600,22 +615,22 @@ proc check-flags { args } {
     # The next two arguments are optional.  If they were not specified,
     # use the defaults.
     if { [llength $args] == 2 } {
-       lappend $args [list "*"]
+        lappend $args [list "*"]
     }
     if { [llength $args] == 3 } {
-       lappend $args [list ""]
+        lappend $args [list ""]
     }
 
     # If the option strings are the defaults, or the same as the
     # defaults, there is no need to call check_conditional_xfail to
     # compare them to the actual options.
     if { [string compare [lindex $args 2] "*"] == 0
-        && [string compare [lindex $args 3] "" ] == 0 } {
-       set result 1    
+         && [string compare [lindex $args 3] "" ] == 0 } {
+        set result 1
     } else {
-       # The target list might be an effective-target keyword, so replace
-       # the original list with "*-*-*", since we already know it matches.
-       set result [check_conditional_xfail [lreplace $args 1 1 "*-*-*"]]
+        # The target list might be an effective-target keyword, so replace
+        # the original list with "*-*-*", since we already know it matches.
+        set result [check_conditional_xfail [lreplace $args 1 1 "*-*-*"]]
     }
 
     return $result
@@ -631,7 +646,7 @@ proc dg-skip-if { args } {
     # Don't bother if we're already skipping the test.
     upvar dg-do-what dg-do-what
     if { [lindex ${dg-do-what} 1] == "N" } {
-      return
+        return
     }
 
     set selector [list target [lindex $args 1]]
@@ -656,18 +671,18 @@ if { [info procs saved-dg-test] == [list] } {
     rename dg-test saved-dg-test
 
     proc dg-test { args } {
-       global additional_files
-       global additional_sources
-       global errorInfo
-
-       if { [ catch { eval saved-dg-test $args } errmsg ] } {
-           set saved_info $errorInfo
-           set additional_files ""
-           set additional_sources ""
-           error $errmsg $saved_info
-       }
-       set additional_files ""
-       set additional_sources ""
+        global additional_files
+        global additional_sources
+        global errorInfo
+
+        if { [ catch { eval saved-dg-test $args } errmsg ] } {
+            set saved_info $errorInfo
+            set additional_files ""
+            set additional_sources ""
+            error $errmsg $saved_info
+        }
+        set additional_files ""
+        set additional_sources ""
     }
 }
 
index 6b7beba93516a99582c1b42bc5c8ef29ee9f922f..e33a656c6cc0d7b4b74e605e5951b1d3b36c501b 100644 (file)
@@ -175,7 +175,7 @@ proc set_ld_library_path_env_vars { } {
   } else {
     setenv DYLD_LIBRARY_PATH "$ld_library_path"
   }
-  if { [istarget *-*-cygwin*] || [istarget *-*-mingw*] } {
+  if { [istarget *-*-cygwin*] || [ istarget *-*-msys* ] || [istarget *-*-mingw*] } {
     if { $orig_path_saved } {
       setenv PATH "$ld_library_path:$orig_path"
     } else {
@@ -271,7 +271,7 @@ proc get_shlib_extension { } {
 
     if { [ istarget *-*-darwin* ] } {
        set shlib_ext "dylib"
-    } elseif { [ istarget *-*-cygwin* ] || [ istarget *-*-mingw* ] } {
+    } elseif { [ istarget *-*-cygwin* ] || [ istarget *-*-msys* ] || [ istarget *-*-mingw* ] } {
        set shlib_ext "dll"
     } elseif { [ istarget hppa*-*-hpux* ] } {
        set shlib_ext "sl"
index cf9219e26637848b032cdc85d7e6dbb63d2f3617..4887e0092ebc38cb770b8d7a8abca56b2ec224f0 100644 (file)
@@ -50,6 +50,7 @@ int _fprintf(FILE *stream, const char *format, ...)
     case 3:
       vsprintf(&rbuf2[strlen(rbuf2)], format, args);
       printf("%s", rbuf2);
+      fflush (stdout);
       if (strcmp (rbuf1, rbuf2)) abort();
       break;
     }
index 23a6f466096f7c4a652b1e3905b376c8e8705e25..22cf1ebb5ccbbcbf2282bddb55c2d7ad8312484d 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <stdio.h>
 
-FILE* out;
+FILE* out = NULL;
 
 #define uchar unsigned char
 #define ushort unsigned short
diff --git a/libffi/testsuite/libffi.call/bpo_38748.c b/libffi/testsuite/libffi.call/bpo_38748.c
new file mode 100644 (file)
index 0000000..294bda0
--- /dev/null
@@ -0,0 +1,41 @@
+/* Area:       bpo-38748
+   Purpose:    test for stdcall alignment problem
+   Source:      github.com/python/cpython/pull/26204 */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+#include "ffi_common.h"
+
+static UINT32 ABI_ATTR align_arguments(UINT32 l1,
+                                      UINT64 l2)
+{
+  return l1 + (UINT32) l2;
+}
+
+int main(void)
+{
+  ffi_cif cif;
+  ffi_type *args[4] = {
+    &ffi_type_uint32,
+    &ffi_type_uint64
+  };
+  ffi_arg lr1, lr2;
+  UINT32 l1 = 1;
+  UINT64 l2 = 2;
+  void *values[2] = {&l1, &l2};
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 2,
+                    &ffi_type_uint32, args) == FFI_OK);
+
+  lr1 = align_arguments(l1, l2);
+
+  ffi_call(&cif, FFI_FN(align_arguments), &lr2, values);
+
+  if (lr1 == lr2)
+    printf("bpo-38748 arguments tests ok!\n");
+  else
+    CHECK(0);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/callback.c b/libffi/testsuite/libffi.call/callback.c
new file mode 100644 (file)
index 0000000..70248cb
--- /dev/null
@@ -0,0 +1,99 @@
+/* Area:       ffi_call
+   Purpose:    Check structures with array and callback.
+   Limitations:        none.
+   PR:         none.
+   Originator: David Tenty <daltenty@ibm.com>  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static int i=5;
+
+static void callback(void) { i++; }
+
+typedef struct
+{
+  unsigned char c1;
+  double s[2];
+  unsigned char c2;
+} test_structure_12;
+
+static test_structure_12 ABI_ATTR struct12 (test_structure_12 ts, void (*func)(void))
+{
+  ts.c1 += 1;
+  ts.c2 += 1;
+  ts.s[0] += 1;
+  ts.s[1] += 1;
+
+  func();
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts12_type,ts12a_type;
+  ffi_type *ts12_type_elements[4];
+  ffi_type *ts12a_type_elements[3];
+
+  test_structure_12 ts12_arg;
+  void (*ptr)(void)=&callback;
+
+  test_structure_12 *ts12_result =
+    (test_structure_12 *) malloc (sizeof(test_structure_12));
+
+  ts12a_type.size = 0;
+  ts12a_type.alignment = 0;
+  ts12a_type.type = FFI_TYPE_STRUCT;
+  ts12a_type.elements = ts12a_type_elements;
+  ts12a_type_elements[0] = &ffi_type_double;
+  ts12a_type_elements[1] = &ffi_type_double;
+  ts12a_type_elements[2] = NULL;
+
+  ts12_type.size = 0;
+  ts12_type.alignment = 0;
+  ts12_type.type = FFI_TYPE_STRUCT;
+  ts12_type.elements = ts12_type_elements;
+  ts12_type_elements[0] = &ffi_type_uchar;
+  ts12_type_elements[1] = &ts12a_type;
+  ts12_type_elements[2] = &ffi_type_uchar;
+  ts12_type_elements[3] = NULL;
+
+
+  args[0] = &ts12_type;
+  args[1] = &ffi_type_pointer;
+  values[0] = &ts12_arg;
+  values[1] = &ptr;
+
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 2, &ts12_type, args) == FFI_OK);
+
+  ts12_arg.c1 = 5;
+  ts12_arg.c2 = 6;
+  ts12_arg.s[0] = 7.77;
+  ts12_arg.s[1] = 8.88;
+
+  printf ("%u\n", ts12_arg.c1);
+  printf ("%u\n", ts12_arg.c2);
+  printf ("%g\n", ts12_arg.s[0]);
+  printf ("%g\n", ts12_arg.s[1]);
+  printf ("%d\n", i);
+
+  ffi_call(&cif, FFI_FN(struct12), ts12_result, values);
+
+  printf ("%u\n", ts12_result->c1);
+  printf ("%u\n", ts12_result->c2);
+  printf ("%g\n", ts12_result->s[0]);
+  printf ("%g\n", ts12_result->s[1]);
+  printf ("%d\n", i);
+  CHECK(ts12_result->c1 == 5 + 1);
+  CHECK(ts12_result->c2 == 6 + 1);
+  CHECK(ts12_result->s[0] == 7.77 + 1);
+  CHECK(ts12_result->s[1] == 8.88 + 1);
+  CHECK(i == 5 + 1);
+  CHECK(ts12_type.size == sizeof(test_structure_12));
+
+  free (ts12_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/callback2.c b/libffi/testsuite/libffi.call/callback2.c
new file mode 100644 (file)
index 0000000..0fcc614
--- /dev/null
@@ -0,0 +1,108 @@
+/* Area:       ffi_call
+   Purpose:    Check structures with nested array and callback.
+   Limitations:        none.
+   PR:         none.
+   Originator: David Tenty <daltenty@ibm.com>  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static int i=5;
+
+static void callback(void) { i++; }
+
+typedef struct
+{
+  struct { double d; } s1;
+  double s[2];
+  unsigned char c2;
+} test_structure_12;
+
+static test_structure_12 ABI_ATTR struct12 (test_structure_12 ts, void (*func)(void))
+{
+  ts.s1.d += 1;
+  ts.c2 += 1;
+  ts.s[0] += 1;
+  ts.s[1] += 1;
+
+  func();
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts12_type,ts12a_type, ts12b_type;
+  ffi_type *ts12_type_elements[4];
+  ffi_type *ts12a_type_elements[2];
+  ffi_type *ts12b_type_elements[3];
+
+
+  test_structure_12 ts12_arg;
+  void (*ptr)(void)=&callback;
+
+  test_structure_12 *ts12_result =
+    (test_structure_12 *) malloc (sizeof(test_structure_12));
+
+  ts12a_type.size = 0;
+  ts12a_type.alignment = 0;
+  ts12a_type.type = FFI_TYPE_STRUCT;
+  ts12a_type.elements = ts12a_type_elements;
+  ts12a_type_elements[0] = &ffi_type_double;
+  ts12a_type_elements[1] = NULL;
+
+  ts12b_type.size = 0;
+  ts12b_type.alignment = 0;
+  ts12b_type.type = FFI_TYPE_STRUCT;
+  ts12b_type.elements = ts12b_type_elements;
+  ts12b_type_elements[0] = &ffi_type_double;
+  ts12b_type_elements[1] = &ffi_type_double;
+  ts12b_type_elements[2] = NULL;
+
+  ts12_type.size = 0;
+  ts12_type.alignment = 0;
+  ts12_type.type = FFI_TYPE_STRUCT;
+  ts12_type.elements = ts12_type_elements;
+  ts12_type_elements[0] = &ts12a_type;
+  ts12_type_elements[1] = &ts12b_type;
+  ts12_type_elements[2] = &ffi_type_uchar;
+  ts12_type_elements[3] = NULL;
+
+
+  args[0] = &ts12_type;
+  args[1] = &ffi_type_pointer;
+  values[0] = &ts12_arg;
+  values[1] = &ptr;
+
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 2, &ts12_type, args) == FFI_OK);
+
+  ts12_arg.s1.d = 5.55;
+  ts12_arg.c2 = 6;
+  ts12_arg.s[0] = 7.77;
+  ts12_arg.s[1] = 8.88;
+
+  printf ("%g\n", ts12_arg.s1.d);
+  printf ("%u\n", ts12_arg.c2);
+  printf ("%g\n", ts12_arg.s[0]);
+  printf ("%g\n", ts12_arg.s[1]);
+  printf ("%d\n", i);
+
+  ffi_call(&cif, FFI_FN(struct12), ts12_result, values);
+
+  printf ("%g\n", ts12_result->s1.d);
+  printf ("%u\n", ts12_result->c2);
+  printf ("%g\n", ts12_result->s[0]);
+  printf ("%g\n", ts12_result->s[1]);
+  printf ("%d\n", i);
+  CHECK(ts12_result->s1.d == 5.55 + 1);
+  CHECK(ts12_result->c2 == 6 + 1);
+  CHECK(ts12_result->s[0] == 7.77 + 1);
+  CHECK(ts12_result->s[1] == 8.88 + 1);
+  CHECK(i == 5 + 1);
+  CHECK(ts12_type.size == sizeof(test_structure_12));
+
+  free (ts12_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/callback3.c b/libffi/testsuite/libffi.call/callback3.c
new file mode 100644 (file)
index 0000000..05bdbf6
--- /dev/null
@@ -0,0 +1,114 @@
+/* Area:       ffi_call
+   Purpose:    Check structures with array and callback.
+   Limitations:        none.
+   PR:         none.
+   Originator: David Tenty <daltenty@ibm.com>  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static int i=5;
+
+static void callback(void) { i++; }
+
+
+typedef struct
+{
+  struct { unsigned char c; double d; } s1;
+  double s[2];
+  unsigned char c2;
+} test_structure_12;
+
+static test_structure_12 ABI_ATTR struct12 (test_structure_12 ts, void (*func)(void))
+{
+  ts.s1.c += 1;
+  ts.s1.d += 1;
+  ts.c2 += 1;
+  ts.s[0] += 1;
+  ts.s[1] += 1;
+
+  func();
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts12_type,ts12b_type, ts12a_type;
+  ffi_type *ts12_type_elements[4];
+  ffi_type *ts12b_type_elements[3];
+  ffi_type *ts12a_type_elements[3];
+
+  test_structure_12 ts12_arg;
+  void (*ptr)(void)=&callback;
+
+  test_structure_12 *ts12_result =
+    (test_structure_12 *) malloc (sizeof(test_structure_12));
+
+  ts12a_type.size = 0;
+  ts12a_type.alignment = 0;
+  ts12a_type.type = FFI_TYPE_STRUCT;
+  ts12a_type.elements = ts12a_type_elements;
+  ts12a_type_elements[0] = &ffi_type_uchar;
+  ts12a_type_elements[1] = &ffi_type_double;
+  ts12a_type_elements[2] = NULL;
+
+  ts12b_type.size = 0;
+  ts12b_type.alignment = 0;
+  ts12b_type.type = FFI_TYPE_STRUCT;
+  ts12b_type.elements = ts12b_type_elements;
+  ts12b_type_elements[0] = &ffi_type_double;
+  ts12b_type_elements[1] = &ffi_type_double;
+  ts12b_type_elements[2] = NULL;
+
+  ts12_type.size = 0;
+  ts12_type.alignment = 0;
+  ts12_type.type = FFI_TYPE_STRUCT;
+  ts12_type.elements = ts12_type_elements;
+  ts12_type_elements[0] = &ts12a_type;
+  ts12_type_elements[1] = &ts12b_type;
+  ts12_type_elements[2] = &ffi_type_uchar;
+  ts12_type_elements[3] = NULL;
+
+
+  args[0] = &ts12_type;
+  args[1] = &ffi_type_pointer;
+  values[0] = &ts12_arg;
+  values[1] = &ptr;
+
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 2, &ts12_type, args) == FFI_OK);
+
+  ts12_arg.s1.c = 5;
+  ts12_arg.s1.d = 5.55;
+  ts12_arg.c2 = 6;
+  ts12_arg.s[0] = 7.77;
+  ts12_arg.s[1] = 8.88;
+
+  printf ("%d\n", ts12_arg.s1.c);
+  printf ("%g\n", ts12_arg.s1.d);
+  printf ("%u\n", ts12_arg.c2);
+  printf ("%g\n", ts12_arg.s[0]);
+  printf ("%g\n", ts12_arg.s[1]);
+  printf ("%d\n", i);
+
+  ffi_call(&cif, FFI_FN(struct12), ts12_result, values);
+
+  printf ("%d\n", ts12_result->s1.c);
+  printf ("%g\n", ts12_result->s1.d);
+  printf ("%u\n", ts12_result->c2);
+  printf ("%g\n", ts12_result->s[0]);
+  printf ("%g\n", ts12_result->s[1]);
+  printf ("%d\n", i);
+  CHECK(ts12_result->s1.c == 5 + 1);
+  CHECK(ts12_result->s1.d == 5.55 + 1);
+  CHECK(ts12_result->c2 == 6 + 1);
+  CHECK(ts12_result->s[0] == 7.77 + 1);
+  CHECK(ts12_result->s[1] == 8.88 + 1);
+  CHECK(i == 5 + 1);
+  CHECK(ts12_type.size == sizeof(test_structure_12));
+
+  free (ts12_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/callback4.c b/libffi/testsuite/libffi.call/callback4.c
new file mode 100644 (file)
index 0000000..309ad35
--- /dev/null
@@ -0,0 +1,119 @@
+/* Area:       ffi_call
+   Purpose:    Check structures with array and callback.
+   Limitations:        none.
+   PR:         none.
+   Originator: David Tenty <daltenty@ibm.com>  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static int i=5;
+
+static void callback(void) { i++; }
+
+
+typedef struct
+{
+  unsigned char c1;
+  struct { double d; unsigned char c; } s[2];
+  unsigned char c2;
+} test_structure_12;
+
+static test_structure_12 ABI_ATTR struct12 (test_structure_12 ts, void (*func)(void))
+{
+  ts.c1 += 1;
+  ts.s[0].d += 1;
+  ts.s[0].c += 1;
+  ts.s[1].d += 1;
+  ts.s[1].c += 1;
+  ts.c2 += 1;
+
+  func();
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts12_type,ts12b_type, ts12a_type;
+  ffi_type *ts12_type_elements[4];
+  ffi_type *ts12b_type_elements[3];
+  ffi_type *ts12a_type_elements[3];
+
+  test_structure_12 ts12_arg;
+  void (*ptr)(void)=&callback;
+
+  test_structure_12 *ts12_result =
+    (test_structure_12 *) malloc (sizeof(test_structure_12));
+
+  ts12a_type.size = 0;
+  ts12a_type.alignment = 0;
+  ts12a_type.type = FFI_TYPE_STRUCT;
+  ts12a_type.elements = ts12a_type_elements;
+  ts12a_type_elements[0] = &ffi_type_double;
+  ts12a_type_elements[1] = &ffi_type_uchar;
+  ts12a_type_elements[2] = NULL;
+
+  ts12b_type.size = 0;
+  ts12b_type.alignment = 0;
+  ts12b_type.type = FFI_TYPE_STRUCT;
+  ts12b_type.elements = ts12b_type_elements;
+  ts12b_type_elements[0] = &ts12a_type;
+  ts12b_type_elements[1] = &ts12a_type;
+  ts12b_type_elements[2] = NULL;
+
+  ts12_type.size = 0;
+  ts12_type.alignment = 0;
+  ts12_type.type = FFI_TYPE_STRUCT;
+  ts12_type.elements = ts12_type_elements;
+  ts12_type_elements[0] = &ffi_type_uchar;
+  ts12_type_elements[1] = &ts12b_type;
+  ts12_type_elements[2] = &ffi_type_uchar;
+  ts12_type_elements[3] = NULL;
+
+
+  args[0] = &ts12_type;
+  args[1] = &ffi_type_pointer;
+  values[0] = &ts12_arg;
+  values[1] = &ptr;
+
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 2, &ts12_type, args) == FFI_OK);
+
+  ts12_arg.c1 = 5;
+  ts12_arg.s[0].d = 5.55;
+  ts12_arg.s[0].c = 6;
+  ts12_arg.s[1].d = 7.77;
+  ts12_arg.s[1].c = 8;
+  ts12_arg.c2 = 9;
+
+  printf ("%u\n", ts12_arg.c1);
+  printf ("%g\n", ts12_arg.s[0].d);
+  printf ("%u\n", ts12_arg.s[0].c);
+  printf ("%g\n", ts12_arg.s[1].d);
+  printf ("%u\n", ts12_arg.s[1].c);
+  printf ("%u\n", ts12_arg.c2);
+  printf ("%d\n", i);
+
+  ffi_call(&cif, FFI_FN(struct12), ts12_result, values);
+
+  printf ("%u\n", ts12_result->c1);
+  printf ("%g\n", ts12_result->s[0].d);
+  printf ("%u\n", ts12_result->s[0].c);
+  printf ("%g\n", ts12_result->s[1].d);
+  printf ("%u\n", ts12_result->s[1].c);
+  printf ("%u\n", ts12_result->c2);
+  printf ("%d\n", i);
+  CHECK(ts12_result->c1 == 5 + 1);
+  CHECK(ts12_result->s[0].d == 5.55 + 1);
+  CHECK(ts12_result->s[0].c == 6 + 1);
+  CHECK(ts12_result->s[1].d == 7.77 + 1);
+  CHECK(ts12_result->s[1].c == 8 + 1);
+  CHECK(ts12_result->c2 == 9 + 1);
+  CHECK(i == 5 + 1);
+  CHECK(ts12_type.size == sizeof(test_structure_12));
+
+  free (ts12_result);
+  exit(0);
+}
index 95d96a83f18c7dfa3cb6beea988e71e7f90b1514..a7c634b4c630ce5193603e4af6b3ec31f8a332bc 100644 (file)
@@ -1,3 +1,6 @@
+#undef __USE_MINGW_ANSI_STDIO
+#define __USE_MINGW_ANSI_STDIO 1
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -5,6 +8,9 @@
 #include <ffi.h>
 #include "fficonfig.h"
 
+#include <float.h>
+#include <math.h>
+
 #if defined HAVE_STDINT_H
 #include <stdint.h>
 #endif
       } \
    } while(0)
 
+#define CHECK_FLOAT_EQ(x, y) \
+   do { \
+      if(fabs((x) - (y)) > FLT_EPSILON){ \
+         printf("Check failed CHECK_FLOAT_EQ(%s, %s)\n", #x, #y); \
+         abort(); \
+      } \
+   } while(0)
+
+#define CHECK_DOUBLE_EQ(x, y) \
+   do { \
+      if(fabs((x) - (y)) > DBL_EPSILON){ \
+         printf("Check failed CHECK_FLOAT_EQ(%s, %s)\n", #x, #y); \
+         abort(); \
+      } \
+   } while(0)
+
 /* Define macros so that compilers other than gcc can run the tests.  */
 #undef __UNUSED__
 #if defined(__GNUC__)
@@ -69,8 +91,8 @@
 
 #endif
 
-/* MinGW kludge.  */
-#if defined(_WIN64) | defined(_WIN32)
+/* msvc kludge.  */
+#if defined(_MSC_VER)
 #define PRIdLL "I64d"
 #define PRIuLL "I64u"
 #else
index 5acff91f66333839f536c2c05cc08df2f03b0513..d01d9d0a9c5da7ea49c1b3f9bfb73b5837a3ec6e 100644 (file)
@@ -74,6 +74,7 @@ int main (void)
   /* { dg-output "\n0: 2.0 : total: 2.0" } */
   printf("ffi: %.1f\n", resfp);
   /* { dg-output "\nffi: 2.0" } */
+  CHECK_DOUBLE_EQ(resfp, 2);
 
   /* Second test, float_va_fn(2,2.0,3.0,4.0), now with variadic params */
   /* Call it statically and then via ffi */
@@ -81,6 +82,7 @@ int main (void)
   /* { dg-output "\n2: 2.0 : 0:3.0  1:4.0  total: 11.0" } */
   printf("compiled: %.1f\n", resfp);
   /* { dg-output "\ncompiled: 11.0" } */
+  CHECK_DOUBLE_EQ(resfp, 11);
 
   arg_types[0] = &ffi_type_uint;
   arg_types[1] = &ffi_type_double;
@@ -102,6 +104,7 @@ int main (void)
   /* { dg-output "\n2: 2.0 : 0:3.0  1:4.0  total: 11.0" } */
   printf("ffi: %.1f\n", resfp);
   /* { dg-output "\nffi: 11.0" } */
+  CHECK_DOUBLE_EQ(resfp, 11);
 
   exit(0);
 }
diff --git a/libffi/testsuite/libffi.call/longjmp.c b/libffi/testsuite/libffi.call/longjmp.c
new file mode 100644 (file)
index 0000000..fc0c7ff
--- /dev/null
@@ -0,0 +1,60 @@
+/* Area:       ffi_call
+   Purpose:    Test longjmp over ffi_call frames */
+
+/* Test code adapted from Lars Kanis' bug report:
+   https://github.com/libffi/libffi/issues/905 */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+#include "ffi_common.h"
+
+#include <setjmp.h>
+
+static jmp_buf buf;
+
+static void ABI_ATTR lev2(const char *str) {
+  printf("lev2 %s\n", str);
+  // jumps back to where setjmp was called - making setjmp now return 1
+  longjmp(buf, 1);
+}
+
+static void ABI_ATTR lev1(const char *str) {
+  lev2(str);
+
+  // will not be reached
+  printf("lev1 %s\n", str);
+}
+
+int main()
+{
+  ffi_cif cif;
+  ffi_type *args[1];
+  void *values[1];
+  char *s;
+  ffi_arg rc;
+  /* Initialize the argument info vectors */
+  args[0] = &ffi_type_pointer;
+  values[0] = &s;
+  /* Initialize the cif */
+  if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+    &ffi_type_sint, args) == FFI_OK)
+  {
+    s = "direct call";
+    if (!setjmp(buf)){
+      // works on x64 and arm64
+      lev1(s);
+    } else {
+      printf("back to main\n");
+    }
+
+    s = "through libffi";
+    if (!setjmp(buf)){
+      // works on x64 but segfaults on arm64
+      ffi_call(&cif, (void (*)(void))lev1, &rc, values);
+    } else {
+      printf("back to main\n");
+    }
+  }
+  return 0;
+}
diff --git a/libffi/testsuite/libffi.call/overread.c b/libffi/testsuite/libffi.call/overread.c
new file mode 100644 (file)
index 0000000..5ba1077
--- /dev/null
@@ -0,0 +1,54 @@
+/* Area:        ffi_call
+   Purpose:     Tests if ffi_call reads data beyond end.
+   Limitations: needs mmap.
+   PR:          887
+   Originator:  Mikulas Patocka <mikulas@twibright.com>  */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+#ifdef __linux__
+#include <sys/mman.h>
+#include <unistd.h>
+
+static int ABI_ATTR fn(unsigned char a, unsigned short b, unsigned int c, unsigned long d)
+{
+       return (int)(a + b + c + d);
+}
+#endif
+
+int main(void)
+{
+#ifdef __linux__
+       ffi_cif cif;
+       ffi_type *args[MAX_ARGS];
+       void *values[MAX_ARGS];
+       ffi_arg rint;
+       char *m;
+       int ps;
+       args[0] = &ffi_type_uchar;
+       args[1] = &ffi_type_ushort;
+       args[2] = &ffi_type_uint;
+       args[3] = &ffi_type_ulong;
+       CHECK(ffi_prep_cif(&cif, ABI_NUM, 4, &ffi_type_sint, args) == FFI_OK);
+       ps = getpagesize();
+       m = mmap(NULL, ps * 3, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+       CHECK(m != MAP_FAILED);
+       CHECK(mprotect(m, ps, PROT_NONE) == 0);
+       CHECK(mprotect(m + ps * 2, ps, PROT_NONE) == 0);
+       values[0] = m + ps * 2 - sizeof(unsigned char);
+       values[1] = m + ps * 2 - sizeof(unsigned short);
+       values[2] = m + ps * 2 - sizeof(unsigned int);
+       values[3] = m + ps * 2 - sizeof(unsigned long);
+       ffi_call(&cif, FFI_FN(fn), &rint, values);
+       CHECK((int)rint == 0);
+       values[0] = m + ps;
+       values[1] = m + ps;
+       values[2] = m + ps;
+       values[3] = m + ps;
+       ffi_call(&cif, FFI_FN(fn), &rint, values);
+       CHECK((int)rint == 0);
+#endif
+       exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/pyobjc_tc.c b/libffi/testsuite/libffi.call/pyobjc_tc.c
new file mode 100644 (file)
index 0000000..e29bd6c
--- /dev/null
@@ -0,0 +1,114 @@
+/* Area:       ffi_call
+   Purpose:    Check different structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: Ronald Oussoren <oussoren@cistron.nl> 20030824  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct Point {
+       float x;
+       float y;
+} Point;
+
+typedef struct Size {
+       float h;
+       float w;
+} Size;
+
+typedef struct Rect {
+       Point o;
+       Size  s;
+} Rect;
+
+int doit(int o, char* s, Point p, Rect r, int last)
+{
+       printf("CALLED WITH %d %s {%f %f} {{%f %f} {%f %f}} %d\n",
+               o, s, p.x, p.y, r.o.x, r.o.y, r.s.h, r.s.w, last);
+       return 42;
+}
+
+
+int main(void)
+{
+       ffi_type point_type;
+       ffi_type size_type;
+       ffi_type rect_type;
+       ffi_cif cif;
+       ffi_type* arglist[6];
+       void* values[6];
+       int r;
+
+       /*
+        *  First set up FFI types for the 3 struct types
+        */
+
+       point_type.size = 0; /*sizeof(Point);*/
+       point_type.alignment = 0; /*__alignof__(Point);*/
+       point_type.type = FFI_TYPE_STRUCT;
+       point_type.elements = malloc(3 * sizeof(ffi_type*));
+       point_type.elements[0] = &ffi_type_float;
+       point_type.elements[1] = &ffi_type_float;
+       point_type.elements[2] = NULL;
+
+       size_type.size = 0;/* sizeof(Size);*/
+       size_type.alignment = 0;/* __alignof__(Size);*/
+       size_type.type = FFI_TYPE_STRUCT;
+       size_type.elements = malloc(3 * sizeof(ffi_type*));
+       size_type.elements[0] = &ffi_type_float;
+       size_type.elements[1] = &ffi_type_float;
+       size_type.elements[2] = NULL;
+
+       rect_type.size = 0;/*sizeof(Rect);*/
+       rect_type.alignment =0;/* __alignof__(Rect);*/
+       rect_type.type = FFI_TYPE_STRUCT;
+       rect_type.elements = malloc(3 * sizeof(ffi_type*));
+       rect_type.elements[0] = &point_type;
+       rect_type.elements[1] = &size_type;
+       rect_type.elements[2] = NULL;
+
+       /*
+        * Create a CIF
+        */
+       arglist[0] = &ffi_type_sint;
+       arglist[1] = &ffi_type_pointer;
+       arglist[2] = &point_type;
+       arglist[3] = &rect_type;
+       arglist[4] = &ffi_type_sint;
+       arglist[5] = NULL;
+
+       r = ffi_prep_cif(&cif, FFI_DEFAULT_ABI,
+                       5, &ffi_type_sint, arglist);
+       if (r != FFI_OK) {
+               abort();
+       }
+
+
+       /* And call the function through the CIF */
+
+       {
+       Point p = { 1.0, 2.0 };
+       Rect  r = { { 9.0, 10.0}, { -1.0, -2.0 } };
+       int   o = 0;
+       int   l = 42;
+       char* m = "myMethod";
+       ffi_arg result;
+
+       values[0] = &o;
+       values[1] = &m;
+       values[2] = &p;
+       values[3] = &r;
+       values[4] = &l;
+       values[5] = NULL;
+
+       printf("CALLING WITH %d %s {%f %f} {{%f %f} {%f %f}} %d\n",
+               o, m, p.x, p.y, r.o.x, r.o.y, r.s.h, r.s.w, l);
+
+       ffi_call(&cif, FFI_FN(doit), &result, values);
+
+       printf ("The result is %d\n", (int)result);
+
+       }
+       exit(0);
+}
index 593e8a307cec8124b723adc5b797fcbd25e4936f..a2426ec93545ebf1fc34f366416a5a20a94d2764 100644 (file)
@@ -9,6 +9,9 @@
 #include "ffitest.h"
 static long long return_ll(int ll0, long long ll1, int ll2)
 {
+  CHECK(ll0 == 11111111);
+  CHECK(ll1 == 11111111111000LL);
+  CHECK(ll2 == 11111111);
   return ll0 + ll1 + ll2;
 }
 
@@ -39,5 +42,7 @@ int main (void)
   ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
   printf("res: %" PRIdLL ", %" PRIdLL "\n", rlonglong, ll0 + ll1 + ll2);
   /* { dg-output "res: 11111133333222, 11111133333222" } */
+  CHECK(rlonglong == 11111133333222);
+  CHECK(ll0 + ll1 + ll2 == 11111133333222);
   exit(0);
 }
index f0fd345f7a898ea6ae663db340772a9631803220..51bfb49459bb484513dd226915bef0f9f384e268 100644 (file)
@@ -8,6 +8,8 @@
 #include "ffitest.h"
 static long return_sl(long l1, long l2)
 {
+  CHECK(l1 == 1073741823L);
+  CHECK(l2 == 1073741824L);
   return l1 - l2;
 }
 
@@ -33,6 +35,8 @@ int main (void)
   ffi_call(&cif, FFI_FN(return_sl), &res, values);
   printf("res: %ld, %ld\n", (long)res, l1 - l2);
   /* { dg-output "res: -1, -1" } */
+  CHECK((long)res == -1);
+  CHECK(l1 + 1 == l2);
 
   exit(0);
 }
index 12b266f0373d23c9b8790cea995abe5c84c959c9..fedcc25abd163a5f3329720bc4ee84a545bf5f19 100644 (file)
@@ -8,6 +8,8 @@
 #include "ffitest.h"
 static unsigned long return_ul(unsigned long ul1, unsigned long ul2)
 {
+  CHECK(ul1 == 1073741823L);
+  CHECK(ul2 == 1073741824L);
   return ul1 + ul2;
 }
 
@@ -33,6 +35,8 @@ int main (void)
   ffi_call(&cif, FFI_FN(return_ul), &res, values);
   printf("res: %lu, %lu\n", (unsigned long)res, ul1 + ul2);
   /* { dg-output "res: 2147483647, 2147483647" } */
+  CHECK(res == 2147483647L);
+  CHECK(ul1 + ul2 == 2147483647L);
 
   exit(0);
 }
diff --git a/libffi/testsuite/libffi.call/s55.c b/libffi/testsuite/libffi.call/s55.c
new file mode 100644 (file)
index 0000000..94dfd5f
--- /dev/null
@@ -0,0 +1,60 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct
+{
+  float f;
+} s55;
+
+static s55 ABI_ATTR f55(s55 ts, float f)
+{
+  s55 r;
+  r.f = ts.f + f;
+  printf ("f55>> %g + %g = %g\n", ts.f, f, r.f);
+  return r;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  s55 F, Fr;
+  float f;
+  void *values[] = { &F, &f };
+  ffi_type s55_type;
+  ffi_type *args[] = { &s55_type, &ffi_type_float };
+  ffi_type *s55_type_elements[] = { &ffi_type_float, NULL };
+
+  /* This is a hack to get a properly aligned result buffer */
+  s55 *s55_result =
+    (s55 *) malloc (sizeof(s55));
+
+  s55_type.size = 0;
+  s55_type.alignment = 0;
+  s55_type.type = FFI_TYPE_STRUCT;
+  s55_type.elements = s55_type_elements;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 2, &s55_type, args) == FFI_OK);
+
+  F.f = 1;
+  Fr = f55(F, 2.14);
+  printf ("%g\n", Fr.f);
+
+  F.f = 1;
+  f = 2.14;
+  ffi_call(&cif, FFI_FN(f55), s55_result, values);
+  printf ("%g\n", s55_result->f);
+
+  fflush(0);
+
+  CHECK(fabs(Fr.f - s55_result->f) < FLT_EPSILON);
+
+  free (s55_result);
+  exit(0);
+}
index 35b70ea4e2e1cfb191d7030e777dfb1c734ad8b2..3ed53d55802c0aa4aa772c64f5fbabade130c27a 100644 (file)
@@ -7,9 +7,9 @@
 /* { dg-do run } */
 #include "ffitest.h"
 
-static size_t ABI_ATTR my_strlen(char *s)
+static unsigned int ABI_ATTR my_strlen(char *s)
 {
-  return (strlen(s));
+  return (unsigned int) (strlen(s));
 }
 
 int main (void)
@@ -22,23 +22,22 @@ int main (void)
 
   args[0] = &ffi_type_pointer;
   values[0] = (void*) &s;
-  
+
   /* Initialize the cif */
   CHECK(ffi_prep_cif(&cif, ABI_NUM, 1,
-                    &ffi_type_sint, args) == FFI_OK);
-  
+                    &ffi_type_uint, args) == FFI_OK);
+
   s = "a";
   ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
   CHECK(rint == 1);
-  
+
   s = "1234567";
   ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
   CHECK(rint == 7);
-  
+
   s = "1234567890123456789012345";
   ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
   CHECK(rint == 25);
-  
+
   exit (0);
 }
-  
index 96282bc0a1fa45d8d8cdaf59ee855fdd63785cf3..93e5a33028cbaa828d4674b9d2a2e588cd289eb6 100644 (file)
@@ -8,9 +8,9 @@
 
 #include "ffitest.h"
 
-static size_t ABI_ATTR my_f(char *s, float a)
+static int ABI_ATTR my_f(char *s, float a)
 {
-  return (size_t) ((int) strlen(s) + (int) a);
+  return (int) strlen(s) + (int) a;
 }
 
 int main (void)
index beba86e9eacf4910fc416b7ec6f443153a66536b..c7d472d22d8359523d4e6c5b5d6f22ceb19d5826 100644 (file)
@@ -8,9 +8,9 @@
 
 #include "ffitest.h"
 
-static size_t ABI_ATTR my_f(float a, char *s)
+static int ABI_ATTR my_f(float a, char *s)
 {
-  return (size_t) ((int) strlen(s) + (int) a);
+  return (int) strlen(s) + (int) a;
 }
 
 int main (void)
index d5d42b4f6ddff4d3181eafebe20c9489c5859e98..ba5c2740ec0f3da4037d05edef8add8934af9b7e 100644 (file)
@@ -8,9 +8,9 @@
 
 #include "ffitest.h"
 
-static size_t ABI_ATTR my_f(float a, char *s, int i)
+static int ABI_ATTR my_f(float a, char *s, int i)
 {
-  return (size_t) ((int) strlen(s) + (int) a + i);
+  return (int) strlen(s) + (int) a + i;
 }
 
 int main (void)
index 17b1377424121af0c8fed36675941ddd24832110..1edbd5ffb98c699740594ffab78ea0c1d41a3498 100644 (file)
@@ -16,7 +16,7 @@ struct s {
   signed char s8;
 };
 
-struct s make_s(void) {
+struct s ABI_ATTR make_s(void) {
   struct s r;
   r.s32 = 0x1234;
   r.f32 = 7.0;
diff --git a/libffi/testsuite/libffi.call/struct_by_value_2.c b/libffi/testsuite/libffi.call/struct_by_value_2.c
new file mode 100644 (file)
index 0000000..f170289
--- /dev/null
@@ -0,0 +1,63 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct
+{
+  unsigned int ui01;
+  unsigned int ui02;
+} test_structure_1;
+
+static test_structure_1 ABI_ATTR struct1(test_structure_1 ts)
+{
+  ts.ui02++;
+
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts1_type;
+  ffi_type *ts1_type_elements[3];
+
+  test_structure_1 ts1_arg;
+
+  /* This is a hack to get a properly aligned result buffer */
+  test_structure_1 *ts1_result =
+    (test_structure_1 *) malloc (sizeof(test_structure_1));
+
+  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_uint;
+  ts1_type_elements[1] = &ffi_type_uint;
+  ts1_type_elements[2] = NULL;
+
+  args[0] = &ts1_type;
+  values[0] = &ts1_arg;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 1,
+                    &ts1_type, args) == FFI_OK);
+
+  ts1_arg.ui02 = 555;
+
+  ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
+
+  CHECK(ts1_result->ui02 == 556);
+
+  /* This will fail if ffi_call isn't passing the struct by value. */
+  CHECK(ts1_arg.ui02 == 555);
+
+  free (ts1_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/struct_by_value_3.c b/libffi/testsuite/libffi.call/struct_by_value_3.c
new file mode 100644 (file)
index 0000000..55cf113
--- /dev/null
@@ -0,0 +1,65 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct
+{
+  unsigned int ui01;
+  unsigned int ui02;
+  unsigned int ui03;
+} test_structure_1;
+
+static test_structure_1 ABI_ATTR struct1(test_structure_1 ts)
+{
+  ts.ui03++;
+
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts1_type;
+  ffi_type *ts1_type_elements[4];
+
+  test_structure_1 ts1_arg;
+
+  /* This is a hack to get a properly aligned result buffer */
+  test_structure_1 *ts1_result =
+    (test_structure_1 *) malloc (sizeof(test_structure_1));
+
+  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_uint;
+  ts1_type_elements[1] = &ffi_type_uint;
+  ts1_type_elements[2] = &ffi_type_uint;
+  ts1_type_elements[3] = NULL;
+
+  args[0] = &ts1_type;
+  values[0] = &ts1_arg;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 1,
+                    &ts1_type, args) == FFI_OK);
+
+  ts1_arg.ui03 = 555;
+
+  ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
+
+  CHECK(ts1_result->ui03 == 556);
+
+  /* This will fail if ffi_call isn't passing the struct by value. */
+  CHECK(ts1_arg.ui03 == 555);
+
+  free (ts1_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/struct_by_value_3f.c b/libffi/testsuite/libffi.call/struct_by_value_3f.c
new file mode 100644 (file)
index 0000000..8b5b1db
--- /dev/null
@@ -0,0 +1,65 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct
+{
+  float f01;
+  float f02;
+  float f03;
+} test_structure_1;
+
+static test_structure_1 ABI_ATTR struct1(test_structure_1 ts)
+{
+  ts.f03++;
+
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts1_type;
+  ffi_type *ts1_type_elements[5];
+
+  test_structure_1 ts1_arg;
+
+  /* This is a hack to get a properly aligned result buffer */
+  test_structure_1 *ts1_result =
+    (test_structure_1 *) malloc (sizeof(test_structure_1));
+
+  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_float;
+  ts1_type_elements[1] = &ffi_type_float;
+  ts1_type_elements[2] = &ffi_type_float;
+  ts1_type_elements[3] = NULL;
+
+  args[0] = &ts1_type;
+  values[0] = &ts1_arg;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 1,
+                    &ts1_type, args) == FFI_OK);
+
+  ts1_arg.f03 = 555.5;
+
+  ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
+
+  CHECK(fabs(ts1_result->f03 - 556.5) < FLT_EPSILON);
+
+  /* This will fail if ffi_call isn't passing the struct by value. */
+  CHECK(fabs(ts1_arg.f03 - 555.5) < FLT_EPSILON);
+
+  free (ts1_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/struct_by_value_4.c b/libffi/testsuite/libffi.call/struct_by_value_4.c
new file mode 100644 (file)
index 0000000..768650f
--- /dev/null
@@ -0,0 +1,67 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct
+{
+  unsigned int ui01;
+  unsigned int ui02;
+  unsigned int ui03;
+  unsigned int ui04;
+} test_structure_1;
+
+static test_structure_1 ABI_ATTR struct1(test_structure_1 ts)
+{
+  ts.ui04++;
+
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts1_type;
+  ffi_type *ts1_type_elements[5];
+
+  test_structure_1 ts1_arg;
+
+  /* This is a hack to get a properly aligned result buffer */
+  test_structure_1 *ts1_result =
+    (test_structure_1 *) malloc (sizeof(test_structure_1));
+
+  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_uint;
+  ts1_type_elements[1] = &ffi_type_uint;
+  ts1_type_elements[2] = &ffi_type_uint;
+  ts1_type_elements[3] = &ffi_type_uint;
+  ts1_type_elements[4] = NULL;
+
+  args[0] = &ts1_type;
+  values[0] = &ts1_arg;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 1,
+                    &ts1_type, args) == FFI_OK);
+
+  ts1_arg.ui04 = 555;
+
+  ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
+
+  CHECK(ts1_result->ui04 == 556);
+
+  /* This will fail if ffi_call isn't passing the struct by value. */
+  CHECK(ts1_arg.ui04 == 555);
+
+  free (ts1_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/struct_by_value_4f.c b/libffi/testsuite/libffi.call/struct_by_value_4f.c
new file mode 100644 (file)
index 0000000..bf6775a
--- /dev/null
@@ -0,0 +1,67 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct
+{
+  float f01;
+  float f02;
+  float f03;
+  float f04;
+} test_structure_1;
+
+static test_structure_1 ABI_ATTR struct1(test_structure_1 ts)
+{
+  ts.f04++;
+
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts1_type;
+  ffi_type *ts1_type_elements[5];
+
+  test_structure_1 ts1_arg;
+
+  /* This is a hack to get a properly aligned result buffer */
+  test_structure_1 *ts1_result =
+    (test_structure_1 *) malloc (sizeof(test_structure_1));
+
+  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_float;
+  ts1_type_elements[1] = &ffi_type_float;
+  ts1_type_elements[2] = &ffi_type_float;
+  ts1_type_elements[3] = &ffi_type_float;
+  ts1_type_elements[4] = NULL;
+
+  args[0] = &ts1_type;
+  values[0] = &ts1_arg;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 1,
+                    &ts1_type, args) == FFI_OK);
+
+  ts1_arg.f04 = 555.5;
+
+  ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
+
+  CHECK(fabs(ts1_result->f04 - 556.5) < FLT_EPSILON);
+
+  /* This will fail if ffi_call isn't passing the struct by value. */
+  CHECK(fabs(ts1_arg.f04 - 555.5) < FLT_EPSILON);
+
+  free (ts1_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/struct_by_value_big.c b/libffi/testsuite/libffi.call/struct_by_value_big.c
new file mode 100644 (file)
index 0000000..06422ca
--- /dev/null
@@ -0,0 +1,93 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct
+{
+  unsigned int ui01;
+  unsigned int ui02;
+  unsigned int ui03;
+  unsigned int ui04;
+  unsigned int ui05;
+  unsigned int ui06;
+  unsigned int ui07;
+  unsigned int ui08;
+  unsigned int ui09;
+  unsigned int ui10;
+  unsigned int ui11;
+  unsigned int ui12;
+  unsigned int ui13;
+  unsigned int ui14;
+  unsigned int ui15;
+  unsigned int ui16;
+  unsigned int ui17;
+} test_structure_1;
+
+static test_structure_1 ABI_ATTR struct1(test_structure_1 ts)
+{
+  ts.ui17++;
+
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts1_type;
+  ffi_type *ts1_type_elements[18];
+
+  test_structure_1 ts1_arg;
+
+  /* This is a hack to get a properly aligned result buffer */
+  test_structure_1 *ts1_result =
+    (test_structure_1 *) malloc (sizeof(test_structure_1));
+
+  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_uint;
+  ts1_type_elements[1] = &ffi_type_uint;
+  ts1_type_elements[2] = &ffi_type_uint;
+  ts1_type_elements[3] = &ffi_type_uint;
+  ts1_type_elements[4] = &ffi_type_uint;
+  ts1_type_elements[5] = &ffi_type_uint;
+  ts1_type_elements[6] = &ffi_type_uint;
+  ts1_type_elements[7] = &ffi_type_uint;
+  ts1_type_elements[8] = &ffi_type_uint;
+  ts1_type_elements[9] = &ffi_type_uint;
+  ts1_type_elements[10] = &ffi_type_uint;
+  ts1_type_elements[11] = &ffi_type_uint;
+  ts1_type_elements[12] = &ffi_type_uint;
+  ts1_type_elements[13] = &ffi_type_uint;
+  ts1_type_elements[14] = &ffi_type_uint;
+  ts1_type_elements[15] = &ffi_type_uint;
+  ts1_type_elements[16] = &ffi_type_uint;
+  ts1_type_elements[17] = NULL;
+
+  args[0] = &ts1_type;
+  values[0] = &ts1_arg;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 1,
+                    &ts1_type, args) == FFI_OK);
+
+  ts1_arg.ui17 = 555;
+
+  ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
+
+  CHECK(ts1_result->ui17 == 556);
+
+  /* This will fail if ffi_call isn't passing the struct by value. */
+  CHECK(ts1_arg.ui17 == 555);
+
+  free (ts1_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/struct_by_value_small.c b/libffi/testsuite/libffi.call/struct_by_value_small.c
new file mode 100644 (file)
index 0000000..19613f8
--- /dev/null
@@ -0,0 +1,61 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct
+{
+  unsigned int ui17;
+} test_structure_1;
+
+static test_structure_1 ABI_ATTR struct1(test_structure_1 ts)
+{
+  ts.ui17++;
+
+  return ts;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts1_type;
+  ffi_type *ts1_type_elements[2];
+
+  test_structure_1 ts1_arg;
+
+  /* This is a hack to get a properly aligned result buffer */
+  test_structure_1 *ts1_result =
+    (test_structure_1 *) malloc (sizeof(test_structure_1));
+
+  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_uint;
+  ts1_type_elements[1] = NULL;
+
+  args[0] = &ts1_type;
+  values[0] = &ts1_arg;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 1,
+                    &ts1_type, args) == FFI_OK);
+
+  ts1_arg.ui17 = 555;
+
+  ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
+
+  CHECK(ts1_result->ui17 == 556);
+
+  /* This will fail if ffi_call isn't passing the struct by value. */
+  CHECK(ts1_arg.ui17 == 555);
+
+  free (ts1_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/struct_int_float.c b/libffi/testsuite/libffi.call/struct_int_float.c
new file mode 100644 (file)
index 0000000..66ef6c4
--- /dev/null
@@ -0,0 +1,88 @@
+/* Area:       ffi_call
+   Purpose:    Demonstrate structures with integers corrupting earlier floats
+   Limitations:        none.
+   PR:         #848
+   Originator: kellda  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+typedef struct
+{
+  unsigned long i;
+  float f;
+} test_structure_int_float;
+
+static float ABI_ATTR struct_int_float(test_structure_int_float ts1,
+                                       test_structure_int_float ts2 __UNUSED__,
+                                       test_structure_int_float ts3 __UNUSED__,
+                                       test_structure_int_float ts4 __UNUSED__,
+                                       test_structure_int_float ts5 __UNUSED__,
+                                       test_structure_int_float ts6 __UNUSED__)
+{
+  return ts1.f;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts_type;
+  ffi_type *ts_type_elements[3];
+  float rfloat;
+
+  test_structure_int_float ts_arg[6];
+
+  ts_type.size = 0;
+  ts_type.alignment = 0;
+  ts_type.type = FFI_TYPE_STRUCT;
+  ts_type.elements = ts_type_elements;
+  ts_type_elements[0] = &ffi_type_ulong;
+  ts_type_elements[1] = &ffi_type_float;
+  ts_type_elements[2] = NULL;
+
+  args[0] = &ts_type;
+  values[0] = &ts_arg[0];
+  args[1] = &ts_type;
+  values[1] = &ts_arg[1];
+  args[2] = &ts_type;
+  values[2] = &ts_arg[2];
+  args[3] = &ts_type;
+  values[3] = &ts_arg[3];
+  args[4] = &ts_type;
+  values[4] = &ts_arg[4];
+  args[5] = &ts_type;
+  values[5] = &ts_arg[5];
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 6, &ffi_type_float, args) == FFI_OK);
+
+  ts_arg[0].i = 1;
+  ts_arg[0].f = 11.11f;
+  ts_arg[1].i = 2;
+  ts_arg[1].f = 22.22f;
+  ts_arg[2].i = 3;
+  ts_arg[2].f = 33.33f;
+  ts_arg[3].i = 4;
+  ts_arg[3].f = 44.44f;
+  ts_arg[4].i = 5;
+  ts_arg[4].f = 55.55f;
+  ts_arg[5].i = 6;
+  ts_arg[5].f = 66.66f;
+
+  printf ("%g\n", ts_arg[0].f);
+  printf ("%g\n", ts_arg[1].f);
+  printf ("%g\n", ts_arg[2].f);
+  printf ("%g\n", ts_arg[3].f);
+  printf ("%g\n", ts_arg[4].f);
+  printf ("%g\n", ts_arg[5].f);
+
+  ffi_call(&cif, FFI_FN(struct_int_float), &rfloat, values);
+
+  printf ("%g\n", rfloat);
+
+  CHECK(fabs(rfloat - 11.11) < 3 * FLT_EPSILON);
+
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/struct_return_2H.c b/libffi/testsuite/libffi.call/struct_return_2H.c
new file mode 100644 (file)
index 0000000..2773550
--- /dev/null
@@ -0,0 +1,63 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+typedef struct
+{
+  short x;
+  short y;
+} test_structure_5;
+
+static test_structure_5 ABI_ATTR struct5(test_structure_5 inp)
+{
+  inp.x *= 2;
+  inp.y *= 3;
+
+  return inp;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts5_type;
+  ffi_type *ts5_type_elements[3];
+
+  test_structure_5 ts5_arg1;
+
+  /* This is a hack to get a properly aligned result buffer */
+  test_structure_5 *ts5_result =
+    (test_structure_5 *) malloc (sizeof(test_structure_5));
+
+  ts5_type.size = 0;
+  ts5_type.alignment = 0;
+  ts5_type.type = FFI_TYPE_STRUCT;
+  ts5_type.elements = ts5_type_elements;
+  ts5_type_elements[0] = &ffi_type_sshort;
+  ts5_type_elements[1] = &ffi_type_sshort;
+  ts5_type_elements[2] = NULL;
+
+  args[0] = &ts5_type;
+  values[0] = &ts5_arg1;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts5_type, args) == FFI_OK);
+
+  ts5_arg1.x = 99;
+  ts5_arg1.y = 88;
+
+  ffi_call (&cif, FFI_FN(struct5), ts5_result, values);
+
+  CHECK(ts5_result->x == 99*2);
+  CHECK(ts5_result->y == 88*3);
+  CHECK(ts5_arg1.x == 99);
+  CHECK(ts5_arg1.y == 88);
+
+  free (ts5_result);
+  exit(0);
+}
diff --git a/libffi/testsuite/libffi.call/struct_return_8H.c b/libffi/testsuite/libffi.call/struct_return_8H.c
new file mode 100644 (file)
index 0000000..5018daa
--- /dev/null
@@ -0,0 +1,90 @@
+/* Area:       ffi_call
+   Purpose:    Check structures.
+   Limitations:        none.
+   PR:         none.
+   Originator: From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+typedef struct
+{
+  int a;
+  int b;
+  int c;
+  int d;
+  int e;
+  int f;
+  int g;
+  int h;
+} test_structure_5;
+
+static test_structure_5 ABI_ATTR struct5(test_structure_5 inp)
+{
+  inp.a *= 2;
+  inp.b *= 3;
+  inp.c *= 4;
+  inp.d *= 5;
+  inp.e *= 6;
+  inp.f *= 7;
+  inp.g *= 8;
+  inp.h *= 9;
+  return inp;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+  ffi_type ts5_type;
+  ffi_type *ts5_type_elements[9];
+
+  test_structure_5 ts5_arg1;
+
+  /* This is a hack to get a properly aligned result buffer */
+  test_structure_5 *ts5_result =
+    (test_structure_5 *) malloc (sizeof(test_structure_5));
+
+  ts5_type.size = 0;
+  ts5_type.alignment = 0;
+  ts5_type.type = FFI_TYPE_STRUCT;
+  ts5_type.elements = ts5_type_elements;
+  ts5_type_elements[0] = &ffi_type_sint;
+  ts5_type_elements[1] = &ffi_type_sint;
+  ts5_type_elements[2] = &ffi_type_sint;
+  ts5_type_elements[3] = &ffi_type_sint;
+  ts5_type_elements[4] = &ffi_type_sint;
+  ts5_type_elements[5] = &ffi_type_sint;
+  ts5_type_elements[6] = &ffi_type_sint;
+  ts5_type_elements[7] = &ffi_type_sint;
+  ts5_type_elements[8] = NULL;
+
+  args[0] = &ts5_type;
+  values[0] = &ts5_arg1;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts5_type, args) == FFI_OK);
+
+  ts5_arg1.a = 9;
+  ts5_arg1.b = 8;
+  ts5_arg1.c = 7;
+  ts5_arg1.d = 6;
+  ts5_arg1.e = 5;
+  ts5_arg1.f = 4;
+  ts5_arg1.g = 3;
+  ts5_arg1.h = 2;
+
+  ffi_call (&cif, FFI_FN(struct5), ts5_result, values);
+
+  CHECK(ts5_result->a == 9*2);
+  CHECK(ts5_result->b == 8*3);
+  CHECK(ts5_result->c == 7*4);
+  CHECK(ts5_result->d == 6*5);
+  CHECK(ts5_result->e == 5*6);
+  CHECK(ts5_result->f == 4*7);
+  CHECK(ts5_result->g == 3*8);
+  CHECK(ts5_result->h == 2*9);
+
+  free (ts5_result);
+  exit(0);
+}
index 0589d08489ca812199ae76750b2988fdc9758d29..75d4dfc3dda54c32230e6b5544bf48b646d6e600 100644 (file)
@@ -5,7 +5,7 @@
    Originator:         ARM Ltd. */
 
 /* { dg-do run } */
-/* { dg-output "" { xfail avr32*-*-* m68k-*-* alpha-*-* } } */
+/* { dg-output "" { xfail avr32*-*-* m68k-*-* } } */
 
 #include "ffitest.h"
 #include <stdarg.h>
@@ -25,6 +25,7 @@ struct large_tag
   unsigned e;
 };
 
+
 static int
 test_fn (int n, ...)
 {
@@ -72,7 +73,29 @@ test_fn (int n, ...)
          ui, si,
          ul, sl,
          f, d);
+
   va_end (ap);
+
+  CHECK(s1.a == 5);
+  CHECK(s1.b == 6);
+  CHECK(l.a == 10);
+  CHECK(l.b == 11);
+  CHECK(l.c == 12);
+  CHECK(l.d == 13);
+  CHECK(l.e == 14);
+  CHECK(s2.a == 7);
+  CHECK(s2.b == 8);
+  CHECK(uc == 9);
+  CHECK(sc == 10);
+  CHECK(us == 11);
+  CHECK(ss == 12);
+  CHECK(ui == 13);
+  CHECK(si == 14);
+  CHECK(ul == 15);
+  CHECK(sl == 16);
+  CHECK((int)f == 2);
+  CHECK((int)d == 3);
+
   return n + 1;
 }
 
@@ -191,6 +214,7 @@ main (void)
   /* { dg-output "5 6 10 11 12 13 14 7 8 uc=9 sc=10 11 12 13 14 15 16 2.120000 3.130000" } */
   printf("res: %d\n", (int) res);
   /* { dg-output "\nres: 42" } */
+  CHECK(res == 42);
 
   return 0;
 }
diff --git a/libffi/testsuite/libffi.call/va_3.c b/libffi/testsuite/libffi.call/va_3.c
new file mode 100644 (file)
index 0000000..b3e73b5
--- /dev/null
@@ -0,0 +1,154 @@
+/* Area:               ffi_call
+   Purpose:            Test function with multiple fixed args and variable argument list.
+   Limitations:        none.
+   PR:                 none.
+   Originator:         ARM Ltd., Oracle */
+
+/* { dg-do run } */
+/* { dg-output "" { xfail avr32*-*-* m68k-*-* } } */
+
+#include "ffitest.h"
+#include <stdarg.h>
+
+/*
+ * This is a modified version of va_2.c that has fixed arguments with "small" types that
+ * are not allowed as variable arguments, but they should be still allowed as fixed args.
+ */
+
+static int
+test_fn (char a1, float a2, int n, ...)
+{
+  va_list ap;
+  unsigned char uc;
+  signed char sc;
+  unsigned short us;
+  signed short ss;
+  unsigned int ui;
+  signed int si;
+  unsigned long ul;
+  signed long sl;
+  float f;
+  double d;
+
+  va_start (ap, n);
+
+  uc = va_arg (ap, unsigned);
+  sc = va_arg (ap, signed);
+
+  us = va_arg (ap, unsigned);
+  ss = va_arg (ap, signed);
+
+  ui = va_arg (ap, unsigned int);
+  si = va_arg (ap, signed int);
+
+  ul = va_arg (ap, unsigned long);
+  sl = va_arg (ap, signed long);
+
+  f = va_arg (ap, double);     /* C standard promotes float->double
+                                  when anonymous */
+  d = va_arg (ap, double);
+
+  printf ("%d %f uc=%u sc=%d %u %d %u %d %lu %ld %f %f\n",
+         a1, a2,
+         uc, sc,
+         us, ss,
+         ui, si,
+         ul, sl,
+         f, d);
+
+  va_end (ap);
+
+  CHECK(a1 == 1);
+  CHECK((int)a2 == 2);
+  CHECK(uc == 9);
+  CHECK(sc == 10);
+  CHECK(us == 11);
+  CHECK(ss == 12);
+  CHECK(ui == 13);
+  CHECK(si == 14);
+  CHECK(ul == 15);
+  CHECK(sl == 16);
+  CHECK((int)f == 2);
+  CHECK((int)d == 3);
+
+  return n + 1;
+}
+
+int
+main (void)
+{
+  ffi_cif cif;
+  void* args[14];
+  ffi_type* arg_types[14];
+
+  char a1;
+  float a2;
+  int n;
+  ffi_arg res;
+
+  unsigned int uc;
+  signed int sc;
+  unsigned int us;
+  signed int ss;
+  unsigned int ui;
+  signed int si;
+  unsigned long ul;
+  signed long sl;
+  double d1;
+  double f1;
+
+  arg_types[0] = &ffi_type_schar;
+  arg_types[1] = &ffi_type_float;
+  arg_types[2] = &ffi_type_sint;
+  arg_types[3] = &ffi_type_uint;
+  arg_types[4] = &ffi_type_sint;
+  arg_types[5] = &ffi_type_uint;
+  arg_types[6] = &ffi_type_sint;
+  arg_types[7] = &ffi_type_uint;
+  arg_types[8] = &ffi_type_sint;
+  arg_types[9] = &ffi_type_ulong;
+  arg_types[10] = &ffi_type_slong;
+  arg_types[11] = &ffi_type_double;
+  arg_types[12] = &ffi_type_double;
+  arg_types[13] = NULL;
+
+  CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 3, 13, &ffi_type_sint, arg_types) == FFI_OK);
+
+  a1 = 1;
+  a2 = 2.0f;
+  n = 41;
+
+  uc = 9;
+  sc = 10;
+  us = 11;
+  ss = 12;
+  ui = 13;
+  si = 14;
+  ul = 15;
+  sl = 16;
+  f1 = 2.12;
+  d1 = 3.13;
+
+  args[0] = &a1;
+  args[1] = &a2;
+  args[2] = &n;
+  args[3] = &uc;
+  args[4] = &sc;
+  args[5] = &us;
+  args[6] = &ss;
+  args[7] = &ui;
+  args[8] = &si;
+  args[9] = &ul;
+  args[10] = &sl;
+  args[11] = &f1;
+  args[12] = &d1;
+  args[13] = NULL;
+
+  ffi_call(&cif, FFI_FN(test_fn), &res, args);
+  /* { dg-output "1 2.000000 uc=9 sc=10 11 12 13 14 15 16 2.120000 3.130000" } */
+  printf("res: %d\n", (int) res);
+  /* { dg-output "\nres: 42" } */
+  CHECK(res == 42);
+
+  return 0;
+}
index e6452061c1d3b5427c41b062186a329e080a9f41..fff5c9accfd78e694176e1bc8be4f03583992839 100644 (file)
@@ -40,6 +40,18 @@ test_fn (int n, ...)
   printf ("%u %u %u %u %u %u %u %u %u\n", s1.a, s1.b, l.a, l.b, l.c, l.d, l.e,
          s2.a, s2.b);
   va_end (ap);
+
+  CHECK(s1.a == 5);
+  CHECK(s1.b == 6);
+
+  CHECK(l.a == 10);
+  CHECK(l.b == 11);
+  CHECK(l.c == 12);
+  CHECK(l.d == 13);
+  CHECK(l.e == 14);
+
+  CHECK(s2.a == 7);
+  CHECK(s2.b == 8);
   return n + 1;
 }
 
@@ -116,6 +128,7 @@ main (void)
   /* { dg-output "5 6 10 11 12 13 14 7 8" } */
   printf("res: %d\n", (int) res);
   /* { dg-output "\nres: 42" } */
+  CHECK(res == 42);
 
   return 0;
 }
index 49359be712cad694c94423065d05c4a148adbe17..a034087077516d32bc2625167f200f3ddc612f74 100644 (file)
@@ -40,6 +40,15 @@ test_fn (int n, ...)
   s2 = va_arg (ap, struct small_tag);
   printf ("%u %u %u %u %u %u %u %u %u\n", s1.a, s1.b, l.a, l.b, l.c, l.d, l.e,
          s2.a, s2.b);
+  CHECK(s1.a == 5);
+  CHECK(s1.b == 6);
+  CHECK(l.a == 10);
+  CHECK(l.b == 11);
+  CHECK(l.c == 12);
+  CHECK(l.d == 13);
+  CHECK(l.e == 14);
+  CHECK(s2.a == 7);
+  CHECK(s2.b == 8);
   va_end (ap);
   s1.a += s2.a;
   s1.b += s2.b;
@@ -119,6 +128,8 @@ main (void)
   /* { dg-output "5 6 10 11 12 13 14 7 8" } */
   printf("res: %d %d\n", res.a, res.b);
   /* { dg-output "\nres: 12 14" } */
+  CHECK(res.a == 12);
+  CHECK(res.b == 14);
 
   return 0;
 }
index c30f9af88940a8a9d9d8670a3407e073f8439ea9..5a52c9f23e268084a25cfc630c5b18a011a3d496 100644 (file)
@@ -40,6 +40,16 @@ test_fn (int n, ...)
   s2 = va_arg (ap, struct small_tag);
   printf ("%u %u %u %u %u %u %u %u %u\n", s1.a, s1.b, l.a, l.b, l.c, l.d, l.e,
          s2.a, s2.b);
+
+  CHECK(s1.a == 5);
+  CHECK(s1.b == 6);
+  CHECK(l.a == 10);
+  CHECK(l.b == 11);
+  CHECK(l.c == 12);
+  CHECK(l.d == 13);
+  CHECK(l.e == 14);
+  CHECK(s2.a == 7);
+  CHECK(s2.b == 8);
   va_end (ap);
   l.a += s1.a;
   l.b += s1.b;
@@ -121,6 +131,11 @@ main (void)
   /* { dg-output "5 6 10 11 12 13 14 7 8" } */
   printf("res: %d %d %d %d %d\n", res.a, res.b, res.c, res.d, res.e);
   /* { dg-output "\nres: 15 17 19 21 14" } */
+  CHECK(res.a == 15);
+  CHECK(res.b == 17);
+  CHECK(res.c == 19);
+  CHECK(res.d == 21);
+  CHECK(res.e == 14);
 
   return 0;
 }
diff --git a/libffi/testsuite/libffi.call/x32.c b/libffi/testsuite/libffi.call/x32.c
new file mode 100644 (file)
index 0000000..9c380a5
--- /dev/null
@@ -0,0 +1,31 @@
+/* Area:        ffi_call
+   Purpose:     Check zero-extension of pointers on x32.
+   Limitations: none.
+   PR:          887
+   Originator:  Mikulas Patocka <mikulas@twibright.com>  */
+
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+static int ABI_ATTR fn(int *a)
+{
+       if (a)
+               return *a;
+       return -1;
+}
+
+int main(void)
+{
+       ffi_cif cif;
+       ffi_type *args[MAX_ARGS];
+       void *values[MAX_ARGS];
+       void *z[2] = { (void *)0, (void *)1 };
+       ffi_arg rint;
+       args[0] = &ffi_type_pointer;
+       values[0] = z;
+       CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ffi_type_sint, args) == FFI_OK);
+       ffi_call(&cif, FFI_FN(fn), &rint, values);
+       CHECK((int)rint == -1);
+       exit(0);
+}
index a579ff6c979f3f219cd5fab04c52678c67cf12f0..dfadb05563d35c040b9dd8e5736bdf594ad779d0 100644 (file)
@@ -38,7 +38,7 @@ closure_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args,
         (int)*(int *)args[12], (int)(*(int *)args[13]),
         (int)(*(int *)args[14]),*(int *)args[15],
         (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
-
+  CHECK((int)*(ffi_arg *)resp == 680);
 }
 
 typedef int (*closure_test_type0)(unsigned long long, int, unsigned long long,
@@ -85,5 +85,6 @@ int main (void)
   /* { 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);
+  CHECK(res == 680);
+  exit(0);
 }
index 91231738c13b5240d2ee07b2d416b0738e9dac7a..a90bb291b5b5cb535f23bd41f2b9d6274deff819 100644 (file)
@@ -33,6 +33,7 @@ static void closure_test_fn1(ffi_cif* cif __UNUSED__, void* resp, void** args,
         (int)*(int *)args[12], (int)(*(int *)args[13]),
         (int)(*(int *)args[14]), *(int *)args[15],
         (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+  CHECK((int)*(ffi_arg *)resp == 255);
 }
 
 typedef int (*closure_test_type1)(float, float, float, float, signed short,
@@ -77,5 +78,6 @@ int main (void)
   /* { 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" } */
+  CHECK(res == 255);
   exit(0);
 }
index 08ff9d92274c317162ec862934e7e226564ada56..7d7af4b59baa2edd469b98ca20fba5d1659096e1 100644 (file)
@@ -32,6 +32,7 @@ static void closure_test_fn2(ffi_cif* cif __UNUSED__, void* resp, void** args,
         (int)*(int *)args[12], (int)(*(float *)args[13]),
         (int)(*(int *)args[14]), *(int *)args[15], (int)(intptr_t)userdata,
         (int)*(ffi_arg *)resp);
+  CHECK((int)*(ffi_arg *)resp == 255);
 }
 
 typedef int (*closure_test_type2)(double, double, double, double, signed short,
@@ -77,5 +78,6 @@ int main (void)
   /* { 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" } */
+  CHECK(res == 255);
   exit(0);
 }
index 9b54d805c8296ad87dd89502dc158284e90a2927..1ad8f9d86f42df625dbcc9e35de53cbd250f32e8 100644 (file)
@@ -31,8 +31,27 @@ static void closure_test_fn3(ffi_cif* cif __UNUSED__, void* resp, void** args,
          (int)(*(float *)args[10]), (int)(*(float *)args[11]),
          (int)*(int *)args[12], (int)(*(float *)args[13]),
          (int)(*(float *)args[14]), *(int *)args[15], (int)(intptr_t)userdata,
-         (int)*(ffi_arg *)resp);
+    (int)*(ffi_arg *)resp);
 
+    CHECK((int)*(float *)args[0] == 1);
+    CHECK((int)(*(float *)args[1]) == 2);
+    CHECK((int)(*(float *)args[2]) == 3);
+    CHECK((int)(*(float *)args[3]) == 4);
+    CHECK((int)(*(float *)args[4]) == 5);
+    CHECK((int)(*(float *)args[5]) == 6);
+    CHECK((int)*(float *)args[6] == 7);
+    CHECK((int)(*(float *)args[7]) == 8);
+    CHECK((int)(*(double *)args[8]) == 9);
+    CHECK((int)*(int *)args[9] == 10);
+    CHECK((int)(*(float *)args[10]) == 11);
+    CHECK((int)(*(float *)args[11]) == 12);
+    CHECK((int)*(int *)args[12] == 13);
+    CHECK((int)(*(float *)args[13]) == 19);
+    CHECK((int)(*(float *)args[14]) == 21);
+    CHECK(*(int *)args[15] == 1);
+    CHECK((int)(intptr_t)userdata == 3);
+
+    CHECK((int)*(ffi_arg *)resp == 135);
  }
 
 typedef int (*closure_test_type3)(float, float, float, float, float, float,
@@ -78,5 +97,6 @@ int main (void)
   /* { 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" } */
+  CHECK(res == 135);
   exit(0);
 }
index d4a1530b065b21a0cf87a4515cd3ce216b6225db..e5f1f53d1c776d2314f6d7add71b35a3831c4fab 100644 (file)
@@ -45,6 +45,7 @@ closure_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args,
         (int)*(unsigned long long *)args[14],
         *(int *)args[15],
         (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+  CHECK((int)*(ffi_arg *)resp == 680);
 
 }
 
@@ -84,6 +85,7 @@ int main (void)
   /* { 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" } */
+  CHECK(res == 680);
 
   exit(0);
 }
index 99074426c67b5a65e383b48254ea0b8a8950fdda..97277f5c318b10781eaa721b13efde8b32f921fb 100644 (file)
@@ -44,6 +44,7 @@ closure_test_fn5(ffi_cif* cif __UNUSED__, void* resp, void** args,
         (int)*(unsigned long long *)args[14],
         *(int *)args[15],
         (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+  CHECK((int)*(ffi_arg *)resp == 680);
 
 }
 
@@ -87,6 +88,7 @@ int main (void)
   /* { 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" } */
+  CHECK(res == 680);
 
   exit(0);
 }
index 73c54fd6b16016846b47c10b6d6d2f69da45f73a..fb079e2efcd83dd1ae34bb44e48376288fb0819c 100644 (file)
@@ -37,6 +37,7 @@ closure_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args,
         (int)*(int *)args[12], (int)(*(int *)args[13]),
         (int)(*(double *)args[14]), (int)(*(double *)args[15]),
         (int)(intptr_t)userdata, (int)*(ffi_arg *)resp);
+  CHECK((int)*(ffi_arg *)resp == 680);
 
 }
 
@@ -86,5 +87,6 @@ int main (void)
   /* { 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" } */
+  CHECK(res == 680);
   exit(0);
 }
index ad488acaa877d8317ae30b8c180a18074255e579..f344a6074e14297a31ef4531c51dc88180654296 100644 (file)
@@ -7,9 +7,6 @@
    Originator: <andreast@gcc.gnu.org> 20030828  */
 
 
-
-
-/* { dg-do run } */
 #include "ffitest.h"
 
 static void
@@ -82,10 +79,10 @@ int main (void)
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, closure_loc_test_fn0,
                         (void *) 3 /* userdata */, codeloc) == FFI_OK);
-  
-#ifndef FFI_EXEC_STATIC_TRAMP
+
+#if !defined(FFI_EXEC_STATIC_TRAMP) && !defined(__EMSCRIPTEN__)
   /* With static trampolines, the codeloc does not point to closure */
-  CHECK(memcmp(pcl, codeloc, sizeof(*pcl)) == 0);
+  CHECK(memcmp(pcl, FFI_CL(codeloc), sizeof(*pcl)) == 0);
 #endif
 
   res = (*((closure_loc_test_type0)codeloc))
@@ -94,5 +91,6 @@ int main (void)
   /* { 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);
+  CHECK(res == 680);
+  exit(0);
 }
index 5a4e728d4a42a72ff4d5f1dfdabc35880c44cd9d..a18b4a4ff83a2184a2ed3b8e8a7f258beb49cf89 100644 (file)
@@ -20,6 +20,11 @@ closure_test(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata)
         (int)(*(int *)args[2]), (int)(*(int *)args[3]),
          (int)*(ffi_arg *)resp);
 
+  CHECK((int)*(int *)args[0] == 0);
+  CHECK((int)*(int *)args[1] == 1);
+  CHECK((int)*(int *)args[2] == 2);
+  CHECK((int)*(int *)args[3] == 3);
+  CHECK((int)*(ffi_arg *)resp == 9);
 }
 
 typedef int (ABI_ATTR *closure_test_type0)(int, int, int, int);
@@ -50,6 +55,7 @@ int main (void)
 
   printf("res: %d\n",res);
   /* { dg-output "\nres: 9" } */
+  CHECK(res == 9);
 
   exit(0);
 }
index ea0825d175a6571e5706505010971bc1ea86bf6a..a1fdcd76f43e5e6b756792ec2ad07db61d53a418 100644 (file)
@@ -25,6 +25,17 @@ cls_struct_12byte cls_struct_12byte_fn(struct cls_struct_12byte b1,
   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);
 
+  CHECK(b1.a == 7);
+  CHECK(b1.b == 4);
+  CHECK(b1.c == 9);
+
+  CHECK(b2.a == 1);
+  CHECK(b2.b == 5);
+  CHECK(b2.c == 3);
+
+  CHECK(result.a == 8);
+  CHECK(result.b == 9);
+  CHECK(result.c == 12);
   return result;
 }
 
@@ -78,6 +89,9 @@ int main (void)
   /* { 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(res_dbl.a == 8);
+  CHECK(res_dbl.b == 9);
+  CHECK(res_dbl.c == 12);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_12byte_gn, NULL, code) == FFI_OK);
 
@@ -87,8 +101,12 @@ int main (void)
 
   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" } */
+  CHECK(res_dbl.a == 8);
+  CHECK(res_dbl.b == 9);
+  CHECK(res_dbl.c == 12);
 
   exit(0);
 }
index 89a08a2d97bb1a45a41dede9fab9559ed20bab54..57fe8737b1efd213cbbcfbee3bbba83ae4a74800 100644 (file)
@@ -26,6 +26,19 @@ cls_struct_16byte cls_struct_16byte_fn(struct cls_struct_16byte b1,
   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);
 
+  CHECK(b1.a == 7);
+  CHECK(b1.b == 8);
+  CHECK(b1.c == 9);
+
+  CHECK(b2.a == 1);
+  CHECK(b2.b == 9);
+  CHECK(b2.c == 3);
+
+  CHECK(result.a == 8);
+  CHECK(result.b == 17);
+  CHECK(result.c == 12);
+
+
   return result;
 }
 
@@ -80,6 +93,10 @@ int main (void)
   printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
   /* { dg-output "\nres: 8 17 12" } */
 
+  CHECK(res_dbl.a == 8);
+  CHECK(res_dbl.b == 17);
+  CHECK(res_dbl.c == 12);
+
   res_dbl.a = 0;
   res_dbl.b = 0.0;
   res_dbl.c = 0;
@@ -91,5 +108,10 @@ int main (void)
   printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
   /* { dg-output "\nres: 8 17 12" } */
 
+  CHECK(res_dbl.a == 8);
+  CHECK(res_dbl.b == 17);
+  CHECK(res_dbl.c == 12);
+
+
   exit(0);
 }
index 9f75da80aa05faa5aea74f237ac5c20e6fda0b09..3783121b9fefdb34f473566238cc1c8783e4f307 100644 (file)
@@ -29,6 +29,22 @@ cls_struct_18byte cls_struct_18byte_fn(struct cls_struct_18byte a1,
   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);
+
+  CHECK(a1.a == 1);
+  CHECK(a1.b == 127);
+  CHECK(a1.c == 126);
+  CHECK(a1.d == 3);
+
+  CHECK(a2.a == 4);
+  CHECK(a2.b == 125);
+  CHECK(a2.c == 124);
+  CHECK(a2.d == 5);
+
+  CHECK(result.a == 5);
+  CHECK(result.b == 252);
+  CHECK(result.c == 250);
+  CHECK(result.d == 8);
+
   return result;
 }
 
@@ -84,6 +100,10 @@ int main (void)
   /* { 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(res_dbl.a == 5);
+  CHECK(res_dbl.b == 252);
+  CHECK(res_dbl.c == 250);
+  CHECK(res_dbl.d == 8);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_18byte_gn, NULL, code) == FFI_OK);
 
@@ -91,6 +111,10 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 5);
+  CHECK(res_dbl.b == 252);
+  CHECK(res_dbl.c == 250);
+  CHECK(res_dbl.d == 8);
 
   exit(0);
 }
index 278794b5b8773039a5b1d7a9c9ddcc378f98bc27..98ce65a48a2ddb8f7cfa0c92b85fc52e36f12456 100644 (file)
@@ -32,6 +32,25 @@ cls_struct_19byte cls_struct_19byte_fn(struct cls_struct_19byte a1,
         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);
+
+  CHECK(a1.a == 1);
+  CHECK(a1.b == 127);
+  CHECK(a1.c == 126);
+  CHECK(a1.d == 3);
+  CHECK(a1.e == 120);
+
+  CHECK(a2.a == 4);
+  CHECK(a2.b == 125);
+  CHECK(a2.c == 124);
+  CHECK(a2.d == 5);
+  CHECK(a2.e == 119);
+
+  CHECK(result.a == 5);
+  CHECK(result.b == 252);
+  CHECK(result.c == 250);
+  CHECK(result.d == 8);
+  CHECK(result.e == 239);
+
   return result;
 }
 
@@ -89,6 +108,11 @@ int main (void)
   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(res_dbl.a == 5);
+  CHECK(res_dbl.b == 252);
+  CHECK(res_dbl.c == 250);
+  CHECK(res_dbl.d == 8);
+  CHECK(res_dbl.e == 239);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_19byte_gn, NULL, code) == FFI_OK);
 
@@ -97,6 +121,11 @@ int main (void)
   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(res_dbl.a == 5);
+  CHECK(res_dbl.b == 252);
+  CHECK(res_dbl.c == 250);
+  CHECK(res_dbl.d == 8);
+  CHECK(res_dbl.e == 239);
 
   exit(0);
 }
index 82492c020e2bc8452b6064d5e64a88cfca910609..49e33b9bac9b83a30172cb5b977c552e408ee31e 100644 (file)
@@ -23,6 +23,9 @@ cls_struct_1_1byte cls_struct_1_1byte_fn(struct cls_struct_1_1byte a1,
   result.a = a1.a + a2.a;
 
   printf("%d %d: %d\n", a1.a, a2.a, result.a);
+  CHECK(a1.a == 12);
+  CHECK(a2.a == 178);
+  CHECK(result.a == 190);
 
   return  result;
 }
@@ -84,6 +87,7 @@ int main (void)
   /* { dg-output "\n12 178: 190" } */
   printf("res: %d\n", res_dbl.a);
   /* { dg-output "\nres: 190" } */
+  CHECK(res_dbl.a == 190);
 
   exit(0);
 }
index 34ea021fb885eddb15151e5c8b87a3e83f320188..fdae6f7236ab7bdd84279ddad31ffd3d7d43a354 100644 (file)
@@ -25,6 +25,18 @@ static cls_struct_20byte cls_struct_20byte_fn(struct cls_struct_20byte a1,
 
   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);
+
+  CHECK(a1.a == 1);
+  CHECK(a1.b == 2);
+  CHECK(a1.c == 3);
+
+  CHECK(a2.a == 4);
+  CHECK(a2.b == 5);
+  CHECK(a2.c == 7);
+
+  CHECK(result.a == 5);
+  CHECK(result.b == 7);
+  CHECK(result.c == 10);
   return result;
 }
 
@@ -79,6 +91,9 @@ int main (void)
   /* { 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(res_dbl.a == 5);
+  CHECK(res_dbl.b == 7);
+  CHECK(res_dbl.c == 10);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_20byte_gn, NULL, code) == FFI_OK);
 
@@ -86,6 +101,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 5);
+  CHECK(res_dbl.b == 7);
+  CHECK(res_dbl.c == 10);
 
   exit(0);
 }
index eab4be6031d8a9f6a558a401d3901071ddc1a89c..e6979b5620a391413a278f257f9c440a8ec4bafe 100644 (file)
@@ -27,6 +27,19 @@ static cls_struct_20byte cls_struct_20byte_fn(struct cls_struct_20byte a1,
 
   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);
+
+  CHECK(a1.a == 1);
+  CHECK(a1.b == 2);
+  CHECK(a1.c == 3);
+
+  CHECK(a2.a == 4);
+  CHECK(a2.b == 5);
+  CHECK(a2.c == 7);
+
+  CHECK(result.a == 5);
+  CHECK(result.b == 7);
+  CHECK(result.c == 10);
+
   return result;
 }
 
@@ -81,6 +94,9 @@ int main (void)
   /* { 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(res_dbl.a == 5);
+  CHECK(res_dbl.b == 7);
+  CHECK(res_dbl.c == 10);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_20byte_gn, NULL, code) == FFI_OK);
 
@@ -89,5 +105,9 @@ int main (void)
   printf("res: %d %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c);
   /* { dg-output "\nres: 5 7 10" } */
 
+  CHECK(res_dbl.a == 5);
+  CHECK(res_dbl.b == 7);
+  CHECK(res_dbl.c == 10);
+
   exit(0);
 }
index 78796da92dd92d8f7320cdee1e1914cecd3ce27a..b204966e7edfb872710f8201cf7114c5c33c8e8d 100644 (file)
@@ -33,6 +33,30 @@ cls_struct_24byte cls_struct_24byte_fn(struct cls_struct_24byte b0,
         b2.a, b2.b, b2.c, b2.d,
         b3.a, b3.b, b3.c, b3.d,
         result.a, result.b, result.c, result.d);
+  CHECK_DOUBLE_EQ(b0.a, 9);
+  CHECK_DOUBLE_EQ(b0.b, 2);
+  CHECK(b0.c == 6);
+  CHECK_FLOAT_EQ(b0.d, 5);
+
+  CHECK_DOUBLE_EQ(b1.a, 1);
+  CHECK_DOUBLE_EQ(b1.b, 2);
+  CHECK(b1.c == 3);
+  CHECK_FLOAT_EQ(b1.d, 7);
+
+  CHECK_DOUBLE_EQ(b2.a, 4);
+  CHECK_DOUBLE_EQ(b2.b, 5);
+  CHECK(b2.c == 7);
+  CHECK_FLOAT_EQ(b2.d, 9);
+
+  CHECK_DOUBLE_EQ(b3.a, 8);
+  CHECK_DOUBLE_EQ(b3.b, 6);
+  CHECK(b3.c == 1);
+  CHECK_FLOAT_EQ(b3.d, 4);
+
+  CHECK_DOUBLE_EQ(result.a, 22);
+  CHECK_DOUBLE_EQ(result.b, 15);
+  CHECK(result.c == 17);
+  CHECK_FLOAT_EQ(result.d, 25);
 
   return result;
 }
@@ -97,6 +121,10 @@ int main (void)
   /* { dg-output "9 2 6 5 1 2 3 7 4 5 7 9 8 6 1 4: 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_DOUBLE_EQ(res_dbl.a, 22);
+  CHECK_DOUBLE_EQ(res_dbl.b, 15);
+  CHECK(res_dbl.c == 17);
+  CHECK_FLOAT_EQ(res_dbl.d, 25);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_24byte_gn, NULL, code) == FFI_OK);
 
@@ -108,6 +136,10 @@ int main (void)
   /* { dg-output "\n9 2 6 5 1 2 3 7 4 5 7 9 8 6 1 4: 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_DOUBLE_EQ(res_dbl.a, 22);
+  CHECK_DOUBLE_EQ(res_dbl.b, 15);
+  CHECK(res_dbl.c == 17);
+  CHECK_FLOAT_EQ(res_dbl.d, 25);
 
   exit(0);
 }
index 81bb0a64a3ee50eeedfcb373b531f7e563a48913..c5209b783418238913a42706f3c97758c12ffd08 100644 (file)
@@ -24,6 +24,15 @@ cls_struct_2byte cls_struct_2byte_fn(struct cls_struct_2byte a1,
 
   printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
 
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 140);
+
   return  result;
 }
 
@@ -78,6 +87,8 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 140);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_2byte_gn, NULL, code) == FFI_OK);
 
@@ -85,6 +96,8 @@ int main (void)
   /* { dg-output "\n12 127 1 13: 13 140" } */
   printf("res: %d %d\n", res_dbl.a, res_dbl.b);
   /* { dg-output "\nres: 13 140" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 140);
 
   exit(0);
 }
index b7827466f6ef43b17176c4abd0976f96d3491768..aaa7ccc5c16e3fcb0ed4a71cf0f75deda5c14eb1 100644 (file)
@@ -28,6 +28,18 @@ cls_struct_3_1byte cls_struct_3_1byte_fn(struct cls_struct_3_1byte a1,
         a2.a, a2.b, a2.c,
         result.a, result.b, result.c);
 
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 13);
+  CHECK(a1.c == 14);
+
+  CHECK(a2.a == 178);
+  CHECK(a2.b == 179);
+  CHECK(a2.c == 180);
+
+  CHECK(result.a == 190);
+  CHECK(result.b == 192);
+  CHECK(result.c == 194);
+
   return  result;
 }
 
@@ -83,6 +95,9 @@ int main (void)
   /* { 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(res_dbl.a == 190);
+  CHECK(res_dbl.b == 192);
+  CHECK(res_dbl.c == 194);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3_1byte_gn, NULL, code) == FFI_OK);
 
@@ -91,5 +106,9 @@ int main (void)
   printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
   /* { dg-output "\nres: 190 192 194" } */
 
+  CHECK(res_dbl.a == 190);
+  CHECK(res_dbl.b == 192);
+  CHECK(res_dbl.c == 194);
+
   exit(0);
 }
index a02c463af9f0f36cd81a768bb1c6d05cf3f22460..b4249175443184da3ed6136e320e3b30d9c3d989 100644 (file)
@@ -24,6 +24,15 @@ cls_struct_3byte cls_struct_3byte_fn(struct cls_struct_3byte a1,
 
   printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
 
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 119);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 15);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 134);
+
   return  result;
 }
 
@@ -78,6 +87,8 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 134);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3byte_gn, NULL, code) == FFI_OK);
 
@@ -85,6 +96,8 @@ int main (void)
   /* { dg-output "\n12 119 1 15: 13 134" } */
   printf("res: %d %d\n", res_dbl.a, res_dbl.b);
   /* { dg-output "\nres: 13 134" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 134);
 
   exit(0);
 }
index c7251cead60308e21e2f889f92ba603bdee30fe8..f13590e4b5bf48fd1be8cca5b252358c82beff13 100644 (file)
@@ -24,6 +24,15 @@ cls_struct_3byte_1 cls_struct_3byte_fn1(struct cls_struct_3byte_1 a1,
 
   printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
 
+  CHECK(a1.a == 15);
+  CHECK(a1.b == 125);
+
+  CHECK(a2.a == 9);
+  CHECK(a2.b == 19);
+
+  CHECK(result.a == 24);
+  CHECK(result.b == 144);
+
   return  result;
 }
 
@@ -78,6 +87,8 @@ int main (void)
   /* { 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(res_dbl.a == 24);
+  CHECK(res_dbl.b == 144);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3byte_gn1, NULL, code) == FFI_OK);
 
@@ -85,6 +96,8 @@ int main (void)
   /* { dg-output "\n15 125 9 19: 24 144" } */
   printf("res: %d %d\n", res_dbl.a, res_dbl.b);
   /* { dg-output "\nres: 24 144" } */
+  CHECK(res_dbl.a == 24);
+  CHECK(res_dbl.b == 144);
 
   exit(0);
 }
index 48888f8405f95daa8b77732ad156173834082104..63171bc7fd81ac102b7821337f0fe2016f4dec4a 100644 (file)
@@ -27,6 +27,18 @@ cls_struct_3float cls_struct_3float_fn(struct cls_struct_3float a1,
   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);
 
+  CHECK_FLOAT_EQ(a1.f, 1);
+  CHECK_FLOAT_EQ(a1.g, 2);
+  CHECK_FLOAT_EQ(a1.h, 3);
+
+  CHECK_FLOAT_EQ(a2.f, 1);
+  CHECK_FLOAT_EQ(a2.g, 2);
+  CHECK_FLOAT_EQ(a2.h, 3);
+
+  CHECK_FLOAT_EQ(result.f, 2);
+  CHECK_FLOAT_EQ(result.g, 4);
+  CHECK_FLOAT_EQ(result.h, 6);
+
   return result;
 }
 
@@ -81,6 +93,9 @@ int main (void)
   /* { 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_FLOAT_EQ(res_dbl.f, 2);
+  CHECK_FLOAT_EQ(res_dbl.g, 4);
+  CHECK_FLOAT_EQ(res_dbl.h, 6);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3float_gn, NULL, code) ==
        FFI_OK);
@@ -90,6 +105,9 @@ int main (void)
   /* { 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" } */
+  CHECK_FLOAT_EQ(res_dbl.f, 2);
+  CHECK_FLOAT_EQ(res_dbl.g, 4);
+  CHECK_FLOAT_EQ(res_dbl.h, 6);
 
   exit(0);
 }
index 2d6d8b622c3734c3b68c2a89294c1f5020294fae..b5d3f70320aa7504728054706ebdafa23e593e13 100644 (file)
@@ -30,6 +30,20 @@ cls_struct_4_1byte cls_struct_4_1byte_fn(struct cls_struct_4_1byte a1,
         a2.a, a2.b, a2.c, a2.d,
         result.a, result.b, result.c, result.d);
 
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 13);
+  CHECK(a1.c == 14);
+  CHECK(a1.d == 15);
+
+  CHECK(a2.a == 178);
+  CHECK(a2.b == 179);
+  CHECK(a2.c == 180);
+  CHECK(a2.d == 181);
+
+  CHECK(result.a == 190);
+  CHECK(result.b == 192);
+  CHECK(result.c == 194);
+  CHECK(result.d == 196);
   return  result;
 }
 
@@ -86,6 +100,10 @@ int main (void)
   /* { 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(res_dbl.a == 190);
+  CHECK(res_dbl.b == 192);
+  CHECK(res_dbl.c == 194);
+  CHECK(res_dbl.d == 196);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_4_1byte_gn, NULL, code) == FFI_OK);
 
@@ -93,6 +111,10 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 190);
+  CHECK(res_dbl.b == 192);
+  CHECK(res_dbl.c == 194);
+  CHECK(res_dbl.d == 196);
 
   exit(0);
 }
index 4ac378776b5cd1ea6792b2ffdda31fb0549a0430..4f8d173bf94892a114aa47cbc187d6acc3dd352b 100644 (file)
@@ -24,6 +24,15 @@ cls_struct_4byte cls_struct_4byte_fn(struct cls_struct_4byte a1,
 
   printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
 
+  CHECK(a1.a == 127);
+  CHECK(a1.b == 120);
+
+  CHECK(a2.a == 12);
+  CHECK(a2.b == 128);
+
+  CHECK(result.a == 139);
+  CHECK(result.b == 248);
+
   return  result;
 }
 
@@ -78,6 +87,8 @@ int main (void)
   /* { 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(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_4byte_gn, NULL, code) == FFI_OK);
 
@@ -85,6 +96,8 @@ int main (void)
   /* { dg-output "\n127 120 12 128: 139 248" } */
   printf("res: %d %d\n", res_dbl.a, res_dbl.b);
   /* { dg-output "\nres: 139 248" } */
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
 
   exit(0);
 }
index 8db761cd5b79c1693390bad3a9d45d2ec8fffab3..07552cde7761f3ab8407893e2c273a7b5d4014cb 100644 (file)
@@ -32,6 +32,24 @@ static cls_struct_5byte cls_struct_5byte_fn(struct cls_struct_5byte a1,
         a2.a, a2.b, a2.c, a2.d, a2.e,
         result.a, result.b, result.c, result.d, result.e);
 
+  CHECK(a1.a == 127);
+  CHECK(a1.b == 120);
+  CHECK(a1.c == 1);
+  CHECK(a1.d == 3);
+  CHECK(a1.e == 4);
+
+  CHECK(a2.a == 12);
+  CHECK(a2.b == 128);
+  CHECK(a2.c == 9);
+  CHECK(a2.d == 3);
+  CHECK(a2.e == 4);
+
+  CHECK(result.a == 139);
+  CHECK(result.b == 248);
+  CHECK(result.c == 10);
+  CHECK(result.d == 6);
+  CHECK(result.e == 8);
+
   return  result;
 }
 
@@ -90,6 +108,11 @@ int main (void)
   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" } */
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
+  CHECK(res_dbl.d == 6);
+  CHECK(res_dbl.e == 8);
 
   res_dbl.a = 0;
   res_dbl.b = 0;
@@ -104,6 +127,11 @@ int main (void)
   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" } */
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
+  CHECK(res_dbl.d == 6);
+  CHECK(res_dbl.e == 8);
 
   exit(0);
 }
index fbb69ce4a83095092a1a37c8472239a7dcc0495e..9f8936b5909575bf6380292685cc94588a888ea5 100644 (file)
@@ -27,6 +27,18 @@ static cls_struct_5byte cls_struct_5byte_fn(struct cls_struct_5byte a1,
         a2.a, a2.b, a2.c,
         result.a, result.b, result.c);
 
+  CHECK(a1.a == 127);
+  CHECK(a1.b == 120);
+  CHECK(a1.c == 1);
+
+  CHECK(a2.a == 12);
+  CHECK(a2.b == 128);
+  CHECK(a2.c == 9);
+
+  CHECK(result.a == 139);
+  CHECK(result.b == 248);
+  CHECK(result.c == 10);
+
   return  result;
 }
 
@@ -82,6 +94,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
 
   res_dbl.a = 0;
   res_dbl.b = 0;
@@ -93,6 +108,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
 
   exit(0);
 }
index a55edc2c7b9df3e70689730920fab6dc03400074..5adedc944c93b9d471f77b889bb1c32ce2f6d43b 100644 (file)
@@ -38,6 +38,14 @@ cls_struct_64byte cls_struct_64byte_fn(struct cls_struct_64byte b0,
 
   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);
+  CHECK(result.a == 22);
+  CHECK(result.b == 15);
+  CHECK(result.c == 17);
+  CHECK(result.d == 25);
+  CHECK(result.e == 6);
+  CHECK(result.f == 13);
+  CHECK(result.g == 19);
+  CHECK(result.h == 18);
 
   return result;
 }
@@ -107,6 +115,14 @@ int main (void)
   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(res_dbl.a == 22);
+  CHECK(res_dbl.b == 15);
+  CHECK(res_dbl.c == 17);
+  CHECK(res_dbl.d == 25);
+  CHECK(res_dbl.e == 6);
+  CHECK(res_dbl.f == 13);
+  CHECK(res_dbl.g == 19);
+  CHECK(res_dbl.h == 18);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_64byte_gn, NULL, code) == FFI_OK);
 
@@ -119,6 +135,14 @@ int main (void)
   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(res_dbl.a == 22);
+  CHECK(res_dbl.b == 15);
+  CHECK(res_dbl.c == 17);
+  CHECK(res_dbl.d == 25);
+  CHECK(res_dbl.e == 6);
+  CHECK(res_dbl.f == 13);
+  CHECK(res_dbl.g == 19);
+  CHECK(res_dbl.h == 18);
 
   exit(0);
 }
index 797098628663af9fa7ebc765c4d203d23e5fa534..05e2945b6804bd46e06c1e11fd7ab66cb6fc1776 100644 (file)
@@ -34,6 +34,27 @@ static cls_struct_6byte cls_struct_6byte_fn(struct cls_struct_6byte a1,
         a2.a, a2.b, a2.c, a2.d, a2.e, a2.f,
         result.a, result.b, result.c, result.d, result.e, result.f);
 
+  CHECK(a1.a == 127);
+  CHECK(a1.b == 120);
+  CHECK(a1.c == 1);
+  CHECK(a1.d == 3);
+  CHECK(a1.e == 4);
+  CHECK(a1.f == 5);
+
+  CHECK(a2.a == 12);
+  CHECK(a2.b == 128);
+  CHECK(a2.c == 9);
+  CHECK(a2.d == 3);
+  CHECK(a2.e == 4);
+  CHECK(a2.f == 5);
+
+  CHECK(result.a == 139);
+  CHECK(result.b == 248);
+  CHECK(result.c == 10);
+  CHECK(result.d == 6);
+  CHECK(result.e == 8);
+  CHECK(result.f == 10);
+
   return  result;
 }
 
@@ -109,5 +130,11 @@ int main (void)
         res_dbl.d, res_dbl.e, res_dbl.f);
   /* { dg-output "\nres: 139 248 10 6 8 10" } */
 
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
+  CHECK(res_dbl.d == 6);
+  CHECK(res_dbl.e == 8);
+  CHECK(res_dbl.f == 10);
   exit(0);
 }
index e89c73cf88d13164fec105a18f9e6f2d3e4c6aa3..a8e3ea0716fe961c40ae3de9f815fd86959c21f8 100644 (file)
@@ -30,6 +30,21 @@ static cls_struct_6byte cls_struct_6byte_fn(struct cls_struct_6byte a1,
         a2.a, a2.b, a2.c, a2.d,
         result.a, result.b, result.c, result.d);
 
+  CHECK(a1.a == 127);
+  CHECK(a1.b == 120);
+  CHECK(a1.c == 1);
+  CHECK(a1.d == 128);
+
+  CHECK(a2.a == 12);
+  CHECK(a2.b == 128);
+  CHECK(a2.c == 9);
+  CHECK(a2.d == 127);
+
+  CHECK(result.a == 139);
+  CHECK(result.b == 248);
+  CHECK(result.c == 10);
+  CHECK(result.d == 255);
+
   return  result;
 }
 
@@ -86,6 +101,10 @@ int main (void)
   /* { 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(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
+  CHECK(res_dbl.d == 255);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_6byte_gn, NULL, code) == FFI_OK);
 
@@ -93,7 +112,10 @@ int main (void)
   /* { 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" } */
-
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
+  CHECK(res_dbl.d == 255);
 
   exit(0);
 }
index 94b1a44bded9a6dfcede9148e6792f5e46bd1b47..3f17964833e61524fec19d0bb6d48ac7f4a18de1 100644 (file)
@@ -36,6 +36,30 @@ static cls_struct_7byte cls_struct_7byte_fn(struct cls_struct_7byte a1,
         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);
 
+  CHECK(a1.a == 127);
+  CHECK(a1.b == 120);
+  CHECK(a1.c == 1);
+  CHECK(a1.d == 3);
+  CHECK(a1.e == 4);
+  CHECK(a1.f == 5);
+  CHECK(a1.g == 6);
+
+  CHECK(a2.a == 12);
+  CHECK(a2.b == 128);
+  CHECK(a2.c == 9);
+  CHECK(a2.d == 3);
+  CHECK(a2.e == 4);
+  CHECK(a2.f == 5);
+  CHECK(a2.g == 6);
+
+  CHECK(result.a == 139);
+  CHECK(result.b == 248);
+  CHECK(result.c == 10);
+  CHECK(result.d == 6);
+  CHECK(result.e == 8);
+  CHECK(result.f == 10);
+  CHECK(result.g == 12);
+
   return  result;
 }
 
@@ -96,6 +120,13 @@ int main (void)
   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" } */
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
+  CHECK(res_dbl.d == 6);
+  CHECK(res_dbl.e == 8);
+  CHECK(res_dbl.f == 10);
+  CHECK(res_dbl.g == 12);
 
   res_dbl.a = 0;
   res_dbl.b = 0;
@@ -112,6 +143,13 @@ int main (void)
   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" } */
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
+  CHECK(res_dbl.d == 6);
+  CHECK(res_dbl.e == 8);
+  CHECK(res_dbl.f == 10);
+  CHECK(res_dbl.g == 12);
 
   exit(0);
 }
index 3aa8d6cfe377ab2a6868716b94000c7d38b93313..dcfc29b82a5b9d38644eba4e45a44db9e7f6364d 100644 (file)
@@ -29,6 +29,22 @@ static cls_struct_7byte cls_struct_7byte_fn(struct cls_struct_7byte a1,
         a2.a, a2.b, a2.c, a2.d,
         result.a, result.b, result.c, result.d);
 
+  CHECK(a1.a == 127);
+  CHECK(a1.b == 120);
+  CHECK(a1.c == 1);
+  CHECK(a1.d == 254);
+       
+  CHECK(a2.a == 12);
+  CHECK(a2.b == 128);
+  CHECK(a2.c == 9);
+  CHECK(a2.d == 255);
+
+  CHECK(result.a == 139);
+  CHECK(result.b == 248);
+  CHECK(result.c == 10);
+  CHECK(result.d == 509);
+
+
   return  result;
 }
 
@@ -85,6 +101,10 @@ int main (void)
   /* { 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(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
+  CHECK(res_dbl.d == 509);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_7byte_gn, NULL, code) == FFI_OK);
 
@@ -92,6 +112,10 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 139);
+  CHECK(res_dbl.b == 248);
+  CHECK(res_dbl.c == 10);
+  CHECK(res_dbl.d == 509);
 
   exit(0);
 }
index f6c1ea570ac8638227b2e8541bc42f7f8ef71506..7a519e95e3eb7ee9cc1d5faac44459d3912d1b27 100644 (file)
@@ -23,6 +23,15 @@ cls_struct_8byte cls_struct_8byte_fn(struct cls_struct_8byte a1,
 
   printf("%d %g %d %g: %d %g\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b);
 
+  CHECK(a1.a == 1);
+  CHECK_FLOAT_EQ(a1.b, 2);
+
+  CHECK(a2.a == 4);
+  CHECK_FLOAT_EQ(a2.b, 5);
+
+  CHECK(result.a == 5);
+  CHECK_FLOAT_EQ(result.b, 7);
+
   return  result;
 }
 
@@ -76,6 +85,9 @@ int main (void)
   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);
+  CHECK(res_dbl.a == 5);
+  CHECK_FLOAT_EQ(res_dbl.b, 7);
+
   /* { dg-output "\nres: 5 7" } */
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_8byte_gn, NULL, code) == FFI_OK);
 
@@ -83,6 +95,8 @@ int main (void)
   /* { dg-output "\n1 2 4 5: 5 7" } */
   printf("res: %d %g\n", res_dbl.a, res_dbl.b);
   /* { dg-output "\nres: 5 7" } */
+  CHECK(res_dbl.a == 5);
+  CHECK_FLOAT_EQ(res_dbl.b, 7);
 
   exit(0);
 }
index 6eb45203688ae92c765ccb673db80e544876c72b..9d3b609d3f864d20fb7edee2d40716173fa1150e 100644 (file)
@@ -26,6 +26,15 @@ static cls_struct_9byte cls_struct_9byte_fn(struct cls_struct_9byte b1,
   printf("%d %g %d %g: %d %g\n", b1.a, b1.b,  b2.a, b2.b,
         result.a, result.b);
 
+  CHECK(b1.a == 7);
+  CHECK(b1.b == 8);
+
+  CHECK(b2.a == 1);
+  CHECK(b2.b == 9);
+
+  CHECK(result.a == 8);
+  CHECK(result.b == 17);
+
   return result;
 }
 
@@ -78,6 +87,8 @@ int main (void)
   /* { 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(res_dbl.a == 8);
+  CHECK(res_dbl.b == 17);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_9byte_gn, NULL, code) == FFI_OK);
 
@@ -85,6 +96,8 @@ int main (void)
   /* { dg-output "\n7 8 1 9: 8 17" } */
   printf("res: %d %g\n", res_dbl.a, res_dbl.b);
   /* { dg-output "\nres: 8 17" } */
+  CHECK(res_dbl.a == 8);
+  CHECK(res_dbl.b == 17);
 
   exit(0);
 }
index 26e460bc7ecf81c59dd5253bd098cfbcb2622d12..6cfaaf39722682e2cac803d2050137c345ee2084 100644 (file)
@@ -26,6 +26,15 @@ static cls_struct_9byte cls_struct_9byte_fn(struct cls_struct_9byte b1,
   printf("%g %d %g %d: %g %d\n", b1.a, b1.b,  b2.a, b2.b,
         result.a, result.b);
 
+  CHECK(b1.a == 7);
+  CHECK(b1.b == 8);
+
+  CHECK(b2.a == 1);
+  CHECK(b2.b == 9);
+
+  CHECK(result.a == 8);
+  CHECK(result.b == 17);
+
   return result;
 }
 
@@ -78,7 +87,8 @@ int main (void)
   /* { 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(res_dbl.a == 8);
+  CHECK(res_dbl.b == 17);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_9byte_gn, NULL, code) == FFI_OK);
 
@@ -86,6 +96,8 @@ int main (void)
   /* { dg-output "\n7 8 1 9: 8 17" } */
   printf("res: %g %d\n", res_dbl.a, res_dbl.b);
   /* { dg-output "\nres: 8 17" } */
+  CHECK(res_dbl.a == 8);
+  CHECK(res_dbl.b == 17);
 
   exit(0);
 }
index 910e2287d9e339344570e50ab1ffb03db1dd52e8..036cca37f1146ad4ab1eb8b886c93ba6d999caf1 100644 (file)
@@ -26,6 +26,18 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
 
   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);
 
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 14271);
+  CHECK(result.c == 140);
+
   return  result;
 }
 
@@ -81,6 +93,9 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -88,6 +103,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   exit(0);
 }
index 56161ef632e2446aa2605a79cecf64a641d9d32f..c7dbdfd8f694d2121ddcce3c398bb253f9971513 100644 (file)
@@ -24,6 +24,18 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
 
   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);
 
+  CHECK(a1.a == 12);
+  CHECK_FLOAT_EQ(a1.b, 4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK_FLOAT_EQ(a2.b, 9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK_FLOAT_EQ(result.b, 14271);
+  CHECK(result.c == 140);
+
   return  result;
 }
 
@@ -79,6 +91,9 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK_FLOAT_EQ(res_dbl.b, 14271);
+  CHECK(res_dbl.c == 140);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -86,6 +101,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 13);
+  CHECK_FLOAT_EQ(res_dbl.b, 14271);
+  CHECK(res_dbl.c == 140);
 
   exit(0);
 }
index 3dccdef10e15d814538b522df62de1bb9850924f..1cdb10bdbec2e9c50be9fc3a98a5b867dd5108d5 100644 (file)
@@ -25,6 +25,18 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
 
   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);
 
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 14271);
+  CHECK(result.c == 140);
+
   return  result;
 }
 
@@ -80,6 +92,10 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
+
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -87,6 +103,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   exit(0);
 }
index 9b01cbd01a5873068743a213ad9ecb0f776f3dbd..128d6e1b403997967104ffbed08c50bd5c0631f8 100644 (file)
@@ -5,7 +5,7 @@
    Originator: <hos@tamanegi.org> 20031203      */
 
 /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
-/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
+/* { dg-options -mlong-double-128 { target powerpc64*-*-linux-gnu* } } */
 
 #include "ffitest.h"
 
@@ -39,32 +39,34 @@ static cls_struct_align cls_struct_align_fn(
                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);
-
+       CHECK(a1.a == 1);
+       CHECK(a1.b == 2);
+       CHECK(a1.c == 3);
+       CHECK(a1.d == 4);
+       CHECK(a1.e == 5);
+       CHECK(a1.f == 6);
+       CHECK(a1.g == 7);
+
+       CHECK(a2.a == 8);
+       CHECK(a2.b == 9);
+       CHECK(a2.c == 10);
+       CHECK(a2.d == 11);
+       CHECK(a2.e == 12);
+       CHECK(a2.f == 13);
+       CHECK(a2.g == 14);
+
+       CHECK(r.a == 9);
+       CHECK(r.b == 11);
+       CHECK(r.c == 13);
+       CHECK(r.d == 15);
+       CHECK(r.e == 17);
+       CHECK(r.f == 19);
+       CHECK(r.g == 21);
        return r;
 }
 
 static void
-cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, 
+cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args,
                    void* userdata __UNUSED__)
 {
        struct cls_struct_align a1, a2;
@@ -119,6 +121,13 @@ int main (void)
        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(res_dbl.a == 9);
+       CHECK(res_dbl.b == 11);
+       CHECK(res_dbl.c == 13);
+       CHECK(res_dbl.d == 15);
+       CHECK(res_dbl.e == 17);
+       CHECK(res_dbl.f == 19);
+       CHECK(res_dbl.g == 21);
 
        CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -127,6 +136,12 @@ int main (void)
        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(res_dbl.a == 9);
+       CHECK(res_dbl.b == 11);
+       CHECK(res_dbl.c == 13);
+       CHECK(res_dbl.d == 15);
+       CHECK(res_dbl.e == 17);
+       CHECK(res_dbl.f == 19);
+       CHECK(res_dbl.g == 21);
   exit(0);
 }
index 8a973e7a22d15ac4482a30800a7189ffaf99450b..3562a57fabdabe20d094c95df63a4932714d177b 100644 (file)
@@ -6,7 +6,7 @@
 */
 
 /* { dg-do run { xfail strongarm*-*-* } } */
-/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
+/* { dg-options -mlong-double-128 { target powerpc64*-*-linux-gnu* } } */
 
 #include "ffitest.h"
 
@@ -40,6 +40,30 @@ static cls_struct_align cls_struct_align_fn(
                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);
 
+       CHECK(a1.a == 1);
+       CHECK(a1.b == 2);
+       CHECK(a1.c == 3);
+       CHECK(a1.d == 4);
+       CHECK(a1.e == 5);
+       CHECK(a1.f == 6);
+       CHECK(a1.g == 7);
+
+       CHECK(a2.a == 8);
+       CHECK(a2.b == 9);
+       CHECK(a2.c == 10);
+       CHECK(a2.d == 11);
+       CHECK(a2.e == 12);
+       CHECK(a2.f == 13);
+       CHECK(a2.g == 14);
+
+       CHECK(r.a == 9);
+       CHECK(r.b == 11);
+       CHECK(r.c == 13);
+       CHECK(r.d == 15);
+       CHECK(r.e == 17);
+       CHECK(r.f == 19);
+       CHECK(r.g == 21);
+
        return r;
 }
 
@@ -99,6 +123,13 @@ int main (void)
        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(res_dbl.a == 9);
+       CHECK(res_dbl.b == 11);
+       CHECK(res_dbl.c == 13);
+       CHECK(res_dbl.d == 15);
+       CHECK(res_dbl.e == 17);
+       CHECK(res_dbl.f == 19);
+       CHECK(res_dbl.g == 21);
 
        CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -107,7 +138,13 @@ int main (void)
        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(res_dbl.a == 9);
+       CHECK(res_dbl.b == 11);
+       CHECK(res_dbl.c == 13);
+       CHECK(res_dbl.d == 15);
+       CHECK(res_dbl.e == 17);
+       CHECK(res_dbl.f == 19);
+       CHECK(res_dbl.g == 21);
   exit(0);
 }
 
index ef59259dff0233e34426364769a2498ff2561b43..5fb3f09ac3849d6fd9f5377103f3c5dacbeac584 100644 (file)
@@ -28,6 +28,18 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
          result.a, (uintptr_t)result.b,
         result.c);
 
+  CHECK(a1.a == 12);
+  CHECK(a1.b == (void *)4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == (void *)9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == (void *)14271);
+  CHECK(result.c == 140);
+
   return result;
 }
 
@@ -83,6 +95,9 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == (void *)14271);
+  CHECK(res_dbl.c == 140);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -90,6 +105,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == (void *)14271);
+  CHECK(res_dbl.c == 140);
 
   exit(0);
 }
index 79977093d0e497acd583bfa39d31b1efdc0f1345..d2c9bf40fe9bec3483c4ced553ccbf7c25138192 100644 (file)
@@ -23,6 +23,17 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
   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);
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 14271);
+  CHECK(result.c == 140);
 
   return  result;
 }
@@ -79,6 +90,9 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -86,6 +100,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   exit(0);
 }
index 5edde72249fa27dbe3336478e24a0e1daa11e08a..570f45ffd6c0c0962f2333dddcfd499cbeefe1c4 100644 (file)
@@ -23,6 +23,17 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
   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);
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 14271);
+  CHECK(result.c == 140);
 
   return  result;
 }
@@ -79,13 +90,17 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 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" } */
-
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
   exit(0);
 }
index bcba22f3ed66405dda680f79f97244990593bbf1..49ee5612b1fc669af8e035c763f99c1221a2e3c7 100644 (file)
@@ -24,6 +24,17 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
   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);
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 14271);
+  CHECK(result.c == 140);
 
   return  result;
 }
@@ -80,6 +91,9 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -87,6 +101,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   exit(0);
 }
index f33c0ec6866046ae404a1f56c1f6b4a50dde0211..2204dff92bf9eb623b5ec50bfbb953476799c603 100644 (file)
@@ -23,6 +23,17 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
   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);
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 14271);
+  CHECK(result.c == 140);
 
   return  result;
 }
@@ -79,6 +90,9 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -86,6 +100,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   exit(0);
 }
index c96eee6bb29bf9fb955954bdec6e8d4d4278c90f..1ce23daf5d2e2522e618f84ad2a26f7fa3c497a8 100644 (file)
@@ -24,6 +24,18 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
 
   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);
 
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 14271);
+  CHECK(result.c == 140);
+
   return  result;
 }
 
@@ -79,6 +91,9 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -86,6 +101,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   exit(0);
 }
index 958e1c2cab035ebf1cbb3785497c53c73b9f1f28..aee958a86d0829c8fddee9d683319811454dd721 100644 (file)
@@ -26,6 +26,18 @@ static cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
 
   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);
 
+  CHECK(a1.a == 12);
+  CHECK(a1.b == 4951);
+  CHECK(a1.c == 127);
+
+  CHECK(a2.a == 1);
+  CHECK(a2.b == 9320);
+  CHECK(a2.c == 13);
+
+  CHECK(result.a == 13);
+  CHECK(result.b == 14271);
+  CHECK(result.c == 140);
+
   return  result;
 }
 
@@ -81,6 +93,9 @@ int main (void)
   /* { 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(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
 
@@ -88,6 +103,9 @@ int main (void)
   /* { 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" } */
+  CHECK(res_dbl.a == 13);
+  CHECK(res_dbl.b == 14271);
+  CHECK(res_dbl.c == 140);
 
   exit(0);
 }
index 25b8b635069e24a9e7db29bce9b8f35f4a60d915..d0c206c0487ad216d9b9003f2f71f244a3a8ae79 100644 (file)
@@ -17,6 +17,8 @@ void
 closure_test_fn(Dbls p)
 {
        printf("%.1f %.1f\n", p.x, p.y);
+       CHECK(p.x == 1);
+       CHECK(p.y == 2);
 }
 
 void
@@ -26,7 +28,7 @@ closure_test_gn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__,
        closure_test_fn(*(Dbls*)args[0]);
 }
 
-int main(int argc __UNUSED__, char** argv __UNUSED__)
+int main(void)
 {
        ffi_cif cif;
 
index e077f92b8638398efdf87211f0ef5af26c8978cc..a6c445b826e532aa5156578cbc05d5513521238f 100644 (file)
 
 #include "ffitest.h"
 
+#define BUF_SIZE 50
+static char buffer[BUF_SIZE];
+
 static void
-cls_double_va_fn(ffi_cif* cif __UNUSED__, void* resp, 
+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);
+       CHECK(*(ffi_arg*)resp == 4);
+       snprintf(buffer, BUF_SIZE, format, doubleValue);
+       CHECK(strncmp(buffer, "7.0\n", 4) == 0);
 }
 
 int main (void)
@@ -48,6 +54,7 @@ int main (void)
        /* { dg-output "7.0" } */
        printf("res: %d\n", (int) res);
        /* { dg-output "\nres: 4" } */
+       CHECK(res == 4);
 
        CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL,
                                   code) == FFI_OK);
@@ -56,6 +63,7 @@ int main (void)
        /* { dg-output "\n7.0" } */
        printf("res: %d\n", (int) res);
        /* { dg-output "\nres: 4" } */
+       CHECK(res == 4);
 
        exit(0);
 }
index 0090fed9063174d0e2e2412280e9841b4ecc86ae..97c2ac02b7abeca42fc4b179f61e4fd070b8bce2 100644 (file)
@@ -14,6 +14,9 @@ static void cls_ret_float_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
 
    printf("%g: %g\n",*(float *)args[0],
          *(float *)resp);
+
+   CHECK((int)(*(float *)args[0]) == -2122);
+   CHECK((int)(*(float *)resp) == -2122);
  }
 
 typedef float (*cls_ret_float)(float);
@@ -38,5 +41,6 @@ int main (void)
   /* { dg-output "\\-2122.12: \\-2122.12" } */
   printf("res: %.6f\n", res);
   /* { dg-output "\nres: \-2122.120117" } */
+  CHECK((int)res == -2122);
   exit(0);
 }
index d24e72e4aed3c48b73a1acc53e4220c523e3b682..2cfac4bafef92ed8ddc09efc73324575fbd7e258 100644 (file)
@@ -7,7 +7,7 @@
 /* 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* } } */
+/* { dg-options -mlong-double-128 { target powerpc64*-*-linux-gnu* } } */
 
 #include "ffitest.h"
 
@@ -25,6 +25,14 @@ long double cls_ldouble_fn(
 
        printf("%Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg: %Lg\n",
                a1, a2, a3, a4, a5, a6, a7, a8, r);
+       CHECK(a1 == 1);
+       CHECK(a2 == 2);
+       CHECK(a3 == 3);
+       CHECK(a4 == 4);
+       CHECK(a5 == 5);
+       CHECK(a6 == 6);
+       CHECK(a7 == 7);
+       CHECK(a8 == 8);
 
        return r;
 }
@@ -91,6 +99,7 @@ int main(void)
        /* { dg-output "1 2 3 4 5 6 7 8: 36" } */
        printf("res: %Lg\n", res);
        /* { dg-output "\nres: 36" } */
+       CHECK(res == 36);
 
        CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ldouble_gn, NULL, code) == FFI_OK);
 
@@ -100,6 +109,7 @@ int main(void)
        /* { dg-output "\n1 2 3 4 5 6 7 8: 36" } */
        printf("res: %Lg\n", res);
        /* { dg-output "\nres: 36" } */
+       CHECK(res == 36);
 
        return 0;
 }
index 39b438b289a85e4c8b24cde34c29ef42b895e5dd..ba32f5c8513e53fcb31b9dede9f07aa4dd7d1bc2 100644 (file)
@@ -5,19 +5,36 @@
    Originator: Blake Chaffin 6/6/2007   */
 
 /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
-/* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
+/* { dg-output "" { xfail avr32*-*-* } } */
 /* { dg-output "" { xfail mips-sgi-irix6* } } PR libffi/46660 */
 
 #include "ffitest.h"
+#include <stdarg.h>
+
+#define BUF_SIZE 50
+static char buffer[BUF_SIZE];
+
+static int
+wrap_printf(char* fmt, ...) {
+       va_list ap;
+       va_start(ap, fmt);
+       long double ldArg = va_arg(ap, long double);
+       va_end(ap);
+       CHECK((int)ldArg == 7);
+       return printf(fmt, ldArg);      
+}
 
 static void
-cls_longdouble_va_fn(ffi_cif* cif __UNUSED__, void* resp, 
+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);
+       CHECK(*(ffi_arg*)resp == 4);
+       snprintf(buffer, BUF_SIZE, format, ldValue);
+       CHECK(strncmp(buffer, "7.0\n", BUF_SIZE) == 0);
 }
 
 int main (void)
@@ -44,10 +61,11 @@ int main (void)
        args[1] = &ldArg;
        args[2] = NULL;
 
-       ffi_call(&cif, FFI_FN(printf), &res, args);
+       ffi_call(&cif, FFI_FN(wrap_printf), &res, args);
        /* { dg-output "7.0" } */
        printf("res: %d\n", (int) res);
        /* { dg-output "\nres: 4" } */
+       CHECK(res == 4);
 
        CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL,
                                   code) == FFI_OK);
@@ -56,6 +74,7 @@ int main (void)
        /* { dg-output "\n7.0" } */
        printf("res: %d\n", (int) res);
        /* { dg-output "\nres: 4" } */
+       CHECK(res == 4);
 
        exit(0);
 }
index 417f7be8299c8c981c9e6e335afd32fca599a80f..9eb02f9e3c001da21a64c98dbe91cdb60ed276a4 100644 (file)
@@ -26,6 +26,8 @@ static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals,
 
   a1 = *(signed char *)avals[0];
   a2 = *(signed char *)avals[1];
+  CHECK(a1 == 2);
+  CHECK(a2 == 125);
 
   *(ffi_arg *)rval = test_func_fn(a1, a2);
 
@@ -62,6 +64,7 @@ int main (void)
   /* { dg-output "2 125: 127" } */
   printf("res: %d\n", (signed char)res_call);
   /* { dg-output "\nres: 127" } */
+  CHECK((signed char)res_call == 127);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code)  == FFI_OK);
 
@@ -69,6 +72,7 @@ int main (void)
   /* { dg-output "\n2 125: 127" } */
   printf("res: %d\n", res_closure);
   /* { dg-output "\nres: 127" } */
+  CHECK(res_closure == 127);
 
   exit(0);
 }
index 467146dbd60c4e88f1d53e17cc92273d349b3bfb..9d4db5b6c85aa300c56251217ec36baf6b95a001 100644 (file)
@@ -14,6 +14,9 @@ static signed short test_func_fn(signed short a1, signed short a2)
   result = a1 + a2;
 
   printf("%d %d: %d\n", a1, a2, result);
+  CHECK(a1 == 2);
+  CHECK(a2 == 32765);
+  CHECK(result == 32767);
 
   return result;
 
@@ -62,6 +65,7 @@ int main (void)
   /* { dg-output "2 32765: 32767" } */
   printf("res: %d\n", (unsigned short)res_call);
   /* { dg-output "\nres: 32767" } */
+  CHECK((unsigned short)res_call == 32767);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code)  == FFI_OK);
 
@@ -69,6 +73,7 @@ int main (void)
   /* { dg-output "\n2 32765: 32767" } */
   printf("res: %d\n", res_closure);
   /* { dg-output "\nres: 32767" } */
+  CHECK(res_closure == 32767);
 
   exit(0);
 }
index de45b593e32a4e084f7c02e9979888a837342cf6..42f3ddeee8ae04381e31e77539e187d1154d3734 100644 (file)
@@ -16,6 +16,12 @@ static signed short test_func_fn(signed char a1, signed short a2,
 
   printf("%d %d %d %d: %d\n", a1, a2, a3, a4, result);
 
+  CHECK(a1 == 1);
+  CHECK(a2 == 32765);
+  CHECK(a3 == 127);
+  CHECK(a4 == -128);
+  CHECK(result == 32765);
+
   return result;
 
 }
@@ -74,6 +80,7 @@ int main (void)
   /* { dg-output "1 32765 127 -128: 32765" } */
   printf("res: %d\n", (signed short)res_call);
   /* { dg-output "\nres: 32765" } */
+  CHECK((signed short)res_call == 32765);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code)  == FFI_OK);
 
@@ -81,6 +88,7 @@ int main (void)
   /* { dg-output "\n1 32765 127 -128: 32765" } */
   printf("res: %d\n", res_closure);
   /* { dg-output "\nres: 32765" } */
+  CHECK(res_closure == 32765);
 
   exit(0);
 }
index eb93e95e3b3545196941103a7038be26fa6f0fa3..76f90a02453da8d9659c015728ad32b6c88db18f 100644 (file)
@@ -16,6 +16,12 @@ static unsigned char test_func_fn(unsigned char a1, unsigned char a2,
 
   printf("%d %d %d %d: %d\n", a1, a2, a3, a4, result);
 
+  CHECK(a1 == 1);
+  CHECK(a2 == 2);
+  CHECK(a3 == 127);
+  CHECK(a4 == 125);
+  CHECK(result == 255);
+
   return result;
 
 }
@@ -79,6 +85,7 @@ int main (void)
   /* { dg-output "1 2 127 125: 255" } */
   printf("res: %d\n", (unsigned char)res_call);
   /* { dg-output "\nres: 255" } */
+  CHECK((unsigned char)res_call == 255);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code)  == FFI_OK);
 
@@ -86,6 +93,7 @@ int main (void)
   /* { dg-output "\n1 2 127 125: 255" } */
   printf("res: %d\n", res_closure);
   /* { dg-output "\nres: 255" } */
+  CHECK(res_closure == 255);
 
   exit(0);
 }
index 0e5838df103a31ca440bac2c16127172f3c9cda8..f61a62793dc500bb0c4656467579f0878c87287f 100644 (file)
@@ -15,8 +15,11 @@ static unsigned short test_func_fn(unsigned short a1, unsigned short a2)
 
   printf("%d %d: %d\n", a1, a2, result);
 
-  return result;
+  CHECK(a1 == 2);
+  CHECK(a2 == 32765);
+  CHECK(result == 32767);
 
+  return result;
 }
 
 static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals,
@@ -69,6 +72,7 @@ int main (void)
   /* { dg-output "\n2 32765: 32767" } */
   printf("res: %d\n", res_closure);
   /* { dg-output "\nres: 32767" } */
+  CHECK(res_closure == 32767);
 
   exit(0);
 }
index 69aedfe0d233531def5e876a8b19377a079881b6..c5af5765b3646455ca4cf8432a594c305c9292bd 100644 (file)
@@ -16,6 +16,12 @@ static unsigned short test_func_fn(unsigned char a1, unsigned short a2,
 
   printf("%d %d %d %d: %d\n", a1, a2, a3, a4, result);
 
+  CHECK(a1 == 1);
+  CHECK(a2 == 2);
+  CHECK(a3 == 127);
+  CHECK(a4 == 128);
+  CHECK(result == 258);
+
   return result;
 
 }
@@ -74,6 +80,7 @@ int main (void)
   /* { dg-output "1 2 127 128: 258" } */
   printf("res: %d\n", (unsigned short)res_call);
   /* { dg-output "\nres: 258" } */
+  CHECK((unsigned short)res_call == 258);
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code)  == FFI_OK);
 
@@ -81,6 +88,7 @@ int main (void)
   /* { dg-output "\n1 2 127 128: 258" } */
   printf("res: %d\n", res_closure);
   /* { dg-output "\nres: 258" } */
+  CHECK(res_closure == 258);
 
   exit(0);
 }
index d82a87a71b6168414fdcd35bdc973ad2b1c75561..73a4cba7864feab8d0fea6e8e67c22328ddc554f 100644 (file)
@@ -16,6 +16,10 @@ void* cls_pointer_fn(void* a1, void* a2)
                (unsigned int)(uintptr_t) a2,
                (unsigned int)(uintptr_t) result);
 
+       CHECK((unsigned int)(uintptr_t) a1 == 0x12345678);
+       CHECK((unsigned int)(uintptr_t) a2 == 0x89abcdef);
+       CHECK((unsigned int)(uintptr_t) result == 0x9be02467);
+
        return result;
 }
 
@@ -69,6 +73,7 @@ int main (void)
        /* { dg-output "\n0x12345678 0x89abcdef: 0x9be02467" } */
        printf("res: 0x%08x\n", (unsigned int) res);
        /* { dg-output "\nres: 0x9be02467" } */
+       CHECK(res == 0x9be02467);
 
        exit(0);
 }
index 1f1d9157b9d967ee82a49cc721230e6d0203cf3e..2054f254766875e333c3441683dce208e760d357 100644 (file)
@@ -40,6 +40,10 @@ void* cls_pointer_fn2(void* a1, void* a2)
                (unsigned int)(uintptr_t) a2,
                (unsigned int)(uintptr_t) result);
 
+       CHECK((unsigned int)(uintptr_t) a1 == 0x8acf1356);
+       CHECK((unsigned int)(uintptr_t) a2 == 0x01234567);
+       CHECK((unsigned int)(uintptr_t) result == 0x8bf258bd);
+
        return result;
 }
 
@@ -65,6 +69,10 @@ void* cls_pointer_fn1(void* a1, void* a2)
                (unsigned int)(intptr_t) a2,
                (unsigned int)(intptr_t) result);
 
+       CHECK((unsigned int)(uintptr_t) a1 == 0x01234567);
+       CHECK((unsigned int)(uintptr_t) a2 == 0x89abcdef);
+       CHECK((unsigned int)(uintptr_t) result == 0x8acf1356);
+
        result  = cls_pointer_fn2(result, a1);
 
        return result;
@@ -128,6 +136,7 @@ int main (void)
        /* { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } */
        /* { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } */
        /* { dg-output "\nres: 0x8bf258bd" } */
+       CHECK(res == 0x8bf258bd);
 
        CHECK(ffi_prep_closure_loc(pcl, &cif, cls_pointer_gn, NULL, code) == FFI_OK);
 
@@ -137,6 +146,7 @@ int main (void)
        /* { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } */
        /* { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } */
        /* { dg-output "\nres: 0x8bf258bd" } */
+       CHECK(res == 0x8bf258bd);
 
        exit(0);
 }
index 82986b172c365d2d9bf9313568b056eb922ae821..22446c3171c5fedd3e45bd2c661eb440ad4a34e4 100644 (file)
@@ -15,6 +15,8 @@ static void cls_ret_schar_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
   *(ffi_arg*)resp = *(signed char *)args[0];
   printf("%d: %d\n",*(signed char *)args[0],
         (int)*(ffi_arg *)(resp));
+  CHECK(*(signed char *)args[0] == 127);
+  CHECK((int)*(ffi_arg *)(resp) == 127);
 }
 typedef signed char (*cls_ret_schar)(signed char);
 
@@ -39,6 +41,7 @@ int main (void)
   /* { dg-output "127: 127" } */
   printf("res: %d\n", res);
   /* { dg-output "\nres: 127" } */
+  CHECK(res == 127);
 
   exit(0);
 }
index c7e13b73a3bae7e9f6efed156bea48e28e6c1052..a3f72c1298aef2350c97d0a6b9bb7e0fd361d91d 100644 (file)
@@ -13,6 +13,8 @@ static void cls_ret_sint_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
   *(ffi_arg*)resp = *(signed int *)args[0];
   printf("%d: %d\n",*(signed int *)args[0],
         (int)*(ffi_arg *)(resp));
+  CHECK(*(signed int *)args[0] == 65534);
+  CHECK((int)*(ffi_arg *)(resp) == 65534);
 }
 typedef signed int (*cls_ret_sint)(signed int);
 
index 846d57ed1ba553794ae52c4cca7cf952647dfd2e..8061a0296daf1e0ef882fa0f3cd14a9de6a3beba 100644 (file)
@@ -13,6 +13,8 @@ static void cls_ret_sshort_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
   *(ffi_arg*)resp = *(signed short *)args[0];
   printf("%d: %d\n",*(signed short *)args[0],
         (int)*(ffi_arg *)(resp));
+  CHECK(*(signed short *)args[0] == 255);
+  CHECK((int)*(ffi_arg *)(resp) == 255);
 }
 typedef signed short (*cls_ret_sshort)(signed short);
 
@@ -37,6 +39,7 @@ int main (void)
   /* { dg-output "255: 255" } */
   printf("res: %d\n",res);
   /* { dg-output "\nres: 255" } */
+  CHECK(res == 255);
 
   exit(0);
 }
index 6d1fdaeb606ac90f09cdd1ec2408e67a846d0681..c59a27f3d9192cc23cffc37767a8712485e9123c 100644 (file)
@@ -35,6 +35,16 @@ test_fn (ffi_cif* cif __UNUSED__, void* resp,
   printf ("%d %d %d %d %d %d %d %d %d %d\n", n, s1.a, s1.b,
          l1.a, l1.b, l1.c, l1.d, l1.e,
          s2.a, s2.b);
+  CHECK(n == 4);
+  CHECK(s1.a == 5);
+  CHECK(s1.b == 6);
+  CHECK(l1.a == 10);
+  CHECK(l1.b == 11);
+  CHECK(l1.c == 12);
+  CHECK(l1.d == 13);
+  CHECK(l1.e == 14);
+  CHECK(s2.a == 20);
+  CHECK(s2.b == 21);
   * (ffi_arg*) resp = 42;
 }
 
@@ -109,6 +119,7 @@ main (void)
   /* { dg-output "4 5 6 10 11 12 13 14 20 21" } */
   printf("res: %d\n", (int) res);
   /* { dg-output "\nres: 42" } */
+  CHECK(res == 42);
 
   exit(0);
 }
index c1317e795fd65d1b9d5328c449a4b38ca41c2c64..aa2023ffd857290c577c5616b72a95961c0727c5 100644 (file)
@@ -13,6 +13,8 @@ static void cls_ret_uchar_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
   *(ffi_arg*)resp = *(unsigned char *)args[0];
   printf("%d: %d\n",*(unsigned char *)args[0],
         (int)*(ffi_arg *)(resp));
+  CHECK(*(unsigned char *)args[0] == 127);
+  CHECK((int)*(ffi_arg *)(resp) == 127);
 }
 typedef unsigned char (*cls_ret_uchar)(unsigned char);
 
@@ -37,6 +39,7 @@ int main (void)
   /* { dg-output "127: 127" } */
   printf("res: %d\n",res);
   /* { dg-output "\nres: 127" } */
+  CHECK(res == 127);
 
   exit(0);
 }
index 885cff5c3146831c3a2736ebf885afdea0c1f03d..23b88de2d0f8b159067faed76c6678cf4d945bf1 100644 (file)
@@ -14,6 +14,9 @@ static void cls_ret_uint_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
 
   printf("%d: %d\n",*(unsigned int *)args[0],
         (int)*(ffi_arg *)(resp));
+
+  CHECK(*(unsigned int *)args[0] == 2147483647);
+  CHECK((int)*(ffi_arg *)(resp) == 2147483647);
 }
 typedef unsigned int (*cls_ret_uint)(unsigned int);
 
@@ -38,6 +41,7 @@ int main (void)
   /* { dg-output "2147483647: 2147483647" } */
   printf("res: %d\n",res);
   /* { dg-output "\nres: 2147483647" } */
+  CHECK(res == 2147483647);
 
   exit(0);
 }
index b04cfd19c2ce42fbd08906fd8e72aa7eac928f90..0048a02d48943a433111601c81690ce227e1112a 100644 (file)
@@ -16,6 +16,9 @@ static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
    *(ffi_arg *)resp = *(T *)args[0];
 
    printf("%d: %d %d\n", (int)*(ffi_arg *)resp, *(T *)args[0], *(T *)args[1]);
+   CHECK(*(T *)args[0] == 67);
+   CHECK(*(T *)args[1] == 4);
+   CHECK((int)*(ffi_arg *)resp == 67);
  }
 
 typedef T (*cls_ret_T)(T, ...);
@@ -41,5 +44,6 @@ int main (void)
   /* { dg-output "67: 67 4" } */
   printf("res: %d\n", res);
   /* { dg-output "\nres: 67" } */
+  CHECK(res == 67);
   exit(0);
 }
index 0315082e093ba0154e0429ec1b7c67575b619091..79f41706a3c252d17ac01eecae298d94df11e174 100644 (file)
@@ -16,6 +16,9 @@ static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
    *(T *)resp = *(T *)args[0];
 
    printf("%ld: %ld %ld\n", *(T *)resp, *(T *)args[0], *(T *)args[1]);
+   CHECK(*(T *)args[0] == 67);
+   CHECK(*(T *)args[1] == 4);
+   CHECK(*(T *)resp == 67);
  }
 
 typedef T (*cls_ret_T)(T, ...);
@@ -41,5 +44,6 @@ int main (void)
   /* { dg-output "67: 67 4" } */
   printf("res: %ld\n", res);
   /* { dg-output "\nres: 67" } */
+  CHECK(res == 67);
   exit(0);
 }
index 62f2cae63a9b48d9a2c46c148ed5864f23b5ea1c..813bb2eff03a957eb219bd996c1e3ebb40355dd1 100644 (file)
@@ -37,11 +37,13 @@ int main (void)
   /* { dg-output "214: 1152921504606846761" } */
   printf("res: %" PRIdLL "\n", res);
   /* { dg-output "\nres: 1152921504606846761" } */
+  CHECK(res == 1152921504606846761LL);
 
   res = (*((cls_ret_ulonglong)code))(9223372035854775808LL);
   /* { dg-output "\n9223372035854775808: 8070450533247928831" } */
   printf("res: %" PRIdLL "\n", res);
   /* { dg-output "\nres: 8070450533247928831" } */
+  CHECK(res == 8070450533247928831LL);
 
   exit(0);
 }
index a00100e07f8c954f7a15a08ee5a873754d8558d5..bfe5e657c17e38eef874b17bdef03f5f528ba6be 100644 (file)
@@ -14,6 +14,8 @@ static void cls_ret_ushort_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
 
   printf("%d: %d\n",*(unsigned short *)args[0],
         (int)*(ffi_arg *)(resp));
+  CHECK(*(unsigned short *)args[0] == 65535);
+  CHECK((int)*(ffi_arg *)(resp) == 65535);
 }
 typedef unsigned short (*cls_ret_ushort)(unsigned short);
 
@@ -38,6 +40,7 @@ int main (void)
   /* { dg-output "65535: 65535" } */
   printf("res: %d\n",res);
   /* { dg-output "\nres: 65535" } */
+  CHECK(res == 65535);
 
   exit(0);
 }
index 95d96a83f18c7dfa3cb6beea988e71e7f90b1514..d27d362d6a6e7e99787be66a5ccbb6c2f487c3a5 100644 (file)
@@ -1,144 +1 @@
-#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) \
-   do { \
-      if(!(x)){ \
-         printf("Check failed:\n%s\n", #x); \
-         abort(); \
-      } \
-   } while(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
+#include "../libffi.call/ffitest.h"
index e8e1d8601fb050e937a711778773afa7092d0a54..b3488304c1a61196469d7dbb0ff3df520e8c1852 100644 (file)
@@ -6,7 +6,7 @@
 */
 
 /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
-/* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */
+/* { dg-options -mlong-double-128 { target powerpc64*-*-linux-gnu* } } */
 /* { dg-options -Wformat=0 { target moxie*-*-elf or1k-*-* } } */
 
 #include <inttypes.h>
@@ -121,13 +121,13 @@ test_large_fn(
 {
        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), 
+                       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), 
+                       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), 
+                       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), 
+                       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 "
@@ -138,18 +138,18 @@ test_large_fn(
                "%" 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,
+              ui8_1, si8_1, ui16_1, si16_1, ui32_1, si32_1, ui64_1, si64_1, f_1, d_1, ld_1, (long)(intptr_t)p_1,
+               ui8_2, si8_2, ui16_2, si16_2, ui32_2, si32_2, ui64_2, si64_2, f_2, d_2, ld_2, (long)(intptr_t)p_2,
+               ui8_3, si8_3, ui16_3, si16_3, ui32_3, si32_3, ui64_3, si64_3, f_3, d_3, ld_3, (long)(intptr_t)p_3,
+               ui8_4, si8_4, ui16_4, si16_4, ui32_4, si32_4, ui64_4, si64_4, f_4, d_4, ld_4, (long)(intptr_t)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.g, retVal.h, retVal.i, retVal.j, retVal.k, (long)(intptr_t)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.s, retVal.t, retVal.u, retVal.v, retVal.w, (long)(intptr_t)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.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (long)(intptr_t)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);
+              retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (long)(intptr_t)retVal.vv, retVal.ww, retVal.xx);
 
        return  retVal;
 }
@@ -216,8 +216,7 @@ cls_large_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __
                ui8_5, si8_5);
 }
 
-int
-main(int argc __UNUSED__, const char** argv __UNUSED__)
+int main (void)
 {
         void *code;
        ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
@@ -302,13 +301,13 @@ main(int argc __UNUSED__, const char** argv __UNUSED__)
                "%" 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.g, retVal.h, retVal.i, retVal.j, retVal.k, (long)(intptr_t)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.s, retVal.t, retVal.u, retVal.v, retVal.w, (long)(intptr_t)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.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (long)(intptr_t)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);
+              retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (long)(intptr_t)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);
@@ -330,13 +329,13 @@ main(int argc __UNUSED__, const char** argv __UNUSED__)
                "%" 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.g, retVal.h, retVal.i, retVal.j, retVal.k, (long)(intptr_t)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.s, retVal.t, retVal.u, retVal.v, retVal.w, (long)(intptr_t)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.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (long)(intptr_t)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);
+              retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (long)(intptr_t)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;
index 10797a345f2ed1f91bdac82e3f857998226edaf6..8b1b4ba79c17ea40546c6e0ef5453d1c0ddfc913 100644 (file)
@@ -46,6 +46,29 @@ static cls_struct_combined cls_struct_combined_fn(struct cls_struct_16byte1 b0,
         result.d.a, result.d.b, result.d.c,
         result.e.ii, result.e.dd, result.e.ff);
 
+  CHECK_DOUBLE_EQ(b0.a, 9);
+  CHECK_FLOAT_EQ(b0.b, 2);
+  CHECK(b0.c == 6);
+
+  CHECK(b1.ii == 1);
+  CHECK_DOUBLE_EQ(b1.dd, 2);
+  CHECK_FLOAT_EQ(b1.ff, 3);
+
+  CHECK_DOUBLE_EQ(b2.d.a, 4);
+  CHECK_FLOAT_EQ(b2.d.b, 5);
+  CHECK(b2.d.c == 6);
+
+  CHECK(b2.e.ii == 3);
+  CHECK_DOUBLE_EQ(b2.e.dd, 1);
+  CHECK_FLOAT_EQ(b2.e.ff, 8);
+
+  CHECK_DOUBLE_EQ(result.d.a, 15);
+  CHECK_FLOAT_EQ(result.d.b, 10);
+  CHECK(result.d.c == 13);
+  CHECK(result.e.ii == 10);
+  CHECK_DOUBLE_EQ(result.e.dd, 12);
+  CHECK_FLOAT_EQ(result.e.ff, 13);
+
   return result;
 }
 
@@ -128,12 +151,12 @@ int main (void)
 
   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_DOUBLE_EQ( res_dbl.d.a, (e_dbl.a + f_dbl.dd + g_dbl.d.a));
+  CHECK_FLOAT_EQ( 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_DOUBLE_EQ( res_dbl.e.dd, (e_dbl.a + f_dbl.dd + g_dbl.e.dd));
+  CHECK_FLOAT_EQ( 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);
 
@@ -142,11 +165,11 @@ int main (void)
                                     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_DOUBLE_EQ( res_dbl.d.a, (e_dbl.a + f_dbl.dd + g_dbl.d.a));
+  CHECK_FLOAT_EQ( 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_DOUBLE_EQ( res_dbl.e.dd, (e_dbl.a + f_dbl.dd + g_dbl.e.dd));
+  CHECK_FLOAT_EQ( res_dbl.e.ff, (e_dbl.b + f_dbl.ff + g_dbl.e.ff));
   exit(0);
 }
index 3cf2b44abe89e9790fd75cdc0af3469b50aa0faa..a2cdc649463285a58e0c0553ad5b471f92d86a84 100644 (file)
@@ -38,6 +38,18 @@ static B B_fn(struct A b2, struct B b3, struct C b4)
         (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);
 
+  CHECK((int)b2.a == 1);
+  CHECK(b2.b == 7);
+  CHECK((int)b3.x.a == 12);
+  CHECK(b3.x.b == 127);
+  CHECK(b3.y == 99);
+  CHECK(b3.z == 255);
+  CHECK((int)b4.d == 2);
+  CHECK(b4.e == 9);
+  CHECK((int)result.x.a == 270);
+  CHECK(result.x.b == 242);
+  CHECK(result.y == 143);
+
   return result;
 }
 
index 351049382c620224d544f49d3bc57564d2cc0310..c9821e49303338ca2e96f46a5b995c6cf3b59fbe 100644 (file)
@@ -35,6 +35,13 @@ static C C_fn (int x, int y, int z, C source, int i, int j, int k)
 
   printf ("%d, %d, %d, %d, %d, %d\n", x, y, z, i, j, k);
 
+  CHECK(x == 1);
+  CHECK(y == 1);
+  CHECK(z == 1);
+  CHECK(i == 1);
+  CHECK(j == 1);
+  CHECK(k == 1);
+
   printf ("%.1f, %.1f, %.1f, %.1f, "
          "%.1f, %.1f, %.1f, %.1f\n",
          source.a.a_x, source.a.a_y,
@@ -42,6 +49,15 @@ static C C_fn (int x, int y, int z, C source, int i, int j, int k)
          result.a.a_x, result.a.a_y,
          result.b.b_x, result.b.b_y);
 
+    CHECK_FLOAT_EQ(source.a.a_x, 1.0);
+    CHECK_FLOAT_EQ(source.a.a_y, 2.0);
+    CHECK_FLOAT_EQ(source.b.b_x, 4.0);
+    CHECK_FLOAT_EQ(source.b.b_y, 8.0);
+    CHECK_FLOAT_EQ(result.a.a_x, 1.0);
+    CHECK_FLOAT_EQ(result.a.a_y, 2.0);
+    CHECK_FLOAT_EQ(result.b.b_x, 4.0);
+    CHECK_FLOAT_EQ(result.b.b_y, 8.0);
+
   return result;
 }
 
@@ -113,9 +129,9 @@ int main (void)
   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);
+  CHECK_FLOAT_EQ(result.a.a_x, source.a.a_x);
+  CHECK_FLOAT_EQ(result.a.a_y, source.a.a_y);
+  CHECK_FLOAT_EQ(result.b.b_x, source.b.b_x);
+  CHECK_FLOAT_EQ(result.b.b_y, source.b.b_y);
+  exit(0);
 }
index 0d307ae91f1e783abc2bd7837eda51e0c6c95334..7ca16c17d1e181b69de333c4fef1e90ace077a76 100644 (file)
@@ -75,7 +75,7 @@ int main (void)
 
        CHECK( ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, retType, args) == FFI_OK);
        ffi_call(&cif, FFI_FN(testNestedFloatStruct), &ts12_result, values);
-       CHECK(ts12_result == 138.2f);
+       CHECK_FLOAT_EQ(ts12_result, 138.2f);
 
        free(struct_float1);
        free(struct_float2);
index 6c139b9526882b7d3bd1a6fdb7055727eaa43996..6edfdcbb5e30e87a898c0c8188215afada3be6f7 100644 (file)
@@ -27,6 +27,14 @@ B B_fn(float b0, struct B b1)
   printf("%g %g %g %g: %g %g %g\n", b0, b1.x, b1.y.a, b1.y.b,
         result.x, result.y.a, result.y.b);
 
+  CHECK_FLOAT_EQ(b0, 12.125);
+  CHECK_FLOAT_EQ(b1.x, 24.75);
+  CHECK_FLOAT_EQ(b1.y.a, 31.625);
+  CHECK_FLOAT_EQ(b1.y.b, 32.25);
+  CHECK_FLOAT_EQ(result.x, 36.875);
+  CHECK_FLOAT_EQ(result.y.a, 43.75);
+  CHECK_FLOAT_EQ(result.y.b, 44.375);
+
   return result;
 }
 
@@ -91,17 +99,17 @@ int main (void)
 
   ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl);
   /* { dg-output "12.125 24.75 31.625 32.25: 36.875 43.75 44.375" } */
-  CHECK( res_dbl.x == (e_dbl + f_dbl.x));
-  CHECK( res_dbl.y.a == (e_dbl + f_dbl.y.a));
-  CHECK( res_dbl.y.b == (e_dbl + f_dbl.y.b));
+  CHECK_FLOAT_EQ( res_dbl.x, (e_dbl + f_dbl.x));
+  CHECK_FLOAT_EQ( res_dbl.y.a, (e_dbl + f_dbl.y.a));
+  CHECK_FLOAT_EQ( res_dbl.y.b, (e_dbl + f_dbl.y.b));
 
   CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK);
 
   res_dbl = ((B(*)(float, B))(code))(e_dbl, f_dbl);
   /* { dg-output "\n12.125 24.75 31.625 32.25: 36.875 43.75 44.375" } */
-  CHECK( res_dbl.x == (e_dbl + f_dbl.x));
-  CHECK( res_dbl.y.a == (e_dbl + f_dbl.y.a));
-  CHECK( res_dbl.y.b == (e_dbl + f_dbl.y.b));
+  CHECK_FLOAT_EQ( res_dbl.x, (e_dbl + f_dbl.x));
+  CHECK_FLOAT_EQ( res_dbl.y.a, (e_dbl + f_dbl.y.a));
+  CHECK_FLOAT_EQ( res_dbl.y.b, (e_dbl + f_dbl.y.b));
 
   exit(0);
 }
index d919e5c932db663d4d8285265417a14321014750..93a913d32162a000f2b02cde55bc6ce641fd87d3 100644 (file)
@@ -30,6 +30,15 @@ static B B_fn(struct A b0, struct B b1)
   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);
 
+  CHECK(b0.a == 1);
+  CHECK(b0.b == 7);
+  CHECK(b1.x.a == 12);
+  CHECK(b1.x.b == 127);
+  CHECK(b1.y == 99);
+  CHECK(result.x.a == 13);
+  CHECK(result.x.b == 233);
+  CHECK(result.y == 134);
+
   return result;
 }
 
index 7d4c2cf801b41bca9368c45f2e362f3dd849840b..d39a9ccfe5aca2c6d950c9a2c54af3cebe23935a 100644 (file)
@@ -31,6 +31,15 @@ static B B_fn(struct A b0, struct B b1)
         (int)b1.x.a, b1.x.b, b1.y,
         (int)result.x.a, result.x.b, result.y);
 
+  CHECK((int)b0.a == 1);
+  CHECK(b0.b == 7);
+  CHECK((int)b1.x.a == 12);
+  CHECK(b1.x.b == 127);
+  CHECK(b1.y == 99);
+  CHECK((int)result.x.a == 13);
+  CHECK(result.x.b == 233);
+  CHECK(result.y == 134);
+
   return result;
 }
 
index 2ffb4d65a0635cafa530d0f2f35f597f12c50142..d5c960dce7da04bb6c009f699ad1b15b71869797 100644 (file)
@@ -31,6 +31,15 @@ static B B_fn(struct A b2, struct B b3)
         (int)b3.x.a, b3.x.b, b3.y,
         (int)result.x.a, result.x.b, result.y);
 
+  CHECK((int)b2.a == 1);
+  CHECK(b2.b == 7);
+  CHECK((int)b3.x.a == 12);
+  CHECK(b3.x.b == 127);
+  CHECK(b3.y == 99);
+  CHECK((int)result.x.a == 13);
+  CHECK(result.x.b == 233);
+  CHECK(result.y == 134);
+
   return result;
 }
 
index 6c79845d984a68693c4a21087ebb99b9afd52e8d..b053f52b0204d3a6b5da870b0242dcbb39c078bb 100644 (file)
@@ -31,6 +31,15 @@ static B B_fn(struct A b2, struct B b3)
         (int)b3.x.a, b3.x.b, b3.y,
         (int)result.x.a, result.x.b, result.y);
 
+  CHECK((int)b2.a == 1);
+  CHECK(b2.b == 7);
+  CHECK((int)b3.x.a == 12);
+  CHECK(b3.x.b == 127);
+  CHECK(b3.y == 99);
+  CHECK((int)result.x.a == 13);
+  CHECK(result.x.b == 233);
+  CHECK(result.y == 134);
+
   return result;
 }
 
index 59d35796f8def3db59580e42343f203d5c7de194..690ec0be89a7c729697f88ecc3a964cd8b260cc0 100644 (file)
@@ -36,6 +36,17 @@ static B B_fn(struct A b2, struct B b3, struct C b4)
         (int)b3.x.a, b3.x.b, b3.y, (int)b4.d, b4.e,
         (int)result.x.a, result.x.b, result.y);
 
+  CHECK((int)b2.a == 1);
+  CHECK(b2.b == 7);
+  CHECK((int)b3.x.a == 12);
+  CHECK(b3.x.b == 127);
+  CHECK(b3.y == 99);
+  CHECK((int)b4.d == 2);
+  CHECK(b4.e == 9);
+  CHECK((int)result.x.a == 15);
+  CHECK(result.x.b == 242);
+  CHECK(result.y == 143);
+
   return result;
 }
 
index 27595e6f5c301c151cf192d4da680f863aefca90..b3ddd030d280d3168f1007c46458bc57c7563472 100644 (file)
@@ -31,6 +31,15 @@ static B B_fn(struct A b2, struct B b3)
         (int)b3.x.a, b3.x.b, b3.y,
         (int)result.x.a, result.x.b, result.y);
 
+  CHECK((int)b2.a == 1);
+  CHECK(b2.b == 7);
+  CHECK((int)b3.x.a == 12);
+  CHECK(b3.x.b == 127);
+  CHECK(b3.y == 99);
+  CHECK((int)result.x.a == 13);
+  CHECK(result.x.b == 233);
+  CHECK(result.y == 134);
+
   return result;
 }
 
index 0e6c68281e1a0ff66d8afc5e93b9466dd7e6d93e..768f3331b2b4de58477a2624eb40a4efe5bbf039 100644 (file)
@@ -36,6 +36,17 @@ static B B_fn(struct A b2, struct B b3, struct C b4)
         (int)b3.x.a, b3.x.b, b3.y, (int)b4.d, b4.e,
         (int)result.x.a, result.x.b, result.y);
 
+  CHECK((int)b2.a == 1);
+  CHECK(b2.b == 7);
+  CHECK((int)b3.x.a == 12);
+  CHECK(b3.x.b == 127);
+  CHECK(b3.y == 99);
+  CHECK((int)b4.d == 2);
+  CHECK(b4.e == 9);
+  CHECK((int)result.x.a == 15);
+  CHECK(result.x.b == 242);
+  CHECK(result.y == 143);
+
   return result;
 }
 
index 5f7ac67752caa154ed93eaeeff46b706795f8f95..f88ab0a94fa6c2ed98b6c1226ecae2dd7dae9d12 100644 (file)
@@ -36,6 +36,17 @@ static B B_fn(struct A b2, struct B b3, struct C b4)
         b3.x.a, (int)b3.x.b, b3.y, (int)b4.d, b4.e,
         result.x.a, (int)result.x.b, result.y);
 
+  CHECK((int)b2.a == 1);
+  CHECK(b2.b == 7);
+  CHECK((int)b3.x.a == 12);
+  CHECK(b3.x.b == 127);
+  CHECK(b3.y == 99);
+  CHECK((int)b4.d == 2); 
+  CHECK(b4.e == 9);
+  CHECK((int)result.x.a == 15);
+  CHECK(result.x.b == 242);
+  CHECK(result.y == 143);
+  
   return result;
 }
 
index 600368e0c9d08944d9c32157ddc2b52fd188d771..e738a01fb029d41fa4fe838d216aacea9e0368b7 100644 (file)
@@ -20,6 +20,11 @@ static void cls_struct_combined_fn(struct cls_struct_combined arg)
         arg.a, arg.b,
         arg.c, arg.d);
   fflush(stdout);
+
+  CHECK_FLOAT_EQ(arg.a, 4);
+  CHECK_FLOAT_EQ(arg.b, 5);
+  CHECK_FLOAT_EQ(arg.c, 1);
+  CHECK_FLOAT_EQ(arg.d, 8);
 }
 
 static void
index e1145657d14d59509706914cc7f23366a0e6202a..634fb716bf863b3a76f047d54ba442bedbd17008 100644 (file)
@@ -4,7 +4,7 @@
    PR:         none.
    Originator: Jeff Sturm <jsturm@one-point.com>  */
 
-/* { dg-do run { xfail x86_64-apple-darwin* moxie*-*-* } } */
+/* { dg-do run { xfail moxie*-*-* } } */
 
 #include "ffitest.h"
 
@@ -48,6 +48,9 @@ typedef int (*closure_test_type1)(float, float, float, float, signed short,
                                  float, float, int, double, int, int, float,
                                  int, int, int, int);
 
+#ifdef __EMSCRIPTEN__
+extern "C"
+#endif
 int main (void)
 {
   ffi_cif cif;
index 153d24094080e00f75e92b10a575feea296ca9ca..1b86cc0716dff23c6e32375ddf3a3983ef018c29 100644 (file)
@@ -14,6 +14,9 @@ static int checking(int a __UNUSED__, short b __UNUSED__,
   throw 9;
 }
 
+#ifdef __EMSCRIPTEN__
+extern "C"
+#endif
 int main (void)
 {
   ffi_cif cif;
index bac319081e61389ff40bf51fa56a3010eccff6c4..cae5c4558f75170358e93acc8e0a1e08fd0ce03f 100644 (file)
@@ -76,7 +76,7 @@ int main (void)
 
   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" */
+  /* { 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);
diff --git a/libffi/testsuite/libffi.threads/ffitest.h b/libffi/testsuite/libffi.threads/ffitest.h
new file mode 100644 (file)
index 0000000..d27d362
--- /dev/null
@@ -0,0 +1 @@
+#include "../libffi.call/ffitest.h"
diff --git a/libffi/testsuite/libffi.threads/threads.exp b/libffi/testsuite/libffi.threads/threads.exp
new file mode 100644 (file)
index 0000000..ca03750
--- /dev/null
@@ -0,0 +1,50 @@
+# 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
+
+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]]
+
+# No pthreads for windows or wasm
+if { [string match $compiler_vendor "microsoft"] || [istarget "wasm*-*-*"] } {
+    foreach test $tlist {
+        unsupported "$test"
+    }
+} else {
+    run-many-tests $tlist $additional_options
+}
+
+dg-finish
+
+# Local Variables:
+# tcl-indent-level:4
+# End:
diff --git a/libffi/testsuite/libffi.threads/tsan.c b/libffi/testsuite/libffi.threads/tsan.c
new file mode 100644 (file)
index 0000000..aeff60c
--- /dev/null
@@ -0,0 +1,74 @@
+/* { dg-do run } */
+
+#include "ffitest.h"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_THREADS 20
+
+#ifdef _POSIX_BARRIERS
+pthread_barrier_t barrier;
+#endif
+
+typedef float (*callback_fn)(float, float);
+
+void callback(ffi_cif *cif __UNUSED__, void *ret, void **args, void *userdata __UNUSED__) {
+    float a = *(float *)args[0];
+    float b = *(float *)args[1];
+    *(float *)ret = a / 2 + b / 2;
+}
+
+void *thread_func(void *arg) {
+#ifdef _POSIX_BARRIERS
+    pthread_barrier_wait(&barrier);
+#endif
+
+    ffi_cif cif;
+    ffi_type *args[2] = { &ffi_type_float, &ffi_type_float };
+
+    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_float, args) != FFI_OK) {
+        fprintf(stderr, "ffi_prep_cif failed\n");
+        return NULL;
+    }
+
+    ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), (void **)&arg);
+
+    if (ffi_prep_closure_loc(closure, &cif, callback, NULL, arg) != FFI_OK) {
+        fprintf(stderr, "ffi_prep_closure_loc failed\n");
+        return NULL;
+    }
+
+    callback_fn fn = (callback_fn)arg;
+    (void) fn(4.0f, 6.0f);
+
+    ffi_closure_free(closure);
+    return NULL;
+}
+
+int main() {
+    pthread_t threads[NUM_THREADS];
+
+#ifdef _POSIX_BARRIERS
+    pthread_barrier_init(&barrier, NULL, NUM_THREADS);
+#endif
+
+    for (int i = 0; i < NUM_THREADS; ++i) {
+        if (pthread_create(&threads[i], NULL, thread_func, NULL) != 0) {
+            perror("pthread_create");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    for (int i = 0; i < NUM_THREADS; ++i) {
+        pthread_join(threads[i], NULL);
+    }
+
+#ifdef _POSIX_BARRIERS
+    pthread_barrier_destroy(&barrier);
+#endif
+
+    printf("Completed\n");
+    return 0;
+}