diff options
221 files changed, 22974 insertions, 15885 deletions
diff --git a/libffi/ChangeLog b/libffi/ChangeLog index 2b5c10e..7416793 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,7 @@ +2015-01-12 Richard Henderson <rth@redhat.com> + + Merge to upstream commit c82cc159426d8d4402375fa1ae3f045b9cf82e16. + 2014-11-21 H.J. Lu <hongjiu.lu@intel.com> PR bootstrap/63784 diff --git a/libffi/LICENSE b/libffi/LICENSE index aa60342..a66fab4 100644 --- a/libffi/LICENSE +++ b/libffi/LICENSE @@ -1,4 +1,4 @@ -libffi - Copyright (c) 1996-2012 Anthony Green, Red Hat, Inc and others. +libffi - Copyright (c) 1996-2014 Anthony Green, Red Hat, Inc and others. See source files for details. Permission is hereby granted, free of charge, to any person obtaining diff --git a/libffi/Makefile.am b/libffi/Makefile.am index 645dc12..64ff1c1 100644 --- a/libffi/Makefile.am +++ b/libffi/Makefile.am @@ -1,46 +1,19 @@ ## Process this with automake to create Makefile.in AUTOMAKE_OPTIONS = foreign subdir-objects + ACLOCAL_AMFLAGS = -I .. -I ../config SUBDIRS = include testsuite man -EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj configure.host \ - src/aarch64/ffi.c src/aarch64/ffitarget.h \ - src/alpha/ffi.c src/alpha/osf.S src/alpha/ffitarget.h \ - src/arm/ffi.c src/arm/sysv.S src/arm/ffitarget.h \ - src/avr32/ffi.c src/avr32/sysv.S src/avr32/ffitarget.h \ - src/cris/ffi.c src/cris/sysv.S src/cris/ffitarget.h \ - src/ia64/ffi.c src/ia64/ffitarget.h src/ia64/ia64_flags.h \ - src/ia64/unix.S src/mips/ffi.c src/mips/n32.S src/mips/o32.S \ - src/mips/ffitarget.h src/m32r/ffi.c src/m32r/sysv.S \ - src/m32r/ffitarget.h src/m68k/ffi.c src/m68k/sysv.S \ - src/m68k/ffitarget.h \ - src/powerpc/ffi.c src/powerpc/ffi_powerpc.h \ - src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c \ - src/powerpc/sysv.S src/powerpc/linux64.S \ - src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S \ - src/powerpc/asm.h src/powerpc/aix.S src/powerpc/darwin.S \ - src/powerpc/aix_closure.S src/powerpc/darwin_closure.S \ - src/powerpc/ffi_darwin.c src/powerpc/ffitarget.h \ - src/s390/ffi.c src/s390/sysv.S src/s390/ffitarget.h \ - src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h src/sh64/ffi.c \ - src/sh64/sysv.S src/sh64/ffitarget.h src/sparc/v8.S \ - src/sparc/v9.S src/sparc/ffitarget.h src/sparc/ffi.c \ - src/x86/darwin64.S src/x86/ffi.c src/x86/sysv.S \ - src/x86/win32.S src/x86/darwin.S src/x86/win64.S \ - src/x86/freebsd.S src/x86/ffi64.c src/x86/unix64.S \ - src/x86/ffitarget.h src/pa/ffitarget.h src/pa/ffi.c \ - src/pa/linux.S src/pa/hpux32.S src/frv/ffi.c src/bfin/ffi.c \ - src/bfin/ffitarget.h src/bfin/sysv.S src/frv/eabi.S \ - src/frv/ffitarget.h src/dlmalloc.c src/tile/ffi.c \ - src/tile/ffitarget.h src/tile/tile.S libtool-version \ - ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4 \ +EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \ + ChangeLog.libffi ChangeLog.libffi-3.1 \ + m4/libtool.m4 m4/lt~obsolete.m4 \ m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \ - m4/ltversion.m4 src/arm/gentramp.sh src/debug.c msvcc.sh \ - generate-ios-source-and-headers.py \ - generate-osx-source-and-headers.py \ - libffi.xcodeproj/project.pbxproj src/arm/trampoline.S + m4/ltversion.m4 src/debug.c msvcc.sh \ + generate-darwin-source-and-headers.py \ + libffi.xcodeproj/project.pbxproj \ + libtool-ldflags # Automake Documentation: # If your package has Texinfo files in many directories, you can use the @@ -79,7 +52,6 @@ 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) doc/libffi.info MAINTAINERCLEANFILES = $(srcdir)/doc/libffi.info @@ -93,153 +65,147 @@ MAINTAINERCLEANFILES = $(srcdir)/doc/libffi.info # 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)" + '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) MAKEOVERRIDES= +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libffi.pc + toolexeclib_LTLIBRARIES = libffi.la noinst_LTLIBRARIES = libffi_convenience.la libffi_la_SOURCES = src/prep_cif.c src/types.c \ src/raw_api.c src/java_raw_api.c src/closures.c -nodist_libffi_la_SOURCES = - if FFI_DEBUG -nodist_libffi_la_SOURCES += src/debug.c -endif - -if MIPS -nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S -endif -if BFIN -nodist_libffi_la_SOURCES += src/bfin/ffi.c src/bfin/sysv.S -endif -if X86 -nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S -endif -if X86_FREEBSD -nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/freebsd.S -endif -if X86_WIN32 -nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/win32.S -endif -if X86_WIN64 -nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/win64.S -endif -if X86_DARWIN -nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S -endif -if SPARC -nodist_libffi_la_SOURCES += src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S -endif -if ALPHA -nodist_libffi_la_SOURCES += src/alpha/ffi.c src/alpha/osf.S -endif -if IA64 -nodist_libffi_la_SOURCES += src/ia64/ffi.c src/ia64/unix.S -endif -if M32R -nodist_libffi_la_SOURCES += src/m32r/sysv.S src/m32r/ffi.c -endif -if M68K -nodist_libffi_la_SOURCES += src/m68k/ffi.c src/m68k/sysv.S -endif -if POWERPC -nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S -endif -if POWERPC_AIX -nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S -endif -if POWERPC_DARWIN -nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S -endif -if POWERPC_FREEBSD -nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/sysv.S src/powerpc/ppc_closure.S -endif -if AARCH64 -nodist_libffi_la_SOURCES += src/aarch64/sysv.S src/aarch64/ffi.c -endif -if ARM -nodist_libffi_la_SOURCES += src/arm/sysv.S src/arm/ffi.c -if FFI_EXEC_TRAMPOLINE_TABLE -nodist_libffi_la_SOURCES += src/arm/trampoline.S -endif -endif -if AVR32 -nodist_libffi_la_SOURCES += src/avr32/sysv.S src/avr32/ffi.c -endif -if LIBFFI_CRIS -nodist_libffi_la_SOURCES += src/cris/sysv.S src/cris/ffi.c -endif -if FRV -nodist_libffi_la_SOURCES += src/frv/eabi.S src/frv/ffi.c -endif -if S390 -nodist_libffi_la_SOURCES += src/s390/sysv.S src/s390/ffi.c -endif -if X86_64 -nodist_libffi_la_SOURCES += src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S -endif -if SH -nodist_libffi_la_SOURCES += src/sh/sysv.S src/sh/ffi.c -endif -if SH64 -nodist_libffi_la_SOURCES += src/sh64/sysv.S src/sh64/ffi.c -endif -if PA_LINUX -nodist_libffi_la_SOURCES += src/pa/linux.S src/pa/ffi.c -endif -if PA_HPUX -nodist_libffi_la_SOURCES += src/pa/hpux32.S src/pa/ffi.c -endif -if TILE -nodist_libffi_la_SOURCES += src/tile/tile.S src/tile/ffi.c -endif +libffi_la_SOURCES += src/debug.c +endif + +noinst_HEADERS = \ + src/aarch64/ffitarget.h src/aarch64/internal.h \ + src/alpha/ffitarget.h src/alpha/internal.h \ + src/arc/ffitarget.h \ + src/arm/ffitarget.h src/arm/internal.h \ + src/avr32/ffitarget.h \ + src/bfin/ffitarget.h \ + src/cris/ffitarget.h \ + src/frv/ffitarget.h \ + src/ia64/ffitarget.h src/ia64/ia64_flags.h \ + src/m32r/ffitarget.h \ + src/m68k/ffitarget.h \ + src/m88k/ffitarget.h \ + src/metag/ffitarget.h \ + src/microblaze/ffitarget.h \ + src/mips/ffitarget.h \ + src/moxie/ffitarget.h \ + src/nios2/ffitarget.h \ + src/or1k/ffitarget.h \ + src/pa/ffitarget.h \ + src/powerpc/ffitarget.h src/powerpc/asm.h src/powerpc/ffi_powerpc.h \ + src/s390/ffitarget.h \ + src/sh/ffitarget.h \ + src/sh64/ffitarget.h \ + src/sparc/ffitarget.h src/sparc/internal.h \ + src/tile/ffitarget.h \ + src/vax/ffitarget.h \ + src/x86/ffitarget.h src/x86/internal.h src/x86/internal64.h \ + src/xtensa/ffitarget.h \ + src/dlmalloc.c + +EXTRA_libffi_la_SOURCES = \ + src/aarch64/ffi.c src/aarch64/sysv.S \ + src/alpha/ffi.c src/alpha/osf.S \ + src/arc/ffi.c src/arc/arcompact.S \ + src/arm/ffi.c src/arm/sysv.S \ + src/avr32/ffi.c src/avr32/sysv.S \ + src/bfin/ffi.c src/bfin/sysv.S \ + src/cris/ffi.c src/cris/sysv.S \ + src/frv/ffi.c src/frv/eabi.S \ + src/ia64/ffi.c src/ia64/unix.S \ + src/m32r/ffi.c src/m32r/sysv.S \ + src/m68k/ffi.c src/m68k/sysv.S \ + src/m88k/ffi.c src/m88k/obsd.S \ + src/metag/ffi.c src/metag/sysv.S \ + src/microblaze/ffi.c src/microblaze/sysv.S \ + src/mips/ffi.c src/mips/o32.S src/mips/n32.S \ + src/moxie/ffi.c src/moxie/eabi.S \ + src/nios2/ffi.c src/nios2/sysv.S \ + src/or1k/ffi.c src/or1k/sysv.S \ + src/pa/ffi.c src/pa/linux.S src/pa/hpux32.S \ + src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c \ + src/powerpc/sysv.S src/powerpc/linux64.S \ + src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S \ + src/powerpc/aix.S src/powerpc/darwin.S src/powerpc/aix_closure.S \ + src/powerpc/darwin_closure.S src/powerpc/ffi_darwin.c \ + src/s390/ffi.c src/s390/sysv.S \ + src/sh/ffi.c src/sh/sysv.S \ + src/sh64/ffi.c src/sh64/sysv.S \ + src/sparc/ffi.c src/sparc/ffi64.c src/sparc/v8.S src/sparc/v9.S \ + src/tile/ffi.c src/tile/tile.S \ + src/vax/ffi.c src/vax/elfbsd.S \ + src/x86/ffi.c src/x86/sysv.S \ + src/x86/ffiw64.c src/x86/win64.S \ + src/x86/ffi64.c src/x86/unix64.S \ + src/x86/darwin64.S src/x86/darwin.S \ + src/x86/darwin64_c.c src/x86/darwin_c.c \ + src/xtensa/ffi.c src/xtensa/sysv.S + +TARGET_OBJ = @TARGET_OBJ@ +libffi_la_LIBADD = $(TARGET_OBJ) +libffi_la_DEPENDENCIES = $(TARGET_OBJ) libffi_convenience_la_SOURCES = $(libffi_la_SOURCES) +EXTRA_libffi_convenience_la_SOURCES = $(EXTRA_libffi_la_SOURCES) +libffi_convenience_la_LIBADD = $(libffi_la_LIBADD) +libffi_convenience_la_DEPENDENCIES = $(libffi_la_DEPENDENCIES) nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES) -AM_CFLAGS = -Wall -g -fexceptions - LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) -libffi_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LTLDFLAGS) $(AM_LTLDFLAGS) +AM_CFLAGS = -Wall -g -fexceptions +if FFI_DEBUG +# Build debug. Define FFI_DEBUG on the commandline so that, when building with +# MSVC, it can link against the debug CRT. +AM_CFLAGS += -DFFI_DEBUG +endif + +libffi_la_LDFLAGS = -no-undefined -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LTLDFLAGS) $(AM_LTLDFLAGS) AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src AM_CCASFLAGS = $(AM_CPPFLAGS) diff --git a/libffi/Makefile.in b/libffi/Makefile.in index 2a04e0b..80ad274 100644 --- a/libffi/Makefile.in +++ b/libffi/Makefile.in @@ -15,6 +15,8 @@ @SET_MAKE@ + + VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ @@ -36,41 +38,16 @@ build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @FFI_DEBUG_TRUE@am__append_1 = src/debug.c -@MIPS_TRUE@am__append_2 = src/mips/ffi.c src/mips/o32.S src/mips/n32.S -@BFIN_TRUE@am__append_3 = src/bfin/ffi.c src/bfin/sysv.S -@X86_TRUE@am__append_4 = src/x86/ffi.c src/x86/sysv.S -@X86_FREEBSD_TRUE@am__append_5 = src/x86/ffi.c src/x86/freebsd.S -@X86_WIN32_TRUE@am__append_6 = src/x86/ffi.c src/x86/win32.S -@X86_WIN64_TRUE@am__append_7 = src/x86/ffi.c src/x86/win64.S -@X86_DARWIN_TRUE@am__append_8 = src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S -@SPARC_TRUE@am__append_9 = src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S -@ALPHA_TRUE@am__append_10 = src/alpha/ffi.c src/alpha/osf.S -@IA64_TRUE@am__append_11 = src/ia64/ffi.c src/ia64/unix.S -@M32R_TRUE@am__append_12 = src/m32r/sysv.S src/m32r/ffi.c -@M68K_TRUE@am__append_13 = src/m68k/ffi.c src/m68k/sysv.S -@POWERPC_TRUE@am__append_14 = src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S -@POWERPC_AIX_TRUE@am__append_15 = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S -@POWERPC_DARWIN_TRUE@am__append_16 = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S -@POWERPC_FREEBSD_TRUE@am__append_17 = src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/sysv.S src/powerpc/ppc_closure.S -@AARCH64_TRUE@am__append_18 = src/aarch64/sysv.S src/aarch64/ffi.c -@ARM_TRUE@am__append_19 = src/arm/sysv.S src/arm/ffi.c -@ARM_TRUE@@FFI_EXEC_TRAMPOLINE_TABLE_TRUE@am__append_20 = src/arm/trampoline.S -@AVR32_TRUE@am__append_21 = src/avr32/sysv.S src/avr32/ffi.c -@LIBFFI_CRIS_TRUE@am__append_22 = src/cris/sysv.S src/cris/ffi.c -@FRV_TRUE@am__append_23 = src/frv/eabi.S src/frv/ffi.c -@S390_TRUE@am__append_24 = src/s390/sysv.S src/s390/ffi.c -@X86_64_TRUE@am__append_25 = src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S -@SH_TRUE@am__append_26 = src/sh/sysv.S src/sh/ffi.c -@SH64_TRUE@am__append_27 = src/sh64/sysv.S src/sh64/ffi.c -@PA_LINUX_TRUE@am__append_28 = src/pa/linux.S src/pa/ffi.c -@PA_HPUX_TRUE@am__append_29 = src/pa/hpux32.S src/pa/ffi.c -@TILE_TRUE@am__append_30 = src/tile/tile.S src/tile/ffi.c +# Build debug. Define FFI_DEBUG on the commandline so that, when building with +# MSVC, it can link against the debug CRT. +@FFI_DEBUG_TRUE@am__append_2 = -DFFI_DEBUG subdir = . DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(srcdir)/fficonfig.h.in \ - $(srcdir)/../mkinstalldirs $(srcdir)/../depcomp mdate-sh \ - $(srcdir)/doc/version.texi $(srcdir)/doc/stamp-vti + $(srcdir)/../mkinstalldirs $(srcdir)/libffi.pc.in \ + $(srcdir)/../depcomp mdate-sh $(srcdir)/doc/version.texi \ + $(srcdir)/doc/stamp-vti $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ $(top_srcdir)/../config/asmcfi.m4 \ @@ -88,7 +65,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs CONFIG_HEADER = fficonfig.h -CONFIG_CLEAN_FILES = +CONFIG_CLEAN_FILES = libffi.pc CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ @@ -111,89 +88,23 @@ am__nobase_list = $(am__nobase_strip_setup); \ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(infodir)" +am__installdirs = "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(infodir)" \ + "$(DESTDIR)$(pkgconfigdir)" LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES) -libffi_la_LIBADD = +am__DEPENDENCIES_1 = am__dirstamp = $(am__leading_dot)dirstamp -am_libffi_la_OBJECTS = src/prep_cif.lo src/types.lo src/raw_api.lo \ - src/java_raw_api.lo src/closures.lo @FFI_DEBUG_TRUE@am__objects_1 = src/debug.lo -@MIPS_TRUE@am__objects_2 = src/mips/ffi.lo src/mips/o32.lo \ -@MIPS_TRUE@ src/mips/n32.lo -@BFIN_TRUE@am__objects_3 = src/bfin/ffi.lo src/bfin/sysv.lo -@X86_TRUE@am__objects_4 = src/x86/ffi.lo src/x86/sysv.lo -@X86_FREEBSD_TRUE@am__objects_5 = src/x86/ffi.lo src/x86/freebsd.lo -@X86_WIN32_TRUE@am__objects_6 = src/x86/ffi.lo src/x86/win32.lo -@X86_WIN64_TRUE@am__objects_7 = src/x86/ffi.lo src/x86/win64.lo -@X86_DARWIN_TRUE@am__objects_8 = src/x86/ffi.lo src/x86/darwin.lo \ -@X86_DARWIN_TRUE@ src/x86/ffi64.lo src/x86/darwin64.lo -@SPARC_TRUE@am__objects_9 = src/sparc/ffi.lo src/sparc/v8.lo \ -@SPARC_TRUE@ src/sparc/v9.lo -@ALPHA_TRUE@am__objects_10 = src/alpha/ffi.lo src/alpha/osf.lo -@IA64_TRUE@am__objects_11 = src/ia64/ffi.lo src/ia64/unix.lo -@M32R_TRUE@am__objects_12 = src/m32r/sysv.lo src/m32r/ffi.lo -@M68K_TRUE@am__objects_13 = src/m68k/ffi.lo src/m68k/sysv.lo -@POWERPC_TRUE@am__objects_14 = src/powerpc/ffi.lo \ -@POWERPC_TRUE@ src/powerpc/ffi_sysv.lo \ -@POWERPC_TRUE@ src/powerpc/ffi_linux64.lo src/powerpc/sysv.lo \ -@POWERPC_TRUE@ src/powerpc/ppc_closure.lo \ -@POWERPC_TRUE@ src/powerpc/linux64.lo \ -@POWERPC_TRUE@ src/powerpc/linux64_closure.lo -@POWERPC_AIX_TRUE@am__objects_15 = src/powerpc/ffi_darwin.lo \ -@POWERPC_AIX_TRUE@ src/powerpc/aix.lo \ -@POWERPC_AIX_TRUE@ src/powerpc/aix_closure.lo -@POWERPC_DARWIN_TRUE@am__objects_16 = src/powerpc/ffi_darwin.lo \ -@POWERPC_DARWIN_TRUE@ src/powerpc/darwin.lo \ -@POWERPC_DARWIN_TRUE@ src/powerpc/darwin_closure.lo -@POWERPC_FREEBSD_TRUE@am__objects_17 = src/powerpc/ffi.lo \ -@POWERPC_FREEBSD_TRUE@ src/powerpc/ffi_sysv.lo \ -@POWERPC_FREEBSD_TRUE@ src/powerpc/sysv.lo \ -@POWERPC_FREEBSD_TRUE@ src/powerpc/ppc_closure.lo -@AARCH64_TRUE@am__objects_18 = src/aarch64/sysv.lo src/aarch64/ffi.lo -@ARM_TRUE@am__objects_19 = src/arm/sysv.lo src/arm/ffi.lo -@ARM_TRUE@@FFI_EXEC_TRAMPOLINE_TABLE_TRUE@am__objects_20 = src/arm/trampoline.lo -@AVR32_TRUE@am__objects_21 = src/avr32/sysv.lo src/avr32/ffi.lo -@LIBFFI_CRIS_TRUE@am__objects_22 = src/cris/sysv.lo src/cris/ffi.lo -@FRV_TRUE@am__objects_23 = src/frv/eabi.lo src/frv/ffi.lo -@S390_TRUE@am__objects_24 = src/s390/sysv.lo src/s390/ffi.lo -@X86_64_TRUE@am__objects_25 = src/x86/ffi64.lo src/x86/unix64.lo \ -@X86_64_TRUE@ src/x86/ffi.lo src/x86/sysv.lo -@SH_TRUE@am__objects_26 = src/sh/sysv.lo src/sh/ffi.lo -@SH64_TRUE@am__objects_27 = src/sh64/sysv.lo src/sh64/ffi.lo -@PA_LINUX_TRUE@am__objects_28 = src/pa/linux.lo src/pa/ffi.lo -@PA_HPUX_TRUE@am__objects_29 = src/pa/hpux32.lo src/pa/ffi.lo -@TILE_TRUE@am__objects_30 = src/tile/tile.lo src/tile/ffi.lo -nodist_libffi_la_OBJECTS = $(am__objects_1) $(am__objects_2) \ - $(am__objects_3) $(am__objects_4) $(am__objects_5) \ - $(am__objects_6) $(am__objects_7) $(am__objects_8) \ - $(am__objects_9) $(am__objects_10) $(am__objects_11) \ - $(am__objects_12) $(am__objects_13) $(am__objects_14) \ - $(am__objects_15) $(am__objects_16) $(am__objects_17) \ - $(am__objects_18) $(am__objects_19) $(am__objects_20) \ - $(am__objects_21) $(am__objects_22) $(am__objects_23) \ - $(am__objects_24) $(am__objects_25) $(am__objects_26) \ - $(am__objects_27) $(am__objects_28) $(am__objects_29) \ - $(am__objects_30) -libffi_la_OBJECTS = $(am_libffi_la_OBJECTS) \ - $(nodist_libffi_la_OBJECTS) +am_libffi_la_OBJECTS = src/prep_cif.lo src/types.lo src/raw_api.lo \ + src/java_raw_api.lo src/closures.lo $(am__objects_1) +libffi_la_OBJECTS = $(am_libffi_la_OBJECTS) libffi_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libffi_la_LDFLAGS) $(LDFLAGS) -o $@ -libffi_convenience_la_LIBADD = -am__objects_31 = src/prep_cif.lo src/types.lo src/raw_api.lo \ - src/java_raw_api.lo src/closures.lo -am_libffi_convenience_la_OBJECTS = $(am__objects_31) -am__objects_32 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ - $(am__objects_4) $(am__objects_5) $(am__objects_6) \ - $(am__objects_7) $(am__objects_8) $(am__objects_9) \ - $(am__objects_10) $(am__objects_11) $(am__objects_12) \ - $(am__objects_13) $(am__objects_14) $(am__objects_15) \ - $(am__objects_16) $(am__objects_17) $(am__objects_18) \ - $(am__objects_19) $(am__objects_20) $(am__objects_21) \ - $(am__objects_22) $(am__objects_23) $(am__objects_24) \ - $(am__objects_25) $(am__objects_26) $(am__objects_27) \ - $(am__objects_28) $(am__objects_29) $(am__objects_30) -nodist_libffi_convenience_la_OBJECTS = $(am__objects_32) +am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) +am__objects_2 = src/prep_cif.lo src/types.lo src/raw_api.lo \ + src/java_raw_api.lo src/closures.lo $(am__objects_1) +am_libffi_convenience_la_OBJECTS = $(am__objects_2) +nodist_libffi_convenience_la_OBJECTS = libffi_convenience_la_OBJECTS = $(am_libffi_convenience_la_OBJECTS) \ $(nodist_libffi_convenience_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ @@ -214,8 +125,9 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(libffi_la_SOURCES) $(nodist_libffi_la_SOURCES) \ +SOURCES = $(libffi_la_SOURCES) $(EXTRA_libffi_la_SOURCES) \ $(libffi_convenience_la_SOURCES) \ + $(EXTRA_libffi_convenience_la_SOURCES) \ $(nodist_libffi_convenience_la_SOURCES) MULTISRCTOP = MULTIBUILDTOP = @@ -242,6 +154,8 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive +DATA = $(pkgconfig_DATA) +HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ @@ -267,6 +181,10 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ @@ -319,12 +237,14 @@ SHELL = @SHELL@ STRIP = @STRIP@ TARGET = @TARGET@ TARGETDIR = @TARGETDIR@ +TARGET_OBJ = @TARGET_OBJ@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ @@ -381,42 +301,14 @@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign subdir-objects ACLOCAL_AMFLAGS = -I .. -I ../config SUBDIRS = include testsuite man -EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj configure.host \ - src/aarch64/ffi.c src/aarch64/ffitarget.h \ - src/alpha/ffi.c src/alpha/osf.S src/alpha/ffitarget.h \ - src/arm/ffi.c src/arm/sysv.S src/arm/ffitarget.h \ - src/avr32/ffi.c src/avr32/sysv.S src/avr32/ffitarget.h \ - src/cris/ffi.c src/cris/sysv.S src/cris/ffitarget.h \ - src/ia64/ffi.c src/ia64/ffitarget.h src/ia64/ia64_flags.h \ - src/ia64/unix.S src/mips/ffi.c src/mips/n32.S src/mips/o32.S \ - src/mips/ffitarget.h src/m32r/ffi.c src/m32r/sysv.S \ - src/m32r/ffitarget.h src/m68k/ffi.c src/m68k/sysv.S \ - src/m68k/ffitarget.h \ - src/powerpc/ffi.c src/powerpc/ffi_powerpc.h \ - src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c \ - src/powerpc/sysv.S src/powerpc/linux64.S \ - src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S \ - src/powerpc/asm.h src/powerpc/aix.S src/powerpc/darwin.S \ - src/powerpc/aix_closure.S src/powerpc/darwin_closure.S \ - src/powerpc/ffi_darwin.c src/powerpc/ffitarget.h \ - src/s390/ffi.c src/s390/sysv.S src/s390/ffitarget.h \ - src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h src/sh64/ffi.c \ - src/sh64/sysv.S src/sh64/ffitarget.h src/sparc/v8.S \ - src/sparc/v9.S src/sparc/ffitarget.h src/sparc/ffi.c \ - src/x86/darwin64.S src/x86/ffi.c src/x86/sysv.S \ - src/x86/win32.S src/x86/darwin.S src/x86/win64.S \ - src/x86/freebsd.S src/x86/ffi64.c src/x86/unix64.S \ - src/x86/ffitarget.h src/pa/ffitarget.h src/pa/ffi.c \ - src/pa/linux.S src/pa/hpux32.S src/frv/ffi.c src/bfin/ffi.c \ - src/bfin/ffitarget.h src/bfin/sysv.S src/frv/eabi.S \ - src/frv/ffitarget.h src/dlmalloc.c src/tile/ffi.c \ - src/tile/ffitarget.h src/tile/tile.S libtool-version \ - ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4 \ +EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \ + ChangeLog.libffi ChangeLog.libffi-3.1 \ + m4/libtool.m4 m4/lt~obsolete.m4 \ m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \ - m4/ltversion.m4 src/arm/gentramp.sh src/debug.c msvcc.sh \ - generate-ios-source-and-headers.py \ - generate-osx-source-and-headers.py \ - libffi.xcodeproj/project.pbxproj src/arm/trampoline.S + m4/ltversion.m4 src/debug.c msvcc.sh \ + generate-darwin-source-and-headers.py \ + libffi.xcodeproj/project.pbxproj \ + libtool-ldflags # Automake Documentation: @@ -444,65 +336,129 @@ MAINTAINERCLEANFILES = $(srcdir)/doc/libffi.info # 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)" + '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) MAKEOVERRIDES = +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libffi.pc toolexeclib_LTLIBRARIES = libffi.la noinst_LTLIBRARIES = libffi_convenience.la -libffi_la_SOURCES = src/prep_cif.c src/types.c \ - src/raw_api.c src/java_raw_api.c src/closures.c - -nodist_libffi_la_SOURCES = $(am__append_1) $(am__append_2) \ - $(am__append_3) $(am__append_4) $(am__append_5) \ - $(am__append_6) $(am__append_7) $(am__append_8) \ - $(am__append_9) $(am__append_10) $(am__append_11) \ - $(am__append_12) $(am__append_13) $(am__append_14) \ - $(am__append_15) $(am__append_16) $(am__append_17) \ - $(am__append_18) $(am__append_19) $(am__append_20) \ - $(am__append_21) $(am__append_22) $(am__append_23) \ - $(am__append_24) $(am__append_25) $(am__append_26) \ - $(am__append_27) $(am__append_28) $(am__append_29) \ - $(am__append_30) +libffi_la_SOURCES = src/prep_cif.c src/types.c src/raw_api.c \ + src/java_raw_api.c src/closures.c $(am__append_1) +noinst_HEADERS = \ + src/aarch64/ffitarget.h src/aarch64/internal.h \ + src/alpha/ffitarget.h src/alpha/internal.h \ + src/arc/ffitarget.h \ + src/arm/ffitarget.h src/arm/internal.h \ + src/avr32/ffitarget.h \ + src/bfin/ffitarget.h \ + src/cris/ffitarget.h \ + src/frv/ffitarget.h \ + src/ia64/ffitarget.h src/ia64/ia64_flags.h \ + src/m32r/ffitarget.h \ + src/m68k/ffitarget.h \ + src/m88k/ffitarget.h \ + src/metag/ffitarget.h \ + src/microblaze/ffitarget.h \ + src/mips/ffitarget.h \ + src/moxie/ffitarget.h \ + src/nios2/ffitarget.h \ + src/or1k/ffitarget.h \ + src/pa/ffitarget.h \ + src/powerpc/ffitarget.h src/powerpc/asm.h src/powerpc/ffi_powerpc.h \ + src/s390/ffitarget.h \ + src/sh/ffitarget.h \ + src/sh64/ffitarget.h \ + src/sparc/ffitarget.h src/sparc/internal.h \ + src/tile/ffitarget.h \ + src/vax/ffitarget.h \ + src/x86/ffitarget.h src/x86/internal.h src/x86/internal64.h \ + src/xtensa/ffitarget.h \ + src/dlmalloc.c + +EXTRA_libffi_la_SOURCES = \ + src/aarch64/ffi.c src/aarch64/sysv.S \ + src/alpha/ffi.c src/alpha/osf.S \ + src/arc/ffi.c src/arc/arcompact.S \ + src/arm/ffi.c src/arm/sysv.S \ + src/avr32/ffi.c src/avr32/sysv.S \ + src/bfin/ffi.c src/bfin/sysv.S \ + src/cris/ffi.c src/cris/sysv.S \ + src/frv/ffi.c src/frv/eabi.S \ + src/ia64/ffi.c src/ia64/unix.S \ + src/m32r/ffi.c src/m32r/sysv.S \ + src/m68k/ffi.c src/m68k/sysv.S \ + src/m88k/ffi.c src/m88k/obsd.S \ + src/metag/ffi.c src/metag/sysv.S \ + src/microblaze/ffi.c src/microblaze/sysv.S \ + src/mips/ffi.c src/mips/o32.S src/mips/n32.S \ + src/moxie/ffi.c src/moxie/eabi.S \ + src/nios2/ffi.c src/nios2/sysv.S \ + src/or1k/ffi.c src/or1k/sysv.S \ + src/pa/ffi.c src/pa/linux.S src/pa/hpux32.S \ + src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c \ + src/powerpc/sysv.S src/powerpc/linux64.S \ + src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S \ + src/powerpc/aix.S src/powerpc/darwin.S src/powerpc/aix_closure.S \ + src/powerpc/darwin_closure.S src/powerpc/ffi_darwin.c \ + src/s390/ffi.c src/s390/sysv.S \ + src/sh/ffi.c src/sh/sysv.S \ + src/sh64/ffi.c src/sh64/sysv.S \ + src/sparc/ffi.c src/sparc/ffi64.c src/sparc/v8.S src/sparc/v9.S \ + src/tile/ffi.c src/tile/tile.S \ + src/vax/ffi.c src/vax/elfbsd.S \ + src/x86/ffi.c src/x86/sysv.S \ + src/x86/ffiw64.c src/x86/win64.S \ + src/x86/ffi64.c src/x86/unix64.S \ + src/x86/darwin64.S src/x86/darwin.S \ + src/x86/darwin64_c.c src/x86/darwin_c.c \ + src/xtensa/ffi.c src/xtensa/sysv.S + +libffi_la_LIBADD = $(TARGET_OBJ) +libffi_la_DEPENDENCIES = $(TARGET_OBJ) libffi_convenience_la_SOURCES = $(libffi_la_SOURCES) +EXTRA_libffi_convenience_la_SOURCES = $(EXTRA_libffi_la_SOURCES) +libffi_convenience_la_LIBADD = $(libffi_la_LIBADD) +libffi_convenience_la_DEPENDENCIES = $(libffi_la_DEPENDENCIES) nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES) -AM_CFLAGS = -Wall -g -fexceptions LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) -libffi_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LTLDFLAGS) $(AM_LTLDFLAGS) +AM_CFLAGS = -Wall -g -fexceptions $(am__append_2) +libffi_la_LDFLAGS = -no-undefined -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LTLDFLAGS) $(AM_LTLDFLAGS) AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src AM_CCASFLAGS = $(AM_CPPFLAGS) all: fficonfig.h @@ -561,6 +517,8 @@ $(srcdir)/fficonfig.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) distclean-hdr: -rm -f fficonfig.h stamp-h1 +libffi.pc: $(top_builddir)/config.status $(srcdir)/libffi.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @@ -613,62 +571,16 @@ src/raw_api.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/java_raw_api.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/closures.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/debug.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) -src/mips/$(am__dirstamp): - @$(MKDIR_P) src/mips - @: > src/mips/$(am__dirstamp) -src/mips/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/mips/$(DEPDIR) - @: > src/mips/$(DEPDIR)/$(am__dirstamp) -src/mips/ffi.lo: src/mips/$(am__dirstamp) \ - src/mips/$(DEPDIR)/$(am__dirstamp) -src/mips/o32.lo: src/mips/$(am__dirstamp) \ - src/mips/$(DEPDIR)/$(am__dirstamp) -src/mips/n32.lo: src/mips/$(am__dirstamp) \ - src/mips/$(DEPDIR)/$(am__dirstamp) -src/bfin/$(am__dirstamp): - @$(MKDIR_P) src/bfin - @: > src/bfin/$(am__dirstamp) -src/bfin/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/bfin/$(DEPDIR) - @: > src/bfin/$(DEPDIR)/$(am__dirstamp) -src/bfin/ffi.lo: src/bfin/$(am__dirstamp) \ - src/bfin/$(DEPDIR)/$(am__dirstamp) -src/bfin/sysv.lo: src/bfin/$(am__dirstamp) \ - src/bfin/$(DEPDIR)/$(am__dirstamp) -src/x86/$(am__dirstamp): - @$(MKDIR_P) src/x86 - @: > src/x86/$(am__dirstamp) -src/x86/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/x86/$(DEPDIR) - @: > src/x86/$(DEPDIR)/$(am__dirstamp) -src/x86/ffi.lo: src/x86/$(am__dirstamp) \ - src/x86/$(DEPDIR)/$(am__dirstamp) -src/x86/sysv.lo: src/x86/$(am__dirstamp) \ - src/x86/$(DEPDIR)/$(am__dirstamp) -src/x86/freebsd.lo: src/x86/$(am__dirstamp) \ - src/x86/$(DEPDIR)/$(am__dirstamp) -src/x86/win32.lo: src/x86/$(am__dirstamp) \ - src/x86/$(DEPDIR)/$(am__dirstamp) -src/x86/win64.lo: src/x86/$(am__dirstamp) \ - src/x86/$(DEPDIR)/$(am__dirstamp) -src/x86/darwin.lo: src/x86/$(am__dirstamp) \ - src/x86/$(DEPDIR)/$(am__dirstamp) -src/x86/ffi64.lo: src/x86/$(am__dirstamp) \ - src/x86/$(DEPDIR)/$(am__dirstamp) -src/x86/darwin64.lo: src/x86/$(am__dirstamp) \ - src/x86/$(DEPDIR)/$(am__dirstamp) -src/sparc/$(am__dirstamp): - @$(MKDIR_P) src/sparc - @: > src/sparc/$(am__dirstamp) -src/sparc/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/sparc/$(DEPDIR) - @: > src/sparc/$(DEPDIR)/$(am__dirstamp) -src/sparc/ffi.lo: src/sparc/$(am__dirstamp) \ - src/sparc/$(DEPDIR)/$(am__dirstamp) -src/sparc/v8.lo: src/sparc/$(am__dirstamp) \ - src/sparc/$(DEPDIR)/$(am__dirstamp) -src/sparc/v9.lo: src/sparc/$(am__dirstamp) \ - src/sparc/$(DEPDIR)/$(am__dirstamp) +src/aarch64/$(am__dirstamp): + @$(MKDIR_P) src/aarch64 + @: > src/aarch64/$(am__dirstamp) +src/aarch64/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/aarch64/$(DEPDIR) + @: > src/aarch64/$(DEPDIR)/$(am__dirstamp) +src/aarch64/ffi.lo: src/aarch64/$(am__dirstamp) \ + src/aarch64/$(DEPDIR)/$(am__dirstamp) +src/aarch64/sysv.lo: src/aarch64/$(am__dirstamp) \ + src/aarch64/$(DEPDIR)/$(am__dirstamp) src/alpha/$(am__dirstamp): @$(MKDIR_P) src/alpha @: > src/alpha/$(am__dirstamp) @@ -679,6 +591,66 @@ src/alpha/ffi.lo: src/alpha/$(am__dirstamp) \ src/alpha/$(DEPDIR)/$(am__dirstamp) src/alpha/osf.lo: src/alpha/$(am__dirstamp) \ src/alpha/$(DEPDIR)/$(am__dirstamp) +src/arc/$(am__dirstamp): + @$(MKDIR_P) src/arc + @: > src/arc/$(am__dirstamp) +src/arc/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/arc/$(DEPDIR) + @: > src/arc/$(DEPDIR)/$(am__dirstamp) +src/arc/ffi.lo: src/arc/$(am__dirstamp) \ + src/arc/$(DEPDIR)/$(am__dirstamp) +src/arc/arcompact.lo: src/arc/$(am__dirstamp) \ + src/arc/$(DEPDIR)/$(am__dirstamp) +src/arm/$(am__dirstamp): + @$(MKDIR_P) src/arm + @: > src/arm/$(am__dirstamp) +src/arm/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/arm/$(DEPDIR) + @: > src/arm/$(DEPDIR)/$(am__dirstamp) +src/arm/ffi.lo: src/arm/$(am__dirstamp) \ + src/arm/$(DEPDIR)/$(am__dirstamp) +src/arm/sysv.lo: src/arm/$(am__dirstamp) \ + src/arm/$(DEPDIR)/$(am__dirstamp) +src/avr32/$(am__dirstamp): + @$(MKDIR_P) src/avr32 + @: > src/avr32/$(am__dirstamp) +src/avr32/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/avr32/$(DEPDIR) + @: > src/avr32/$(DEPDIR)/$(am__dirstamp) +src/avr32/ffi.lo: src/avr32/$(am__dirstamp) \ + src/avr32/$(DEPDIR)/$(am__dirstamp) +src/avr32/sysv.lo: src/avr32/$(am__dirstamp) \ + src/avr32/$(DEPDIR)/$(am__dirstamp) +src/bfin/$(am__dirstamp): + @$(MKDIR_P) src/bfin + @: > src/bfin/$(am__dirstamp) +src/bfin/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/bfin/$(DEPDIR) + @: > src/bfin/$(DEPDIR)/$(am__dirstamp) +src/bfin/ffi.lo: src/bfin/$(am__dirstamp) \ + src/bfin/$(DEPDIR)/$(am__dirstamp) +src/bfin/sysv.lo: src/bfin/$(am__dirstamp) \ + src/bfin/$(DEPDIR)/$(am__dirstamp) +src/cris/$(am__dirstamp): + @$(MKDIR_P) src/cris + @: > src/cris/$(am__dirstamp) +src/cris/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/cris/$(DEPDIR) + @: > src/cris/$(DEPDIR)/$(am__dirstamp) +src/cris/ffi.lo: src/cris/$(am__dirstamp) \ + src/cris/$(DEPDIR)/$(am__dirstamp) +src/cris/sysv.lo: src/cris/$(am__dirstamp) \ + src/cris/$(DEPDIR)/$(am__dirstamp) +src/frv/$(am__dirstamp): + @$(MKDIR_P) src/frv + @: > src/frv/$(am__dirstamp) +src/frv/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/frv/$(DEPDIR) + @: > src/frv/$(DEPDIR)/$(am__dirstamp) +src/frv/ffi.lo: src/frv/$(am__dirstamp) \ + src/frv/$(DEPDIR)/$(am__dirstamp) +src/frv/eabi.lo: src/frv/$(am__dirstamp) \ + src/frv/$(DEPDIR)/$(am__dirstamp) src/ia64/$(am__dirstamp): @$(MKDIR_P) src/ia64 @: > src/ia64/$(am__dirstamp) @@ -695,10 +667,10 @@ src/m32r/$(am__dirstamp): src/m32r/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/m32r/$(DEPDIR) @: > src/m32r/$(DEPDIR)/$(am__dirstamp) -src/m32r/sysv.lo: src/m32r/$(am__dirstamp) \ - src/m32r/$(DEPDIR)/$(am__dirstamp) src/m32r/ffi.lo: src/m32r/$(am__dirstamp) \ src/m32r/$(DEPDIR)/$(am__dirstamp) +src/m32r/sysv.lo: src/m32r/$(am__dirstamp) \ + src/m32r/$(DEPDIR)/$(am__dirstamp) src/m68k/$(am__dirstamp): @$(MKDIR_P) src/m68k @: > src/m68k/$(am__dirstamp) @@ -709,6 +681,89 @@ src/m68k/ffi.lo: src/m68k/$(am__dirstamp) \ src/m68k/$(DEPDIR)/$(am__dirstamp) src/m68k/sysv.lo: src/m68k/$(am__dirstamp) \ src/m68k/$(DEPDIR)/$(am__dirstamp) +src/m88k/$(am__dirstamp): + @$(MKDIR_P) src/m88k + @: > src/m88k/$(am__dirstamp) +src/m88k/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/m88k/$(DEPDIR) + @: > src/m88k/$(DEPDIR)/$(am__dirstamp) +src/m88k/ffi.lo: src/m88k/$(am__dirstamp) \ + src/m88k/$(DEPDIR)/$(am__dirstamp) +src/m88k/obsd.lo: src/m88k/$(am__dirstamp) \ + src/m88k/$(DEPDIR)/$(am__dirstamp) +src/metag/$(am__dirstamp): + @$(MKDIR_P) src/metag + @: > src/metag/$(am__dirstamp) +src/metag/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/metag/$(DEPDIR) + @: > src/metag/$(DEPDIR)/$(am__dirstamp) +src/metag/ffi.lo: src/metag/$(am__dirstamp) \ + src/metag/$(DEPDIR)/$(am__dirstamp) +src/metag/sysv.lo: src/metag/$(am__dirstamp) \ + src/metag/$(DEPDIR)/$(am__dirstamp) +src/microblaze/$(am__dirstamp): + @$(MKDIR_P) src/microblaze + @: > src/microblaze/$(am__dirstamp) +src/microblaze/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/microblaze/$(DEPDIR) + @: > src/microblaze/$(DEPDIR)/$(am__dirstamp) +src/microblaze/ffi.lo: src/microblaze/$(am__dirstamp) \ + src/microblaze/$(DEPDIR)/$(am__dirstamp) +src/microblaze/sysv.lo: src/microblaze/$(am__dirstamp) \ + src/microblaze/$(DEPDIR)/$(am__dirstamp) +src/mips/$(am__dirstamp): + @$(MKDIR_P) src/mips + @: > src/mips/$(am__dirstamp) +src/mips/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/mips/$(DEPDIR) + @: > src/mips/$(DEPDIR)/$(am__dirstamp) +src/mips/ffi.lo: src/mips/$(am__dirstamp) \ + src/mips/$(DEPDIR)/$(am__dirstamp) +src/mips/o32.lo: src/mips/$(am__dirstamp) \ + src/mips/$(DEPDIR)/$(am__dirstamp) +src/mips/n32.lo: src/mips/$(am__dirstamp) \ + src/mips/$(DEPDIR)/$(am__dirstamp) +src/moxie/$(am__dirstamp): + @$(MKDIR_P) src/moxie + @: > src/moxie/$(am__dirstamp) +src/moxie/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/moxie/$(DEPDIR) + @: > src/moxie/$(DEPDIR)/$(am__dirstamp) +src/moxie/ffi.lo: src/moxie/$(am__dirstamp) \ + src/moxie/$(DEPDIR)/$(am__dirstamp) +src/moxie/eabi.lo: src/moxie/$(am__dirstamp) \ + src/moxie/$(DEPDIR)/$(am__dirstamp) +src/nios2/$(am__dirstamp): + @$(MKDIR_P) src/nios2 + @: > src/nios2/$(am__dirstamp) +src/nios2/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/nios2/$(DEPDIR) + @: > src/nios2/$(DEPDIR)/$(am__dirstamp) +src/nios2/ffi.lo: src/nios2/$(am__dirstamp) \ + src/nios2/$(DEPDIR)/$(am__dirstamp) +src/nios2/sysv.lo: src/nios2/$(am__dirstamp) \ + src/nios2/$(DEPDIR)/$(am__dirstamp) +src/or1k/$(am__dirstamp): + @$(MKDIR_P) src/or1k + @: > src/or1k/$(am__dirstamp) +src/or1k/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/or1k/$(DEPDIR) + @: > src/or1k/$(DEPDIR)/$(am__dirstamp) +src/or1k/ffi.lo: src/or1k/$(am__dirstamp) \ + src/or1k/$(DEPDIR)/$(am__dirstamp) +src/or1k/sysv.lo: src/or1k/$(am__dirstamp) \ + src/or1k/$(DEPDIR)/$(am__dirstamp) +src/pa/$(am__dirstamp): + @$(MKDIR_P) src/pa + @: > src/pa/$(am__dirstamp) +src/pa/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/pa/$(DEPDIR) + @: > src/pa/$(DEPDIR)/$(am__dirstamp) +src/pa/ffi.lo: src/pa/$(am__dirstamp) src/pa/$(DEPDIR)/$(am__dirstamp) +src/pa/linux.lo: src/pa/$(am__dirstamp) \ + src/pa/$(DEPDIR)/$(am__dirstamp) +src/pa/hpux32.lo: src/pa/$(am__dirstamp) \ + src/pa/$(DEPDIR)/$(am__dirstamp) src/powerpc/$(am__dirstamp): @$(MKDIR_P) src/powerpc @: > src/powerpc/$(am__dirstamp) @@ -723,126 +778,121 @@ src/powerpc/ffi_linux64.lo: src/powerpc/$(am__dirstamp) \ src/powerpc/$(DEPDIR)/$(am__dirstamp) src/powerpc/sysv.lo: src/powerpc/$(am__dirstamp) \ src/powerpc/$(DEPDIR)/$(am__dirstamp) -src/powerpc/ppc_closure.lo: src/powerpc/$(am__dirstamp) \ - src/powerpc/$(DEPDIR)/$(am__dirstamp) src/powerpc/linux64.lo: src/powerpc/$(am__dirstamp) \ src/powerpc/$(DEPDIR)/$(am__dirstamp) src/powerpc/linux64_closure.lo: src/powerpc/$(am__dirstamp) \ src/powerpc/$(DEPDIR)/$(am__dirstamp) -src/powerpc/ffi_darwin.lo: src/powerpc/$(am__dirstamp) \ +src/powerpc/ppc_closure.lo: src/powerpc/$(am__dirstamp) \ src/powerpc/$(DEPDIR)/$(am__dirstamp) src/powerpc/aix.lo: src/powerpc/$(am__dirstamp) \ src/powerpc/$(DEPDIR)/$(am__dirstamp) -src/powerpc/aix_closure.lo: src/powerpc/$(am__dirstamp) \ - src/powerpc/$(DEPDIR)/$(am__dirstamp) src/powerpc/darwin.lo: src/powerpc/$(am__dirstamp) \ src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/aix_closure.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) src/powerpc/darwin_closure.lo: src/powerpc/$(am__dirstamp) \ src/powerpc/$(DEPDIR)/$(am__dirstamp) -src/aarch64/$(am__dirstamp): - @$(MKDIR_P) src/aarch64 - @: > src/aarch64/$(am__dirstamp) -src/aarch64/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/aarch64/$(DEPDIR) - @: > src/aarch64/$(DEPDIR)/$(am__dirstamp) -src/aarch64/sysv.lo: src/aarch64/$(am__dirstamp) \ - src/aarch64/$(DEPDIR)/$(am__dirstamp) -src/aarch64/ffi.lo: src/aarch64/$(am__dirstamp) \ - src/aarch64/$(DEPDIR)/$(am__dirstamp) -src/arm/$(am__dirstamp): - @$(MKDIR_P) src/arm - @: > src/arm/$(am__dirstamp) -src/arm/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/arm/$(DEPDIR) - @: > src/arm/$(DEPDIR)/$(am__dirstamp) -src/arm/sysv.lo: src/arm/$(am__dirstamp) \ - src/arm/$(DEPDIR)/$(am__dirstamp) -src/arm/ffi.lo: src/arm/$(am__dirstamp) \ - src/arm/$(DEPDIR)/$(am__dirstamp) -src/arm/trampoline.lo: src/arm/$(am__dirstamp) \ - src/arm/$(DEPDIR)/$(am__dirstamp) -src/avr32/$(am__dirstamp): - @$(MKDIR_P) src/avr32 - @: > src/avr32/$(am__dirstamp) -src/avr32/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/avr32/$(DEPDIR) - @: > src/avr32/$(DEPDIR)/$(am__dirstamp) -src/avr32/sysv.lo: src/avr32/$(am__dirstamp) \ - src/avr32/$(DEPDIR)/$(am__dirstamp) -src/avr32/ffi.lo: src/avr32/$(am__dirstamp) \ - src/avr32/$(DEPDIR)/$(am__dirstamp) -src/cris/$(am__dirstamp): - @$(MKDIR_P) src/cris - @: > src/cris/$(am__dirstamp) -src/cris/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/cris/$(DEPDIR) - @: > src/cris/$(DEPDIR)/$(am__dirstamp) -src/cris/sysv.lo: src/cris/$(am__dirstamp) \ - src/cris/$(DEPDIR)/$(am__dirstamp) -src/cris/ffi.lo: src/cris/$(am__dirstamp) \ - src/cris/$(DEPDIR)/$(am__dirstamp) -src/frv/$(am__dirstamp): - @$(MKDIR_P) src/frv - @: > src/frv/$(am__dirstamp) -src/frv/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/frv/$(DEPDIR) - @: > src/frv/$(DEPDIR)/$(am__dirstamp) -src/frv/eabi.lo: src/frv/$(am__dirstamp) \ - src/frv/$(DEPDIR)/$(am__dirstamp) -src/frv/ffi.lo: src/frv/$(am__dirstamp) \ - src/frv/$(DEPDIR)/$(am__dirstamp) +src/powerpc/ffi_darwin.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) src/s390/$(am__dirstamp): @$(MKDIR_P) src/s390 @: > src/s390/$(am__dirstamp) src/s390/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/s390/$(DEPDIR) @: > src/s390/$(DEPDIR)/$(am__dirstamp) -src/s390/sysv.lo: src/s390/$(am__dirstamp) \ - src/s390/$(DEPDIR)/$(am__dirstamp) src/s390/ffi.lo: src/s390/$(am__dirstamp) \ src/s390/$(DEPDIR)/$(am__dirstamp) -src/x86/unix64.lo: src/x86/$(am__dirstamp) \ - src/x86/$(DEPDIR)/$(am__dirstamp) +src/s390/sysv.lo: src/s390/$(am__dirstamp) \ + src/s390/$(DEPDIR)/$(am__dirstamp) src/sh/$(am__dirstamp): @$(MKDIR_P) src/sh @: > src/sh/$(am__dirstamp) src/sh/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/sh/$(DEPDIR) @: > src/sh/$(DEPDIR)/$(am__dirstamp) +src/sh/ffi.lo: src/sh/$(am__dirstamp) src/sh/$(DEPDIR)/$(am__dirstamp) src/sh/sysv.lo: src/sh/$(am__dirstamp) \ src/sh/$(DEPDIR)/$(am__dirstamp) -src/sh/ffi.lo: src/sh/$(am__dirstamp) src/sh/$(DEPDIR)/$(am__dirstamp) src/sh64/$(am__dirstamp): @$(MKDIR_P) src/sh64 @: > src/sh64/$(am__dirstamp) src/sh64/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/sh64/$(DEPDIR) @: > src/sh64/$(DEPDIR)/$(am__dirstamp) -src/sh64/sysv.lo: src/sh64/$(am__dirstamp) \ - src/sh64/$(DEPDIR)/$(am__dirstamp) src/sh64/ffi.lo: src/sh64/$(am__dirstamp) \ src/sh64/$(DEPDIR)/$(am__dirstamp) -src/pa/$(am__dirstamp): - @$(MKDIR_P) src/pa - @: > src/pa/$(am__dirstamp) -src/pa/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/pa/$(DEPDIR) - @: > src/pa/$(DEPDIR)/$(am__dirstamp) -src/pa/linux.lo: src/pa/$(am__dirstamp) \ - src/pa/$(DEPDIR)/$(am__dirstamp) -src/pa/ffi.lo: src/pa/$(am__dirstamp) src/pa/$(DEPDIR)/$(am__dirstamp) -src/pa/hpux32.lo: src/pa/$(am__dirstamp) \ - src/pa/$(DEPDIR)/$(am__dirstamp) +src/sh64/sysv.lo: src/sh64/$(am__dirstamp) \ + src/sh64/$(DEPDIR)/$(am__dirstamp) +src/sparc/$(am__dirstamp): + @$(MKDIR_P) src/sparc + @: > src/sparc/$(am__dirstamp) +src/sparc/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/sparc/$(DEPDIR) + @: > src/sparc/$(DEPDIR)/$(am__dirstamp) +src/sparc/ffi.lo: src/sparc/$(am__dirstamp) \ + src/sparc/$(DEPDIR)/$(am__dirstamp) +src/sparc/ffi64.lo: src/sparc/$(am__dirstamp) \ + src/sparc/$(DEPDIR)/$(am__dirstamp) +src/sparc/v8.lo: src/sparc/$(am__dirstamp) \ + src/sparc/$(DEPDIR)/$(am__dirstamp) +src/sparc/v9.lo: src/sparc/$(am__dirstamp) \ + src/sparc/$(DEPDIR)/$(am__dirstamp) src/tile/$(am__dirstamp): @$(MKDIR_P) src/tile @: > src/tile/$(am__dirstamp) src/tile/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/tile/$(DEPDIR) @: > src/tile/$(DEPDIR)/$(am__dirstamp) -src/tile/tile.lo: src/tile/$(am__dirstamp) \ - src/tile/$(DEPDIR)/$(am__dirstamp) src/tile/ffi.lo: src/tile/$(am__dirstamp) \ src/tile/$(DEPDIR)/$(am__dirstamp) +src/tile/tile.lo: src/tile/$(am__dirstamp) \ + src/tile/$(DEPDIR)/$(am__dirstamp) +src/vax/$(am__dirstamp): + @$(MKDIR_P) src/vax + @: > src/vax/$(am__dirstamp) +src/vax/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/vax/$(DEPDIR) + @: > src/vax/$(DEPDIR)/$(am__dirstamp) +src/vax/ffi.lo: src/vax/$(am__dirstamp) \ + src/vax/$(DEPDIR)/$(am__dirstamp) +src/vax/elfbsd.lo: src/vax/$(am__dirstamp) \ + src/vax/$(DEPDIR)/$(am__dirstamp) +src/x86/$(am__dirstamp): + @$(MKDIR_P) src/x86 + @: > src/x86/$(am__dirstamp) +src/x86/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/x86/$(DEPDIR) + @: > src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/ffi.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/sysv.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/ffiw64.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/win64.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/ffi64.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/unix64.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/darwin64.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/darwin.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/darwin64_c.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/darwin_c.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/xtensa/$(am__dirstamp): + @$(MKDIR_P) src/xtensa + @: > src/xtensa/$(am__dirstamp) +src/xtensa/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/xtensa/$(DEPDIR) + @: > src/xtensa/$(DEPDIR)/$(am__dirstamp) +src/xtensa/ffi.lo: src/xtensa/$(am__dirstamp) \ + src/xtensa/$(DEPDIR)/$(am__dirstamp) +src/xtensa/sysv.lo: src/xtensa/$(am__dirstamp) \ + src/xtensa/$(DEPDIR)/$(am__dirstamp) libffi.la: $(libffi_la_OBJECTS) $(libffi_la_DEPENDENCIES) $(libffi_la_LINK) -rpath $(toolexeclibdir) $(libffi_la_OBJECTS) $(libffi_la_LIBADD) $(LIBS) libffi_convenience.la: $(libffi_convenience_la_OBJECTS) $(libffi_convenience_la_DEPENDENCIES) @@ -858,12 +908,14 @@ mostlyclean-compile: -rm -f src/alpha/ffi.lo -rm -f src/alpha/osf.$(OBJEXT) -rm -f src/alpha/osf.lo + -rm -f src/arc/arcompact.$(OBJEXT) + -rm -f src/arc/arcompact.lo + -rm -f src/arc/ffi.$(OBJEXT) + -rm -f src/arc/ffi.lo -rm -f src/arm/ffi.$(OBJEXT) -rm -f src/arm/ffi.lo -rm -f src/arm/sysv.$(OBJEXT) -rm -f src/arm/sysv.lo - -rm -f src/arm/trampoline.$(OBJEXT) - -rm -f src/arm/trampoline.lo -rm -f src/avr32/ffi.$(OBJEXT) -rm -f src/avr32/ffi.lo -rm -f src/avr32/sysv.$(OBJEXT) @@ -898,12 +950,36 @@ mostlyclean-compile: -rm -f src/m68k/ffi.lo -rm -f src/m68k/sysv.$(OBJEXT) -rm -f src/m68k/sysv.lo + -rm -f src/m88k/ffi.$(OBJEXT) + -rm -f src/m88k/ffi.lo + -rm -f src/m88k/obsd.$(OBJEXT) + -rm -f src/m88k/obsd.lo + -rm -f src/metag/ffi.$(OBJEXT) + -rm -f src/metag/ffi.lo + -rm -f src/metag/sysv.$(OBJEXT) + -rm -f src/metag/sysv.lo + -rm -f src/microblaze/ffi.$(OBJEXT) + -rm -f src/microblaze/ffi.lo + -rm -f src/microblaze/sysv.$(OBJEXT) + -rm -f src/microblaze/sysv.lo -rm -f src/mips/ffi.$(OBJEXT) -rm -f src/mips/ffi.lo -rm -f src/mips/n32.$(OBJEXT) -rm -f src/mips/n32.lo -rm -f src/mips/o32.$(OBJEXT) -rm -f src/mips/o32.lo + -rm -f src/moxie/eabi.$(OBJEXT) + -rm -f src/moxie/eabi.lo + -rm -f src/moxie/ffi.$(OBJEXT) + -rm -f src/moxie/ffi.lo + -rm -f src/nios2/ffi.$(OBJEXT) + -rm -f src/nios2/ffi.lo + -rm -f src/nios2/sysv.$(OBJEXT) + -rm -f src/nios2/sysv.lo + -rm -f src/or1k/ffi.$(OBJEXT) + -rm -f src/or1k/ffi.lo + -rm -f src/or1k/sysv.$(OBJEXT) + -rm -f src/or1k/sysv.lo -rm -f src/pa/ffi.$(OBJEXT) -rm -f src/pa/ffi.lo -rm -f src/pa/hpux32.$(OBJEXT) @@ -952,6 +1028,8 @@ mostlyclean-compile: -rm -f src/sh64/sysv.lo -rm -f src/sparc/ffi.$(OBJEXT) -rm -f src/sparc/ffi.lo + -rm -f src/sparc/ffi64.$(OBJEXT) + -rm -f src/sparc/ffi64.lo -rm -f src/sparc/v8.$(OBJEXT) -rm -f src/sparc/v8.lo -rm -f src/sparc/v9.$(OBJEXT) @@ -962,24 +1040,34 @@ mostlyclean-compile: -rm -f src/tile/tile.lo -rm -f src/types.$(OBJEXT) -rm -f src/types.lo + -rm -f src/vax/elfbsd.$(OBJEXT) + -rm -f src/vax/elfbsd.lo + -rm -f src/vax/ffi.$(OBJEXT) + -rm -f src/vax/ffi.lo -rm -f src/x86/darwin.$(OBJEXT) -rm -f src/x86/darwin.lo -rm -f src/x86/darwin64.$(OBJEXT) -rm -f src/x86/darwin64.lo + -rm -f src/x86/darwin64_c.$(OBJEXT) + -rm -f src/x86/darwin64_c.lo + -rm -f src/x86/darwin_c.$(OBJEXT) + -rm -f src/x86/darwin_c.lo -rm -f src/x86/ffi.$(OBJEXT) -rm -f src/x86/ffi.lo -rm -f src/x86/ffi64.$(OBJEXT) -rm -f src/x86/ffi64.lo - -rm -f src/x86/freebsd.$(OBJEXT) - -rm -f src/x86/freebsd.lo + -rm -f src/x86/ffiw64.$(OBJEXT) + -rm -f src/x86/ffiw64.lo -rm -f src/x86/sysv.$(OBJEXT) -rm -f src/x86/sysv.lo -rm -f src/x86/unix64.$(OBJEXT) -rm -f src/x86/unix64.lo - -rm -f src/x86/win32.$(OBJEXT) - -rm -f src/x86/win32.lo -rm -f src/x86/win64.$(OBJEXT) -rm -f src/x86/win64.lo + -rm -f src/xtensa/ffi.$(OBJEXT) + -rm -f src/xtensa/ffi.lo + -rm -f src/xtensa/sysv.$(OBJEXT) + -rm -f src/xtensa/sysv.lo distclean-compile: -rm -f *.tab.c @@ -994,9 +1082,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/aarch64/$(DEPDIR)/sysv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/alpha/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/alpha/$(DEPDIR)/osf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/arc/$(DEPDIR)/arcompact.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/arc/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/arm/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/arm/$(DEPDIR)/sysv.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/arm/$(DEPDIR)/trampoline.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/avr32/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/avr32/$(DEPDIR)/sysv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/bfin/$(DEPDIR)/ffi.Plo@am__quote@ @@ -1011,9 +1100,21 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/m32r/$(DEPDIR)/sysv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/m68k/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/m68k/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/m88k/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/m88k/$(DEPDIR)/obsd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/metag/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/metag/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/microblaze/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/microblaze/$(DEPDIR)/sysv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/mips/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/mips/$(DEPDIR)/n32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/mips/$(DEPDIR)/o32.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/moxie/$(DEPDIR)/eabi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/moxie/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/nios2/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/nios2/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/or1k/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/or1k/$(DEPDIR)/sysv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/pa/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/pa/$(DEPDIR)/hpux32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/pa/$(DEPDIR)/linux.Plo@am__quote@ @@ -1036,19 +1137,25 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/sh64/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/sh64/$(DEPDIR)/sysv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/sparc/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/sparc/$(DEPDIR)/ffi64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/sparc/$(DEPDIR)/v8.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/sparc/$(DEPDIR)/v9.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/tile/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/tile/$(DEPDIR)/tile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/vax/$(DEPDIR)/elfbsd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/vax/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/darwin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/darwin64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/darwin64_c.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/darwin_c.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/ffi64.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/freebsd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/ffiw64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/sysv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/unix64.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/win32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/win64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/xtensa/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/xtensa/$(DEPDIR)/sysv.Plo@am__quote@ .S.o: @am__fastdepCCAS_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @@ -1106,6 +1213,7 @@ clean-libtool: -rm -rf src/.libs src/_libs -rm -rf src/aarch64/.libs src/aarch64/_libs -rm -rf src/alpha/.libs src/alpha/_libs + -rm -rf src/arc/.libs src/arc/_libs -rm -rf src/arm/.libs src/arm/_libs -rm -rf src/avr32/.libs src/avr32/_libs -rm -rf src/bfin/.libs src/bfin/_libs @@ -1114,7 +1222,13 @@ clean-libtool: -rm -rf src/ia64/.libs src/ia64/_libs -rm -rf src/m32r/.libs src/m32r/_libs -rm -rf src/m68k/.libs src/m68k/_libs + -rm -rf src/m88k/.libs src/m88k/_libs + -rm -rf src/metag/.libs src/metag/_libs + -rm -rf src/microblaze/.libs src/microblaze/_libs -rm -rf src/mips/.libs src/mips/_libs + -rm -rf src/moxie/.libs src/moxie/_libs + -rm -rf src/nios2/.libs src/nios2/_libs + -rm -rf src/or1k/.libs src/or1k/_libs -rm -rf src/pa/.libs src/pa/_libs -rm -rf src/powerpc/.libs src/powerpc/_libs -rm -rf src/s390/.libs src/s390/_libs @@ -1122,7 +1236,9 @@ clean-libtool: -rm -rf src/sh64/.libs src/sh64/_libs -rm -rf src/sparc/.libs src/sparc/_libs -rm -rf src/tile/.libs src/tile/_libs + -rm -rf src/vax/.libs src/vax/_libs -rm -rf src/x86/.libs src/x86/_libs + -rm -rf src/xtensa/.libs src/xtensa/_libs distclean-libtool: -rm -f libtool config.lt @@ -1286,6 +1402,26 @@ maintainer-clean-aminfo: echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \ rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \ done +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. @@ -1423,11 +1559,11 @@ distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-am: all-am check: check-recursive -all-am: Makefile $(INFO_DEPS) $(LTLIBRARIES) all-multi fficonfig.h \ - all-local +all-am: Makefile $(INFO_DEPS) $(LTLIBRARIES) all-multi $(DATA) \ + $(HEADERS) fficonfig.h all-local installdirs: installdirs-recursive installdirs-am: - for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(infodir)"; do \ + for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(infodir)" "$(DESTDIR)$(pkgconfigdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive @@ -1459,6 +1595,8 @@ distclean-generic: -rm -f src/aarch64/$(am__dirstamp) -rm -f src/alpha/$(DEPDIR)/$(am__dirstamp) -rm -f src/alpha/$(am__dirstamp) + -rm -f src/arc/$(DEPDIR)/$(am__dirstamp) + -rm -f src/arc/$(am__dirstamp) -rm -f src/arm/$(DEPDIR)/$(am__dirstamp) -rm -f src/arm/$(am__dirstamp) -rm -f src/avr32/$(DEPDIR)/$(am__dirstamp) @@ -1475,8 +1613,20 @@ distclean-generic: -rm -f src/m32r/$(am__dirstamp) -rm -f src/m68k/$(DEPDIR)/$(am__dirstamp) -rm -f src/m68k/$(am__dirstamp) + -rm -f src/m88k/$(DEPDIR)/$(am__dirstamp) + -rm -f src/m88k/$(am__dirstamp) + -rm -f src/metag/$(DEPDIR)/$(am__dirstamp) + -rm -f src/metag/$(am__dirstamp) + -rm -f src/microblaze/$(DEPDIR)/$(am__dirstamp) + -rm -f src/microblaze/$(am__dirstamp) -rm -f src/mips/$(DEPDIR)/$(am__dirstamp) -rm -f src/mips/$(am__dirstamp) + -rm -f src/moxie/$(DEPDIR)/$(am__dirstamp) + -rm -f src/moxie/$(am__dirstamp) + -rm -f src/nios2/$(DEPDIR)/$(am__dirstamp) + -rm -f src/nios2/$(am__dirstamp) + -rm -f src/or1k/$(DEPDIR)/$(am__dirstamp) + -rm -f src/or1k/$(am__dirstamp) -rm -f src/pa/$(DEPDIR)/$(am__dirstamp) -rm -f src/pa/$(am__dirstamp) -rm -f src/powerpc/$(DEPDIR)/$(am__dirstamp) @@ -1491,8 +1641,12 @@ distclean-generic: -rm -f src/sparc/$(am__dirstamp) -rm -f src/tile/$(DEPDIR)/$(am__dirstamp) -rm -f src/tile/$(am__dirstamp) + -rm -f src/vax/$(DEPDIR)/$(am__dirstamp) + -rm -f src/vax/$(am__dirstamp) -rm -f src/x86/$(DEPDIR)/$(am__dirstamp) -rm -f src/x86/$(am__dirstamp) + -rm -f src/xtensa/$(DEPDIR)/$(am__dirstamp) + -rm -f src/xtensa/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -1506,7 +1660,7 @@ clean-am: clean-aminfo clean-generic clean-libtool \ distclean: distclean-multi distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) src/alpha/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/mips/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) src/x86/$(DEPDIR) + -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) src/vax/$(DEPDIR) src/x86/$(DEPDIR) src/xtensa/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags @@ -1523,7 +1677,7 @@ info: info-recursive info-am: $(INFO_DEPS) -install-data-am: install-info-am +install-data-am: install-info-am install-pkgconfigDATA install-dvi: install-dvi-recursive @@ -1630,7 +1784,7 @@ installcheck-am: maintainer-clean: maintainer-clean-multi maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) src/alpha/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/mips/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) src/x86/$(DEPDIR) + -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) src/vax/$(DEPDIR) src/x86/$(DEPDIR) src/xtensa/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-aminfo \ maintainer-clean-generic maintainer-clean-vti @@ -1649,7 +1803,7 @@ ps: ps-recursive ps-am: $(PSS) uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ - uninstall-pdf-am uninstall-ps-am \ + uninstall-pdf-am uninstall-pkgconfigDATA uninstall-ps-am \ uninstall-toolexeclibLTLIBRARIES .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all all-multi \ @@ -1668,7 +1822,7 @@ uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-multi install-pdf install-pdf-am \ - install-ps install-ps-am install-strip \ + install-pkgconfigDATA install-ps install-ps-am install-strip \ install-toolexeclibLTLIBRARIES installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-aminfo maintainer-clean-generic \ @@ -1677,7 +1831,7 @@ uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ mostlyclean-libtool mostlyclean-multi mostlyclean-vti pdf \ pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ uninstall-dvi-am uninstall-html-am uninstall-info-am \ - uninstall-pdf-am uninstall-ps-am \ + uninstall-pdf-am uninstall-pkgconfigDATA uninstall-ps-am \ uninstall-toolexeclibLTLIBRARIES diff --git a/libffi/README b/libffi/README index a0fb717..c072101 100644 --- a/libffi/README +++ b/libffi/README @@ -1,8 +1,8 @@ Status ====== -libffi-3.0.12 was released on XXXXXXX. Check the libffi web page for -updates: <URL:http://sourceware.org/libffi/>. +libffi-4?? was released on TBD. Check the libffi web +page for updates: <URL:http://sourceware.org/libffi/>. What is libffi? @@ -43,57 +43,78 @@ Libffi has been ported to many different platforms. For specific configuration details and testing status, please refer to the wiki page here: - http://www.moxielogic.org/wiki/index.php?title=Libffi_3.0.11 + http://www.moxielogic.org/wiki/index.php?title=Libffi_3.2 At the time of release, the following basic configurations have been tested: -|-----------------+------------------| -| Architecture | Operating System | -|-----------------+------------------| -| AArch64 | Linux | -| Alpha | Linux | -| Alpha | Tru64 | -| ARM | Linux | -| ARM | iOS | -| AVR32 | Linux | -| Blackfin | uClinux | -| HPPA | HPUX | -| IA-64 | Linux | -| M68K | FreeMiNT | -| M68K | RTEMS | -| MIPS | IRIX | -| MIPS | Linux | -| MIPS | RTEMS | -| MIPS64 | Linux | -| PowerPC | AMIGA | -| PowerPC | Linux | -| PowerPC | Mac OSX | -| PowerPC | FreeBSD | -| PowerPC64 | Linux | -| S390 | Linux | -| S390X | Linux | -| SPARC | Linux | -| SPARC | Solaris | -| SPARC64 | Linux | -| SPARC64 | FreeBSD | -| TILE-Gx/TILEPro | Linux | -| X86 | FreeBSD | -| X86 | Interix | -| X86 | kFreeBSD | -| X86 | Linux | -| X86 | Mac OSX | -| X86 | OpenBSD | -| X86 | OS/2 | -| X86 | Solaris | -| X86 | Windows/Cygwin | -| X86 | Windows/MingW | -| X86-64 | FreeBSD | -| X86-64 | Linux | -| X86-64 | Linux/x32 | -| X86-64 | OpenBSD | -| X86-64 | Windows/MingW | -|-----------------+------------------| +|-----------------+------------------+-------------------------| +| Architecture | Operating System | Compiler | +|-----------------+------------------+-------------------------| +| AArch64 (ARM64) | iOS | Clang | +| AArch64 | Linux | GCC | +| Alpha | Linux | GCC | +| Alpha | Tru64 | GCC | +| ARC | Linux | GCC | +| ARM | Linux | GCC | +| ARM | iOS | GCC | +| AVR32 | Linux | GCC | +| Blackfin | uClinux | GCC | +| HPPA | HPUX | GCC | +| IA-64 | Linux | GCC | +| M68K | FreeMiNT | GCC | +| M68K | Linux | GCC | +| M68K | RTEMS | GCC | +| M88K | OpenBSD/mvme88k | GCC | +| Meta | Linux | GCC | +| MicroBlaze | Linux | GCC | +| MIPS | IRIX | GCC | +| MIPS | Linux | GCC | +| MIPS | RTEMS | GCC | +| MIPS64 | Linux | GCC | +| Moxie | Bare metal | GCC | +| Nios II | Linux | GCC | +| OpenRISC | Linux | GCC | +| PowerPC 32-bit | AIX | IBM XL C | +| PowerPC 64-bit | AIX | IBM XL C | +| PowerPC | AMIGA | GCC | +| PowerPC | Linux | GCC | +| PowerPC | Mac OSX | GCC | +| PowerPC | FreeBSD | GCC | +| PowerPC 64-bit | FreeBSD | GCC | +| PowerPC 64-bit | Linux ELFv1 | GCC | +| PowerPC 64-bit | Linux ELFv2 | GCC | +| S390 | Linux | GCC | +| S390X | Linux | GCC | +| SPARC | Linux | GCC | +| SPARC | Solaris | GCC | +| SPARC | Solaris | Oracle Solaris Studio C | +| SPARC64 | Linux | GCC | +| SPARC64 | FreeBSD | GCC | +| SPARC64 | Solaris | Oracle Solaris Studio C | +| TILE-Gx/TILEPro | Linux | GCC | +| VAX | OpenBSD/vax | GCC | +| X86 | FreeBSD | GCC | +| X86 | GNU HURD | GCC | +| X86 | Interix | GCC | +| X86 | kFreeBSD | GCC | +| X86 | Linux | GCC | +| X86 | Mac OSX | GCC | +| X86 | OpenBSD | GCC | +| X86 | OS/2 | GCC | +| X86 | Solaris | GCC | +| X86 | Solaris | Oracle Solaris Studio C | +| X86 | Windows/Cygwin | GCC | +| X86 | Windows/MingW | GCC | +| X86-64 | FreeBSD | GCC | +| X86-64 | Linux | GCC | +| X86-64 | Linux/x32 | GCC | +| X86-64 | OpenBSD | GCC | +| X86-64 | Solaris | Oracle Solaris Studio C | +| X86-64 | Windows/Cygwin | GCC | +| X86-64 | Windows/MingW | GCC | +| Xtensa | Linux | GCC | +|-----------------+------------------+-------------------------| Please send additional platform test results to libffi-discuss@sourceware.org and feel free to update the wiki page @@ -107,6 +128,9 @@ system. Go to the directory you wish to build libffi in and run the "configure" program found in the root directory of the libffi source distribution. +If you're building libffi directly from version control, configure won't +exist yet; run ./autogen.sh first. + You may want to tell configure where to install the libffi library and header files. To do that, use the --prefix configure switch. Libffi will install under /usr/local by default. @@ -124,20 +148,28 @@ 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 LD=link CPP=\"cl -nologo -EP\" +path/to/configure CC=path/to/msvcc.sh CXX=path/to/msvcc.sh LD=link CPP="cl -nologo -EP" + +For 64-bit Windows builds, use CC="path/to/msvcc.sh -m64" and +CXX="path/to/msvcc.sh -m64". You may also need to specify --build +appropriately. + +It is also possible to build libffi on Windows platforms with the LLVM +project's clang-cl compiler, like below: + +path/to/configure CC="path/to/msvcc.sh -clang-cl" CXX="path/to/msvcc.sh -clang-cl" LD=link CPP="clang-cl -EP" -For 64-bit Windows builds, use CC="path/to/msvcc.sh -m64". -You may also need to specify --build appropriately. When building with MSVC -under a MingW environment, you may need to remove the line in configure -that sets 'fix_srcfile_path' to a 'cygpath' command. ('cygpath' is not -present in MingW, and is not required when using MingW-style paths.) +When building with MSVC under a MingW environment, you may need to +remove the line in configure that sets 'fix_srcfile_path' to a 'cygpath' +command. ('cygpath' is not present in MingW, and is not required when +using MingW-style paths.) For iOS builds, the 'libffi.xcodeproj' Xcode project is available. Configure has many other options. Use "configure --help" to see them all. Once configure has finished, type "make". Note that you must be using -GNU make. You can ftp GNU make from prep.ai.mit.edu:/pub/gnu. +GNU make. You can ftp GNU make from ftp.gnu.org:/pub/gnu/make . To ensure that libffi is working as advertised, type "make check". This will require that you have DejaGNU installed. @@ -148,17 +180,59 @@ To install the library and header files, type "make install". History ======= -See the ChangeLog files for details. - -3.0.12 XXX-XX-XX +See the git log for details at http://github.com/atgreen/libffi. + +4.0 TBD + New API in support of GO closures. + +3.2.1 Nov-12-14 + Build fix for non-iOS AArch64 targets. + +3.2 Nov-11-14 + Add C99 Complex Type support (currently only supported on + s390). + Add support for PASCAL and REGISTER calling conventions on x86 + Windows/Linux. + Add OpenRISC and Cygwin-64 support. + Bug fixes. + +3.1 May-19-14 + Add AArch64 (ARM64) iOS support. + Add Nios II support. + Add m88k and DEC VAX support. + Add support for stdcall, thiscall, and fastcall on non-Windows + 32-bit x86 targets such as Linux. + Various Android, MIPS N32, x86, FreeBSD and UltraSPARC IIi + fixes. + Make the testsuite more robust: eliminate several spurious + failures, and respect the $CC and $CXX environment variables. + Archive off the manually maintained ChangeLog in favor of git + log. + +3.0.13 Mar-17-13 + Add Meta support. + Add missing Moxie bits. + Fix stack alignment bug on 32-bit x86. + Build fix for m68000 targets. + Build fix for soft-float Power targets. + Fix the install dir location for some platforms when building + with GCC (OS X, Solaris). + Fix Cygwin regression. + +3.0.12 Feb-11-13 + Add Moxie support. + Add AArch64 support. Add Blackfin support. Add TILE-Gx/TILEPro support. - Add AArch64 support. + Add MicroBlaze support. + Add Xtensa support. Add support for PaX enabled kernels with MPROTECT. + Add support for native vendor compilers on + Solaris and AIX. + Work around LLVM/GCC interoperability issue on x86_64. 3.0.11 Apr-11-12 Lots of build fixes. - Add Amiga newer MacOS support. Add support for variadic functions (ffi_prep_cif_var). Add Linux/x32 support. Add thiscall, fastcall and MSVC cdecl support on Windows. @@ -167,7 +241,6 @@ See the ChangeLog files for details. Integration with iOS' xcode build tools. Fix Octeon and MC68881 support. Fix code pessimizations. - Lots of build fixes. 3.0.10 Aug-23-11 Add support for Apple's iOS. @@ -311,7 +384,7 @@ See the ChangeLog files for details. Authors & Credits ================= -libffi was originally written by Anthony Green <green@redhat.com>. +libffi was originally written by Anthony Green <green@moxielogic.com>. The developers of the GNU Compiler Collection project have made innumerable valuable contributions. See the ChangeLog file for @@ -335,8 +408,13 @@ frv Anthony Green ia64 Hans Boehm m32r Kazuhiro Inaoka m68k Andreas Schwab +m88k Miod Vallat +microblaze Nathan Rossi mips Anthony Green, Casey Marshall mips64 David Daney +moxie Anthony Green +nios ii Sandra Loosemore +openrisc Sebastian Macke pa Randolph Chung, Dave Anglin, Andreas Tobler powerpc Geoffrey Keating, Andreas Tobler, David Edelsohn, John Hornkvist @@ -346,8 +424,10 @@ sh Kaz Kojima sh64 Kaz Kojima sparc Anthony Green, Gordon Irlam tile-gx/tilepro Walter Lee +vax Miod Vallat x86 Anthony Green, Jon Beniston x86-64 Bo Thorsen +xtensa Chris Zankel Jesper Skov and Andrew Haley both did more than their fair share of stepping through the code and tracking down bugs. diff --git a/libffi/build-ios.sh b/libffi/build-ios.sh deleted file mode 100755 index 3dea242..0000000 --- a/libffi/build-ios.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh - -PLATFORM_IOS=/Developer/Platforms/iPhoneOS.platform/ -PLATFORM_IOS_SIM=/Developer/Platforms/iPhoneSimulator.platform/ -SDK_IOS_VERSION="4.2" -MIN_IOS_VERSION="3.0" -OUTPUT_DIR="universal-ios" - -build_target () { - local platform=$1 - local sdk=$2 - local arch=$3 - local triple=$4 - local builddir=$5 - - mkdir -p "${builddir}" - pushd "${builddir}" - export CC="${platform}"/Developer/usr/bin/gcc-4.2 - export CFLAGS="-arch ${arch} -isysroot ${sdk} -miphoneos-version-min=${MIN_IOS_VERSION}" - ../configure --host=${triple} && make - popd -} - -# Build all targets -build_target "${PLATFORM_IOS}" "${PLATFORM_IOS}/Developer/SDKs/iPhoneOS${SDK_IOS_VERSION}.sdk/" armv6 arm-apple-darwin10 armv6-ios -build_target "${PLATFORM_IOS}" "${PLATFORM_IOS}/Developer/SDKs/iPhoneOS${SDK_IOS_VERSION}.sdk/" armv7 arm-apple-darwin10 armv7-ios -build_target "${PLATFORM_IOS_SIM}" "${PLATFORM_IOS_SIM}/Developer/SDKs/iPhoneSimulator${SDK_IOS_VERSION}.sdk/" i386 i386-apple-darwin10 i386-ios-sim - -# Create universal output directories -mkdir -p "${OUTPUT_DIR}" -mkdir -p "${OUTPUT_DIR}/include" -mkdir -p "${OUTPUT_DIR}/include/armv6" -mkdir -p "${OUTPUT_DIR}/include/armv7" -mkdir -p "${OUTPUT_DIR}/include/i386" - -# Create the universal binary -lipo -create armv6-ios/.libs/libffi.a armv7-ios/.libs/libffi.a i386-ios-sim/.libs/libffi.a -output "${OUTPUT_DIR}/libffi.a" - -# Copy in the headers -copy_headers () { - local src=$1 - local dest=$2 - - # Fix non-relative header reference - sed 's/<ffitarget.h>/"ffitarget.h"/' < "${src}/include/ffi.h" > "${dest}/ffi.h" - cp "${src}/include/ffitarget.h" "${dest}" -} - -copy_headers armv6-ios "${OUTPUT_DIR}/include/armv6" -copy_headers armv7-ios "${OUTPUT_DIR}/include/armv7" -copy_headers i386-ios-sim "${OUTPUT_DIR}/include/i386" - -# Create top-level header -( -cat << EOF -#ifdef __arm__ - #include <arm/arch.h> - #ifdef _ARM_ARCH_6 - #include "include/armv6/ffi.h" - #elif _ARM_ARCH_7 - #include "include/armv7/ffi.h" - #endif -#elif defined(__i386__) - #include "include/i386/ffi.h" -#endif -EOF -) > "${OUTPUT_DIR}/ffi.h" diff --git a/libffi/configure b/libffi/configure index 40247e2..f580af0 100755 --- a/libffi/configure +++ b/libffi/configure @@ -1,8 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.64 for libffi 3.0.11. +# Generated by GNU Autoconf 2.64 for libffi 3.99999. # -# Report bugs to <http://gcc.gnu.org/bugs.html>. +# Report bugs to <http://github.com/atgreen/libffi/issues>. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software @@ -237,8 +237,8 @@ fi $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and -$0: http://gcc.gnu.org/bugs.html about your system, -$0: including any error possibly output before this +$0: http://github.com/atgreen/libffi/issues about your +$0: system, including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi @@ -559,9 +559,9 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='libffi' PACKAGE_TARNAME='libffi' -PACKAGE_VERSION='3.0.11' -PACKAGE_STRING='libffi 3.0.11' -PACKAGE_BUGREPORT='http://gcc.gnu.org/bugs.html' +PACKAGE_VERSION='3.99999' +PACKAGE_STRING='libffi 3.99999' +PACKAGE_BUGREPORT='http://github.com/atgreen/libffi/issues' PACKAGE_URL='' # Factoring default headers for most tests. @@ -608,6 +608,7 @@ toolexeclibdir toolexecdir FFI_DEBUG_FALSE FFI_DEBUG_TRUE +TARGET_OBJ TARGETDIR TARGET FFI_EXEC_TRAMPOLINE_TABLE @@ -616,64 +617,6 @@ FFI_EXEC_TRAMPOLINE_TABLE_TRUE HAVE_LONG_DOUBLE_VARIANT HAVE_LONG_DOUBLE ALLOCA -TILE_FALSE -TILE_TRUE -PA64_HPUX_FALSE -PA64_HPUX_TRUE -PA_HPUX_FALSE -PA_HPUX_TRUE -PA_LINUX_FALSE -PA_LINUX_TRUE -SH64_FALSE -SH64_TRUE -SH_FALSE -SH_TRUE -X86_64_FALSE -X86_64_TRUE -S390_FALSE -S390_TRUE -FRV_FALSE -FRV_TRUE -LIBFFI_CRIS_FALSE -LIBFFI_CRIS_TRUE -AVR32_FALSE -AVR32_TRUE -ARM_FALSE -ARM_TRUE -AARCH64_FALSE -AARCH64_TRUE -POWERPC_FREEBSD_FALSE -POWERPC_FREEBSD_TRUE -POWERPC_DARWIN_FALSE -POWERPC_DARWIN_TRUE -POWERPC_AIX_FALSE -POWERPC_AIX_TRUE -POWERPC_FALSE -POWERPC_TRUE -M68K_FALSE -M68K_TRUE -M32R_FALSE -M32R_TRUE -IA64_FALSE -IA64_TRUE -ALPHA_FALSE -ALPHA_TRUE -X86_DARWIN_FALSE -X86_DARWIN_TRUE -X86_WIN64_FALSE -X86_WIN64_TRUE -X86_WIN32_FALSE -X86_WIN32_TRUE -X86_FREEBSD_FALSE -X86_FREEBSD_TRUE -X86_FALSE -X86_TRUE -SPARC_FALSE -SPARC_TRUE -BFIN_FALSE -BFIN_TRUE -MIPS_FALSE -MIPS_TRUE AM_LTLDFLAGS AM_RUNTESTFLAGS TESTSUBDIR_FALSE @@ -681,6 +624,7 @@ TESTSUBDIR_TRUE MAINT MAINTAINER_MODE_FALSE MAINTAINER_MODE_TRUE +CXXCPP CPP OTOOL64 OTOOL @@ -705,6 +649,12 @@ am__fastdepCCAS_TRUE CCASDEPMODE CCASFLAGS CCAS +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE @@ -824,7 +774,8 @@ target_alias CCAS CCASFLAGS CPP -CPPFLAGS' +CPPFLAGS +CXXCPP' # Initialize some variables set by options. @@ -1366,7 +1317,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures libffi 3.0.11 to adapt to many kinds of systems. +\`configure' configures libffi 3.99999 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1437,7 +1388,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libffi 3.0.11:";; + short | recursive ) echo "Configuration of libffi 3.99999:";; esac cat <<\_ACEOF @@ -1480,14 +1431,17 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l<library> CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if you have headers in a nonstandard directory <include dir> + CXX C++ compiler command + CXXFLAGS C++ compiler flags CCAS assembler compiler command (defaults to CC) CCASFLAGS assembler compiler flags (defaults to CFLAGS) CPP C preprocessor + CXXCPP C++ preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. -Report bugs to <http://gcc.gnu.org/bugs.html>. +Report bugs to <http://github.com/atgreen/libffi/issues>. _ACEOF ac_status=$? fi @@ -1550,7 +1504,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libffi configure 3.0.11 +libffi configure 3.99999 generated by GNU Autoconf 2.64 Copyright (C) 2009 Free Software Foundation, Inc. @@ -1602,6 +1556,44 @@ fi } # ac_fn_c_try_compile +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_cxx_try_compile + # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. @@ -1825,98 +1817,88 @@ $as_echo "$ac_res" >&6; } } # ac_fn_c_check_func -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no + ac_retval=1 fi -rm -f conftest.err conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( cat <<\_ASBOX -## ------------------------------------------- ## -## Report this to http://gcc.gnu.org/bugs.html ## -## ------------------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval -} # ac_fn_c_check_header_mongrel +} # ac_fn_cxx_try_link # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- @@ -2095,11 +2077,104 @@ rm -f conftest.val return $ac_retval } # ac_fn_c_compute_int + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( cat <<\_ASBOX +## ------------------------------------------------------ ## +## Report this to http://github.com/atgreen/libffi/issues ## +## ------------------------------------------------------ ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libffi $as_me 3.0.11, which was +It was created by libffi $as_me 3.99999, which was generated by GNU Autoconf 2.64. Invocation command line was $ $0 $@ @@ -2626,8 +2701,6 @@ test -n "$target_alias" && target_alias=${target_alias-$host_alias} -. ${srcdir}/configure.host - am__api_version='1.11' # Find a good install program. We prefer a C program (faster), @@ -3066,7 +3139,7 @@ fi # Define the identity of the package. PACKAGE='libffi' - VERSION='3.0.11' + VERSION='3.99999' cat >>confdefs.h <<_ACEOF @@ -3215,9 +3288,12 @@ fi # We must force CC to /not/ be precious variables; otherwise # the wrong, non-multilib-adjusted value will be used in multilibs. # As a side effect, we have to subst CFLAGS ourselves. +# Also save and restore CFLAGS, since AC_PROG_CC will come up with +# defaults of its own if none are provided. +save_CFLAGS=$CFLAGS ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4172,6 +4248,392 @@ else fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + rm -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +CFLAGS=$save_CFLAGS + @@ -7433,6 +7895,7 @@ done + # Set options @@ -10907,7 +11370,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10910 "configure" +#line 11373 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11013,7 +11476,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11016 "configure" +#line 11479 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11230,6 +11693,3022 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + gnu*) + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + lt_prog_compiler_pic_CXX='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_prog_compiler_pic_CXX" >&6; } + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if test "${lt_cv_archive_cmds_need_lc_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + @@ -11251,6 +14730,42 @@ CC="$lt_save_CC" +# Test for 64-bit build. +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 +$as_echo_n "checking size of size_t... " >&6; } +if test "${ac_cv_sizeof_size_t+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_size_t" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (size_t) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_size_t=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 +$as_echo "$ac_cv_sizeof_size_t" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t +_ACEOF + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } @@ -11287,12 +14802,14 @@ fi done -for ac_func in mmap +for ac_func in mmap mkostemp do : - ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" -if test "x$ac_cv_func_mmap" = x""yes; then : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF -#define HAVE_MMAP 1 +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi @@ -11451,407 +14968,14 @@ fi TARGETDIR="unknown" HAVE_LONG_DOUBLE_VARIANT=0 -case "$host" in - aarch64*-*-*) - TARGET=AARCH64; TARGETDIR=aarch64 - ;; - - alpha*-*-*) - TARGET=ALPHA; TARGETDIR=alpha; - # Support 128-bit long double, changeable via command-line switch. - HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)' - ;; - - arm*-*-*) - TARGET=ARM; TARGETDIR=arm - ;; - - amd64-*-freebsd* | amd64-*-openbsd*) - TARGET=X86_64; TARGETDIR=x86 - ;; - - amd64-*-freebsd*) - TARGET=X86_64; TARGETDIR=x86 - ;; - - avr32*-*-*) - TARGET=AVR32; TARGETDIR=avr32 - ;; - - bfin*) - TARGET=BFIN; TARGETDIR=bfin - ;; - - cris-*-*) - TARGET=LIBFFI_CRIS; TARGETDIR=cris - ;; - - frv-*-*) - TARGET=FRV; TARGETDIR=frv - ;; - - hppa*-*-linux* | parisc*-*-linux* | hppa*-*-openbsd*) - TARGET=PA_LINUX; TARGETDIR=pa - ;; - hppa*64-*-hpux*) - TARGET=PA64_HPUX; TARGETDIR=pa - ;; - hppa*-*-hpux*) - TARGET=PA_HPUX; TARGETDIR=pa - ;; - - i?86-*-freebsd* | i?86-*-openbsd*) - TARGET=X86_FREEBSD; TARGETDIR=x86 - ;; - i?86-win32* | i?86-*-cygwin* | i?86-*-mingw* | i?86-*-os2* | i?86-*-interix*) - TARGET=X86_WIN32; TARGETDIR=x86 - # All mingw/cygwin/win32 builds require -no-undefined for sharedlib. - # We must also check with_cross_host to decide if this is a native - # or cross-build and select where to install dlls appropriately. - if test -n "$with_cross_host" && - test x"$with_cross_host" != x"no"; then - AM_LTLDFLAGS='-no-undefined -bindir "$(toolexeclibdir)"'; - else - AM_LTLDFLAGS='-no-undefined -bindir "$(bindir)"'; - fi - ;; - i?86-*-darwin*) - TARGET=X86_DARWIN; TARGETDIR=x86 - ;; - i?86-*-solaris2.1[0-9]*) - TARGET=X86_64; TARGETDIR=x86 - ;; - i?86-*-*) - TARGET=X86_64; TARGETDIR=x86 - ;; - - ia64*-*-*) - TARGET=IA64; TARGETDIR=ia64 - ;; - - m32r*-*-*) - TARGET=M32R; TARGETDIR=m32r - ;; - - m68k-*-*) - TARGET=M68K; TARGETDIR=m68k - ;; - - mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*) - TARGET=MIPS; TARGETDIR=mips - ;; - mips*-*-linux* | mips*-*-openbsd*) - # Support 128-bit long double for NewABI. - HAVE_LONG_DOUBLE='defined(__mips64)' - TARGET=MIPS; TARGETDIR=mips - ;; - - powerpc*-*-linux* | powerpc-*-sysv*) - TARGET=POWERPC; TARGETDIR=powerpc - HAVE_LONG_DOUBLE_VARIANT=1 - ;; - powerpc-*-amigaos*) - TARGET=POWERPC; TARGETDIR=powerpc - ;; - powerpc-*-beos*) - TARGET=POWERPC; TARGETDIR=powerpc - ;; - powerpc-*-darwin* | powerpc64-*-darwin*) - TARGET=POWERPC_DARWIN; TARGETDIR=powerpc - ;; - powerpc-*-aix* | rs6000-*-aix*) - TARGET=POWERPC_AIX; TARGETDIR=powerpc - ;; - powerpc-*-freebsd* | powerpc-*-openbsd*) - TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc - HAVE_LONG_DOUBLE_VARIANT=1 - ;; - powerpc64-*-freebsd*) - TARGET=POWERPC; TARGETDIR=powerpc - ;; - powerpc*-*-rtems*) - TARGET=POWERPC; TARGETDIR=powerpc - ;; - - s390-*-* | s390x-*-*) - TARGET=S390; TARGETDIR=s390 - ;; - - sh-*-* | sh[34]*-*-*) - TARGET=SH; TARGETDIR=sh - ;; - sh64-*-* | sh5*-*-*) - TARGET=SH64; TARGETDIR=sh64 - ;; - - sparc*-*-*) - TARGET=SPARC; TARGETDIR=sparc - ;; - - tile*-*) - TARGET=TILE; TARGETDIR=tile - ;; - - x86_64-*-darwin*) - TARGET=X86_DARWIN; TARGETDIR=x86 - ;; - - x86_64-*-cygwin* | x86_64-*-mingw*) - TARGET=X86_WIN64; TARGETDIR=x86 - # All mingw/cygwin/win32 builds require -no-undefined for sharedlib. - # We must also check with_cross_host to decide if this is a native - # or cross-build and select where to install dlls appropriately. - if test -n "$with_cross_host" && - test x"$with_cross_host" != x"no"; then - AM_LTLDFLAGS='-no-undefined -bindir "$(toolexeclibdir)"'; - else - AM_LTLDFLAGS='-no-undefined -bindir "$(bindir)"'; - fi - ;; - - x86_64-*-*) - TARGET=X86_64; TARGETDIR=x86 - ;; -esac - - +. ${srcdir}/configure.host -if test $TARGETDIR = unknown; then +if test -n "${UNSUPPORTED}"; then as_fn_error "\"libffi has not been ported to $host.\"" "$LINENO" 5 fi - if test x$TARGET = xMIPS; then - MIPS_TRUE= - MIPS_FALSE='#' -else - MIPS_TRUE='#' - MIPS_FALSE= -fi - if test x$TARGET = xBFIN; then - BFIN_TRUE= - BFIN_FALSE='#' -else - BFIN_TRUE='#' - BFIN_FALSE= -fi - - if test x$TARGET = xSPARC; then - SPARC_TRUE= - SPARC_FALSE='#' -else - SPARC_TRUE='#' - SPARC_FALSE= -fi - - if test x$TARGET = xX86; then - X86_TRUE= - X86_FALSE='#' -else - X86_TRUE='#' - X86_FALSE= -fi - - if test x$TARGET = xX86_FREEBSD; then - X86_FREEBSD_TRUE= - X86_FREEBSD_FALSE='#' -else - X86_FREEBSD_TRUE='#' - X86_FREEBSD_FALSE= -fi - - if test x$TARGET = xX86_WIN32; then - X86_WIN32_TRUE= - X86_WIN32_FALSE='#' -else - X86_WIN32_TRUE='#' - X86_WIN32_FALSE= -fi - - if test x$TARGET = xX86_WIN64; then - X86_WIN64_TRUE= - X86_WIN64_FALSE='#' -else - X86_WIN64_TRUE='#' - X86_WIN64_FALSE= -fi - - if test x$TARGET = xX86_DARWIN; then - X86_DARWIN_TRUE= - X86_DARWIN_FALSE='#' -else - X86_DARWIN_TRUE='#' - X86_DARWIN_FALSE= -fi - - if test x$TARGET = xALPHA; then - ALPHA_TRUE= - ALPHA_FALSE='#' -else - ALPHA_TRUE='#' - ALPHA_FALSE= -fi - - if test x$TARGET = xIA64; then - IA64_TRUE= - IA64_FALSE='#' -else - IA64_TRUE='#' - IA64_FALSE= -fi - - if test x$TARGET = xM32R; then - M32R_TRUE= - M32R_FALSE='#' -else - M32R_TRUE='#' - M32R_FALSE= -fi - - if test x$TARGET = xM68K; then - M68K_TRUE= - M68K_FALSE='#' -else - M68K_TRUE='#' - M68K_FALSE= -fi - - if test x$TARGET = xPOWERPC; then - POWERPC_TRUE= - POWERPC_FALSE='#' -else - POWERPC_TRUE='#' - POWERPC_FALSE= -fi - - if test x$TARGET = xPOWERPC_AIX; then - POWERPC_AIX_TRUE= - POWERPC_AIX_FALSE='#' -else - POWERPC_AIX_TRUE='#' - POWERPC_AIX_FALSE= -fi - - if test x$TARGET = xPOWERPC_DARWIN; then - POWERPC_DARWIN_TRUE= - POWERPC_DARWIN_FALSE='#' -else - POWERPC_DARWIN_TRUE='#' - POWERPC_DARWIN_FALSE= -fi - - if test x$TARGET = xPOWERPC_FREEBSD; then - POWERPC_FREEBSD_TRUE= - POWERPC_FREEBSD_FALSE='#' -else - POWERPC_FREEBSD_TRUE='#' - POWERPC_FREEBSD_FALSE= -fi - - if test x$TARGET = xAARCH64; then - AARCH64_TRUE= - AARCH64_FALSE='#' -else - AARCH64_TRUE='#' - AARCH64_FALSE= -fi - - if test x$TARGET = xARM; then - ARM_TRUE= - ARM_FALSE='#' -else - ARM_TRUE='#' - ARM_FALSE= -fi - - if test x$TARGET = xAVR32; then - AVR32_TRUE= - AVR32_FALSE='#' -else - AVR32_TRUE='#' - AVR32_FALSE= -fi - - if test x$TARGET = xLIBFFI_CRIS; then - LIBFFI_CRIS_TRUE= - LIBFFI_CRIS_FALSE='#' -else - LIBFFI_CRIS_TRUE='#' - LIBFFI_CRIS_FALSE= -fi - - if test x$TARGET = xFRV; then - FRV_TRUE= - FRV_FALSE='#' -else - FRV_TRUE='#' - FRV_FALSE= -fi - - if test x$TARGET = xS390; then - S390_TRUE= - S390_FALSE='#' -else - S390_TRUE='#' - S390_FALSE= -fi - - if test x$TARGET = xX86_64; then - X86_64_TRUE= - X86_64_FALSE='#' -else - X86_64_TRUE='#' - X86_64_FALSE= -fi - - if test x$TARGET = xSH; then - SH_TRUE= - SH_FALSE='#' -else - SH_TRUE='#' - SH_FALSE= -fi - - if test x$TARGET = xSH64; then - SH64_TRUE= - SH64_FALSE='#' -else - SH64_TRUE='#' - SH64_FALSE= -fi - - if test x$TARGET = xPA_LINUX; then - PA_LINUX_TRUE= - PA_LINUX_FALSE='#' -else - PA_LINUX_TRUE='#' - PA_LINUX_FALSE= -fi - - if test x$TARGET = xPA_HPUX; then - PA_HPUX_TRUE= - PA_HPUX_FALSE='#' -else - PA_HPUX_TRUE='#' - PA_HPUX_FALSE= -fi - - if test x$TARGET = xPA64_HPUX; then - PA64_HPUX_TRUE= - PA64_HPUX_FALSE='#' -else - PA64_HPUX_TRUE='#' - PA64_HPUX_FALSE= -fi - - if test x$TARGET = xTILE; then - TILE_TRUE= - TILE_FALSE='#' -else - TILE_TRUE='#' - TILE_FALSE= -fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 @@ -12519,28 +15643,6 @@ $as_echo "#define HAVE_AS_CFI_PSEUDO_OP 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports -Qunused-arguments" >&5 -$as_echo_n "checking if compiler supports -Qunused-arguments... " >&6; } -if test "${libffi_cv_c_unused_arguments+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - CFLAGS_hold=$CFLAGS -CFLAGS="$CFLAGS -Qunused-arguments" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - libffi_cv_c_unused_arguments=yes -else - libffi_cv_c_unused_arguments=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -CFLAGS=$CFLAGS_hold -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_c_unused_arguments" >&5 -$as_echo "$libffi_cv_c_unused_arguments" >&6; } - if test x$TARGET = xSPARC; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler and linker support unaligned pc related relocs" >&5 $as_echo_n "checking assembler and linker support unaligned pc related relocs... " >&6; } @@ -12591,11 +15693,11 @@ else # Check if we have .register cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -asm (".register %g2, #scratch"); + int main () { - +asm (".register %g2, #scratch"); ; return 0; } @@ -12624,16 +15726,11 @@ if test "${libffi_cv_as_x86_pcrel+set}" = set; then : $as_echo_n "(cached) " >&6 else - libffi_cv_as_x86_pcrel=yes + libffi_cv_as_x86_pcrel=no echo '.text; foo: nop; .data; .long foo-.; .text' > conftest.s - CFLAGS_hold=$CFLAGS - if test "$libffi_cv_c_unused_arguments" = yes; then - CFLAGS="$CFLAGS -Qunused-arguments" - fi - if $CC $CFLAGS -c conftest.s 2>&1 | $EGREP -i 'illegal|warning' > /dev/null; then - libffi_cv_as_x86_pcrel=no + if $CC $CFLAGS -c conftest.s > /dev/null 2>&1; then + libffi_cv_as_x86_pcrel=yes fi - CFLAGS=$CFLAGS_hold fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_x86_pcrel" >&5 @@ -12654,11 +15751,11 @@ else # Check if we have .ascii cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -asm (".ascii \\"string\\""); + int main () { - +asm (".ascii \\"string\\""); ; return 0; } @@ -12689,11 +15786,11 @@ else # Check if we have .string cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -asm (".string \\"string\\""); + int main () { - +asm (".string \\"string\\""); ; return 0; } @@ -12715,6 +15812,31 @@ $as_echo "#define HAVE_AS_STRING_PSEUDO_OP 1" >>confdefs.h fi fi +if test x$TARGET = xS390; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler uses zarch features" >&5 +$as_echo_n "checking compiler uses zarch features... " >&6; } +if test "${libffi_cv_as_s390_zarch+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + libffi_cv_as_s390_zarch=no + echo 'void foo(void) { bar(); bar(); }' > conftest.c + if $CC $CFLAGS -S conftest.c > /dev/null 2>&1; then + if grep -q brasl conftest.s; then + libffi_cv_as_s390_zarch=yes + fi + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_s390_zarch" >&5 +$as_echo "$libffi_cv_as_s390_zarch" >&6; } + if test "x$libffi_cv_as_s390_zarch" = xyes; then + +$as_echo "#define HAVE_AS_S390_ZARCH 1" >>confdefs.h + + fi +fi + # On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. # Check whether --enable-pax_emutramp was given. if test "${enable_pax_emutramp+set}" = set; then : @@ -12751,22 +15873,33 @@ fi if test x$TARGET = xX86_64; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler supports unwind section type" >&5 -$as_echo_n "checking assembler supports unwind section type... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking toolchain supports unwind section type" >&5 +$as_echo_n "checking toolchain supports unwind section type... " >&6; } if test "${libffi_cv_as_x86_64_unwind_section_type+set}" = set; then : $as_echo_n "(cached) " >&6 else - libffi_cv_as_x86_64_unwind_section_type=yes - echo '.section .eh_frame,"a",@unwind' > conftest.s - CFLAGS_hold=$CFLAGS - if test "$libffi_cv_c_unused_arguments" = yes; then - CFLAGS="$CFLAGS -Qunused-arguments" + cat > conftest1.s << EOF +.text +.globl foo +foo: +jmp bar +.section .eh_frame,"a",@unwind +bar: +EOF + + cat > conftest2.c << EOF +extern void foo(); +int main(){foo();} +EOF + + libffi_cv_as_x86_64_unwind_section_type=no + # we ensure that we can compile _and_ link an assembly file containing an @unwind section + # since the compiler can support it and not the linker (ie old binutils) + if $CC -Wa,--fatal-warnings $CFLAGS -c conftest1.s > /dev/null 2>&1 && \ + $CC conftest2.c conftest1.o > /dev/null 2>&1 ; then + libffi_cv_as_x86_64_unwind_section_type=yes fi - if $CC $CFLAGS -c conftest.s 2>&1 | grep -i warning > /dev/null; then - libffi_cv_as_x86_64_unwind_section_type=no - fi - CFLAGS=$CFLAGS_hold fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_x86_64_unwind_section_type" >&5 @@ -12787,13 +15920,16 @@ else libffi_cv_ro_eh_frame=no echo 'extern void foo (void); void bar (void) { foo (); foo (); }' > conftest.c - if $CC $CFLAGS -S -fpic -fexceptions -o conftest.s conftest.c > /dev/null 2>&1; then - if grep '.section.*eh_frame.*"a"' conftest.s > /dev/null; then - libffi_cv_ro_eh_frame=yes - elif grep '.section.*eh_frame.*#alloc' conftest.c \ - | grep -v '#write' > /dev/null; then - libffi_cv_ro_eh_frame=yes - fi + if $CC $CFLAGS -c -fpic -fexceptions -o conftest.o conftest.c > /dev/null 2>&1; then + objdump -h conftest.o > conftest.dump 2>&1 + libffi_eh_frame_line=`grep -n eh_frame conftest.dump | cut -d: -f 1` + if test "x$libffi_eh_frame_line" != "x"; then + libffi_test_line=`expr $libffi_eh_frame_line + 1`p + sed -n $libffi_test_line conftest.dump > conftest.line + if grep READONLY conftest.line > /dev/null; then + libffi_cv_ro_eh_frame=yes + fi + fi fi rm -f conftest.* @@ -12849,6 +15985,14 @@ fi +TARGET_OBJ= +for i in $SOURCES; do + TARGET_OBJ="${TARGET_OBJ} src/${TARGETDIR}/"`echo $i | sed 's/[cS]$/lo/'` +done + + + + # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : @@ -12877,6 +16021,14 @@ $as_echo "#define FFI_NO_STRUCTS 1" >>confdefs.h fi fi + if test "$enable_debug" = "yes"; then + FFI_DEBUG_TRUE= + FFI_DEBUG_FALSE='#' +else + FFI_DEBUG_TRUE='#' + FFI_DEBUG_FALSE= +fi + # Check whether --enable-raw-api was given. if test "${enable_raw_api+set}" = set; then : @@ -12928,7 +16080,7 @@ ac_config_commands="$ac_config_commands src" ac_config_links="$ac_config_links include/ffitarget.h:src/$TARGETDIR/ffitarget.h" -ac_config_files="$ac_config_files include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile" +ac_config_files="$ac_config_files include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile libffi.pc" cat >confcache <<\_ACEOF @@ -13052,6 +16204,10 @@ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then as_fn_error "conditional \"am__fastdepCCAS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -13064,122 +16220,6 @@ if test -z "${TESTSUBDIR_TRUE}" && test -z "${TESTSUBDIR_FALSE}"; then as_fn_error "conditional \"TESTSUBDIR\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${MIPS_TRUE}" && test -z "${MIPS_FALSE}"; then - as_fn_error "conditional \"MIPS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${BFIN_TRUE}" && test -z "${BFIN_FALSE}"; then - as_fn_error "conditional \"BFIN\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${SPARC_TRUE}" && test -z "${SPARC_FALSE}"; then - as_fn_error "conditional \"SPARC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${X86_TRUE}" && test -z "${X86_FALSE}"; then - as_fn_error "conditional \"X86\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${X86_FREEBSD_TRUE}" && test -z "${X86_FREEBSD_FALSE}"; then - as_fn_error "conditional \"X86_FREEBSD\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${X86_WIN32_TRUE}" && test -z "${X86_WIN32_FALSE}"; then - as_fn_error "conditional \"X86_WIN32\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${X86_WIN64_TRUE}" && test -z "${X86_WIN64_FALSE}"; then - as_fn_error "conditional \"X86_WIN64\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${X86_DARWIN_TRUE}" && test -z "${X86_DARWIN_FALSE}"; then - as_fn_error "conditional \"X86_DARWIN\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${ALPHA_TRUE}" && test -z "${ALPHA_FALSE}"; then - as_fn_error "conditional \"ALPHA\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${IA64_TRUE}" && test -z "${IA64_FALSE}"; then - as_fn_error "conditional \"IA64\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${M32R_TRUE}" && test -z "${M32R_FALSE}"; then - as_fn_error "conditional \"M32R\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${M68K_TRUE}" && test -z "${M68K_FALSE}"; then - as_fn_error "conditional \"M68K\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${POWERPC_TRUE}" && test -z "${POWERPC_FALSE}"; then - as_fn_error "conditional \"POWERPC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${POWERPC_AIX_TRUE}" && test -z "${POWERPC_AIX_FALSE}"; then - as_fn_error "conditional \"POWERPC_AIX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${POWERPC_DARWIN_TRUE}" && test -z "${POWERPC_DARWIN_FALSE}"; then - as_fn_error "conditional \"POWERPC_DARWIN\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${POWERPC_FREEBSD_TRUE}" && test -z "${POWERPC_FREEBSD_FALSE}"; then - as_fn_error "conditional \"POWERPC_FREEBSD\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${AARCH64_TRUE}" && test -z "${AARCH64_FALSE}"; then - as_fn_error "conditional \"AARCH64\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${ARM_TRUE}" && test -z "${ARM_FALSE}"; then - as_fn_error "conditional \"ARM\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${AVR32_TRUE}" && test -z "${AVR32_FALSE}"; then - as_fn_error "conditional \"AVR32\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${LIBFFI_CRIS_TRUE}" && test -z "${LIBFFI_CRIS_FALSE}"; then - as_fn_error "conditional \"LIBFFI_CRIS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${FRV_TRUE}" && test -z "${FRV_FALSE}"; then - as_fn_error "conditional \"FRV\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${S390_TRUE}" && test -z "${S390_FALSE}"; then - as_fn_error "conditional \"S390\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${X86_64_TRUE}" && test -z "${X86_64_FALSE}"; then - as_fn_error "conditional \"X86_64\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${SH_TRUE}" && test -z "${SH_FALSE}"; then - as_fn_error "conditional \"SH\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${SH64_TRUE}" && test -z "${SH64_FALSE}"; then - as_fn_error "conditional \"SH64\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${PA_LINUX_TRUE}" && test -z "${PA_LINUX_FALSE}"; then - as_fn_error "conditional \"PA_LINUX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${PA_HPUX_TRUE}" && test -z "${PA_HPUX_FALSE}"; then - as_fn_error "conditional \"PA_HPUX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${PA64_HPUX_TRUE}" && test -z "${PA64_HPUX_FALSE}"; then - as_fn_error "conditional \"PA64_HPUX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${TILE_TRUE}" && test -z "${TILE_FALSE}"; then - as_fn_error "conditional \"TILE\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi if test -z "${FFI_EXEC_TRAMPOLINE_TABLE_TRUE}" && test -z "${FFI_EXEC_TRAMPOLINE_TABLE_FALSE}"; then as_fn_error "conditional \"FFI_EXEC_TRAMPOLINE_TABLE\" was never defined. @@ -13189,6 +16229,10 @@ if test -z "${FFI_DEBUG_TRUE}" && test -z "${FFI_DEBUG_FALSE}"; then as_fn_error "conditional \"FFI_DEBUG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${FFI_DEBUG_TRUE}" && test -z "${FFI_DEBUG_FALSE}"; then + as_fn_error "conditional \"FFI_DEBUG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : ${CONFIG_STATUS=./config.status} ac_write_fail=0 @@ -13597,7 +16641,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libffi $as_me 3.0.11, which was +This file was extended by libffi $as_me 3.99999, which was generated by GNU Autoconf 2.64. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13660,12 +16704,12 @@ $config_links Configuration commands: $config_commands -Report bugs to <http://gcc.gnu.org/bugs.html>." +Report bugs to <http://github.com/atgreen/libffi/issues>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -libffi config.status 3.0.11 +libffi config.status 3.99999 configured by $0, generated by GNU Autoconf 2.64, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" @@ -13920,6 +16964,61 @@ enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_sub enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +fix_srcfile_path_CXX='`$ECHO "$fix_srcfile_path_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' @@ -13992,7 +17091,40 @@ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ -striplib; do +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_flag_spec_ld_CXX \ +hardcode_libdir_separator_CXX \ +fix_srcfile_path_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" @@ -14021,7 +17153,17 @@ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ -sys_lib_dlsearch_path_spec; do +sys_lib_dlsearch_path_spec \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" @@ -14051,6 +17193,8 @@ fi + + TARGETDIR="$TARGETDIR" _ACEOF @@ -14073,6 +17217,7 @@ do "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "testsuite/Makefile") CONFIG_FILES="$CONFIG_FILES testsuite/Makefile" ;; "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; + "libffi.pc") CONFIG_FILES="$CONFIG_FILES libffi.pc" ;; *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac @@ -14841,7 +17986,7 @@ $as_echo X"$file" | # The names of the tagged configurations supported by this script. -available_tags="" +available_tags="CXX " # ### BEGIN LIBTOOL CONFIG @@ -15197,6 +18342,20 @@ file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + # ### END LIBTOOL CONFIG _LT_EOF @@ -15430,6 +18589,163 @@ _LT_EOF (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + ;; "include":C) test -d include || mkdir include ;; "src":C) diff --git a/libffi/configure.ac b/libffi/configure.ac index 97d2641..07ec10d 100644 --- a/libffi/configure.ac +++ b/libffi/configure.ac @@ -2,7 +2,7 @@ dnl Process this with autoconf to create configure AC_PREREQ(2.64) -AC_INIT([libffi], [3.0.11], [http://gcc.gnu.org/bugs.html]) +AC_INIT([libffi], [3.99999], [http://github.com/atgreen/libffi/issues]) AC_CONFIG_HEADERS([fficonfig.h]) AM_ENABLE_MULTILIB(, ..) @@ -10,8 +10,6 @@ AM_ENABLE_MULTILIB(, ..) AC_CANONICAL_SYSTEM target_alias=${target_alias-$host_alias} -. ${srcdir}/configure.host - AM_INIT_AUTOMAKE([no-dist]) # See if makeinfo has been installed and is modern enough @@ -43,10 +41,16 @@ AM_CONDITIONAL(GENINSRC, test "$enable_generated_files_in_srcdir" = yes) # We must force CC to /not/ be precious variables; otherwise # the wrong, non-multilib-adjusted value will be used in multilibs. # As a side effect, we have to subst CFLAGS ourselves. +# Also save and restore CFLAGS, since AC_PROG_CC will come up with +# defaults of its own if none are provided. m4_rename([_AC_ARG_VAR_PRECIOUS],[real_PRECIOUS]) m4_define([_AC_ARG_VAR_PRECIOUS],[]) +save_CFLAGS=$CFLAGS AC_PROG_CC +AC_PROG_CXX +CFLAGS=$save_CFLAGS +m4_undefine([_AC_ARG_VAR_PRECIOUS]) m4_rename_force([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) AC_SUBST(CFLAGS) @@ -55,10 +59,13 @@ AM_PROG_AS AM_PROG_CC_C_O AC_PROG_LIBTOOL +# Test for 64-bit build. +AC_CHECK_SIZEOF([size_t]) + AM_MAINTAINER_MODE AC_CHECK_HEADERS(sys/mman.h) -AC_CHECK_FUNCS(mmap) +AC_CHECK_FUNCS([mmap mkostemp]) AC_FUNC_MMAP_BLACKLIST dnl The -no-testsuite modules omit the test subdir. @@ -66,205 +73,15 @@ AM_CONDITIONAL(TESTSUBDIR, test -d $srcdir/testsuite) TARGETDIR="unknown" HAVE_LONG_DOUBLE_VARIANT=0 -case "$host" in - aarch64*-*-*) - TARGET=AARCH64; TARGETDIR=aarch64 - ;; - - alpha*-*-*) - TARGET=ALPHA; TARGETDIR=alpha; - # Support 128-bit long double, changeable via command-line switch. - HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)' - ;; - - arm*-*-*) - TARGET=ARM; TARGETDIR=arm - ;; - - amd64-*-freebsd* | amd64-*-openbsd*) - TARGET=X86_64; TARGETDIR=x86 - ;; - - amd64-*-freebsd*) - TARGET=X86_64; TARGETDIR=x86 - ;; - - avr32*-*-*) - TARGET=AVR32; TARGETDIR=avr32 - ;; - - bfin*) - TARGET=BFIN; TARGETDIR=bfin - ;; - - cris-*-*) - TARGET=LIBFFI_CRIS; TARGETDIR=cris - ;; - - frv-*-*) - TARGET=FRV; TARGETDIR=frv - ;; - - hppa*-*-linux* | parisc*-*-linux* | hppa*-*-openbsd*) - TARGET=PA_LINUX; TARGETDIR=pa - ;; - hppa*64-*-hpux*) - TARGET=PA64_HPUX; TARGETDIR=pa - ;; - hppa*-*-hpux*) - TARGET=PA_HPUX; TARGETDIR=pa - ;; - - i?86-*-freebsd* | i?86-*-openbsd*) - TARGET=X86_FREEBSD; TARGETDIR=x86 - ;; - i?86-win32* | i?86-*-cygwin* | i?86-*-mingw* | i?86-*-os2* | i?86-*-interix*) - TARGET=X86_WIN32; TARGETDIR=x86 - # All mingw/cygwin/win32 builds require -no-undefined for sharedlib. - # We must also check with_cross_host to decide if this is a native - # or cross-build and select where to install dlls appropriately. - if test -n "$with_cross_host" && - test x"$with_cross_host" != x"no"; then - AM_LTLDFLAGS='-no-undefined -bindir "$(toolexeclibdir)"'; - else - AM_LTLDFLAGS='-no-undefined -bindir "$(bindir)"'; - fi - ;; - i?86-*-darwin*) - TARGET=X86_DARWIN; TARGETDIR=x86 - ;; - i?86-*-solaris2.1[[0-9]]*) - TARGET=X86_64; TARGETDIR=x86 - ;; - i?86-*-*) - TARGET=X86_64; TARGETDIR=x86 - ;; - - ia64*-*-*) - TARGET=IA64; TARGETDIR=ia64 - ;; - - m32r*-*-*) - TARGET=M32R; TARGETDIR=m32r - ;; - - m68k-*-*) - TARGET=M68K; TARGETDIR=m68k - ;; - - mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*) - TARGET=MIPS; TARGETDIR=mips - ;; - mips*-*-linux* | mips*-*-openbsd*) - # Support 128-bit long double for NewABI. - HAVE_LONG_DOUBLE='defined(__mips64)' - TARGET=MIPS; TARGETDIR=mips - ;; - - powerpc*-*-linux* | powerpc-*-sysv*) - TARGET=POWERPC; TARGETDIR=powerpc - HAVE_LONG_DOUBLE_VARIANT=1 - ;; - powerpc-*-amigaos*) - TARGET=POWERPC; TARGETDIR=powerpc - ;; - powerpc-*-beos*) - TARGET=POWERPC; TARGETDIR=powerpc - ;; - powerpc-*-darwin* | powerpc64-*-darwin*) - TARGET=POWERPC_DARWIN; TARGETDIR=powerpc - ;; - powerpc-*-aix* | rs6000-*-aix*) - TARGET=POWERPC_AIX; TARGETDIR=powerpc - ;; - powerpc-*-freebsd* | powerpc-*-openbsd*) - TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc - HAVE_LONG_DOUBLE_VARIANT=1 - ;; - powerpc64-*-freebsd*) - TARGET=POWERPC; TARGETDIR=powerpc - ;; - powerpc*-*-rtems*) - TARGET=POWERPC; TARGETDIR=powerpc - ;; - - s390-*-* | s390x-*-*) - TARGET=S390; TARGETDIR=s390 - ;; - - sh-*-* | sh[[34]]*-*-*) - TARGET=SH; TARGETDIR=sh - ;; - sh64-*-* | sh5*-*-*) - TARGET=SH64; TARGETDIR=sh64 - ;; - - sparc*-*-*) - TARGET=SPARC; TARGETDIR=sparc - ;; - - tile*-*) - TARGET=TILE; TARGETDIR=tile - ;; - - x86_64-*-darwin*) - TARGET=X86_DARWIN; TARGETDIR=x86 - ;; - - x86_64-*-cygwin* | x86_64-*-mingw*) - TARGET=X86_WIN64; TARGETDIR=x86 - # All mingw/cygwin/win32 builds require -no-undefined for sharedlib. - # We must also check with_cross_host to decide if this is a native - # or cross-build and select where to install dlls appropriately. - if test -n "$with_cross_host" && - test x"$with_cross_host" != x"no"; then - AM_LTLDFLAGS='-no-undefined -bindir "$(toolexeclibdir)"'; - else - AM_LTLDFLAGS='-no-undefined -bindir "$(bindir)"'; - fi - ;; - - x86_64-*-*) - TARGET=X86_64; TARGETDIR=x86 - ;; -esac -AC_SUBST(AM_RUNTESTFLAGS) -AC_SUBST(AM_LTLDFLAGS) +. ${srcdir}/configure.host -if test $TARGETDIR = unknown; then +if test -n "${UNSUPPORTED}"; then AC_MSG_ERROR(["libffi has not been ported to $host."]) fi -AM_CONDITIONAL(MIPS, test x$TARGET = xMIPS) -AM_CONDITIONAL(BFIN, test x$TARGET = xBFIN) -AM_CONDITIONAL(SPARC, test x$TARGET = xSPARC) -AM_CONDITIONAL(X86, test x$TARGET = xX86) -AM_CONDITIONAL(X86_FREEBSD, test x$TARGET = xX86_FREEBSD) -AM_CONDITIONAL(X86_WIN32, test x$TARGET = xX86_WIN32) -AM_CONDITIONAL(X86_WIN64, test x$TARGET = xX86_WIN64) -AM_CONDITIONAL(X86_DARWIN, test x$TARGET = xX86_DARWIN) -AM_CONDITIONAL(ALPHA, test x$TARGET = xALPHA) -AM_CONDITIONAL(IA64, test x$TARGET = xIA64) -AM_CONDITIONAL(M32R, test x$TARGET = xM32R) -AM_CONDITIONAL(M68K, test x$TARGET = xM68K) -AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC) -AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX) -AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN) -AM_CONDITIONAL(POWERPC_FREEBSD, test x$TARGET = xPOWERPC_FREEBSD) -AM_CONDITIONAL(AARCH64, test x$TARGET = xAARCH64) -AM_CONDITIONAL(ARM, test x$TARGET = xARM) -AM_CONDITIONAL(AVR32, test x$TARGET = xAVR32) -AM_CONDITIONAL(LIBFFI_CRIS, test x$TARGET = xLIBFFI_CRIS) -AM_CONDITIONAL(FRV, test x$TARGET = xFRV) -AM_CONDITIONAL(S390, test x$TARGET = xS390) -AM_CONDITIONAL(X86_64, test x$TARGET = xX86_64) -AM_CONDITIONAL(SH, test x$TARGET = xSH) -AM_CONDITIONAL(SH64, test x$TARGET = xSH64) -AM_CONDITIONAL(PA_LINUX, test x$TARGET = xPA_LINUX) -AM_CONDITIONAL(PA_HPUX, test x$TARGET = xPA_HPUX) -AM_CONDITIONAL(PA64_HPUX, test x$TARGET = xPA64_HPUX) -AM_CONDITIONAL(TILE, test x$TARGET = xTILE) +AC_SUBST(AM_RUNTESTFLAGS) +AC_SUBST(AM_LTLDFLAGS) AC_HEADER_STDC AC_CHECK_FUNCS(memcpy) @@ -295,15 +112,6 @@ AC_C_BIGENDIAN GCC_AS_CFI_PSEUDO_OP -AC_CACHE_CHECK([if compiler supports -Qunused-arguments], -[libffi_cv_c_unused_arguments], -[CFLAGS_hold=$CFLAGS -CFLAGS="$CFLAGS -Qunused-arguments" -AC_COMPILE_IFELSE([[int i;]], -[libffi_cv_c_unused_arguments=yes], -[libffi_cv_c_unused_arguments=no]) -CFLAGS=$CFLAGS_hold]) - if test x$TARGET = xSPARC; then AC_CACHE_CHECK([assembler and linker support unaligned pc related relocs], libffi_cv_as_sparc_ua_pcrel, [ @@ -325,7 +133,7 @@ if test x$TARGET = xSPARC; then 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");],, + AC_TRY_COMPILE(,[asm (".register %g2, #scratch");], [libffi_cv_as_register_pseudo_op=yes], [libffi_cv_as_register_pseudo_op=no]) ]) @@ -338,16 +146,11 @@ fi if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64; then AC_CACHE_CHECK([assembler supports pc related relocs], libffi_cv_as_x86_pcrel, [ - libffi_cv_as_x86_pcrel=yes + libffi_cv_as_x86_pcrel=no echo '.text; foo: nop; .data; .long foo-.; .text' > conftest.s - CFLAGS_hold=$CFLAGS - if test "$libffi_cv_c_unused_arguments" = yes; then - CFLAGS="$CFLAGS -Qunused-arguments" - fi - if $CC $CFLAGS -c conftest.s 2>&1 | $EGREP -i 'illegal|warning' > /dev/null; then - libffi_cv_as_x86_pcrel=no + if $CC $CFLAGS -c conftest.s > /dev/null 2>&1; then + libffi_cv_as_x86_pcrel=yes fi - CFLAGS=$CFLAGS_hold ]) if test "x$libffi_cv_as_x86_pcrel" = xyes; then AC_DEFINE(HAVE_AS_X86_PCREL, 1, @@ -358,7 +161,7 @@ if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64 libffi_cv_as_ascii_pseudo_op, [ libffi_cv_as_ascii_pseudo_op=unknown # Check if we have .ascii - AC_TRY_COMPILE([asm (".ascii \\"string\\"");],, + AC_TRY_COMPILE(,[asm (".ascii \\"string\\"");], [libffi_cv_as_ascii_pseudo_op=yes], [libffi_cv_as_ascii_pseudo_op=no]) ]) @@ -371,7 +174,7 @@ if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64 libffi_cv_as_string_pseudo_op, [ libffi_cv_as_string_pseudo_op=unknown # Check if we have .string - AC_TRY_COMPILE([asm (".string \\"string\\"");],, + AC_TRY_COMPILE(,[asm (".string \\"string\\"");], [libffi_cv_as_string_pseudo_op=yes], [libffi_cv_as_string_pseudo_op=no]) ]) @@ -381,6 +184,23 @@ if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64 fi fi +if test x$TARGET = xS390; then + AC_CACHE_CHECK([compiler uses zarch features], + libffi_cv_as_s390_zarch, [ + libffi_cv_as_s390_zarch=no + echo 'void foo(void) { bar(); bar(); }' > conftest.c + if $CC $CFLAGS -S conftest.c > /dev/null 2>&1; then + if grep -q brasl conftest.s; then + libffi_cv_as_s390_zarch=yes + fi + fi + ]) + if test "x$libffi_cv_as_s390_zarch" = xyes; then + AC_DEFINE(HAVE_AS_S390_ZARCH, 1, + [Define if the compiler uses zarch features.]) + fi +fi + # On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. AC_ARG_ENABLE(pax_emutramp, [ --enable-pax_emutramp enable pax emulated trampolines, for we can't use PROT_EXEC], @@ -407,18 +227,29 @@ AM_CONDITIONAL(FFI_EXEC_TRAMPOLINE_TABLE, test x$FFI_EXEC_TRAMPOLINE_TABLE = x1) AC_SUBST(FFI_EXEC_TRAMPOLINE_TABLE) if test x$TARGET = xX86_64; then - AC_CACHE_CHECK([assembler supports unwind section type], + AC_CACHE_CHECK([toolchain supports unwind section type], libffi_cv_as_x86_64_unwind_section_type, [ - libffi_cv_as_x86_64_unwind_section_type=yes - echo '.section .eh_frame,"a",@unwind' > conftest.s - CFLAGS_hold=$CFLAGS - if test "$libffi_cv_c_unused_arguments" = yes; then - CFLAGS="$CFLAGS -Qunused-arguments" - fi - if $CC $CFLAGS -c conftest.s 2>&1 | grep -i warning > /dev/null; then - libffi_cv_as_x86_64_unwind_section_type=no + cat > conftest1.s << EOF +.text +.globl foo +foo: +jmp bar +.section .eh_frame,"a",@unwind +bar: +EOF + + cat > conftest2.c << EOF +extern void foo(); +int main(){foo();} +EOF + + libffi_cv_as_x86_64_unwind_section_type=no + # we ensure that we can compile _and_ link an assembly file containing an @unwind section + # since the compiler can support it and not the linker (ie old binutils) + if $CC -Wa,--fatal-warnings $CFLAGS -c conftest1.s > /dev/null 2>&1 && \ + $CC conftest2.c conftest1.o > /dev/null 2>&1 ; then + libffi_cv_as_x86_64_unwind_section_type=yes fi - CFLAGS=$CFLAGS_hold ]) if test "x$libffi_cv_as_x86_64_unwind_section_type" = xyes; then AC_DEFINE(HAVE_AS_X86_64_UNWIND_SECTION_TYPE, 1, @@ -431,13 +262,16 @@ if test "x$GCC" = "xyes"; then libffi_cv_ro_eh_frame, [ libffi_cv_ro_eh_frame=no echo 'extern void foo (void); void bar (void) { foo (); foo (); }' > conftest.c - if $CC $CFLAGS -S -fpic -fexceptions -o conftest.s conftest.c > /dev/null 2>&1; then - if grep '.section.*eh_frame.*"a"' conftest.s > /dev/null; then - libffi_cv_ro_eh_frame=yes - elif grep '.section.*eh_frame.*#alloc' conftest.c \ - | grep -v '#write' > /dev/null; then - libffi_cv_ro_eh_frame=yes - fi + if $CC $CFLAGS -c -fpic -fexceptions -o conftest.o conftest.c > /dev/null 2>&1; then + objdump -h conftest.o > conftest.dump 2>&1 + libffi_eh_frame_line=`grep -n eh_frame conftest.dump | cut -d: -f 1` + if test "x$libffi_eh_frame_line" != "x"; then + libffi_test_line=`expr $libffi_eh_frame_line + 1`p + sed -n $libffi_test_line conftest.dump > conftest.line + if grep READONLY conftest.line > /dev/null; then + libffi_cv_ro_eh_frame=yes + fi + fi fi rm -f conftest.* ]) @@ -487,6 +321,14 @@ AH_BOTTOM([ AC_SUBST(TARGET) AC_SUBST(TARGETDIR) +changequote(<,>) +TARGET_OBJ= +for i in $SOURCES; do + TARGET_OBJ="${TARGET_OBJ} src/${TARGETDIR}/"`echo $i | sed 's/[cS]$/lo/'` +done +changequote([,]) +AC_SUBST(TARGET_OBJ) + AC_SUBST(SHELL) AC_ARG_ENABLE(debug, @@ -499,13 +341,14 @@ AM_CONDITIONAL(FFI_DEBUG, test "$enable_debug" = "yes") AC_ARG_ENABLE(structs, [ --disable-structs omit code for struct support], if test "$enable_structs" = "no"; then - AC_DEFINE(FFI_NO_STRUCTS, 1, [Define this is you do not want support for aggregate types.]) + AC_DEFINE(FFI_NO_STRUCTS, 1, [Define this if you do not want support for aggregate types.]) fi) +AM_CONDITIONAL(FFI_DEBUG, test "$enable_debug" = "yes") AC_ARG_ENABLE(raw-api, [ --disable-raw-api make the raw api unavailable], if test "$enable_raw_api" = "no"; then - AC_DEFINE(FFI_NO_RAW_API, 1, [Define this is you do not want support for the raw API.]) + AC_DEFINE(FFI_NO_RAW_API, 1, [Define this if you do not want support for the raw API.]) fi) AC_ARG_ENABLE(purify-safety, @@ -544,6 +387,6 @@ test -d src/$TARGETDIR || mkdir src/$TARGETDIR AC_CONFIG_LINKS(include/ffitarget.h:src/$TARGETDIR/ffitarget.h) -AC_CONFIG_FILES(include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile) +AC_CONFIG_FILES(include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile libffi.pc) AC_OUTPUT diff --git a/libffi/configure.host b/libffi/configure.host index f52457b..90de638 100644 --- a/libffi/configure.host +++ b/libffi/configure.host @@ -1,11 +1,265 @@ # configure.host # # This shell script handles all host based configuration for libffi. -# +# # THIS TABLE IS SORTED. KEEP IT THAT WAY. +# Most of the time we can define all the variables all at once... case "${host}" in - frv*-elf) - LDFLAGS=`echo $LDFLAGS | sed "s/\-B[^ ]*libgloss\/frv\///"`\ -B`pwd`/../libgloss/frv/ - ;; + aarch64*-*-*) + TARGET=AARCH64; TARGETDIR=aarch64 + SOURCES="ffi.c sysv.S" + ;; + + alpha*-*-*) + TARGET=ALPHA; TARGETDIR=alpha; + # Support 128-bit long double, changeable via command-line switch. + HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)' + SOURCES="ffi.c osf.S" + ;; + + arc*-*-*) + TARGET=ARC; TARGETDIR=arc + SOURCES="ffi.c arcompact.S" + ;; + + arm*-*-*) + TARGET=ARM; TARGETDIR=arm + SOURCES="ffi.c sysv.S" + ;; + + avr32*-*-*) + TARGET=AVR32; TARGETDIR=avr32 + SOURCES="ffi.c sysv.S" + ;; + + bfin*) + TARGET=BFIN; TARGETDIR=bfin + SOURCES="ffi.c sysv.S" + ;; + + cris-*-*) + TARGET=LIBFFI_CRIS; TARGETDIR=cris + SOURCES="ffi.c sysv.S" + ;; + + frv-*-*) + TARGET=FRV; TARGETDIR=frv + SOURCES="ffi.c eabi.S" + ;; + + hppa*-*-linux* | parisc*-*-linux* | hppa*-*-openbsd*) + TARGET=PA_LINUX; TARGETDIR=pa + SOURCES="ffi.c linux.S" + ;; + hppa*64-*-hpux*) + TARGET=PA64_HPUX; TARGETDIR=pa + ;; + hppa*-*-hpux*) + TARGET=PA_HPUX; TARGETDIR=pa + SOURCES="ffi.c hpux32.S" + ;; + + i?86-*-freebsd* | i?86-*-openbsd*) + TARGET=X86_FREEBSD; TARGETDIR=x86 + ;; + + i?86-win32* | i?86-*-cygwin* | i?86-*-mingw* | i?86-*-os2* | i?86-*-interix* \ + | x86_64-*-cygwin* | x86_64-*-mingw*) + TARGETDIR=x86 + if test $ac_cv_sizeof_size_t = 4; then + TARGET=X86_WIN32 + else + TARGET=X86_WIN64 + fi + # All mingw/cygwin/win32 builds require -no-undefined for sharedlib. + # We must also check with_cross_host to decide if this is a native + # or cross-build and select where to install dlls appropriately. + if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + AM_LTLDFLAGS='-no-undefined -bindir "$(toolexeclibdir)"'; + else + AM_LTLDFLAGS='-no-undefined -bindir "$(bindir)"'; + fi + ;; + + i?86-*-darwin* | x86_64-*-darwin*) + TARGETDIR=x86 + if test $ac_cv_sizeof_size_t = 4; then + TARGET=X86_DARWIN + else + TARGET=X86_64_DARWIN + fi + ;; + + i?86-*-* | x86_64-*-* | amd64-*) + TARGETDIR=x86 + if test $ac_cv_sizeof_size_t = 4; then + case "$host" in + *-gnux32) + TARGET=X86_64 + ;; + *) + TARGET=X86 + ;; + esac + else + TARGET=X86_64; + fi + ;; + + ia64*-*-*) + TARGET=IA64; TARGETDIR=ia64 + SOURCES="ffi.c unix.S" + ;; + + m32r*-*-*) + TARGET=M32R; TARGETDIR=m32r + SOURCES="ffi.c sysv.S" + ;; + + m68k-*-*) + TARGET=M68K; TARGETDIR=m68k + SOURCES="ffi.c sysv.S" + ;; + + m88k-*-*) + TARGET=M88K; TARGETDIR=m88k + SOURCES="ffi.c obsd.S" + ;; + + microblaze*-*-*) + TARGET=MICROBLAZE; TARGETDIR=microblaze + SOURCES="ffi.c sysv.S" + ;; + + moxie-*-*) + TARGET=MOXIE; TARGETDIR=moxie + SOURCES="ffi.c eabi.S" + ;; + + metag-*-*) + TARGET=METAG; TARGETDIR=metag + SOURCES="ffi.c sysv.S" + ;; + + mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*) + TARGET=MIPS; TARGETDIR=mips + ;; + mips*-*linux* | mips*-*-openbsd*) + # Support 128-bit long double for NewABI. + HAVE_LONG_DOUBLE='defined(__mips64)' + TARGET=MIPS; TARGETDIR=mips + ;; + + nios2*-linux*) + TARGET=NIOS2; TARGETDIR=nios2 + SOURCES="ffi.c sysv.S" + ;; + + or1k*-linux*) + TARGET=OR1K; TARGETDIR=or1k + SOURCES="ffi.c sysv.S" + ;; + + powerpc*-*-linux* | powerpc-*-sysv*) + TARGET=POWERPC; TARGETDIR=powerpc + HAVE_LONG_DOUBLE_VARIANT=1 + ;; + powerpc-*-amigaos*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + powerpc-*-beos*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + powerpc-*-darwin* | powerpc64-*-darwin*) + TARGET=POWERPC_DARWIN; TARGETDIR=powerpc + ;; + powerpc-*-aix* | rs6000-*-aix*) + TARGET=POWERPC_AIX; TARGETDIR=powerpc + ;; + powerpc-*-freebsd* | powerpc-*-openbsd*) + TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc + HAVE_LONG_DOUBLE_VARIANT=1 + ;; + powerpc64-*-freebsd*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + powerpc*-*-rtems*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + + s390-*-* | s390x-*-*) + TARGET=S390; TARGETDIR=s390 + SOURCES="ffi.c sysv.S" + ;; + + sh-*-* | sh[[34]]*-*-*) + TARGET=SH; TARGETDIR=sh + SOURCES="ffi.c sysv.S" + ;; + sh64-*-* | sh5*-*-*) + TARGET=SH64; TARGETDIR=sh64 + SOURCES="ffi.c sysv.S" + ;; + + sparc*-*-*) + TARGET=SPARC; TARGETDIR=sparc + SOURCES="ffi.c ffi64.c v8.S v9.S" + ;; + + tile*-*) + TARGET=TILE; TARGETDIR=tile + SOURCES="ffi.c tile.S" + ;; + + vax-*-*) + TARGET=VAX; TARGETDIR=vax + SOURCES="ffi.c elfbsd.S" + ;; + + xtensa*-*) + TARGET=XTENSA; TARGETDIR=xtensa + SOURCES="ffi.c sysv.S" + ;; +esac + +# ... but some of the cases above share configury. +case "${TARGET}" in + MIPS) + SOURCES="ffi.c o32.S n32.S" + ;; + POWERPC) + SOURCES="ffi.c ffi_sysv.c ffi_linux64.c sysv.S ppc_closure.S" + SOURCES="${SOURCES} linux64.S linux64_closure.S" + ;; + POWERPC_AIX) + SOURCES="ffi_darwin.c aix.S aix_closure.S" + ;; + POWERPC_DARWIN) + SOURCES="ffi_darwin.c darwin.S darwin_closure.S" + ;; + POWERPC_FREEBSD) + SOURCES="ffi.c ffi_sysv.c sysv.S ppc_closure.S" + ;; + X86 | X86_FREEBSD | X86_WIN32) + SOURCES="ffi.c sysv.S" + ;; + X86_64) + SOURCES="ffi64.c unix64.S" + ;; + X86_WIN64) + SOURCES="ffiw64.c win64.S" + ;; + X86_DARWIN) + SOURCES="darwin_c.c darwin.S" + ;; + X86_64_DARWIN) + SOURCES="darwin64_c.c darwin64.S" + ;; esac + +# If we failed to configure SOURCES, we can't do anything. +if test -z "${SOURCES}"; then + UNSUPPORTED=1 +fi diff --git a/libffi/doc/libffi.texi b/libffi/doc/libffi.texi index 04888ec..b1c9bc3 100644 --- a/libffi/doc/libffi.texi +++ b/libffi/doc/libffi.texi @@ -63,14 +63,14 @@ section entitled ``GNU General Public License''. @node Introduction @chapter What is libffi? -Compilers for high-level languages generate code that follow certain +Compilers for high level languages generate code that follow certain conventions. These conventions are necessary, in part, for separate compilation to work. One such convention is the @dfn{calling convention}. The calling convention is a set of assumptions made by the compiler about where function arguments will be found on entry to a function. A calling convention also specifies where the return -value for a function is found. The calling convention is part of -what is called the @dfn{ABI} or @dfn{Application Binary Interface}. +value for a function is found. The calling convention is also +sometimes called the @dfn{ABI} or @dfn{Application Binary Interface}. @cindex calling convention @cindex ABI @cindex Application Binary Interface @@ -247,6 +247,8 @@ int main() * Primitive Types:: Built-in types. * Structures:: Structure types. * Type Example:: Structure type example. +* Complex:: Complex types. +* Complex Type Example:: Complex type example. @end menu @node Primitive Types @@ -345,6 +347,20 @@ On other platforms, it is not. @tindex ffi_type_pointer A generic @code{void *} pointer. You should use this for all pointers, regardless of their real type. + +@item ffi_type_complex_float +@tindex ffi_type_complex_float +The C @code{_Complex float} type. + +@item ffi_type_complex_double +@tindex ffi_type_complex_double +The C @code{_Complex double} type. + +@item ffi_type_complex_longdouble +@tindex ffi_type_complex_longdouble +The C @code{_Complex long double} type. +On platforms that have a C @code{long double} type, this is defined. +On other platforms, it is not. @end table Each of these is of type @code{ffi_type}, so you must take the address @@ -429,6 +445,135 @@ Here is the corresponding code to describe this struct to @} @end example +@node Complex +@subsection Complex Types + +@samp{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 +@code{ffi_type_complex_longdouble}. + +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}. + +@tindex ffi_type +@deftp {Data type} ffi_type +@table @code +@item size_t size +This must be manually set to the size of the complex type. + +@item unsigned short alignment +This must be manually set to the alignment of the complex type. + +@item unsigned short type +For a complex type, this must be set to @code{FFI_TYPE_COMPLEX}. + +@item ffi_type **elements + +This is a @samp{NULL}-terminated array of pointers to +@code{ffi_type} objects. The first element is set to the +@code{ffi_type} of the complex's base type. The second element +must be set to @code{NULL}. +@end table +@end deftp + +The section @ref{Complex Type Example} shows a way to determine +the @code{size} and @code{alignment} members in a platform +independent way. + +For platforms that have no complex support in @code{libffi} yet, +the functions @code{ffi_prep_cif} and @code{ffi_prep_args} abort +the program if they encounter a complex type. + +@node Complex Type Example +@subsection Complex Type Example + +This example demonstrates how to use complex types: + +@example +#include <stdio.h> +#include <ffi.h> +#include <complex.h> + +void complex_fn(_Complex float cf, + _Complex double cd, + _Complex long double cld) +@{ + printf("cf=%f+%fi\ncd=%f+%fi\ncld=%f+%fi\n", + (float)creal (cf), (float)cimag (cf), + (float)creal (cd), (float)cimag (cd), + (float)creal (cld), (float)cimag (cld)); +@} + +int main() +@{ + ffi_cif cif; + ffi_type *args[3]; + void *values[3]; + _Complex float cf; + _Complex double cd; + _Complex long double cld; + + /* Initialize the argument info vectors */ + args[0] = &ffi_type_complex_float; + args[1] = &ffi_type_complex_double; + args[2] = &ffi_type_complex_longdouble; + values[0] = &cf; + values[1] = &cd; + values[2] = &cld; + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, + &ffi_type_void, args) == FFI_OK) + @{ + cf = 1.0 + 20.0 * I; + cd = 300.0 + 4000.0 * I; + cld = 50000.0 + 600000.0 * I; + /* Call the function */ + ffi_call(&cif, (void (*)(void))complex_fn, 0, values); + @} + + return 0; +@} +@end example + +This is an example for defining a custom complex type descriptor +for compilers that support them: + +@example +/* + * This macro can be used to define new complex type descriptors + * in a platform independent way. + * + * name: Name of the new descriptor is ffi_type_complex_<name>. + * type: The C base type of the complex type. + */ +#define FFI_COMPLEX_TYPEDEF(name, type, ffitype) \ + static ffi_type *ffi_elements_complex_##name [2] = @{ \ + (ffi_type *)(&ffitype), NULL \ + @}; \ + struct struct_align_complex_##name @{ \ + char c; \ + _Complex type x; \ + @}; \ + ffi_type ffi_type_complex_##name = @{ \ + sizeof(_Complex type), \ + offsetof(struct struct_align_complex_##name, x), \ + FFI_TYPE_COMPLEX, \ + (ffi_type **)ffi_elements_complex_##name \ + @} + +/* Define new complex type descriptors using the macro: */ +/* ffi_type_complex_sint */ +FFI_COMPLEX_TYPEDEF(sint, int, ffi_type_sint); +/* ffi_type_complex_uchar */ +FFI_COMPLEX_TYPEDEF(uchar, unsigned char, ffi_type_uint8); +@end example + +The new type descriptors can then be used like one of the built-in +type descriptors in the previous example. @node Multiple ABIs @section Multiple ABIs @@ -534,7 +679,7 @@ writable and executable addresses. @section Closure Example A trivial example that creates a new @code{puts} by binding -@code{fputs} with @code{stdin}. +@code{fputs} with @code{stdout}. @example #include <stdio.h> diff --git a/libffi/doc/stamp-vti b/libffi/doc/stamp-vti deleted file mode 100644 index b9b2131..0000000 --- a/libffi/doc/stamp-vti +++ /dev/null @@ -1,4 +0,0 @@ -@set UPDATED 6 March 2012 -@set UPDATED-MONTH March 2012 -@set EDITION 3.0.11 -@set VERSION 3.0.11 diff --git a/libffi/doc/version.texi b/libffi/doc/version.texi index b9b2131..ccef70f4 100644 --- a/libffi/doc/version.texi +++ b/libffi/doc/version.texi @@ -1,4 +1,4 @@ -@set UPDATED 6 March 2012 -@set UPDATED-MONTH March 2012 -@set EDITION 3.0.11 -@set VERSION 3.0.11 +@set UPDATED 8 November 2014 +@set UPDATED-MONTH November 2014 +@set EDITION 3.2.1 +@set VERSION 3.2.1 diff --git a/libffi/fficonfig.h.in b/libffi/fficonfig.h.in index 19d66d0..f245ce0 100644 --- a/libffi/fficonfig.h.in +++ b/libffi/fficonfig.h.in @@ -26,10 +26,10 @@ /* Cannot use malloc on this target, so, we revert to alternative means */ #undef FFI_MMAP_EXEC_WRIT -/* Define this is you do not want support for the raw API. */ +/* Define this if you do not want support for the raw API. */ #undef FFI_NO_RAW_API -/* Define this is you do not want support for aggregate types. */ +/* Define this if you do not want support for aggregate types. */ #undef FFI_NO_STRUCTS /* Define to 1 if you have `alloca', as a function or macro. */ @@ -48,6 +48,9 @@ /* Define if your assembler supports .register. */ #undef HAVE_AS_REGISTER_PSEUDO_OP +/* Define if the compiler uses zarch features. */ +#undef HAVE_AS_S390_ZARCH + /* Define if your assembler and linker support unaligned PC relative relocs. */ #undef HAVE_AS_SPARC_UA_PCREL @@ -82,6 +85,9 @@ /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H +/* Define to 1 if you have the `mkostemp' function. */ +#undef HAVE_MKOSTEMP + /* Define to 1 if you have the `mmap' function. */ #undef HAVE_MMAP @@ -155,6 +161,9 @@ /* The size of `long double', as computed by sizeof. */ #undef SIZEOF_LONG_DOUBLE +/* The size of `size_t', as computed by sizeof. */ +#undef SIZEOF_SIZE_T + /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. diff --git a/libffi/generate-darwin-source-and-headers.py b/libffi/generate-darwin-source-and-headers.py new file mode 100644 index 0000000..306136f --- /dev/null +++ b/libffi/generate-darwin-source-and-headers.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +import subprocess +import os +import errno +import collections +import glob +import argparse + +class Platform(object): + pass + +class simulator_platform(Platform): + directory = 'darwin_ios' + sdk = 'iphonesimulator' + arch = 'i386' + triple = 'i386-apple-darwin11' + version_min = '-miphoneos-version-min=7.0' + + prefix = "#ifdef __i386__\n\n" + suffix = "\n\n#endif" + src_dir = 'x86' + src_files = ['darwin.S', 'win32.S', 'ffi.c'] + + +class simulator64_platform(Platform): + directory = 'darwin_ios' + sdk = 'iphonesimulator' + arch = 'x86_64' + triple = 'x86_64-apple-darwin13' + version_min = '-miphoneos-version-min=7.0' + + prefix = "#ifdef __x86_64__\n\n" + suffix = "\n\n#endif" + src_dir = 'x86' + src_files = ['darwin64.S', 'ffi64.c'] + + +class device_platform(Platform): + directory = 'darwin_ios' + sdk = 'iphoneos' + arch = 'armv7' + triple = 'arm-apple-darwin11' + version_min = '-miphoneos-version-min=7.0' + + prefix = "#ifdef __arm__\n\n" + suffix = "\n\n#endif" + src_dir = 'arm' + src_files = ['sysv.S', 'trampoline.S', 'ffi.c'] + + +class device64_platform(Platform): + directory = 'darwin_ios' + sdk = 'iphoneos' + arch = 'arm64' + triple = 'aarch64-apple-darwin13' + version_min = '-miphoneos-version-min=7.0' + + prefix = "#ifdef __arm64__\n\n" + suffix = "\n\n#endif" + src_dir = 'aarch64' + src_files = ['sysv.S', 'ffi.c'] + + +class desktop32_platform(Platform): + directory = 'darwin_osx' + sdk = 'macosx' + arch = 'i386' + triple = 'i386-apple-darwin10' + version_min = '-mmacosx-version-min=10.6' + src_dir = 'x86' + src_files = ['darwin.S', 'win32.S', 'ffi.c'] + + prefix = "#ifdef __i386__\n\n" + suffix = "\n\n#endif" + + +class desktop64_platform(Platform): + directory = 'darwin_osx' + sdk = 'macosx' + arch = 'x86_64' + triple = 'x86_64-apple-darwin10' + version_min = '-mmacosx-version-min=10.6' + + prefix = "#ifdef __x86_64__\n\n" + suffix = "\n\n#endif" + src_dir = 'x86' + src_files = ['darwin64.S', 'ffi64.c'] + + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST: + pass + else: + raise + + +def move_file(src_dir, dst_dir, filename, file_suffix=None, prefix='', suffix=''): + mkdir_p(dst_dir) + out_filename = filename + + if file_suffix: + split_name = os.path.splitext(filename) + out_filename = "%s_%s%s" % (split_name[0], file_suffix, split_name[1]) + + with open(os.path.join(src_dir, filename)) as in_file: + with open(os.path.join(dst_dir, out_filename), 'w') as out_file: + if prefix: + out_file.write(prefix) + + out_file.write(in_file.read()) + + if suffix: + out_file.write(suffix) + + +def list_files(src_dir, pattern=None, filelist=None): + if pattern: filelist = glob.iglob(os.path.join(src_dir, pattern)) + for file in filelist: + yield os.path.basename(file) + + +def copy_files(src_dir, dst_dir, pattern=None, filelist=None, file_suffix=None, prefix=None, suffix=None): + for filename in list_files(src_dir, pattern=pattern, filelist=filelist): + move_file(src_dir, dst_dir, filename, file_suffix=file_suffix, prefix=prefix, suffix=suffix) + + +def copy_src_platform_files(platform): + src_dir = os.path.join('src', platform.src_dir) + dst_dir = os.path.join(platform.directory, 'src', platform.src_dir) + copy_files(src_dir, dst_dir, filelist=platform.src_files, file_suffix=platform.arch, prefix=platform.prefix, suffix=platform.suffix) + + +def build_target(platform, platform_headers): + def xcrun_cmd(cmd): + return 'xcrun -sdk %s %s -arch %s' % (platform.sdk, cmd, platform.arch) + + 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' % (platform.version_min)) + working_dir = os.getcwd() + try: + os.chdir(build_dir) + subprocess.check_call(['../configure', '-host', platform.triple], env=env) + finally: + os.chdir(working_dir) + + for src_dir in [build_dir, os.path.join(build_dir, 'include')]: + copy_files(src_dir, + os.path.join(platform.directory, 'include'), + pattern='*.h', + file_suffix=platform.arch, + prefix=platform.prefix, + suffix=platform.suffix) + + for filename in list_files(src_dir, pattern='*.h'): + platform_headers[filename].add((platform.prefix, platform.arch, platform.suffix)) + + +def make_tramp(): + with open('src/arm/trampoline.S', 'w') as tramp_out: + p = subprocess.Popen(['bash', 'src/arm/gentramp.sh'], stdout=tramp_out) + p.wait() + + +def generate_source_and_headers(generate_osx=True, generate_ios=True): + copy_files('src', 'darwin_common/src', pattern='*.c') + copy_files('include', 'darwin_common/include', pattern='*.h') + + if generate_ios: + make_tramp() + copy_src_platform_files(simulator_platform) + copy_src_platform_files(simulator64_platform) + copy_src_platform_files(device_platform) + copy_src_platform_files(device64_platform) + if generate_osx: + copy_src_platform_files(desktop32_platform) + copy_src_platform_files(desktop64_platform) + + platform_headers = collections.defaultdict(set) + + if generate_ios: + build_target(simulator_platform, platform_headers) + build_target(simulator64_platform, platform_headers) + build_target(device_platform, platform_headers) + build_target(device64_platform, platform_headers) + if generate_osx: + build_target(desktop32_platform, platform_headers) + build_target(desktop64_platform, platform_headers) + + mkdir_p('darwin_common/include') + for header_name, tag_tuples in platform_headers.iteritems(): + basename, suffix = os.path.splitext(header_name) + with open(os.path.join('darwin_common/include', header_name), 'w') as header: + for tag_tuple in tag_tuples: + header.write('%s#include <%s_%s%s>\n%s\n' % (tag_tuple[0], basename, tag_tuple[1], suffix, tag_tuple[2])) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--only-ios', action='store_true', default=False) + parser.add_argument('--only-osx', action='store_true', default=False) + args = parser.parse_args() + + generate_source_and_headers(generate_osx=not args.only_ios, generate_ios=not args.only_osx) diff --git a/libffi/generate-ios-source-and-headers.py b/libffi/generate-ios-source-and-headers.py deleted file mode 100644 index c2bca73..0000000 --- a/libffi/generate-ios-source-and-headers.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python - -import subprocess -import re -import os -import errno -import collections -import sys - -class Platform(object): - pass - -sdk_re = re.compile(r'.*-sdk ([a-zA-Z0-9.]*)') - -def sdkinfo(sdkname): - ret = {} - for line in subprocess.Popen(['xcodebuild', '-sdk', sdkname, '-version'], stdout=subprocess.PIPE).stdout: - kv = line.strip().split(': ', 1) - if len(kv) == 2: - k,v = kv - ret[k] = v - return ret - -sim_sdk_info = sdkinfo('iphonesimulator') -device_sdk_info = sdkinfo('iphoneos') - -def latest_sdks(): - latest_sim = None - latest_device = None - for line in subprocess.Popen(['xcodebuild', '-showsdks'], stdout=subprocess.PIPE).stdout: - match = sdk_re.match(line) - if match: - if 'Simulator' in line: - latest_sim = match.group(1) - elif 'iOS' in line: - latest_device = match.group(1) - - return latest_sim, latest_device - -sim_sdk, device_sdk = latest_sdks() - -class simulator_platform(Platform): - sdk='iphonesimulator' - arch = 'i386' - name = 'simulator' - triple = 'i386-apple-darwin10' - sdkroot = sim_sdk_info['Path'] - - prefix = "#if !defined(__arm__) && defined(__i386__)\n\n" - suffix = "\n\n#endif" - -class device_platform(Platform): - sdk='iphoneos' - name = 'ios' - arch = 'armv7' - triple = 'arm-apple-darwin10' - sdkroot = device_sdk_info['Path'] - - prefix = "#ifdef __arm__\n\n" - suffix = "\n\n#endif" - - -def move_file(src_dir, dst_dir, filename, file_suffix=None, prefix='', suffix=''): - if not os.path.exists(dst_dir): - os.makedirs(dst_dir) - - out_filename = filename - - if file_suffix: - split_name = os.path.splitext(filename) - out_filename = "%s_%s%s" % (split_name[0], file_suffix, split_name[1]) - - with open(os.path.join(src_dir, filename)) as in_file: - with open(os.path.join(dst_dir, out_filename), 'w') as out_file: - if prefix: - out_file.write(prefix) - - out_file.write(in_file.read()) - - if suffix: - out_file.write(suffix) - -headers_seen = collections.defaultdict(set) - -def move_source_tree(src_dir, dest_dir, dest_include_dir, arch=None, prefix=None, suffix=None): - for root, dirs, files in os.walk(src_dir, followlinks=True): - relroot = os.path.relpath(root,src_dir) - - def move_dir(arch, prefix='', suffix='', files=[]): - for file in files: - file_suffix = None - if file.endswith('.h'): - if dest_include_dir: - file_suffix = arch - if arch: - headers_seen[file].add(arch) - move_file(root, dest_include_dir, file, arch, prefix=prefix, suffix=suffix) - - elif dest_dir: - outroot = os.path.join(dest_dir, relroot) - move_file(root, outroot, file, prefix=prefix, suffix=suffix) - - if relroot == '.': - move_dir(arch=arch, - files=files, - prefix=prefix, - suffix=suffix) - elif relroot == 'arm': - move_dir(arch='arm', - prefix="#ifdef __arm__\n\n", - suffix="\n\n#endif", - files=files) - elif relroot == 'x86': - move_dir(arch='i386', - prefix="#if !defined(__arm__) && defined(__i386__)\n\n", - suffix="\n\n#endif", - files=files) - -def build_target(platform): - def xcrun_cmd(cmd): - return subprocess.check_output(['xcrun', '-sdk', platform.sdkroot, '-find', cmd]).strip() - - build_dir = 'build_' + platform.name - if not os.path.exists(build_dir): - os.makedirs(build_dir) - env = dict(CC=xcrun_cmd('clang'), - LD=xcrun_cmd('ld'), - CFLAGS='-arch %s -isysroot %s -miphoneos-version-min=4.0' % (platform.arch, platform.sdkroot)) - working_dir=os.getcwd() - try: - os.chdir(build_dir) - subprocess.check_call(['../configure', '-host', platform.triple], env=env) - move_source_tree('.', None, '../ios/include', - arch=platform.arch, - prefix=platform.prefix, - suffix=platform.suffix) - move_source_tree('./include', None, '../ios/include', - arch=platform.arch, - prefix=platform.prefix, - suffix=platform.suffix) - finally: - os.chdir(working_dir) - - for header_name, archs in headers_seen.iteritems(): - basename, suffix = os.path.splitext(header_name) - -def main(): - move_source_tree('src', 'ios/src', 'ios/include') - move_source_tree('include', None, 'ios/include') - build_target(simulator_platform) - build_target(device_platform) - - for header_name, archs in headers_seen.iteritems(): - basename, suffix = os.path.splitext(header_name) - with open(os.path.join('ios/include', header_name), 'w') as header: - for arch in archs: - header.write('#include <%s_%s%s>\n' % (basename, arch, suffix)) - -if __name__ == '__main__': - main() diff --git a/libffi/generate-osx-source-and-headers.py b/libffi/generate-osx-source-and-headers.py deleted file mode 100644 index 64313c1..0000000 --- a/libffi/generate-osx-source-and-headers.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env python -import subprocess -import re -import os -import errno -import collections -import sys - -class Platform(object): - pass - -sdk_re = re.compile(r'.*-sdk ([a-zA-Z0-9.]*)') - -def sdkinfo(sdkname): - ret = {} - for line in subprocess.Popen(['xcodebuild', '-sdk', sdkname, '-version'], stdout=subprocess.PIPE).stdout: - kv = line.strip().split(': ', 1) - if len(kv) == 2: - k,v = kv - ret[k] = v - return ret - -desktop_sdk_info = sdkinfo('macosx') - -def latest_sdks(): - latest_desktop = None - for line in subprocess.Popen(['xcodebuild', '-showsdks'], stdout=subprocess.PIPE).stdout: - match = sdk_re.match(line) - if match: - if 'OS X' in line: - latest_desktop = match.group(1) - - return latest_desktop - -desktop_sdk = latest_sdks() - -class desktop_platform_32(Platform): - sdk='macosx' - arch = 'i386' - name = 'mac32' - triple = 'i386-apple-darwin10' - sdkroot = desktop_sdk_info['Path'] - - prefix = "#if defined(__i386__) && !defined(__x86_64__)\n\n" - suffix = "\n\n#endif" - -class desktop_platform_64(Platform): - sdk='macosx' - arch = 'x86_64' - name = 'mac' - triple = 'x86_64-apple-darwin10' - sdkroot = desktop_sdk_info['Path'] - - prefix = "#if !defined(__i386__) && defined(__x86_64__)\n\n" - suffix = "\n\n#endif" - -def move_file(src_dir, dst_dir, filename, file_suffix=None, prefix='', suffix=''): - if not os.path.exists(dst_dir): - os.makedirs(dst_dir) - - out_filename = filename - - if file_suffix: - split_name = os.path.splitext(filename) - out_filename = "%s_%s%s" % (split_name[0], file_suffix, split_name[1]) - - with open(os.path.join(src_dir, filename)) as in_file: - with open(os.path.join(dst_dir, out_filename), 'w') as out_file: - if prefix: - out_file.write(prefix) - - out_file.write(in_file.read()) - - if suffix: - out_file.write(suffix) - -headers_seen = collections.defaultdict(set) - -def move_source_tree(src_dir, dest_dir, dest_include_dir, arch=None, prefix=None, suffix=None): - for root, dirs, files in os.walk(src_dir, followlinks=True): - relroot = os.path.relpath(root,src_dir) - - def move_dir(arch, prefix='', suffix='', files=[]): - for file in files: - file_suffix = None - if file.endswith('.h'): - if dest_include_dir: - file_suffix = arch - if arch: - headers_seen[file].add(arch) - move_file(root, dest_include_dir, file, arch, prefix=prefix, suffix=suffix) - - elif dest_dir: - outroot = os.path.join(dest_dir, relroot) - move_file(root, outroot, file, prefix=prefix, suffix=suffix) - - if relroot == '.': - move_dir(arch=arch, - files=files, - prefix=prefix, - suffix=suffix) - elif relroot == 'x86': - move_dir(arch='i386', - prefix="#if defined(__i386__) && !defined(__x86_64__)\n\n", - suffix="\n\n#endif", - files=files) - move_dir(arch='x86_64', - prefix="#if !defined(__i386__) && defined(__x86_64__)\n\n", - suffix="\n\n#endif", - files=files) - -def build_target(platform): - def xcrun_cmd(cmd): - return subprocess.check_output(['xcrun', '-sdk', platform.sdkroot, '-find', cmd]).strip() - - build_dir = 'build_' + platform.name - if not os.path.exists(build_dir): - os.makedirs(build_dir) - env = dict(CC=xcrun_cmd('clang'), - LD=xcrun_cmd('ld'), - CFLAGS='-arch %s -isysroot %s -mmacosx-version-min=10.6' % (platform.arch, platform.sdkroot)) - working_dir=os.getcwd() - try: - os.chdir(build_dir) - subprocess.check_call(['../configure', '-host', platform.triple], env=env) - move_source_tree('.', None, '../osx/include', - arch=platform.arch, - prefix=platform.prefix, - suffix=platform.suffix) - move_source_tree('./include', None, '../osx/include', - arch=platform.arch, - prefix=platform.prefix, - suffix=platform.suffix) - finally: - os.chdir(working_dir) - - for header_name, archs in headers_seen.iteritems(): - basename, suffix = os.path.splitext(header_name) - -def main(): - move_source_tree('src', 'osx/src', 'osx/include') - move_source_tree('include', None, 'osx/include') - build_target(desktop_platform_32) - build_target(desktop_platform_64) - - for header_name, archs in headers_seen.iteritems(): - basename, suffix = os.path.splitext(header_name) - with open(os.path.join('osx/include', header_name), 'w') as header: - for arch in archs: - header.write('#include <%s_%s%s>\n' % (basename, arch, suffix)) - -if __name__ == '__main__': - main() diff --git a/libffi/include/Makefile.am b/libffi/include/Makefile.am index f11151e..79f222c 100644 --- a/libffi/include/Makefile.am +++ b/libffi/include/Makefile.am @@ -3,7 +3,8 @@ AUTOMAKE_OPTIONS=foreign DISTCLEANFILES=ffitarget.h -EXTRA_DIST=ffi.h.in ffi_common.h +noinst_HEADERS=ffi_common.h ffi_cfi.h +EXTRA_DIST=ffi.h.in # Where generated headers like ffitarget.h get installed. gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) diff --git a/libffi/include/Makefile.in b/libffi/include/Makefile.in index c923bf2..d8d17f1 100644 --- a/libffi/include/Makefile.in +++ b/libffi/include/Makefile.in @@ -37,7 +37,7 @@ host_triplet = @host@ target_triplet = @target@ subdir = include DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(srcdir)/ffi.h.in $(toollibffi_HEADERS) + $(srcdir)/ffi.h.in $(noinst_HEADERS) $(toollibffi_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ $(top_srcdir)/../config/asmcfi.m4 \ @@ -78,7 +78,7 @@ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(toollibffidir)" -HEADERS = $(toollibffi_HEADERS) +HEADERS = $(noinst_HEADERS) $(toollibffi_HEADERS) ETAGS = etags CTAGS = ctags ACLOCAL = @ACLOCAL@ @@ -99,6 +99,10 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ @@ -151,12 +155,14 @@ SHELL = @SHELL@ STRIP = @STRIP@ TARGET = @TARGET@ TARGETDIR = @TARGETDIR@ +TARGET_OBJ = @TARGET_OBJ@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ @@ -212,7 +218,8 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign DISTCLEANFILES = ffitarget.h -EXTRA_DIST = ffi.h.in ffi_common.h +noinst_HEADERS = ffi_common.h ffi_cfi.h +EXTRA_DIST = ffi.h.in # Where generated headers like ffitarget.h get installed. gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in index 380673b..c43d52f 100644 --- a/libffi/include/ffi.h.in +++ b/libffi/include/ffi.h.in @@ -1,5 +1,5 @@ /* -----------------------------------------------------------------*-C-*- - libffi @VERSION@ - Copyright (c) 2011 Anthony Green + libffi @VERSION@ - Copyright (c) 2011, 2014 Anthony Green - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. Permission is hereby granted, free of charge, to any person @@ -68,7 +68,7 @@ extern "C" { #ifndef LIBFFI_ASM -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) #define __attribute__(X) #endif @@ -166,25 +166,49 @@ typedef struct _ffi_type #error "long size not supported" #endif +/* Need minimal decorations for DLLs to works on Windows. */ +/* GCC has autoimport and autoexport. Rely on Libtool to */ +/* help MSVC export from a DLL, but always declare data */ +/* to be imported for MSVC clients. This costs an extra */ +/* indirection for MSVC clients using the static version */ +/* of the library, but don't worry about that. Besides, */ +/* as a workaround, they can define FFI_BUILDING if they */ +/* *know* they are going to link with the static library. */ +#if defined _MSC_VER && !defined FFI_BUILDING +#define FFI_EXTERN extern __declspec(dllimport) +#else +#define FFI_EXTERN extern +#endif + /* These are defined in types.c */ -extern ffi_type ffi_type_void; -extern ffi_type ffi_type_uint8; -extern ffi_type ffi_type_sint8; -extern ffi_type ffi_type_uint16; -extern ffi_type ffi_type_sint16; -extern ffi_type ffi_type_uint32; -extern ffi_type ffi_type_sint32; -extern ffi_type ffi_type_uint64; -extern ffi_type ffi_type_sint64; -extern ffi_type ffi_type_float; -extern ffi_type ffi_type_double; -extern ffi_type ffi_type_pointer; +FFI_EXTERN ffi_type ffi_type_void; +FFI_EXTERN ffi_type ffi_type_uint8; +FFI_EXTERN ffi_type ffi_type_sint8; +FFI_EXTERN ffi_type ffi_type_uint16; +FFI_EXTERN ffi_type ffi_type_sint16; +FFI_EXTERN ffi_type ffi_type_uint32; +FFI_EXTERN ffi_type ffi_type_sint32; +FFI_EXTERN ffi_type ffi_type_uint64; +FFI_EXTERN ffi_type ffi_type_sint64; +FFI_EXTERN ffi_type ffi_type_float; +FFI_EXTERN ffi_type ffi_type_double; +FFI_EXTERN ffi_type ffi_type_pointer; #if @HAVE_LONG_DOUBLE@ -extern ffi_type ffi_type_longdouble; +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 */ typedef enum { @@ -207,10 +231,10 @@ typedef struct { #endif } ffi_cif; -#if HAVE_LONG_DOUBLE_VARIANT +#if @HAVE_LONG_DOUBLE_VARIANT@ /* Used to adjust size/alignment of ffi types. */ void ffi_prep_types (ffi_abi abi); -# endif +#endif /* Used internally, but overridden by some architectures */ ffi_status ffi_prep_cif_core(ffi_cif *cif, @@ -288,7 +312,12 @@ size_t ffi_java_raw_size (ffi_cif *cif); __declspec(align(8)) #endif typedef struct { +#if @FFI_EXEC_TRAMPOLINE_TABLE@ + void *trampoline_table; + void *trampoline_table_entry; +#else char tramp[FFI_TRAMPOLINE_SIZE]; +#endif ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); void *user_data; @@ -321,8 +350,12 @@ ffi_prep_closure_loc (ffi_closure*, # pragma pack 8 #endif typedef struct { +#if @FFI_EXEC_TRAMPOLINE_TABLE@ + void *trampoline_table; + void *trampoline_table_entry; +#else char tramp[FFI_TRAMPOLINE_SIZE]; - +#endif ffi_cif *cif; #if !FFI_NATIVE_RAW_API @@ -342,7 +375,12 @@ typedef struct { } ffi_raw_closure; typedef struct { +#if @FFI_EXEC_TRAMPOLINE_TABLE@ + void *trampoline_table; + void *trampoline_table_entry; +#else char tramp[FFI_TRAMPOLINE_SIZE]; +#endif ffi_cif *cif; @@ -390,6 +428,22 @@ ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, #endif /* FFI_CLOSURES */ +#if FFI_GO_CLOSURES + +typedef struct { + void *tramp; + ffi_cif *cif; + void (*fun)(ffi_cif*,void*,void**,void*); +} ffi_go_closure; + +ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*)); + +void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure); + +#endif /* FFI_GO_CLOSURES */ + /* ---- Public interface definition -------------------------------------- */ ffi_status ffi_prep_cif(ffi_cif *cif, @@ -437,9 +491,10 @@ void ffi_call(ffi_cif *cif, #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_POINTER +#define FFI_TYPE_LAST FFI_TYPE_COMPLEX #ifdef __cplusplus } diff --git a/libffi/include/ffi_cfi.h b/libffi/include/ffi_cfi.h new file mode 100644 index 0000000..244ce57 --- /dev/null +++ b/libffi/include/ffi_cfi.h @@ -0,0 +1,55 @@ +/* ----------------------------------------------------------------------- + ffi_cfi.h - Copyright (c) 2014 Red Hat, Inc. + + Conditionally assemble cfi directives. Only necessary for building libffi. + ----------------------------------------------------------------------- */ + +#ifndef FFI_CFI_H +#define FFI_CFI_H + +#ifdef HAVE_AS_CFI_PSEUDO_OP + +# define cfi_startproc .cfi_startproc +# define cfi_endproc .cfi_endproc +# define cfi_def_cfa(reg, off) .cfi_def_cfa reg, off +# define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg +# define cfi_def_cfa_offset(off) .cfi_def_cfa_offset off +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +# define cfi_offset(reg, off) .cfi_offset reg, off +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +# define cfi_register(r1, r2) .cfi_register r1, r2 +# define cfi_return_column(reg) .cfi_return_column reg +# define cfi_restore(reg) .cfi_restore reg +# define cfi_same_value(reg) .cfi_same_value reg +# define cfi_undefined(reg) .cfi_undefined reg +# define cfi_remember_state .cfi_remember_state +# define cfi_restore_state .cfi_restore_state +# define cfi_window_save .cfi_window_save +# define cfi_personality(enc, exp) .cfi_personality enc, exp +# define cfi_lsda(enc, exp) .cfi_lsda enc, exp +# define cfi_escape(...) .cfi_escape __VA_ARGS__ + +#else + +# define cfi_startproc +# define cfi_endproc +# define cfi_def_cfa(reg, off) +# define cfi_def_cfa_register(reg) +# define cfi_def_cfa_offset(off) +# define cfi_adjust_cfa_offset(off) +# define cfi_offset(reg, off) +# define cfi_rel_offset(reg, off) +# define cfi_register(r1, r2) +# define cfi_return_column(reg) +# define cfi_restore(reg) +# define cfi_same_value(reg) +# define cfi_undefined(reg) +# define cfi_remember_state +# define cfi_restore_state +# define cfi_window_save +# define cfi_personality(enc, exp) +# define cfi_lsda(enc, exp) +# define cfi_escape(...) + +#endif /* HAVE_AS_CFI_PSEUDO_OP */ +#endif /* FFI_CFI_H */ diff --git a/libffi/include/ffi_common.h b/libffi/include/ffi_common.h index c179d68..37f5a9e 100644 --- a/libffi/include/ffi_common.h +++ b/libffi/include/ffi_common.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- - ffi_common.h - Copyright (C) 2011, 2012 Anthony Green + ffi_common.h - Copyright (C) 2011, 2012, 2013 Anthony Green Copyright (C) 2007 Free Software Foundation, Inc Copyright (c) 1996 Red Hat, Inc. @@ -19,10 +19,14 @@ extern "C" { /* Do not move this. Some versions of AIX are very picky about where this is positioned. */ #ifdef __GNUC__ -/* mingw64 defines this already in malloc.h. */ -#ifndef alloca -# define alloca __builtin_alloca -#endif +# if HAVE_ALLOCA_H +# include <alloca.h> +# else + /* mingw64 defines this already in malloc.h. */ +# ifndef alloca +# define alloca __builtin_alloca +# endif +# endif # define MAYBE_UNUSED __attribute__((__unused__)) #else # define MAYBE_UNUSED @@ -30,17 +34,17 @@ extern "C" { # include <alloca.h> # else # ifdef _AIX - #pragma alloca +# pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ # ifdef _MSC_VER # define alloca _alloca # else char *alloca (); -# endif # endif # endif # endif +# endif #endif /* Check for the existence of memcpy. */ @@ -87,7 +91,7 @@ typedef struct } extended_cif; /* Terse sized type definitions. */ -#if defined(_MSC_VER) || defined(__sgi) +#if defined(_MSC_VER) || defined(__sgi) || defined(__SUNPRO_C) typedef unsigned char UINT8; typedef signed char SINT8; typedef unsigned short UINT16; diff --git a/libffi/libffi.pc.in b/libffi/libffi.pc.in new file mode 100644 index 0000000..edf6fde --- /dev/null +++ b/libffi/libffi.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +toolexeclibdir=@toolexeclibdir@ +includedir=${libdir}/@PACKAGE_NAME@-@PACKAGE_VERSION@/include + +Name: @PACKAGE_NAME@ +Description: Library supporting Foreign Function Interfaces +Version: @PACKAGE_VERSION@ +Libs: -L${toolexeclibdir} -lffi +Cflags: -I${includedir} diff --git a/libffi/libffi.xcodeproj/project.pbxproj b/libffi/libffi.xcodeproj/project.pbxproj index 14c39a2..1cf396f 100644 --- a/libffi/libffi.xcodeproj/project.pbxproj +++ b/libffi/libffi.xcodeproj/project.pbxproj @@ -7,473 +7,448 @@ objects = { /* Begin PBXBuildFile section */ - 6C43CBDC1534F76F00162364 /* ffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CBBD1534F76F00162364 /* ffi.c */; }; - 6C43CBDD1534F76F00162364 /* sysv.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CBBF1534F76F00162364 /* sysv.S */; }; - 6C43CBDE1534F76F00162364 /* trampoline.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CBC01534F76F00162364 /* trampoline.S */; }; - 6C43CBE61534F76F00162364 /* darwin.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CBC91534F76F00162364 /* darwin.S */; }; - 6C43CBE81534F76F00162364 /* ffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CBCB1534F76F00162364 /* ffi.c */; }; - 6C43CC1F1534F77800162364 /* darwin.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC051534F77800162364 /* darwin.S */; }; - 6C43CC201534F77800162364 /* darwin64.S in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC061534F77800162364 /* darwin64.S */; }; - 6C43CC211534F77800162364 /* ffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC071534F77800162364 /* ffi.c */; }; - 6C43CC221534F77800162364 /* ffi64.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC081534F77800162364 /* ffi64.c */; }; - 6C43CC2F1534F7BE00162364 /* closures.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC281534F7BE00162364 /* closures.c */; }; - 6C43CC301534F7BE00162364 /* closures.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC281534F7BE00162364 /* closures.c */; }; - 6C43CC351534F7BE00162364 /* java_raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC2B1534F7BE00162364 /* java_raw_api.c */; }; - 6C43CC361534F7BE00162364 /* java_raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC2B1534F7BE00162364 /* java_raw_api.c */; }; - 6C43CC371534F7BE00162364 /* prep_cif.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC2C1534F7BE00162364 /* prep_cif.c */; }; - 6C43CC381534F7BE00162364 /* prep_cif.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC2C1534F7BE00162364 /* prep_cif.c */; }; - 6C43CC391534F7BE00162364 /* raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC2D1534F7BE00162364 /* raw_api.c */; }; - 6C43CC3A1534F7BE00162364 /* raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC2D1534F7BE00162364 /* raw_api.c */; }; - 6C43CC3B1534F7BE00162364 /* types.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC2E1534F7BE00162364 /* types.c */; }; - 6C43CC3C1534F7BE00162364 /* types.c in Sources */ = {isa = PBXBuildFile; fileRef = 6C43CC2E1534F7BE00162364 /* types.c */; }; - 6C43CC971535032600162364 /* ffi.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC8D1535032600162364 /* ffi.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CC981535032600162364 /* ffi_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC8E1535032600162364 /* ffi_common.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CC991535032600162364 /* ffi_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC8F1535032600162364 /* ffi_i386.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CC9A1535032600162364 /* ffi_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC901535032600162364 /* ffi_x86_64.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CC9B1535032600162364 /* fficonfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC911535032600162364 /* fficonfig.h */; }; - 6C43CC9C1535032600162364 /* fficonfig_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC921535032600162364 /* fficonfig_i386.h */; }; - 6C43CC9D1535032600162364 /* fficonfig_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC931535032600162364 /* fficonfig_x86_64.h */; }; - 6C43CC9E1535032600162364 /* ffitarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC941535032600162364 /* ffitarget.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CC9F1535032600162364 /* ffitarget_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC951535032600162364 /* ffitarget_i386.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CCA01535032600162364 /* ffitarget_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CC961535032600162364 /* ffitarget_x86_64.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CCAD1535039600162364 /* ffi.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCA21535039600162364 /* ffi.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CCAE1535039600162364 /* ffi_armv7.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCA31535039600162364 /* ffi_armv7.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CCAF1535039600162364 /* ffi_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCA41535039600162364 /* ffi_common.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CCB01535039600162364 /* ffi_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCA51535039600162364 /* ffi_i386.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CCB11535039600162364 /* fficonfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCA61535039600162364 /* fficonfig.h */; }; - 6C43CCB21535039600162364 /* fficonfig_armv7.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCA71535039600162364 /* fficonfig_armv7.h */; }; - 6C43CCB31535039600162364 /* fficonfig_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCA81535039600162364 /* fficonfig_i386.h */; }; - 6C43CCB41535039600162364 /* ffitarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCA91535039600162364 /* ffitarget.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CCB51535039600162364 /* ffitarget_arm.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCAA1535039600162364 /* ffitarget_arm.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CCB61535039600162364 /* ffitarget_armv7.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCAB1535039600162364 /* ffitarget_armv7.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C43CCB71535039600162364 /* ffitarget_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C43CCAC1535039600162364 /* ffitarget_i386.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DBFA714A187F1D8600A76262 /* ffi.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA713E187F1D8600A76262 /* ffi.h */; }; + DBFA714B187F1D8600A76262 /* ffi_common.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA713F187F1D8600A76262 /* ffi_common.h */; }; + DBFA714C187F1D8600A76262 /* fficonfig.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7140187F1D8600A76262 /* fficonfig.h */; }; + DBFA714D187F1D8600A76262 /* ffitarget.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7141187F1D8600A76262 /* ffitarget.h */; }; + DBFA714E187F1D8600A76262 /* closures.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7143187F1D8600A76262 /* closures.c */; }; + DBFA714F187F1D8600A76262 /* closures.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7143187F1D8600A76262 /* closures.c */; }; + DBFA7156187F1D8600A76262 /* prep_cif.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7147187F1D8600A76262 /* prep_cif.c */; }; + DBFA7157187F1D8600A76262 /* prep_cif.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7147187F1D8600A76262 /* prep_cif.c */; }; + DBFA7158187F1D8600A76262 /* raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7148187F1D8600A76262 /* raw_api.c */; }; + DBFA7159187F1D8600A76262 /* raw_api.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7148187F1D8600A76262 /* raw_api.c */; }; + DBFA715A187F1D8600A76262 /* types.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7149187F1D8600A76262 /* types.c */; }; + DBFA715B187F1D8600A76262 /* types.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7149187F1D8600A76262 /* types.c */; }; + DBFA7177187F1D9B00A76262 /* ffi_arm64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716C187F1D9B00A76262 /* ffi_arm64.c */; }; + DBFA7178187F1D9B00A76262 /* sysv_arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716D187F1D9B00A76262 /* sysv_arm64.S */; }; + DBFA7179187F1D9B00A76262 /* ffi_armv7.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA716F187F1D9B00A76262 /* ffi_armv7.c */; }; + DBFA717A187F1D9B00A76262 /* sysv_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7170187F1D9B00A76262 /* sysv_armv7.S */; }; + DBFA717B187F1D9B00A76262 /* trampoline_armv7.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */; }; + DBFA717C187F1D9B00A76262 /* darwin64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */; }; + DBFA717D187F1D9B00A76262 /* darwin_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7174187F1D9B00A76262 /* darwin_i386.S */; }; + DBFA717E187F1D9B00A76262 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */; }; + DBFA717F187F1D9B00A76262 /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA7176187F1D9B00A76262 /* ffi_i386.c */; }; + DBFA718E187F1DA100A76262 /* ffi_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7182187F1DA100A76262 /* ffi_i386.h */; }; + DBFA718F187F1DA100A76262 /* ffi_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7183187F1DA100A76262 /* ffi_x86_64.h */; }; + DBFA7190187F1DA100A76262 /* fficonfig_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7184187F1DA100A76262 /* fficonfig_i386.h */; }; + DBFA7191187F1DA100A76262 /* fficonfig_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */; }; + DBFA7192187F1DA100A76262 /* ffitarget_i386.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7186187F1DA100A76262 /* ffitarget_i386.h */; }; + DBFA7193187F1DA100A76262 /* ffitarget_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */; }; + DBFA7194187F1DA100A76262 /* darwin64_x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */; }; + DBFA7195187F1DA100A76262 /* darwin_i386.S in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718B187F1DA100A76262 /* darwin_i386.S */; }; + DBFA7196187F1DA100A76262 /* ffi64_x86_64.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */; }; + DBFA7197187F1DA100A76262 /* ffi_i386.c in Sources */ = {isa = PBXBuildFile; fileRef = DBFA718D187F1DA100A76262 /* ffi_i386.c */; }; /* End PBXBuildFile section */ +/* Begin PBXCopyFilesBuildPhase section */ + DB13B1641849DF1E0010F42D /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ - 6C43CB3D1534E9D100162364 /* libffi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 6C43CBBD1534F76F00162364 /* ffi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi.c; sourceTree = "<group>"; }; - 6C43CBBF1534F76F00162364 /* sysv.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv.S; sourceTree = "<group>"; }; - 6C43CBC01534F76F00162364 /* trampoline.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = trampoline.S; sourceTree = "<group>"; }; - 6C43CBC91534F76F00162364 /* darwin.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin.S; sourceTree = "<group>"; }; - 6C43CBCB1534F76F00162364 /* ffi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi.c; sourceTree = "<group>"; }; - 6C43CC051534F77800162364 /* darwin.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin.S; sourceTree = "<group>"; }; - 6C43CC061534F77800162364 /* darwin64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64.S; sourceTree = "<group>"; }; - 6C43CC071534F77800162364 /* ffi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi.c; sourceTree = "<group>"; }; - 6C43CC081534F77800162364 /* ffi64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64.c; sourceTree = "<group>"; }; - 6C43CC281534F7BE00162364 /* closures.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = closures.c; path = src/closures.c; sourceTree = SOURCE_ROOT; }; - 6C43CC2B1534F7BE00162364 /* java_raw_api.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = java_raw_api.c; path = src/java_raw_api.c; sourceTree = SOURCE_ROOT; }; - 6C43CC2C1534F7BE00162364 /* prep_cif.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = prep_cif.c; path = src/prep_cif.c; sourceTree = SOURCE_ROOT; }; - 6C43CC2D1534F7BE00162364 /* raw_api.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = raw_api.c; path = src/raw_api.c; sourceTree = SOURCE_ROOT; }; - 6C43CC2E1534F7BE00162364 /* types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = types.c; path = src/types.c; sourceTree = SOURCE_ROOT; }; - 6C43CC8D1535032600162364 /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = "<group>"; }; - 6C43CC8E1535032600162364 /* ffi_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_common.h; sourceTree = "<group>"; }; - 6C43CC8F1535032600162364 /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = "<group>"; }; - 6C43CC901535032600162364 /* ffi_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_x86_64.h; sourceTree = "<group>"; }; - 6C43CC911535032600162364 /* fficonfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig.h; sourceTree = "<group>"; }; - 6C43CC921535032600162364 /* fficonfig_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_i386.h; sourceTree = "<group>"; }; - 6C43CC931535032600162364 /* fficonfig_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_x86_64.h; sourceTree = "<group>"; }; - 6C43CC941535032600162364 /* ffitarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget.h; sourceTree = "<group>"; }; - 6C43CC951535032600162364 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = "<group>"; }; - 6C43CC961535032600162364 /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = "<group>"; }; - 6C43CCA21535039600162364 /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = "<group>"; }; - 6C43CCA31535039600162364 /* ffi_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_armv7.h; sourceTree = "<group>"; }; - 6C43CCA41535039600162364 /* ffi_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_common.h; sourceTree = "<group>"; }; - 6C43CCA51535039600162364 /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = "<group>"; }; - 6C43CCA61535039600162364 /* fficonfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig.h; sourceTree = "<group>"; }; - 6C43CCA71535039600162364 /* fficonfig_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_armv7.h; sourceTree = "<group>"; }; - 6C43CCA81535039600162364 /* fficonfig_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_i386.h; sourceTree = "<group>"; }; - 6C43CCA91535039600162364 /* ffitarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget.h; sourceTree = "<group>"; }; - 6C43CCAA1535039600162364 /* ffitarget_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_arm.h; sourceTree = "<group>"; }; - 6C43CCAB1535039600162364 /* ffitarget_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_armv7.h; sourceTree = "<group>"; }; - 6C43CCAC1535039600162364 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = "<group>"; }; - F6F980BA147386130008F121 /* libffi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DB13B1661849DF1E0010F42D /* libffi.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libffi.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DB13B1911849DF510010F42D /* ffi.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = ffi.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + DBFA713E187F1D8600A76262 /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = "<group>"; }; + DBFA713F187F1D8600A76262 /* ffi_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_common.h; sourceTree = "<group>"; }; + DBFA7140187F1D8600A76262 /* fficonfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig.h; sourceTree = "<group>"; }; + DBFA7141187F1D8600A76262 /* ffitarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget.h; sourceTree = "<group>"; }; + DBFA7143187F1D8600A76262 /* closures.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = closures.c; sourceTree = "<group>"; }; + DBFA7145187F1D8600A76262 /* dlmalloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dlmalloc.c; sourceTree = "<group>"; }; + DBFA7147187F1D8600A76262 /* prep_cif.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = prep_cif.c; sourceTree = "<group>"; }; + DBFA7148187F1D8600A76262 /* raw_api.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = raw_api.c; sourceTree = "<group>"; }; + DBFA7149187F1D8600A76262 /* types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = types.c; sourceTree = "<group>"; }; + DBFA715E187F1D9B00A76262 /* ffi_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_arm64.h; sourceTree = "<group>"; }; + DBFA715F187F1D9B00A76262 /* ffi_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_armv7.h; sourceTree = "<group>"; }; + DBFA7160187F1D9B00A76262 /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = "<group>"; }; + DBFA7161187F1D9B00A76262 /* ffi_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_x86_64.h; sourceTree = "<group>"; }; + DBFA7162187F1D9B00A76262 /* fficonfig_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_arm64.h; sourceTree = "<group>"; }; + DBFA7163187F1D9B00A76262 /* fficonfig_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_armv7.h; sourceTree = "<group>"; }; + DBFA7164187F1D9B00A76262 /* fficonfig_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_i386.h; sourceTree = "<group>"; }; + DBFA7165187F1D9B00A76262 /* fficonfig_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_x86_64.h; sourceTree = "<group>"; }; + DBFA7166187F1D9B00A76262 /* ffitarget_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_arm64.h; sourceTree = "<group>"; }; + DBFA7167187F1D9B00A76262 /* ffitarget_armv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_armv7.h; sourceTree = "<group>"; }; + DBFA7168187F1D9B00A76262 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = "<group>"; }; + DBFA7169187F1D9B00A76262 /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = "<group>"; }; + DBFA716C187F1D9B00A76262 /* ffi_arm64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_arm64.c; sourceTree = "<group>"; }; + DBFA716D187F1D9B00A76262 /* sysv_arm64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_arm64.S; sourceTree = "<group>"; }; + DBFA716F187F1D9B00A76262 /* ffi_armv7.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_armv7.c; sourceTree = "<group>"; }; + DBFA7170187F1D9B00A76262 /* sysv_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = sysv_armv7.S; sourceTree = "<group>"; }; + DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = trampoline_armv7.S; sourceTree = "<group>"; }; + DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64_x86_64.S; sourceTree = "<group>"; }; + DBFA7174187F1D9B00A76262 /* darwin_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin_i386.S; sourceTree = "<group>"; }; + DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = "<group>"; }; + DBFA7176187F1D9B00A76262 /* ffi_i386.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_i386.c; sourceTree = "<group>"; }; + DBFA7182187F1DA100A76262 /* ffi_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_i386.h; sourceTree = "<group>"; }; + DBFA7183187F1DA100A76262 /* ffi_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi_x86_64.h; sourceTree = "<group>"; }; + DBFA7184187F1DA100A76262 /* fficonfig_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_i386.h; sourceTree = "<group>"; }; + DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fficonfig_x86_64.h; sourceTree = "<group>"; }; + DBFA7186187F1DA100A76262 /* ffitarget_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_i386.h; sourceTree = "<group>"; }; + DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffitarget_x86_64.h; sourceTree = "<group>"; }; + DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin64_x86_64.S; sourceTree = "<group>"; }; + DBFA718B187F1DA100A76262 /* darwin_i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = darwin_i386.S; sourceTree = "<group>"; }; + DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi64_x86_64.c; sourceTree = "<group>"; }; + DBFA718D187F1DA100A76262 /* ffi_i386.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi_i386.c; sourceTree = "<group>"; }; /* End PBXFileReference section */ -/* Begin PBXFrameworksBuildPhase section */ - 6C43CB3A1534E9D100162364 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( +/* Begin PBXGroup section */ + DB13B15B1849DEB70010F42D = { + isa = PBXGroup; + children = ( + DBFA713C187F1D8600A76262 /* darwin_common */, + DBFA715C187F1D9B00A76262 /* darwin_ios */, + DBFA7180187F1DA100A76262 /* darwin_osx */, + DB13B1671849DF1E0010F42D /* Products */, ); - runOnlyForDeploymentPostprocessing = 0; + sourceTree = "<group>"; }; - F6F980B7147386130008F121 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( + DB13B1671849DF1E0010F42D /* Products */ = { + isa = PBXGroup; + children = ( + DB13B1661849DF1E0010F42D /* libffi.a */, + DB13B1911849DF510010F42D /* ffi.dylib */, ); - runOnlyForDeploymentPostprocessing = 0; + name = Products; + sourceTree = "<group>"; }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 6C43CBAF1534F76F00162364 /* iOS */ = { + DBFA713C187F1D8600A76262 /* darwin_common */ = { isa = PBXGroup; children = ( - 6C43CCA11535039600162364 /* include */, - 6C43CBBB1534F76F00162364 /* src */, + DBFA713D187F1D8600A76262 /* include */, + DBFA7142187F1D8600A76262 /* src */, ); - name = iOS; - path = ios; + path = "darwin_common"; sourceTree = "<group>"; }; - 6C43CBBB1534F76F00162364 /* src */ = { + DBFA713D187F1D8600A76262 /* include */ = { isa = PBXGroup; children = ( - 6C43CBC81534F76F00162364 /* x86 */, - 6C43CBBC1534F76F00162364 /* arm */, + DBFA713E187F1D8600A76262 /* ffi.h */, + DBFA713F187F1D8600A76262 /* ffi_common.h */, + DBFA7140187F1D8600A76262 /* fficonfig.h */, + DBFA7141187F1D8600A76262 /* ffitarget.h */, ); - path = src; + path = include; sourceTree = "<group>"; }; - 6C43CBBC1534F76F00162364 /* arm */ = { + DBFA7142187F1D8600A76262 /* src */ = { isa = PBXGroup; children = ( - 6C43CBBD1534F76F00162364 /* ffi.c */, - 6C43CBBF1534F76F00162364 /* sysv.S */, - 6C43CBC01534F76F00162364 /* trampoline.S */, + DBFA7143187F1D8600A76262 /* closures.c */, + DBFA7145187F1D8600A76262 /* dlmalloc.c */, + DBFA7147187F1D8600A76262 /* prep_cif.c */, + DBFA7148187F1D8600A76262 /* raw_api.c */, + DBFA7149187F1D8600A76262 /* types.c */, ); - path = arm; + path = src; sourceTree = "<group>"; }; - 6C43CBC81534F76F00162364 /* x86 */ = { + DBFA715C187F1D9B00A76262 /* darwin_ios */ = { isa = PBXGroup; children = ( - 6C43CBC91534F76F00162364 /* darwin.S */, - 6C43CBCB1534F76F00162364 /* ffi.c */, + DBFA715D187F1D9B00A76262 /* include */, + DBFA716A187F1D9B00A76262 /* src */, ); - path = x86; + path = "darwin_ios"; sourceTree = "<group>"; }; - 6C43CBF01534F77800162364 /* OS X */ = { + DBFA715D187F1D9B00A76262 /* include */ = { isa = PBXGroup; children = ( - 6C43CC8C1535032600162364 /* include */, - 6C43CBFC1534F77800162364 /* src */, + DBFA715E187F1D9B00A76262 /* ffi_arm64.h */, + DBFA715F187F1D9B00A76262 /* ffi_armv7.h */, + DBFA7160187F1D9B00A76262 /* ffi_i386.h */, + DBFA7161187F1D9B00A76262 /* ffi_x86_64.h */, + DBFA7162187F1D9B00A76262 /* fficonfig_arm64.h */, + DBFA7163187F1D9B00A76262 /* fficonfig_armv7.h */, + DBFA7164187F1D9B00A76262 /* fficonfig_i386.h */, + DBFA7165187F1D9B00A76262 /* fficonfig_x86_64.h */, + DBFA7166187F1D9B00A76262 /* ffitarget_arm64.h */, + DBFA7167187F1D9B00A76262 /* ffitarget_armv7.h */, + DBFA7168187F1D9B00A76262 /* ffitarget_i386.h */, + DBFA7169187F1D9B00A76262 /* ffitarget_x86_64.h */, ); - name = "OS X"; - path = osx; + path = include; sourceTree = "<group>"; }; - 6C43CBFC1534F77800162364 /* src */ = { + DBFA716A187F1D9B00A76262 /* src */ = { isa = PBXGroup; children = ( - 6C43CC041534F77800162364 /* x86 */, + DBFA716B187F1D9B00A76262 /* aarch64 */, + DBFA716E187F1D9B00A76262 /* arm */, + DBFA7172187F1D9B00A76262 /* x86 */, ); path = src; sourceTree = "<group>"; }; - 6C43CC041534F77800162364 /* x86 */ = { + DBFA716B187F1D9B00A76262 /* aarch64 */ = { isa = PBXGroup; children = ( - 6C43CC051534F77800162364 /* darwin.S */, - 6C43CC061534F77800162364 /* darwin64.S */, - 6C43CC071534F77800162364 /* ffi.c */, - 6C43CC081534F77800162364 /* ffi64.c */, + DBFA716C187F1D9B00A76262 /* ffi_arm64.c */, + DBFA716D187F1D9B00A76262 /* sysv_arm64.S */, ); - path = x86; + path = aarch64; sourceTree = "<group>"; }; - 6C43CC3D1534F7C400162364 /* src */ = { + DBFA716E187F1D9B00A76262 /* arm */ = { isa = PBXGroup; children = ( - 6C43CC281534F7BE00162364 /* closures.c */, - 6C43CC2B1534F7BE00162364 /* java_raw_api.c */, - 6C43CC2C1534F7BE00162364 /* prep_cif.c */, - 6C43CC2D1534F7BE00162364 /* raw_api.c */, - 6C43CC2E1534F7BE00162364 /* types.c */, - ); - name = src; - path = ios; + DBFA716F187F1D9B00A76262 /* ffi_armv7.c */, + DBFA7170187F1D9B00A76262 /* sysv_armv7.S */, + DBFA7171187F1D9B00A76262 /* trampoline_armv7.S */, + ); + path = arm; sourceTree = "<group>"; }; - 6C43CC8C1535032600162364 /* include */ = { + DBFA7172187F1D9B00A76262 /* x86 */ = { isa = PBXGroup; children = ( - 6C43CC8D1535032600162364 /* ffi.h */, - 6C43CC8E1535032600162364 /* ffi_common.h */, - 6C43CC8F1535032600162364 /* ffi_i386.h */, - 6C43CC901535032600162364 /* ffi_x86_64.h */, - 6C43CC911535032600162364 /* fficonfig.h */, - 6C43CC921535032600162364 /* fficonfig_i386.h */, - 6C43CC931535032600162364 /* fficonfig_x86_64.h */, - 6C43CC941535032600162364 /* ffitarget.h */, - 6C43CC951535032600162364 /* ffitarget_i386.h */, - 6C43CC961535032600162364 /* ffitarget_x86_64.h */, + DBFA7173187F1D9B00A76262 /* darwin64_x86_64.S */, + DBFA7174187F1D9B00A76262 /* darwin_i386.S */, + DBFA7175187F1D9B00A76262 /* ffi64_x86_64.c */, + DBFA7176187F1D9B00A76262 /* ffi_i386.c */, ); - path = include; + path = x86; + sourceTree = "<group>"; + }; + DBFA7180187F1DA100A76262 /* darwin_osx */ = { + isa = PBXGroup; + children = ( + DBFA7181187F1DA100A76262 /* include */, + DBFA7188187F1DA100A76262 /* src */, + ); + path = "darwin_osx"; sourceTree = "<group>"; }; - 6C43CCA11535039600162364 /* include */ = { + DBFA7181187F1DA100A76262 /* include */ = { isa = PBXGroup; children = ( - 6C43CCA21535039600162364 /* ffi.h */, - 6C43CCA31535039600162364 /* ffi_armv7.h */, - 6C43CCA41535039600162364 /* ffi_common.h */, - 6C43CCA51535039600162364 /* ffi_i386.h */, - 6C43CCA61535039600162364 /* fficonfig.h */, - 6C43CCA71535039600162364 /* fficonfig_armv7.h */, - 6C43CCA81535039600162364 /* fficonfig_i386.h */, - 6C43CCA91535039600162364 /* ffitarget.h */, - 6C43CCAA1535039600162364 /* ffitarget_arm.h */, - 6C43CCAB1535039600162364 /* ffitarget_armv7.h */, - 6C43CCAC1535039600162364 /* ffitarget_i386.h */, + DBFA7182187F1DA100A76262 /* ffi_i386.h */, + DBFA7183187F1DA100A76262 /* ffi_x86_64.h */, + DBFA7184187F1DA100A76262 /* fficonfig_i386.h */, + DBFA7185187F1DA100A76262 /* fficonfig_x86_64.h */, + DBFA7186187F1DA100A76262 /* ffitarget_i386.h */, + DBFA7187187F1DA100A76262 /* ffitarget_x86_64.h */, ); path = include; sourceTree = "<group>"; }; - F6B0839514721EE50031D8A1 = { + DBFA7188187F1DA100A76262 /* src */ = { isa = PBXGroup; children = ( - 6C43CC3D1534F7C400162364 /* src */, - 6C43CBAF1534F76F00162364 /* iOS */, - 6C43CBF01534F77800162364 /* OS X */, - F6F980C6147386260008F121 /* Products */, + DBFA7189187F1DA100A76262 /* x86 */, ); + path = src; sourceTree = "<group>"; }; - F6F980C6147386260008F121 /* Products */ = { + DBFA7189187F1DA100A76262 /* x86 */ = { isa = PBXGroup; children = ( - F6F980BA147386130008F121 /* libffi.a */, - 6C43CB3D1534E9D100162364 /* libffi.a */, + DBFA718A187F1DA100A76262 /* darwin64_x86_64.S */, + DBFA718B187F1DA100A76262 /* darwin_i386.S */, + DBFA718C187F1DA100A76262 /* ffi64_x86_64.c */, + DBFA718D187F1DA100A76262 /* ffi_i386.c */, ); - name = Products; - path = ../..; - sourceTree = BUILT_PRODUCTS_DIR; + path = x86; + sourceTree = "<group>"; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 6C43CB3B1534E9D100162364 /* Headers */ = { + DB13B18F1849DF510010F42D /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 6C43CC971535032600162364 /* ffi.h in Headers */, - 6C43CC981535032600162364 /* ffi_common.h in Headers */, - 6C43CC991535032600162364 /* ffi_i386.h in Headers */, - 6C43CC9A1535032600162364 /* ffi_x86_64.h in Headers */, - 6C43CC9E1535032600162364 /* ffitarget.h in Headers */, - 6C43CC9F1535032600162364 /* ffitarget_i386.h in Headers */, - 6C43CCA01535032600162364 /* ffitarget_x86_64.h in Headers */, - 6C43CC9B1535032600162364 /* fficonfig.h in Headers */, - 6C43CC9C1535032600162364 /* fficonfig_i386.h in Headers */, - 6C43CC9D1535032600162364 /* fficonfig_x86_64.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - F6F980B8147386130008F121 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 6C43CCAD1535039600162364 /* ffi.h in Headers */, - 6C43CCAE1535039600162364 /* ffi_armv7.h in Headers */, - 6C43CCAF1535039600162364 /* ffi_common.h in Headers */, - 6C43CCB01535039600162364 /* ffi_i386.h in Headers */, - 6C43CCB41535039600162364 /* ffitarget.h in Headers */, - 6C43CCB51535039600162364 /* ffitarget_arm.h in Headers */, - 6C43CCB61535039600162364 /* ffitarget_armv7.h in Headers */, - 6C43CCB71535039600162364 /* ffitarget_i386.h in Headers */, - 6C43CCB11535039600162364 /* fficonfig.h in Headers */, - 6C43CCB21535039600162364 /* fficonfig_armv7.h in Headers */, - 6C43CCB31535039600162364 /* fficonfig_i386.h in Headers */, + DBFA714C187F1D8600A76262 /* fficonfig.h in Headers */, + DBFA714D187F1D8600A76262 /* ffitarget.h in Headers */, + DBFA714A187F1D8600A76262 /* ffi.h in Headers */, + DBFA718F187F1DA100A76262 /* ffi_x86_64.h in Headers */, + DBFA7191187F1DA100A76262 /* fficonfig_x86_64.h in Headers */, + DBFA718E187F1DA100A76262 /* ffi_i386.h in Headers */, + DBFA7190187F1DA100A76262 /* fficonfig_i386.h in Headers */, + DBFA714B187F1D8600A76262 /* ffi_common.h in Headers */, + DBFA7193187F1DA100A76262 /* ffitarget_x86_64.h in Headers */, + DBFA7192187F1DA100A76262 /* ffitarget_i386.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 6C43CB3C1534E9D100162364 /* libffi OS X */ = { + DB13B1651849DF1E0010F42D /* libffi-iOS */ = { isa = PBXNativeTarget; - buildConfigurationList = 6C43CB4A1534E9D100162364 /* Build configuration list for PBXNativeTarget "libffi OS X" */; + buildConfigurationList = DB13B18B1849DF1E0010F42D /* Build configuration list for PBXNativeTarget "libffi-iOS" */; buildPhases = ( - 6C43CC401534FF3B00162364 /* Generate Source and Headers */, - 6C43CB391534E9D100162364 /* Sources */, - 6C43CB3A1534E9D100162364 /* Frameworks */, - 6C43CB3B1534E9D100162364 /* Headers */, + DB13B3051849E01C0010F42D /* ShellScript */, + DB13B1621849DF1E0010F42D /* Sources */, + DB13B1641849DF1E0010F42D /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); - name = "libffi OS X"; - productName = "ffi OS X"; - productReference = 6C43CB3D1534E9D100162364 /* libffi.a */; + name = "libffi-iOS"; + productName = ffi; + productReference = DB13B1661849DF1E0010F42D /* libffi.a */; productType = "com.apple.product-type.library.static"; }; - F6F980B9147386130008F121 /* libffi iOS */ = { + DB13B1901849DF510010F42D /* libffi-Mac */ = { isa = PBXNativeTarget; - buildConfigurationList = F6F980C4147386130008F121 /* Build configuration list for PBXNativeTarget "libffi iOS" */; + buildConfigurationList = DB13B1B01849DF520010F42D /* Build configuration list for PBXNativeTarget "libffi-Mac" */; buildPhases = ( - 6C43CC3E1534F8E200162364 /* Generate Trampoline */, - 6C43CC3F1534FF1B00162364 /* Generate Source and Headers */, - F6F980B6147386130008F121 /* Sources */, - F6F980B7147386130008F121 /* Frameworks */, - F6F980B8147386130008F121 /* Headers */, + DB13B3061849E0490010F42D /* ShellScript */, + DB13B18D1849DF510010F42D /* Sources */, + DB13B18F1849DF510010F42D /* Headers */, ); buildRules = ( ); dependencies = ( ); - name = "libffi iOS"; + name = "libffi-Mac"; productName = ffi; - productReference = F6F980BA147386130008F121 /* libffi.a */; - productType = "com.apple.product-type.library.static"; + productReference = DB13B1911849DF510010F42D /* ffi.dylib */; + productType = "com.apple.product-type.library.dynamic"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - F6B0839714721EE50031D8A1 /* Project object */ = { + DB13B15C1849DEB70010F42D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0430; + LastUpgradeCheck = 0510; }; - buildConfigurationList = F6B0839A14721EE50031D8A1 /* Build configuration list for PBXProject "libffi" */; + buildConfigurationList = DB13B15F1849DEB70010F42D /* Build configuration list for PBXProject "libffi" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); - mainGroup = F6B0839514721EE50031D8A1; - productRefGroup = F6B0839514721EE50031D8A1; + mainGroup = DB13B15B1849DEB70010F42D; + productRefGroup = DB13B1671849DF1E0010F42D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - F6F980B9147386130008F121 /* libffi iOS */, - 6C43CB3C1534E9D100162364 /* libffi OS X */, + DB13B1651849DF1E0010F42D /* libffi-iOS */, + DB13B1901849DF510010F42D /* libffi-Mac */, ); }; /* End PBXProject section */ /* Begin PBXShellScriptBuildPhase section */ - 6C43CC3E1534F8E200162364 /* Generate Trampoline */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Generate Trampoline"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /usr/bin/python; - shellScript = "import subprocess\nimport re\nimport os\nimport errno\nimport sys\n\ndef main():\n with open('src/arm/trampoline.S', 'w') as tramp_out:\n p = subprocess.Popen(['bash', 'src/arm/gentramp.sh'], stdout=tramp_out)\n p.wait()\n\nif __name__ == '__main__':\n main()"; - }; - 6C43CC3F1534FF1B00162364 /* Generate Source and Headers */ = { + DB13B3051849E01C0010F42D /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Generate Source and Headers"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/usr/bin/python generate-ios-source-and-headers.py"; + shellScript = "/usr/bin/python generate-darwin-source-and-headers.py --only-ios"; }; - 6C43CC401534FF3B00162364 /* Generate Source and Headers */ = { + DB13B3061849E0490010F42D /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Generate Source and Headers"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/usr/bin/python generate-osx-source-and-headers.py"; + shellScript = "/usr/bin/python generate-darwin-source-and-headers.py --only-osx"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 6C43CB391534E9D100162364 /* Sources */ = { + DB13B1621849DF1E0010F42D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6C43CC1F1534F77800162364 /* darwin.S in Sources */, - 6C43CC201534F77800162364 /* darwin64.S in Sources */, - 6C43CC211534F77800162364 /* ffi.c in Sources */, - 6C43CC221534F77800162364 /* ffi64.c in Sources */, - 6C43CC301534F7BE00162364 /* closures.c in Sources */, - 6C43CC361534F7BE00162364 /* java_raw_api.c in Sources */, - 6C43CC381534F7BE00162364 /* prep_cif.c in Sources */, - 6C43CC3A1534F7BE00162364 /* raw_api.c in Sources */, - 6C43CC3C1534F7BE00162364 /* types.c in Sources */, + DBFA717E187F1D9B00A76262 /* ffi64_x86_64.c in Sources */, + DBFA7179187F1D9B00A76262 /* ffi_armv7.c in Sources */, + DBFA717B187F1D9B00A76262 /* trampoline_armv7.S in Sources */, + DBFA714E187F1D8600A76262 /* closures.c in Sources */, + DBFA717A187F1D9B00A76262 /* sysv_armv7.S in Sources */, + DBFA717D187F1D9B00A76262 /* darwin_i386.S in Sources */, + DBFA7156187F1D8600A76262 /* prep_cif.c in Sources */, + DBFA717F187F1D9B00A76262 /* ffi_i386.c in Sources */, + DBFA7158187F1D8600A76262 /* raw_api.c in Sources */, + DBFA7178187F1D9B00A76262 /* sysv_arm64.S in Sources */, + DBFA717C187F1D9B00A76262 /* darwin64_x86_64.S in Sources */, + DBFA715A187F1D8600A76262 /* types.c in Sources */, + DBFA7177187F1D9B00A76262 /* ffi_arm64.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - F6F980B6147386130008F121 /* Sources */ = { + DB13B18D1849DF510010F42D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6C43CBDC1534F76F00162364 /* ffi.c in Sources */, - 6C43CBDD1534F76F00162364 /* sysv.S in Sources */, - 6C43CBDE1534F76F00162364 /* trampoline.S in Sources */, - 6C43CBE61534F76F00162364 /* darwin.S in Sources */, - 6C43CBE81534F76F00162364 /* ffi.c in Sources */, - 6C43CC2F1534F7BE00162364 /* closures.c in Sources */, - 6C43CC351534F7BE00162364 /* java_raw_api.c in Sources */, - 6C43CC371534F7BE00162364 /* prep_cif.c in Sources */, - 6C43CC391534F7BE00162364 /* raw_api.c in Sources */, - 6C43CC3B1534F7BE00162364 /* types.c in Sources */, + DBFA7196187F1DA100A76262 /* ffi64_x86_64.c in Sources */, + DBFA7195187F1DA100A76262 /* darwin_i386.S in Sources */, + DBFA7157187F1D8600A76262 /* prep_cif.c in Sources */, + DBFA7197187F1DA100A76262 /* ffi_i386.c in Sources */, + DBFA715B187F1D8600A76262 /* types.c in Sources */, + DBFA7159187F1D8600A76262 /* raw_api.c in Sources */, + DBFA714F187F1D8600A76262 /* closures.c in Sources */, + DBFA7194187F1DA100A76262 /* darwin64_x86_64.S in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 6C43CB4B1534E9D100162364 /* Debug */ = { + DB13B1601849DEB70010F42D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - DSTROOT = /tmp/ffi.dst; - FRAMEWORK_SEARCH_PATHS = ( + HEADER_SEARCH_PATHS = ( "$(inherited)", - "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"", + "darwin_common/include", ); - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = YES; - PRODUCT_NAME = ffi; - SDKROOT = macosx; }; name = Debug; }; - 6C43CB4C1534E9D100162364 /* Release */ = { + DB13B1611849DEB70010F42D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DSTROOT = /tmp/ffi.dst; - FRAMEWORK_SEARCH_PATHS = ( + HEADER_SEARCH_PATHS = ( "$(inherited)", - "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"", + "darwin_common/include", ); - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - MACOSX_DEPLOYMENT_TARGET = 10.6; - PRODUCT_NAME = ffi; - SDKROOT = macosx; }; name = Release; }; - F6B083AB14721EE50031D8A1 /* Debug */ = { + DB13B1871849DF1E0010F42D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DSTROOT = /tmp/ffi.dst; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -482,98 +457,181 @@ "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ios/include; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "darwin_ios/include", + ); + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + "IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ffi; SDKROOT = iphoneos; + SKIP_INSTALL = YES; }; name = Debug; }; - F6B083AC14721EE50031D8A1 /* Release */ = { + DB13B1881849DF1E0010F42D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; + DSTROOT = /tmp/ffi.dst; + ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_PREPROCESSOR_DEFINITIONS = ""; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ios/include; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "darwin_ios/include", + ); + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + "IPHONEOS_DEPLOYMENT_TARGET[arch=arm64]" = 7.0; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ffi; SDKROOT = iphoneos; + SKIP_INSTALL = YES; VALIDATE_PRODUCT = YES; }; name = Release; }; - F6F980C2147386130008F121 /* Debug */ = { + DB13B1B11849DF520010F42D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = ( - armv6, - armv7, + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", ); - DSTROOT = /tmp/ffi.dst; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_THUMB_SUPPORT = NO; - IPHONEOS_DEPLOYMENT_TARGET = 4.0; - OTHER_LDFLAGS = "-ObjC"; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "darwin_osx/include", + ); + MACOSX_DEPLOYMENT_TARGET = 10.6; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = "-Wl,-no_compact_unwind"; PRODUCT_NAME = ffi; - SKIP_INSTALL = YES; + SDKROOT = macosx; }; name = Debug; }; - F6F980C3147386130008F121 /* Release */ = { + DB13B1B21849DF520010F42D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = ( - armv6, - armv7, + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "darwin_osx/include", ); - DSTROOT = /tmp/ffi.dst; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_THUMB_SUPPORT = NO; - IPHONEOS_DEPLOYMENT_TARGET = 4.0; - OTHER_LDFLAGS = "-ObjC"; + MACOSX_DEPLOYMENT_TARGET = 10.6; + OTHER_LDFLAGS = "-Wl,-no_compact_unwind"; PRODUCT_NAME = ffi; - SKIP_INSTALL = YES; + SDKROOT = macosx; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 6C43CB4A1534E9D100162364 /* Build configuration list for PBXNativeTarget "libffi OS X" */ = { + DB13B15F1849DEB70010F42D /* Build configuration list for PBXProject "libffi" */ = { isa = XCConfigurationList; buildConfigurations = ( - 6C43CB4B1534E9D100162364 /* Debug */, - 6C43CB4C1534E9D100162364 /* Release */, + DB13B1601849DEB70010F42D /* Debug */, + DB13B1611849DEB70010F42D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - F6B0839A14721EE50031D8A1 /* Build configuration list for PBXProject "libffi" */ = { + DB13B18B1849DF1E0010F42D /* Build configuration list for PBXNativeTarget "libffi-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( - F6B083AB14721EE50031D8A1 /* Debug */, - F6B083AC14721EE50031D8A1 /* Release */, + DB13B1871849DF1E0010F42D /* Debug */, + DB13B1881849DF1E0010F42D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - F6F980C4147386130008F121 /* Build configuration list for PBXNativeTarget "libffi iOS" */ = { + DB13B1B01849DF520010F42D /* Build configuration list for PBXNativeTarget "libffi-Mac" */ = { isa = XCConfigurationList; buildConfigurations = ( - F6F980C2147386130008F121 /* Debug */, - F6F980C3147386130008F121 /* Release */, + DB13B1B11849DF520010F42D /* Debug */, + DB13B1B21849DF520010F42D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; - rootObject = F6B0839714721EE50031D8A1 /* Project object */; + rootObject = DB13B15C1849DEB70010F42D /* Project object */; } diff --git a/libffi/man/Makefile.in b/libffi/man/Makefile.in index 743e67b7..39f6cbf 100644 --- a/libffi/man/Makefile.in +++ b/libffi/man/Makefile.in @@ -97,6 +97,10 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ @@ -149,12 +153,14 @@ SHELL = @SHELL@ STRIP = @STRIP@ TARGET = @TARGET@ TARGETDIR = @TARGETDIR@ +TARGET_OBJ = @TARGET_OBJ@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ diff --git a/libffi/man/ffi_prep_cif.3 b/libffi/man/ffi_prep_cif.3 index e1bdbd7..ab2be8a 100644 --- a/libffi/man/ffi_prep_cif.3 +++ b/libffi/man/ffi_prep_cif.3 @@ -61,10 +61,8 @@ does not refer to a valid ABI, .Nm FFI_BAD_ABI will be returned. Available ABIs are defined in -.Nm <ffitarget.h> -. +.Nm <ffitarget.h> . .Sh SEE ALSO .Xr ffi 3 , .Xr ffi_call 3 , .Xr ffi_prep_cif_var 3 - diff --git a/libffi/msvcc.sh b/libffi/msvcc.sh index dcdbeab..65fbfef 100755 --- a/libffi/msvcc.sh +++ b/libffi/msvcc.sh @@ -42,8 +42,10 @@ # format and translated into something sensible for cl or ml. # +args_orig=$@ args="-nologo -W3" -md=-MD +static_crt= +debug_crt= cl="cl" ml="ml" safeseh="-safeseh" @@ -62,31 +64,65 @@ do shift 1 ;; -m64) - cl="cl" # "$MSVC/x86_amd64/cl" ml="ml64" # "$MSVC/x86_amd64/ml64" safeseh= shift 1 ;; + -clang-cl) + cl="clang-cl" + safeseh= + shift 1 + ;; -O0) args="$args -Od" shift 1 ;; -O*) - # If we're optimizing, make sure we explicitly turn on some optimizations - # that are implicitly disabled by debug symbols (-Zi). - args="$args $1 -OPT:REF -OPT:ICF -INCREMENTAL:NO" + # Runtime error checks (enabled by setting -RTC1 in the -DFFI_DEBUG + # case below) are not compatible with optimization flags and will + # cause the build to fail. Therefore, drop the optimization flag if + # -DFFI_DEBUG is also set. + case $args_orig in + *-DFFI_DEBUG*) + args="$args" + ;; + *) + # The ax_cc_maxopt.m4 macro from the upstream autoconf-archive + # project doesn't support MSVC and therefore ends up trying to + # use -O3. Use the equivalent "max optimization" flag for MSVC + # instead of erroring out. + case $1 in + -O3) + args="$args -O2" + ;; + *) + args="$args $1" + ;; + esac + opt="true" + ;; + esac shift 1 ;; -g) # Enable debug symbol generation. - args="$args -Zi -DEBUG" + args="$args -Zi" shift 1 ;; -DFFI_DEBUG) - # Link against debug CRT and enable runtime error checks. + # Enable runtime error checks. args="$args -RTC1" defines="$defines $1" - md=-MDd + shift 1 + ;; + -DUSE_STATIC_RTL) + # Link against static CRT. + static_crt=1 + shift 1 + ;; + -DUSE_DEBUG_RTL) + # Link against debug CRT. + debug_crt=1 shift 1 ;; -c) @@ -126,6 +162,10 @@ do # to do here. shift 1 ;; + -pedantic) + # libffi tests -pedantic with -Wall, so drop it also. + shift 1 + ;; -Werror) args="$args -WX" shift 1 @@ -170,6 +210,23 @@ do esac done +# If -Zi is specified, certain optimizations are implicitly disabled +# by MSVC. Add back those optimizations if this is an optimized build. +# NOTE: These arguments must come after all others. +if [ -n "$opt" ]; then + args="$args -link -OPT:REF -OPT:ICF -INCREMENTAL:NO" +fi + +if [ -n "$static_crt" ]; then + md=-MT +else + md=-MD +fi + +if [ -n "$debug_crt" ]; then + md="${md}d" +fi + if [ -n "$assembly" ]; then if [ -z "$outdir" ]; then outdir="." @@ -189,7 +246,10 @@ if [ -n "$assembly" ]; then else args="$md $args" echo "$cl $args" - eval "\"$cl\" $args" + # Return an error code of 1 if an invalid command line parameter is passed + # instead of just ignoring it. + eval "(\"$cl\" $args 2>&1 1>&3 | \ + awk '{print \$0} /D9002/ {error=1} END{exit error}' >&2) 3>&1" result=$? fi diff --git a/libffi/src/aarch64/ffi.c b/libffi/src/aarch64/ffi.c index 1405665..0cace9d 100644 --- a/libffi/src/aarch64/ffi.c +++ b/libffi/src/aarch64/ffi.c @@ -20,19 +20,22 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include <stdio.h> - +#include <stdlib.h> +#include <stdint.h> #include <ffi.h> #include <ffi_common.h> - -#include <stdlib.h> - -/* Stack alignment requirement in bytes */ -#define AARCH64_STACK_ALIGN 16 - -#define N_X_ARG_REG 8 -#define N_V_ARG_REG 8 - -#define AARCH64_FFI_WITH_V (1 << AARCH64_FFI_WITH_V_BIT) +#include "internal.h" + +/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; + all further uses in this file will refer to the 128-bit type. */ +#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE +# if FFI_TYPE_LONGDOUBLE != 4 +# error FFI_TYPE_LONGDOUBLE out of date +# endif +#else +# undef FFI_TYPE_LONGDOUBLE +# define FFI_TYPE_LONGDOUBLE 4 +#endif union _d { @@ -40,321 +43,184 @@ union _d UINT32 s[2]; }; -struct call_context +struct _v { - UINT64 x [AARCH64_N_XREG]; - struct - { - union _d d[2]; - } v [AARCH64_N_VREG]; + union _d d[2] __attribute__((aligned(16))); }; -static void * -get_x_addr (struct call_context *context, unsigned n) +struct call_context { - return &context->x[n]; -} + struct _v v[N_V_ARG_REG]; + UINT64 x[N_X_ARG_REG]; +}; -static void * -get_s_addr (struct call_context *context, unsigned n) -{ -#if defined __AARCH64EB__ - return &context->v[n].d[1].s[1]; -#else - return &context->v[n].d[0].s[0]; +#if defined (__clang__) && defined (__APPLE__) +extern void sys_icache_invalidate (void *start, size_t len); #endif -} -static void * -get_d_addr (struct call_context *context, unsigned n) +static inline void +ffi_clear_cache (void *start, void *end) { -#if defined __AARCH64EB__ - return &context->v[n].d[1]; +#if defined (__clang__) && defined (__APPLE__) + sys_icache_invalidate (start, (char *)end - (char *)start); +#elif defined (__GNUC__) + __builtin___clear_cache (start, end); #else - return &context->v[n].d[0]; +#error "Missing builtin to flush instruction cache" #endif } -static void * -get_v_addr (struct call_context *context, unsigned n) -{ - return &context->v[n]; -} - -/* Return the memory location at which a basic type would reside - were it to have been stored in register n. */ - -static void * -get_basic_type_addr (unsigned short type, struct call_context *context, - unsigned n) -{ - switch (type) - { - case FFI_TYPE_FLOAT: - return get_s_addr (context, n); - case FFI_TYPE_DOUBLE: - return get_d_addr (context, n); - case FFI_TYPE_LONGDOUBLE: - return get_v_addr (context, n); - case FFI_TYPE_UINT8: - case FFI_TYPE_SINT8: - case FFI_TYPE_UINT16: - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT32: - case FFI_TYPE_SINT32: - case FFI_TYPE_INT: - case FFI_TYPE_POINTER: - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: - return get_x_addr (context, n); - default: - FFI_ASSERT (0); - return NULL; - } -} - -/* Return the alignment width for each of the basic types. */ - -static size_t -get_basic_type_alignment (unsigned short type) -{ - switch (type) - { - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - return sizeof (UINT64); - case FFI_TYPE_LONGDOUBLE: - return sizeof (long double); - case FFI_TYPE_UINT8: - case FFI_TYPE_SINT8: - case FFI_TYPE_UINT16: - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT32: - case FFI_TYPE_INT: - case FFI_TYPE_SINT32: - case FFI_TYPE_POINTER: - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: - return sizeof (UINT64); - - default: - FFI_ASSERT (0); - return 0; - } -} - -/* Return the size in bytes for each of the basic types. */ +/* A subroutine of is_vfp_type. Given a structure type, return the type code + of the first non-structure element. Recurse for structure elements. + Return -1 if the structure is in fact empty, i.e. no nested elements. */ -static size_t -get_basic_type_size (unsigned short type) +static int +is_hfa0 (const ffi_type *ty) { - switch (type) - { - case FFI_TYPE_FLOAT: - return sizeof (UINT32); - case FFI_TYPE_DOUBLE: - return sizeof (UINT64); - case FFI_TYPE_LONGDOUBLE: - return sizeof (long double); - case FFI_TYPE_UINT8: - return sizeof (UINT8); - case FFI_TYPE_SINT8: - return sizeof (SINT8); - case FFI_TYPE_UINT16: - return sizeof (UINT16); - case FFI_TYPE_SINT16: - return sizeof (SINT16); - case FFI_TYPE_UINT32: - return sizeof (UINT32); - case FFI_TYPE_INT: - case FFI_TYPE_SINT32: - return sizeof (SINT32); - case FFI_TYPE_POINTER: - case FFI_TYPE_UINT64: - return sizeof (UINT64); - case FFI_TYPE_SINT64: - return sizeof (SINT64); - - default: - FFI_ASSERT (0); - return 0; - } -} - -extern void -ffi_call_SYSV (unsigned (*)(struct call_context *context, unsigned char *, - extended_cif *), - struct call_context *context, - extended_cif *, - unsigned, - void (*fn)(void)); + ffi_type **elements = ty->elements; + int i, ret = -1; -extern void -ffi_closure_SYSV (ffi_closure *); - -/* Test for an FFI floating point representation. */ + if (elements != NULL) + for (i = 0; elements[i]; ++i) + { + ret = elements[i]->type; + if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX) + { + ret = is_hfa0 (elements[i]); + if (ret < 0) + continue; + } + break; + } -static unsigned -is_floating_type (unsigned short type) -{ - return (type == FFI_TYPE_FLOAT || type == FFI_TYPE_DOUBLE - || type == FFI_TYPE_LONGDOUBLE); + return ret; } -/* Test for a homogeneous structure. */ +/* A subroutine of is_vfp_type. Given a structure type, return true if all + of the non-structure elements are the same as CANDIDATE. */ -static unsigned short -get_homogeneous_type (ffi_type *ty) +static int +is_hfa1 (const ffi_type *ty, int candidate) { - if (ty->type == FFI_TYPE_STRUCT && ty->elements) - { - unsigned i; - unsigned short candidate_type - = get_homogeneous_type (ty->elements[0]); - for (i =1; ty->elements[i]; i++) - { - unsigned short iteration_type = 0; - /* If we have a nested struct, we must find its homogeneous type. - If that fits with our candidate type, we are still - homogeneous. */ - if (ty->elements[i]->type == FFI_TYPE_STRUCT - && ty->elements[i]->elements) - { - iteration_type = get_homogeneous_type (ty->elements[i]); - } - else - { - iteration_type = ty->elements[i]->type; - } + ffi_type **elements = ty->elements; + int i; - /* If we are not homogeneous, return FFI_TYPE_STRUCT. */ - if (candidate_type != iteration_type) - return FFI_TYPE_STRUCT; - } - return candidate_type; - } + if (elements != NULL) + for (i = 0; elements[i]; ++i) + { + int t = elements[i]->type; + if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) + { + if (!is_hfa1 (elements[i], candidate)) + return 0; + } + else if (t != candidate) + return 0; + } - /* Base case, we have no more levels of nesting, so we - are a basic type, and so, trivially homogeneous in that type. */ - return ty->type; + return 1; } -/* Determine the number of elements within a STRUCT. - - Note, we must handle nested structs. +/* Determine if TY may be allocated to the FP registers. This is both an + fp scalar type as well as an homogenous floating point aggregate (HFA). + That is, a structure consisting of 1 to 4 members of all the same type, + where that type is an fp scalar. - If ty is not a STRUCT this function will return 0. */ + Returns non-zero iff TY is an HFA. The result is the AARCH64_RET_* + constant for the type. */ -static unsigned -element_count (ffi_type *ty) +static int +is_vfp_type (const ffi_type *ty) { - if (ty->type == FFI_TYPE_STRUCT && ty->elements) + ffi_type **elements; + int candidate, i; + size_t size, ele_count; + + /* Quickest tests first. */ + candidate = ty->type; + switch (candidate) { - unsigned n; - unsigned elems = 0; - for (n = 0; ty->elements[n]; n++) + default: + return 0; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + ele_count = 1; + goto done; + case FFI_TYPE_COMPLEX: + candidate = ty->elements[0]->type; + switch (candidate) { - if (ty->elements[n]->type == FFI_TYPE_STRUCT - && ty->elements[n]->elements) - elems += element_count (ty->elements[n]); - else - elems++; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + ele_count = 2; + goto done; } - return elems; + return 0; + case FFI_TYPE_STRUCT: + break; } - return 0; -} - -/* Test for a homogeneous floating point aggregate. - A homogeneous floating point aggregate is a homogeneous aggregate of - a half- single- or double- precision floating point type with one - to four elements. Note that this includes nested structs of the - basic type. */ + /* No HFA types are smaller than 4 bytes, or larger than 64 bytes. */ + size = ty->size; + if (size < 4 || size > 64) + return 0; -static int -is_hfa (ffi_type *ty) -{ - if (ty->type == FFI_TYPE_STRUCT - && ty->elements[0] - && is_floating_type (get_homogeneous_type (ty))) + /* Find the type of the first non-structure member. */ + elements = ty->elements; + candidate = elements[0]->type; + if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX) { - unsigned n = element_count (ty); - return n >= 1 && n <= 4; + for (i = 0; ; ++i) + { + candidate = is_hfa0 (elements[i]); + if (candidate >= 0) + break; + } } - return 0; -} - -/* Test if an ffi_type is a candidate for passing in a register. - - This test does not check that sufficient registers of the - appropriate class are actually available, merely that IFF - sufficient registers are available then the argument will be passed - in register(s). - Note that an ffi_type that is deemed to be a register candidate - will always be returned in registers. - - Returns 1 if a register candidate else 0. */ - -static int -is_register_candidate (ffi_type *ty) -{ - switch (ty->type) + /* If the first member is not a floating point type, it's not an HFA. + Also quickly re-check the size of the structure. */ + switch (candidate) { - case FFI_TYPE_VOID: case FFI_TYPE_FLOAT: + ele_count = size / sizeof(float); + if (size != ele_count * sizeof(float)) + return 0; + break; case FFI_TYPE_DOUBLE: + ele_count = size / sizeof(double); + if (size != ele_count * sizeof(double)) + return 0; + break; case FFI_TYPE_LONGDOUBLE: - case FFI_TYPE_UINT8: - case FFI_TYPE_UINT16: - case FFI_TYPE_UINT32: - case FFI_TYPE_UINT64: - case FFI_TYPE_POINTER: - case FFI_TYPE_SINT8: - case FFI_TYPE_SINT16: - case FFI_TYPE_SINT32: - case FFI_TYPE_INT: - case FFI_TYPE_SINT64: - return 1; - - case FFI_TYPE_STRUCT: - if (is_hfa (ty)) - { - return 1; - } - else if (ty->size > 16) - { - /* Too large. Will be replaced with a pointer to memory. The - pointer MAY be passed in a register, but the value will - not. This test specifically fails since the argument will - never be passed by value in registers. */ - return 0; - } - else - { - /* Might be passed in registers depending on the number of - registers required. */ - return (ty->size + 7) / 8 < N_X_ARG_REG; - } + ele_count = size / sizeof(long double); + if (size != ele_count * sizeof(long double)) + return 0; break; - default: - FFI_ASSERT (0); - break; + return 0; } + if (ele_count > 4) + return 0; - return 0; -} - -/* Test if an ffi_type argument or result is a candidate for a vector - register. */ + /* Finally, make sure that all scalar elements are the same type. */ + for (i = 0; elements[i]; ++i) + { + int t = elements[i]->type; + if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) + { + if (!is_hfa1 (elements[i], candidate)) + return 0; + } + else if (t != candidate) + return 0; + } -static int -is_v_register_candidate (ffi_type *ty) -{ - return is_floating_type (ty->type) - || (ty->type == FFI_TYPE_STRUCT && is_hfa (ty)); + /* All tests succeeded. Encode the result. */ + done: + return candidate * 4 + (4 - ele_count); } /* Representation of the procedure call argument marshalling @@ -367,161 +233,198 @@ struct arg_state { unsigned ngrn; /* Next general-purpose register number. */ unsigned nsrn; /* Next vector register number. */ - unsigned nsaa; /* Next stack offset. */ + size_t nsaa; /* Next stack offset. */ + +#if defined (__APPLE__) + unsigned allocating_variadic; +#endif }; /* Initialize a procedure call argument marshalling state. */ static void -arg_init (struct arg_state *state, unsigned call_frame_size) +arg_init (struct arg_state *state) { state->ngrn = 0; state->nsrn = 0; state->nsaa = 0; -} - -/* Return the number of available consecutive core argument - registers. */ - -static unsigned -available_x (struct arg_state *state) -{ - return N_X_ARG_REG - state->ngrn; -} - -/* Return the number of available consecutive vector argument - registers. */ - -static unsigned -available_v (struct arg_state *state) -{ - return N_V_ARG_REG - state->nsrn; -} - -static void * -allocate_to_x (struct call_context *context, struct arg_state *state) -{ - FFI_ASSERT (state->ngrn < N_X_ARG_REG) - return get_x_addr (context, (state->ngrn)++); -} - -static void * -allocate_to_s (struct call_context *context, struct arg_state *state) -{ - FFI_ASSERT (state->nsrn < N_V_ARG_REG) - return get_s_addr (context, (state->nsrn)++); -} - -static void * -allocate_to_d (struct call_context *context, struct arg_state *state) -{ - FFI_ASSERT (state->nsrn < N_V_ARG_REG) - return get_d_addr (context, (state->nsrn)++); -} - -static void * -allocate_to_v (struct call_context *context, struct arg_state *state) -{ - FFI_ASSERT (state->nsrn < N_V_ARG_REG) - return get_v_addr (context, (state->nsrn)++); +#if defined (__APPLE__) + state->allocating_variadic = 0; +#endif } /* Allocate an aligned slot on the stack and return a pointer to it. */ static void * -allocate_to_stack (struct arg_state *state, void *stack, unsigned alignment, - unsigned size) +allocate_to_stack (struct arg_state *state, void *stack, + size_t alignment, size_t size) { - void *allocation; + size_t nsaa = state->nsaa; /* Round up the NSAA to the larger of 8 or the natural alignment of the argument's type. */ - state->nsaa = ALIGN (state->nsaa, alignment); - state->nsaa = ALIGN (state->nsaa, alignment); - state->nsaa = ALIGN (state->nsaa, 8); - - allocation = stack + state->nsaa; +#if defined (__APPLE__) + if (state->allocating_variadic && alignment < 8) + alignment = 8; +#else + if (alignment < 8) + alignment = 8; +#endif + + nsaa = ALIGN (nsaa, alignment); + state->nsaa = nsaa + size; - state->nsaa += size; - return allocation; + return (char *)stack + nsaa; } -static void -copy_basic_type (void *dest, void *source, unsigned short type) +static ffi_arg +extend_integer_type (void *source, int type) { - /* This is neccessary to ensure that basic types are copied - sign extended to 64-bits as libffi expects. */ switch (type) { - case FFI_TYPE_FLOAT: - *(float *) dest = *(float *) source; - break; - case FFI_TYPE_DOUBLE: - *(double *) dest = *(double *) source; - break; - case FFI_TYPE_LONGDOUBLE: - *(long double *) dest = *(long double *) source; - break; case FFI_TYPE_UINT8: - *(ffi_arg *) dest = *(UINT8 *) source; - break; + return *(UINT8 *) source; case FFI_TYPE_SINT8: - *(ffi_sarg *) dest = *(SINT8 *) source; - break; + return *(SINT8 *) source; case FFI_TYPE_UINT16: - *(ffi_arg *) dest = *(UINT16 *) source; - break; + return *(UINT16 *) source; case FFI_TYPE_SINT16: - *(ffi_sarg *) dest = *(SINT16 *) source; - break; + return *(SINT16 *) source; case FFI_TYPE_UINT32: - *(ffi_arg *) dest = *(UINT32 *) source; - break; + return *(UINT32 *) source; case FFI_TYPE_INT: case FFI_TYPE_SINT32: - *(ffi_sarg *) dest = *(SINT32 *) source; - break; - case FFI_TYPE_POINTER: + return *(SINT32 *) source; case FFI_TYPE_UINT64: - *(ffi_arg *) dest = *(UINT64 *) source; - break; case FFI_TYPE_SINT64: - *(ffi_sarg *) dest = *(SINT64 *) source; + return *(UINT64 *) source; break; - + case FFI_TYPE_POINTER: + return *(uintptr_t *) source; default: - FFI_ASSERT (0); + abort(); } } static void -copy_hfa_to_reg_or_stack (void *memory, - ffi_type *ty, - struct call_context *context, - unsigned char *stack, - struct arg_state *state) +extend_hfa_type (void *dest, void *src, int h) +{ + int f = h - AARCH64_RET_S4; + void *x0; + + asm volatile ( + "adr %0, 0f\n" +" add %0, %0, %1\n" +" br %0\n" +"0: ldp s16, s17, [%3]\n" /* S4 */ +" ldp s18, s19, [%3, #8]\n" +" b 4f\n" +" ldp s16, s17, [%3]\n" /* S3 */ +" ldr s18, [%3, #8]\n" +" b 3f\n" +" ldp s16, s17, [%3]\n" /* S2 */ +" b 2f\n" +" nop\n" +" ldr s16, [%3]\n" /* S1 */ +" b 1f\n" +" nop\n" +" ldp d16, d17, [%3]\n" /* D4 */ +" ldp d18, d19, [%3, #16]\n" +" b 4f\n" +" ldp d16, d17, [%3]\n" /* D3 */ +" ldr d18, [%3, #16]\n" +" b 3f\n" +" ldp d16, d17, [%3]\n" /* D2 */ +" b 2f\n" +" nop\n" +" ldr d16, [%3]\n" /* D1 */ +" b 1f\n" +" nop\n" +" ldp q16, q17, [%3]\n" /* Q4 */ +" ldp q18, q19, [%3, #16]\n" +" b 4f\n" +" ldp q16, q17, [%3]\n" /* Q3 */ +" ldr q18, [%3, #16]\n" +" b 3f\n" +" ldp q16, q17, [%3]\n" /* Q2 */ +" b 2f\n" +" nop\n" +" ldr q16, [%3]\n" /* Q1 */ +" b 1f\n" +"4: str q19, [%2, #48]\n" +"3: str q18, [%2, #32]\n" +"2: str q17, [%2, #16]\n" +"1: str q16, [%2]" + : "=&r"(x0) + : "r"(f * 12), "r"(dest), "r"(src) + : "memory", "v16", "v17", "v18", "v19"); +} + +static void * +compress_hfa_type (void *dest, void *reg, int h) { - unsigned elems = element_count (ty); - if (available_v (state) < elems) - { - /* There are insufficient V registers. Further V register allocations - are prevented, the NSAA is adjusted (by allocate_to_stack ()) - and the argument is copied to memory at the adjusted NSAA. */ - state->nsrn = N_V_ARG_REG; - memcpy (allocate_to_stack (state, stack, ty->alignment, ty->size), - memory, - ty->size); - } - else + switch (h) { - int i; - unsigned short type = get_homogeneous_type (ty); - unsigned elems = element_count (ty); - for (i = 0; i < elems; i++) + case AARCH64_RET_S1: + if (dest == reg) + { +#ifdef __AARCH64EB__ + dest += 12; +#endif + } + else + *(float *)dest = *(float *)reg; + break; + case AARCH64_RET_S2: + asm ("ldp q16, q17, [%1]\n\t" + "st2 { v16.s, v17.s }[0], [%0]" + : : "r"(dest), "r"(reg) : "memory", "v16", "v17"); + break; + case AARCH64_RET_S3: + asm ("ldp q16, q17, [%1]\n\t" + "ldr q18, [%1, #32]\n\t" + "st3 { v16.s, v17.s, v18.s }[0], [%0]" + : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18"); + break; + case AARCH64_RET_S4: + asm ("ldp q16, q17, [%1]\n\t" + "ldp q18, q19, [%1, #32]\n\t" + "st4 { v16.s, v17.s, v18.s, v19.s }[0], [%0]" + : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19"); + break; + + case AARCH64_RET_D1: + if (dest == reg) { - void *reg = allocate_to_v (context, state); - copy_basic_type (reg, memory, type); - memory += get_basic_type_size (type); +#ifdef __AARCH64EB__ + dest += 8; +#endif } + else + *(double *)dest = *(double *)reg; + break; + case AARCH64_RET_D2: + asm ("ldp q16, q17, [%1]\n\t" + "st2 { v16.d, v17.d }[0], [%0]" + : : "r"(dest), "r"(reg) : "memory", "v16", "v17"); + break; + case AARCH64_RET_D3: + asm ("ldp q16, q17, [%1]\n\t" + "ldr q18, [%1, #32]\n\t" + "st3 { v16.d, v17.d, v18.d }[0], [%0]" + : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18"); + break; + case AARCH64_RET_D4: + asm ("ldp q16, q17, [%1]\n\t" + "ldp q18, q19, [%1, #32]\n\t" + "st4 { v16.d, v17.d, v18.d, v19.d }[0], [%0]" + : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19"); + break; + + default: + if (dest != reg) + return memcpy (dest, reg, 16 * (4 - (h & 3))); + break; } + return dest; } /* Either allocate an appropriate register for the argument type, or if @@ -529,83 +432,164 @@ copy_hfa_to_reg_or_stack (void *memory, to the allocated space. */ static void * -allocate_to_register_or_stack (struct call_context *context, - unsigned char *stack, - struct arg_state *state, - unsigned short type) +allocate_int_to_reg_or_stack (struct call_context *context, + struct arg_state *state, + void *stack, size_t size) { - size_t alignment = get_basic_type_alignment (type); - size_t size = alignment; - switch (type) + if (state->ngrn < N_X_ARG_REG) + return &context->x[state->ngrn++]; + + state->ngrn = N_X_ARG_REG; + return allocate_to_stack (state, stack, size, size); +} + +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + ffi_type *rtype = cif->rtype; + size_t bytes = cif->bytes; + int flags, i, n; + + switch (rtype->type) { - case FFI_TYPE_FLOAT: - /* This is the only case for which the allocated stack size - should not match the alignment of the type. */ - size = sizeof (UINT32); - /* Fall through. */ - case FFI_TYPE_DOUBLE: - if (state->nsrn < N_V_ARG_REG) - return allocate_to_d (context, state); - state->nsrn = N_V_ARG_REG; - break; - case FFI_TYPE_LONGDOUBLE: - if (state->nsrn < N_V_ARG_REG) - return allocate_to_v (context, state); - state->nsrn = N_V_ARG_REG; + case FFI_TYPE_VOID: + flags = AARCH64_RET_VOID; break; case FFI_TYPE_UINT8: - case FFI_TYPE_SINT8: + flags = AARCH64_RET_UINT8; + break; case FFI_TYPE_UINT16: - case FFI_TYPE_SINT16: + flags = AARCH64_RET_UINT16; + break; case FFI_TYPE_UINT32: - case FFI_TYPE_SINT32: + flags = AARCH64_RET_UINT32; + break; + case FFI_TYPE_SINT8: + flags = AARCH64_RET_SINT8; + break; + case FFI_TYPE_SINT16: + flags = AARCH64_RET_SINT16; + break; case FFI_TYPE_INT: - case FFI_TYPE_POINTER: - case FFI_TYPE_UINT64: + case FFI_TYPE_SINT32: + flags = AARCH64_RET_SINT32; + break; case FFI_TYPE_SINT64: - if (state->ngrn < N_X_ARG_REG) - return allocate_to_x (context, state); - state->ngrn = N_X_ARG_REG; + case FFI_TYPE_UINT64: + flags = AARCH64_RET_INT64; break; + case FFI_TYPE_POINTER: + flags = (sizeof(void *) == 4 ? AARCH64_RET_UINT32 : AARCH64_RET_INT64); + break; + + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + case FFI_TYPE_STRUCT: + case FFI_TYPE_COMPLEX: + flags = is_vfp_type (rtype); + if (flags == 0) + { + size_t s = rtype->size; + if (s > 16) + { + flags = AARCH64_RET_VOID | AARCH64_RET_IN_MEM; + bytes += 8; + } + else if (s == 16) + flags = AARCH64_RET_INT128; + else if (s == 8) + flags = AARCH64_RET_INT64; + else + flags = AARCH64_RET_INT128 | AARCH64_RET_NEED_COPY; + } + break; + default: - FFI_ASSERT (0); + abort(); } - return allocate_to_stack (state, stack, alignment, size); -} + for (i = 0, n = cif->nargs; i < n; i++) + if (is_vfp_type (cif->arg_types[i])) + { + flags |= AARCH64_FLAG_ARG_V; + break; + } -/* Copy a value to an appropriate register, or if none are - available, to the stack. */ + /* Round the stack up to a multiple of the stack alignment requirement. */ + cif->bytes = ALIGN(bytes, 16); + cif->flags = flags; +#if defined (__APPLE__) + cif->aarch64_nfixedargs = 0; +#endif -static void -copy_to_register_or_stack (struct call_context *context, - unsigned char *stack, - struct arg_state *state, - void *value, - unsigned short type) + return FFI_OK; +} + +#if defined (__APPLE__) +/* Perform Apple-specific cif processing for variadic calls */ +ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, + unsigned int nfixedargs, + unsigned int ntotalargs) { - copy_basic_type ( - allocate_to_register_or_stack (context, stack, state, type), - value, - type); + ffi_status status = ffi_prep_cif_machdep (cif); + cif->aarch64_nfixedargs = nfixedargs; + return status; } +#endif /* __APPLE__ */ -/* Marshall the arguments from FFI representation to procedure call - context and stack. */ +extern void ffi_call_SYSV (struct call_context *context, void *frame, + void (*fn)(void), void *rvalue, int flags, + void *closure) FFI_HIDDEN; -static unsigned -aarch64_prep_args (struct call_context *context, unsigned char *stack, - extended_cif *ecif) +/* Call a function with the provided arguments and capture the return + value. */ +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue, + void **avalue, void *closure) { - int i; + struct call_context *context; + void *stack, *frame, *rvalue; struct arg_state state; - - arg_init (&state, ALIGN(ecif->cif->bytes, 16)); - - for (i = 0; i < ecif->cif->nargs; i++) + size_t stack_bytes, rtype_size, rsize; + int i, nargs, flags; + ffi_type *rtype; + + flags = cif->flags; + rtype = cif->rtype; + rtype_size = rtype->size; + stack_bytes = cif->bytes; + + /* If the target function returns a structure via hidden pointer, + then we cannot allow a null rvalue. Otherwise, mash a null + rvalue to void return type. */ + rsize = 0; + if (flags & AARCH64_RET_IN_MEM) + { + if (orig_rvalue == NULL) + rsize = rtype_size; + } + else if (orig_rvalue == NULL) + flags &= AARCH64_FLAG_ARG_V; + else if (flags & AARCH64_RET_NEED_COPY) + rsize = 16; + + /* Allocate consectutive stack for everything we'll need. */ + context = alloca (sizeof(struct call_context) + stack_bytes + 32 + rsize); + stack = context + 1; + frame = stack + stack_bytes; + rvalue = (rsize ? frame + 32 : orig_rvalue); + + arg_init (&state); + for (i = 0, nargs = cif->nargs; i < nargs; i++) { - ffi_type *ty = ecif->cif->arg_types[i]; - switch (ty->type) + ffi_type *ty = cif->arg_types[i]; + size_t s = ty->size; + void *a = avalue[i]; + int h, t; + + t = ty->type; + switch (t) { case FFI_TYPE_VOID: FFI_ASSERT (0); @@ -613,239 +597,194 @@ aarch64_prep_args (struct call_context *context, unsigned char *stack, /* If the argument is a basic type the argument is allocated to an appropriate register, or if none are available, to the stack. */ - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - case FFI_TYPE_LONGDOUBLE: + case FFI_TYPE_INT: case FFI_TYPE_UINT8: case FFI_TYPE_SINT8: case FFI_TYPE_UINT16: case FFI_TYPE_SINT16: case FFI_TYPE_UINT32: - case FFI_TYPE_INT: case FFI_TYPE_SINT32: - case FFI_TYPE_POINTER: case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: - copy_to_register_or_stack (context, stack, &state, - ecif->avalue[i], ty->type); + case FFI_TYPE_POINTER: + do_pointer: + { + ffi_arg ext = extend_integer_type (a, t); + if (state.ngrn < N_X_ARG_REG) + context->x[state.ngrn++] = ext; + else + { + void *d = allocate_to_stack (&state, stack, ty->alignment, s); + state.ngrn = N_X_ARG_REG; + /* Note that the default abi extends each argument + to a full 64-bit slot, while the iOS abi allocates + only enough space. */ +#ifdef __APPLE__ + memcpy(d, a, s); +#else + *(ffi_arg *)d = ext; +#endif + } + } break; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_STRUCT: - if (is_hfa (ty)) - { - copy_hfa_to_reg_or_stack (ecif->avalue[i], ty, context, - stack, &state); - } - else if (ty->size > 16) - { - /* If the argument is a composite type that is larger than 16 - bytes, then the argument has been copied to memory, and - the argument is replaced by a pointer to the copy. */ + case FFI_TYPE_COMPLEX: + { + void *dest; - copy_to_register_or_stack (context, stack, &state, - &(ecif->avalue[i]), FFI_TYPE_POINTER); - } - else if (available_x (&state) >= (ty->size + 7) / 8) - { - /* If the argument is a composite type and the size in - double-words is not more than the number of available - X registers, then the argument is copied into consecutive - X registers. */ - int j; - for (j = 0; j < (ty->size + 7) / 8; j++) - { - memcpy (allocate_to_x (context, &state), - &(((UINT64 *) ecif->avalue[i])[j]), - sizeof (UINT64)); + h = is_vfp_type (ty); + if (h) + { + int elems = 4 - (h & 3); + if (state.nsrn + elems <= N_V_ARG_REG) + { + dest = &context->v[state.nsrn]; + state.nsrn += elems; + extend_hfa_type (dest, a, h); + break; + } + state.nsrn = N_V_ARG_REG; + dest = allocate_to_stack (&state, stack, ty->alignment, s); + } + else if (s > 16) + { + /* If the argument is a composite type that is larger than 16 + bytes, then the argument has been copied to memory, and + the argument is replaced by a pointer to the copy. */ + a = &avalue[i]; + t = FFI_TYPE_POINTER; + goto do_pointer; + } + else + { + size_t n = (s + 7) / 8; + if (state.ngrn + n <= N_X_ARG_REG) + { + /* If the argument is a composite type and the size in + double-words is not more than the number of available + X registers, then the argument is copied into + consecutive X registers. */ + dest = &context->x[state.ngrn]; + state.ngrn += n; + } + else + { + /* Otherwise, there are insufficient X registers. Further + X register allocations are prevented, the NSAA is + adjusted and the argument is copied to memory at the + adjusted NSAA. */ + state.ngrn = N_X_ARG_REG; + dest = allocate_to_stack (&state, stack, ty->alignment, s); + } } - } - else - { - /* Otherwise, there are insufficient X registers. Further X - register allocations are prevented, the NSAA is adjusted - (by allocate_to_stack ()) and the argument is copied to - memory at the adjusted NSAA. */ - state.ngrn = N_X_ARG_REG; - - memcpy (allocate_to_stack (&state, stack, ty->alignment, - ty->size), ecif->avalue + i, ty->size); + memcpy (dest, a, s); } break; default: - FFI_ASSERT (0); - break; + abort(); } + +#if defined (__APPLE__) + if (i + 1 == cif->aarch64_nfixedargs) + { + state.ngrn = N_X_ARG_REG; + state.nsrn = N_V_ARG_REG; + state.allocating_variadic = 1; + } +#endif } - return ecif->cif->aarch64_flags; + ffi_call_SYSV (context, frame, fn, rvalue, flags, closure); + + if (flags & AARCH64_RET_NEED_COPY) + memcpy (orig_rvalue, rvalue, rtype_size); } -ffi_status -ffi_prep_cif_machdep (ffi_cif *cif) +void +ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) { - /* Round the stack up to a multiple of the stack alignment requirement. */ - cif->bytes = - (cif->bytes + (AARCH64_STACK_ALIGN - 1)) & ~ (AARCH64_STACK_ALIGN - 1); - - /* Initialize our flags. We are interested if this CIF will touch a - vector register, if so we will enable context save and load to - those registers, otherwise not. This is intended to be friendly - to lazy float context switching in the kernel. */ - cif->aarch64_flags = 0; - - if (is_v_register_candidate (cif->rtype)) - { - cif->aarch64_flags |= AARCH64_FFI_WITH_V; - } - else - { - int i; - for (i = 0; i < cif->nargs; i++) - if (is_v_register_candidate (cif->arg_types[i])) - { - cif->aarch64_flags |= AARCH64_FFI_WITH_V; - break; - } - } - - return FFI_OK; + ffi_call_int (cif, fn, rvalue, avalue, NULL); } -/* Call a function with the provided arguments and capture the return - value. */ +#ifdef FFI_GO_CLOSURES void -ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, + void **avalue, void *closure) { - extended_cif ecif; + ffi_call_int (cif, fn, rvalue, avalue, closure); +} +#endif /* FFI_GO_CLOSURES */ - ecif.cif = cif; - ecif.avalue = avalue; - ecif.rvalue = rvalue; +/* Build a trampoline. */ - switch (cif->abi) - { - case FFI_SYSV: - { - struct call_context context; - unsigned stack_bytes; +extern void ffi_closure_SYSV (void) FFI_HIDDEN; +extern void ffi_closure_SYSV_V (void) FFI_HIDDEN; - /* Figure out the total amount of stack space we need, the - above call frame space needs to be 16 bytes aligned to - ensure correct alignment of the first object inserted in - that space hence the ALIGN applied to cif->bytes.*/ - stack_bytes = ALIGN(cif->bytes, 16); +ffi_status +ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + static const unsigned char trampoline[16] = { + 0x90, 0x00, 0x00, 0x58, /* ldr x16, tramp+16 */ + 0xf1, 0xff, 0xff, 0x10, /* adr x17, tramp+0 */ + 0x00, 0x02, 0x1f, 0xd6 /* br x16 */ + }; + char *tramp = closure->tramp; + void (*start)(void); - memset (&context, 0, sizeof (context)); - if (is_register_candidate (cif->rtype)) - { - ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn); - switch (cif->rtype->type) - { - case FFI_TYPE_VOID: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - case FFI_TYPE_LONGDOUBLE: - case FFI_TYPE_UINT8: - case FFI_TYPE_SINT8: - case FFI_TYPE_UINT16: - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT32: - case FFI_TYPE_SINT32: - case FFI_TYPE_POINTER: - case FFI_TYPE_UINT64: - case FFI_TYPE_INT: - case FFI_TYPE_SINT64: - { - void *addr = get_basic_type_addr (cif->rtype->type, - &context, 0); - copy_basic_type (rvalue, addr, cif->rtype->type); - break; - } + if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; - case FFI_TYPE_STRUCT: - if (is_hfa (cif->rtype)) - { - int j; - unsigned short type = get_homogeneous_type (cif->rtype); - unsigned elems = element_count (cif->rtype); - for (j = 0; j < elems; j++) - { - void *reg = get_basic_type_addr (type, &context, j); - copy_basic_type (rvalue, reg, type); - rvalue += get_basic_type_size (type); - } - } - else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG) - { - unsigned size = ALIGN (cif->rtype->size, sizeof (UINT64)); - memcpy (rvalue, get_x_addr (&context, 0), size); - } - else - { - FFI_ASSERT (0); - } - break; - - default: - FFI_ASSERT (0); - break; - } - } - else - { - memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64)); - ffi_call_SYSV (aarch64_prep_args, &context, &ecif, - stack_bytes, fn); - } - break; - } + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; - default: - FFI_ASSERT (0); - break; - } -} + memcpy (tramp, trampoline, sizeof(trampoline)); -static unsigned char trampoline [] = -{ 0x70, 0x00, 0x00, 0x58, /* ldr x16, 1f */ - 0x91, 0x00, 0x00, 0x10, /* adr x17, 2f */ - 0x00, 0x02, 0x1f, 0xd6 /* br x16 */ -}; + if (cif->flags & AARCH64_FLAG_ARG_V) + start = ffi_closure_SYSV_V; + else + start = ffi_closure_SYSV; + *(UINT64 *)(tramp + 16) = (uintptr_t)start; -/* Build a trampoline. */ + ffi_clear_cache(tramp, tramp + FFI_TRAMPOLINE_SIZE); + + return FFI_OK; +} -#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,FLAGS) \ - ({unsigned char *__tramp = (unsigned char*)(TRAMP); \ - UINT64 __fun = (UINT64)(FUN); \ - UINT64 __ctx = (UINT64)(CTX); \ - UINT64 __flags = (UINT64)(FLAGS); \ - memcpy (__tramp, trampoline, sizeof (trampoline)); \ - memcpy (__tramp + 12, &__fun, sizeof (__fun)); \ - memcpy (__tramp + 20, &__ctx, sizeof (__ctx)); \ - memcpy (__tramp + 28, &__flags, sizeof (__flags)); \ - __clear_cache(__tramp, __tramp + FFI_TRAMPOLINE_SIZE); \ - }) +#ifdef FFI_GO_CLOSURES +extern void ffi_go_closure_SYSV (void) FFI_HIDDEN; +extern void ffi_go_closure_SYSV_V (void) FFI_HIDDEN; ffi_status -ffi_prep_closure_loc (ffi_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void *codeloc) +ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*)) { + void (*start)(void); + if (cif->abi != FFI_SYSV) return FFI_BAD_ABI; - FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV, codeloc, - cif->aarch64_flags); + if (cif->flags & AARCH64_FLAG_ARG_V) + start = ffi_go_closure_SYSV_V; + else + start = ffi_go_closure_SYSV; - closure->cif = cif; - closure->user_data = user_data; - closure->fun = fun; + closure->tramp = start; + closure->cif = cif; + closure->fun = fun; return FFI_OK; } +#endif /* FFI_GO_CLOSURES */ /* Primary handler to setup and invoke a function within a closure. @@ -857,220 +796,115 @@ ffi_prep_closure_loc (ffi_closure* closure, the stack at the point ffi_closure_SYSV() was invoked. On the return path the assembler wrapper will reload call context - regsiters. + registers. ffi_closure_SYSV_inner() marshalls the call context into ffi value - desriptors, invokes the wrapped function, then marshalls the return + descriptors, invokes the wrapped function, then marshalls the return value back into the call context. */ -void -ffi_closure_SYSV_inner (ffi_closure *closure, struct call_context *context, - void *stack) +int FFI_HIDDEN +ffi_closure_SYSV_inner (ffi_cif *cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + struct call_context *context, + void *stack, void *rvalue, void *struct_rvalue) { - ffi_cif *cif = closure->cif; void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); - void *rvalue = NULL; - int i; + int i, h, nargs, flags; struct arg_state state; - arg_init (&state, ALIGN(cif->bytes, 16)); + arg_init (&state); - for (i = 0; i < cif->nargs; i++) + for (i = 0, nargs = cif->nargs; i < nargs; i++) { ffi_type *ty = cif->arg_types[i]; + int t = ty->type; + size_t n, s = ty->size; - switch (ty->type) + switch (t) { case FFI_TYPE_VOID: FFI_ASSERT (0); break; + case FFI_TYPE_INT: case FFI_TYPE_UINT8: case FFI_TYPE_SINT8: case FFI_TYPE_UINT16: case FFI_TYPE_SINT16: case FFI_TYPE_UINT32: case FFI_TYPE_SINT32: - case FFI_TYPE_INT: - case FFI_TYPE_POINTER: case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - case FFI_TYPE_LONGDOUBLE: - avalue[i] = allocate_to_register_or_stack (context, stack, - &state, ty->type); + case FFI_TYPE_POINTER: + avalue[i] = allocate_int_to_reg_or_stack (context, &state, stack, s); break; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_STRUCT: - if (is_hfa (ty)) + case FFI_TYPE_COMPLEX: + h = is_vfp_type (ty); + if (h) { - unsigned n = element_count (ty); - if (available_v (&state) < n) + n = 4 - (h & 3); + if (state.nsrn + n <= N_V_ARG_REG) { - state.nsrn = N_V_ARG_REG; - avalue[i] = allocate_to_stack (&state, stack, ty->alignment, - ty->size); + void *reg = &context->v[state.nsrn]; + state.nsrn += n; + + /* Eeek! We need a pointer to the structure, however the + homogeneous float elements are being passed in individual + registers, therefore for float and double the structure + is not represented as a contiguous sequence of bytes in + our saved register context. We don't need the original + contents of the register storage, so we reformat the + structure into the same memory. */ + avalue[i] = compress_hfa_type (reg, reg, h); } else { - switch (get_homogeneous_type (ty)) - { - case FFI_TYPE_FLOAT: - { - /* Eeek! We need a pointer to the structure, - however the homogeneous float elements are - being passed in individual S registers, - therefore the structure is not represented as - a contiguous sequence of bytes in our saved - register context. We need to fake up a copy - of the structure layed out in memory - correctly. The fake can be tossed once the - closure function has returned hence alloca() - is sufficient. */ - int j; - UINT32 *p = avalue[i] = alloca (ty->size); - for (j = 0; j < element_count (ty); j++) - memcpy (&p[j], - allocate_to_s (context, &state), - sizeof (*p)); - break; - } - - case FFI_TYPE_DOUBLE: - { - /* Eeek! We need a pointer to the structure, - however the homogeneous float elements are - being passed in individual S registers, - therefore the structure is not represented as - a contiguous sequence of bytes in our saved - register context. We need to fake up a copy - of the structure layed out in memory - correctly. The fake can be tossed once the - closure function has returned hence alloca() - is sufficient. */ - int j; - UINT64 *p = avalue[i] = alloca (ty->size); - for (j = 0; j < element_count (ty); j++) - memcpy (&p[j], - allocate_to_d (context, &state), - sizeof (*p)); - break; - } - - case FFI_TYPE_LONGDOUBLE: - memcpy (&avalue[i], - allocate_to_v (context, &state), - sizeof (*avalue)); - break; - - default: - FFI_ASSERT (0); - break; - } + state.nsrn = N_V_ARG_REG; + avalue[i] = allocate_to_stack (&state, stack, + ty->alignment, s); } } - else if (ty->size > 16) + else if (s > 16) { /* Replace Composite type of size greater than 16 with a pointer. */ - memcpy (&avalue[i], - allocate_to_register_or_stack (context, stack, - &state, FFI_TYPE_POINTER), - sizeof (avalue[i])); - } - else if (available_x (&state) >= (ty->size + 7) / 8) - { - avalue[i] = get_x_addr (context, state.ngrn); - state.ngrn += (ty->size + 7) / 8; + avalue[i] = *(void **) + allocate_int_to_reg_or_stack (context, &state, stack, + sizeof (void *)); } else { - state.ngrn = N_X_ARG_REG; - - avalue[i] = allocate_to_stack (&state, stack, ty->alignment, - ty->size); + n = (s + 7) / 8; + if (state.ngrn + n <= N_X_ARG_REG) + { + avalue[i] = &context->x[state.ngrn]; + state.ngrn += n; + } + else + { + state.ngrn = N_X_ARG_REG; + avalue[i] = allocate_to_stack (&state, stack, + ty->alignment, s); + } } break; default: - FFI_ASSERT (0); - break; + abort(); } } - /* Figure out where the return value will be passed, either in - registers or in a memory block allocated by the caller and passed - in x8. */ + flags = cif->flags; + if (flags & AARCH64_RET_IN_MEM) + rvalue = struct_rvalue; - if (is_register_candidate (cif->rtype)) - { - /* Register candidates are *always* returned in registers. */ - - /* Allocate a scratchpad for the return value, we will let the - callee scrible the result into the scratch pad then move the - contents into the appropriate return value location for the - call convention. */ - rvalue = alloca (cif->rtype->size); - (closure->fun) (cif, rvalue, avalue, closure->user_data); - - /* Copy the return value into the call context so that it is returned - as expected to our caller. */ - switch (cif->rtype->type) - { - case FFI_TYPE_VOID: - break; - - case FFI_TYPE_UINT8: - case FFI_TYPE_UINT16: - case FFI_TYPE_UINT32: - case FFI_TYPE_POINTER: - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT8: - case FFI_TYPE_SINT16: - case FFI_TYPE_INT: - case FFI_TYPE_SINT32: - case FFI_TYPE_SINT64: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - case FFI_TYPE_LONGDOUBLE: - { - void *addr = get_basic_type_addr (cif->rtype->type, context, 0); - copy_basic_type (addr, rvalue, cif->rtype->type); - break; - } - case FFI_TYPE_STRUCT: - if (is_hfa (cif->rtype)) - { - int i; - unsigned short type = get_homogeneous_type (cif->rtype); - unsigned elems = element_count (cif->rtype); - for (i = 0; i < elems; i++) - { - void *reg = get_basic_type_addr (type, context, i); - copy_basic_type (reg, rvalue, type); - rvalue += get_basic_type_size (type); - } - } - else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG) - { - unsigned size = ALIGN (cif->rtype->size, sizeof (UINT64)) ; - memcpy (get_x_addr (context, 0), rvalue, size); - } - else - { - FFI_ASSERT (0); - } - break; - default: - FFI_ASSERT (0); - break; - } - } - else - { - memcpy (&rvalue, get_x_addr (context, 8), sizeof (UINT64)); - (closure->fun) (cif, rvalue, avalue, closure->user_data); - } -} + fun (cif, rvalue, avalue, user_data); + return flags; +} diff --git a/libffi/src/aarch64/ffitarget.h b/libffi/src/aarch64/ffitarget.h index 6f1a348..80d09af 100644 --- a/libffi/src/aarch64/ffitarget.h +++ b/libffi/src/aarch64/ffitarget.h @@ -42,18 +42,20 @@ typedef enum ffi_abi /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 -#define FFI_TRAMPOLINE_SIZE 36 +#define FFI_TRAMPOLINE_SIZE 24 #define FFI_NATIVE_RAW_API 0 /* ---- Internal ---- */ +#if defined (__APPLE__) +#define FFI_TARGET_SPECIFIC_VARIADIC +#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs +#else +/* iOS reserves x18 for the system. Disable Go closures until + a new static chain is chosen. */ +#define FFI_GO_CLOSURES 1 +#endif -#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags - -#define AARCH64_FFI_WITH_V_BIT 0 - -#define AARCH64_N_XREG 32 -#define AARCH64_N_VREG 32 -#define AARCH64_CALL_CONTEXT_SIZE (AARCH64_N_XREG * 8 + AARCH64_N_VREG * 16) +#define FFI_TARGET_HAS_COMPLEX_TYPE #endif diff --git a/libffi/src/aarch64/internal.h b/libffi/src/aarch64/internal.h new file mode 100644 index 0000000..9c3e077 --- /dev/null +++ b/libffi/src/aarch64/internal.h @@ -0,0 +1,67 @@ +/* +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +``Software''), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#define AARCH64_RET_VOID 0 +#define AARCH64_RET_INT64 1 +#define AARCH64_RET_INT128 2 + +#define AARCH64_RET_UNUSED3 3 +#define AARCH64_RET_UNUSED4 4 +#define AARCH64_RET_UNUSED5 5 +#define AARCH64_RET_UNUSED6 6 +#define AARCH64_RET_UNUSED7 7 + +/* Note that FFI_TYPE_FLOAT == 2, _DOUBLE == 3, _LONGDOUBLE == 4, + so _S4 through _Q1 are layed out as (TYPE * 4) + (4 - COUNT). */ +#define AARCH64_RET_S4 8 +#define AARCH64_RET_S3 9 +#define AARCH64_RET_S2 10 +#define AARCH64_RET_S1 11 + +#define AARCH64_RET_D4 12 +#define AARCH64_RET_D3 13 +#define AARCH64_RET_D2 14 +#define AARCH64_RET_D1 15 + +#define AARCH64_RET_Q4 16 +#define AARCH64_RET_Q3 17 +#define AARCH64_RET_Q2 18 +#define AARCH64_RET_Q1 19 + +/* Note that each of the sub-64-bit integers gets two entries. */ +#define AARCH64_RET_UINT8 20 +#define AARCH64_RET_UINT16 22 +#define AARCH64_RET_UINT32 24 + +#define AARCH64_RET_SINT8 26 +#define AARCH64_RET_SINT16 28 +#define AARCH64_RET_SINT32 30 + +#define AARCH64_RET_MASK 31 + +#define AARCH64_RET_IN_MEM (1 << 5) +#define AARCH64_RET_NEED_COPY (1 << 6) + +#define AARCH64_FLAG_ARG_V_BIT 7 +#define AARCH64_FLAG_ARG_V (1 << AARCH64_FLAG_ARG_V_BIT) + +#define N_X_ARG_REG 8 +#define N_V_ARG_REG 8 +#define CALL_CONTEXT_SIZE (N_V_ARG_REG * 16 + N_X_ARG_REG * 8) diff --git a/libffi/src/aarch64/sysv.S b/libffi/src/aarch64/sysv.S index ffb16f8..5c9cdda 100644 --- a/libffi/src/aarch64/sysv.S +++ b/libffi/src/aarch64/sysv.S @@ -22,286 +22,382 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> - -#define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off -#define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off -#define cfi_restore(reg) .cfi_restore reg -#define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg - - .text - .globl ffi_call_SYSV - .type ffi_call_SYSV, #function - -/* ffi_call_SYSV() - - Create a stack frame, setup an argument context, call the callee - and extract the result. - - The maximum required argument stack size is provided, - ffi_call_SYSV() allocates that stack space then calls the - prepare_fn to populate register context and stack. The - argument passing registers are loaded from the register - context and the callee called, on return the register passing - register are saved back to the context. Our caller will - extract the return value from the final state of the saved - register context. - - Prototype: - - extern unsigned - ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *, - extended_cif *), - struct call_context *context, - extended_cif *, - unsigned required_stack_size, - void (*fn)(void)); +#include <ffi_cfi.h> +#include "internal.h" + +#ifdef HAVE_MACHINE_ASM_H +#include <machine/asm.h> +#else +#ifdef __USER_LABEL_PREFIX__ +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ +#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) +#else +#define CNAME(x) x +#endif +#endif + +#ifdef __AARCH64EB__ +# define BE(X) X +#else +# define BE(X) 0 +#endif + + .text + .align 4 + +/* ffi_call_SYSV + extern void ffi_call_SYSV (void *stack, void *frame, + void (*fn)(void), void *rvalue, + int flags, void *closure); Therefore on entry we have: - x0 prepare_fn - x1 &context - x2 &ecif - x3 bytes - x4 fn - - This function uses the following stack frame layout: - - == - saved x30(lr) - x29(fp)-> saved x29(fp) - saved x24 - saved x23 - saved x22 - sp' -> saved x21 - ... - sp -> (constructed callee stack arguments) - == - - Voila! */ - -#define ffi_call_SYSV_FS (8 * 4) - - .cfi_startproc -ffi_call_SYSV: - stp x29, x30, [sp, #-16]! - cfi_adjust_cfa_offset (16) - cfi_rel_offset (x29, 0) - cfi_rel_offset (x30, 8) - - mov x29, sp - cfi_def_cfa_register (x29) - sub sp, sp, #ffi_call_SYSV_FS - - stp x21, x22, [sp, 0] - cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS) - cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS) - - stp x23, x24, [sp, 16] - cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS) - cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS) - - mov x21, x1 - mov x22, x2 - mov x24, x4 - - /* Allocate the stack space for the actual arguments, many - arguments will be passed in registers, but we assume - worst case and allocate sufficient stack for ALL of - the arguments. */ - sub sp, sp, x3 - - /* unsigned (*prepare_fn) (struct call_context *context, - unsigned char *stack, extended_cif *ecif); - */ - mov x23, x0 - mov x0, x1 - mov x1, sp - /* x2 already in place */ - blr x23 - - /* Preserve the flags returned. */ - mov x23, x0 - - /* Figure out if we should touch the vector registers. */ - tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f - - /* Load the vector argument passing registers. */ - ldp q0, q1, [x21, #8*32 + 0] - ldp q2, q3, [x21, #8*32 + 32] - ldp q4, q5, [x21, #8*32 + 64] - ldp q6, q7, [x21, #8*32 + 96] + x0 stack + x1 frame + x2 fn + x3 rvalue + x4 flags + x5 closure +*/ + + cfi_startproc +CNAME(ffi_call_SYSV): + /* Use a stack frame allocated by our caller. */ + cfi_def_cfa(x1, 32); + stp x29, x30, [x1] + mov x29, x1 + mov sp, x0 + cfi_def_cfa_register(x29) + cfi_rel_offset (x29, 0) + cfi_rel_offset (x30, 8) + + mov x9, x2 /* save fn */ + mov x8, x3 /* install structure return */ +#ifdef FFI_GO_CLOSURES + mov x18, x5 /* install static chain */ +#endif + stp x3, x4, [x29, #16] /* save rvalue and flags */ + + /* Load the vector argument passing registers, if necessary. */ + tbz w4, #AARCH64_FLAG_ARG_V_BIT, 1f + ldp q0, q1, [sp, #0] + ldp q2, q3, [sp, #32] + ldp q4, q5, [sp, #64] + ldp q6, q7, [sp, #96] 1: - /* Load the core argument passing registers. */ - ldp x0, x1, [x21, #0] - ldp x2, x3, [x21, #16] - ldp x4, x5, [x21, #32] - ldp x6, x7, [x21, #48] - - /* Don't forget x8 which may be holding the address of a return buffer. - */ - ldr x8, [x21, #8*8] - - blr x24 - - /* Save the core argument passing registers. */ - stp x0, x1, [x21, #0] - stp x2, x3, [x21, #16] - stp x4, x5, [x21, #32] - stp x6, x7, [x21, #48] - - /* Note nothing useful ever comes back in x8! */ - - /* Figure out if we should touch the vector registers. */ - tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f - - /* Save the vector argument passing registers. */ - stp q0, q1, [x21, #8*32 + 0] - stp q2, q3, [x21, #8*32 + 32] - stp q4, q5, [x21, #8*32 + 64] - stp q6, q7, [x21, #8*32 + 96] -1: - /* All done, unwind our stack frame. */ - ldp x21, x22, [x29, # - ffi_call_SYSV_FS] - cfi_restore (x21) - cfi_restore (x22) - - ldp x23, x24, [x29, # - ffi_call_SYSV_FS + 16] - cfi_restore (x23) - cfi_restore (x24) - - mov sp, x29 - cfi_def_cfa_register (sp) + /* Load the core argument passing registers, including + the structure return pointer. */ + ldp x0, x1, [sp, #16*N_V_ARG_REG + 0] + ldp x2, x3, [sp, #16*N_V_ARG_REG + 16] + ldp x4, x5, [sp, #16*N_V_ARG_REG + 32] + ldp x6, x7, [sp, #16*N_V_ARG_REG + 48] - ldp x29, x30, [sp], #16 - cfi_adjust_cfa_offset (-16) - cfi_restore (x29) - cfi_restore (x30) + /* Deallocate the context, leaving the stacked arguments. */ + add sp, sp, #CALL_CONTEXT_SIZE - ret + blr x9 /* call fn */ - .cfi_endproc - .size ffi_call_SYSV, .-ffi_call_SYSV + ldp x3, x4, [x29, #16] /* reload rvalue and flags */ -#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE) + /* Partially deconstruct the stack frame. */ + mov sp, x29 + cfi_def_cfa_register (sp) + ldp x29, x30, [x29] + + /* Save the return value as directed. */ + adr x5, 0f + and w4, w4, #AARCH64_RET_MASK + add x5, x5, x4, lsl #3 + br x5 + + /* Note that each table entry is 2 insns, and thus 8 bytes. + For integer data, note that we're storing into ffi_arg + and therefore we want to extend to 64 bits; these types + have two consecutive entries allocated for them. */ + .align 4 +0: ret /* VOID */ + nop +1: str x0, [x3] /* INT64 */ + ret +2: stp x0, x1, [x3] /* INT128 */ + ret +3: brk #1000 /* UNUSED */ + ret +4: brk #1000 /* UNUSED */ + ret +5: brk #1000 /* UNUSED */ + ret +6: brk #1000 /* UNUSED */ + ret +7: brk #1000 /* UNUSED */ + ret +8: st4 { v0.s-v3.s }[0], [x3] /* S4 */ + ret +9: st3 { v0.s-v2.s }[0], [x3] /* S3 */ + ret +10: stp s0, s1, [x3] /* S2 */ + ret +11: str s0, [x3] /* S1 */ + ret +12: st4 { v0.d-v3.d }[0], [x3] /* D4 */ + ret +13: st3 { v0.d-v2.d }[0], [x3] /* D3 */ + ret +14: stp d0, d1, [x3] /* D2 */ + ret +15: str d0, [x3] /* D1 */ + ret +16: str q3, [x3, #48] /* Q4 */ + nop +17: str q2, [x3, #32] /* Q3 */ + nop +18: stp q0, q1, [x3] /* Q2 */ + ret +19: str q0, [x3] /* Q1 */ + ret +20: uxtb w0, w0 /* UINT8 */ + str x0, [x3] +21: ret /* reserved */ + nop +22: uxth w0, w0 /* UINT16 */ + str x0, [x3] +23: ret /* reserved */ + nop +24: mov w0, w0 /* UINT32 */ + str x0, [x3] +25: ret /* reserved */ + nop +26: sxtb x0, w0 /* SINT8 */ + str x0, [x3] +27: ret /* reserved */ + nop +28: sxth x0, w0 /* SINT16 */ + str x0, [x3] +29: ret /* reserved */ + nop +30: sxtw x0, w0 /* SINT32 */ + str x0, [x3] +31: ret /* reserved */ + nop + + cfi_endproc + + .globl CNAME(ffi_call_SYSV) +#ifdef __ELF__ + .type CNAME(ffi_call_SYSV), #function + .hidden CNAME(ffi_call_SYSV) + .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV) +#endif /* ffi_closure_SYSV Closure invocation glue. This is the low level code invoked directly by the closure trampoline to setup and call a closure. - On entry x17 points to a struct trampoline_data, x16 has been clobbered + On entry x17 points to a struct ffi_closure, x16 has been clobbered all other registers are preserved. We allocate a call context and save the argument passing registers, then invoked the generic C ffi_closure_SYSV_inner() function to do all the real work, on return we load the result passing registers back from the call context. +*/ + +#define ffi_closure_SYSV_FS (8*2 + CALL_CONTEXT_SIZE + 64) + + .align 4 +CNAME(ffi_closure_SYSV_V): + cfi_startproc + stp x29, x30, [sp, #-ffi_closure_SYSV_FS]! + cfi_adjust_cfa_offset (ffi_closure_SYSV_FS) + cfi_rel_offset (x29, 0) + cfi_rel_offset (x30, 8) + + /* Save the argument passing vector registers. */ + stp q0, q1, [sp, #16 + 0] + stp q2, q3, [sp, #16 + 32] + stp q4, q5, [sp, #16 + 64] + stp q6, q7, [sp, #16 + 96] + b 0f + cfi_endproc + + .globl CNAME(ffi_closure_SYSV_V) +#ifdef __ELF__ + .type CNAME(ffi_closure_SYSV_V), #function + .hidden CNAME(ffi_closure_SYSV_V) + .size CNAME(ffi_closure_SYSV_V), . - CNAME(ffi_closure_SYSV_V) +#endif + + .align 4 + cfi_startproc +CNAME(ffi_closure_SYSV): + stp x29, x30, [sp, #-ffi_closure_SYSV_FS]! + cfi_adjust_cfa_offset (ffi_closure_SYSV_FS) + cfi_rel_offset (x29, 0) + cfi_rel_offset (x30, 8) +0: + mov x29, sp + + /* Save the argument passing core registers. */ + stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0] + stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16] + stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32] + stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48] + + /* Load ffi_closure_inner arguments. */ + ldp x0, x1, [x17, #FFI_TRAMPOLINE_SIZE] /* load cif, fn */ + ldr x2, [x17, #FFI_TRAMPOLINE_SIZE+16] /* load user_data */ +.Ldo_closure: + add x3, sp, #16 /* load context */ + add x4, sp, #ffi_closure_SYSV_FS /* load stack */ + add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */ + mov x6, x8 /* load struct_rval */ + bl CNAME(ffi_closure_SYSV_inner) + + /* Load the return value as directed. */ + adr x1, 0f + and w0, w0, #AARCH64_RET_MASK + add x1, x1, x0, lsl #3 + add x3, sp, #16+CALL_CONTEXT_SIZE + br x1 + + /* Note that each table entry is 2 insns, and thus 8 bytes. */ + .align 4 +0: b 99f /* VOID */ + nop +1: ldr x0, [x3] /* INT64 */ + b 99f +2: ldp x0, x1, [x3] /* INT128 */ + b 99f +3: brk #1000 /* UNUSED */ + nop +4: brk #1000 /* UNUSED */ + nop +5: brk #1000 /* UNUSED */ + nop +6: brk #1000 /* UNUSED */ + nop +7: brk #1000 /* UNUSED */ + nop +8: ldr s3, [x3, #12] /* S4 */ + nop +9: ldr s2, [x2, #8] /* S3 */ + nop +10: ldp s0, s1, [x3] /* S2 */ + b 99f +11: ldr s0, [x3] /* S1 */ + b 99f +12: ldr d3, [x3, #24] /* D4 */ + nop +13: ldr d2, [x3, #16] /* D3 */ + nop +14: ldp d0, d1, [x3] /* D2 */ + b 99f +15: ldr d0, [x3] /* D1 */ + b 99f +16: ldr q3, [x3, #48] /* Q4 */ + nop +17: ldr q2, [x3, #32] /* Q3 */ + nop +18: ldp q0, q1, [x3] /* Q2 */ + b 99f +19: ldr q0, [x3] /* Q1 */ + b 99f +20: ldrb w0, [x3, #BE(7)] /* UINT8 */ + b 99f +21: brk #1000 /* reserved */ + nop +22: ldrh w0, [x3, #BE(6)] /* UINT16 */ + b 99f +23: brk #1000 /* reserved */ + nop +24: ldr w0, [x3, #BE(4)] /* UINT32 */ + b 99f +25: brk #1000 /* reserved */ + nop +26: ldrsb x0, [x3, #BE(7)] /* SINT8 */ + b 99f +27: brk #1000 /* reserved */ + nop +28: ldrsh x0, [x3, #BE(6)] /* SINT16 */ + b 99f +29: brk #1000 /* reserved */ + nop +30: ldrsw x0, [x3, #BE(4)] /* SINT32 */ + nop +31: /* reserved */ +99: ldp x29, x30, [sp], #ffi_closure_SYSV_FS + cfi_adjust_cfa_offset (-ffi_closure_SYSV_FS) + cfi_restore (x29) + cfi_restore (x30) + ret + cfi_endproc + + .globl CNAME(ffi_closure_SYSV) +#ifdef __ELF__ + .type CNAME(ffi_closure_SYSV), #function + .hidden CNAME(ffi_closure_SYSV) + .size CNAME(ffi_closure_SYSV), . - CNAME(ffi_closure_SYSV) +#endif + +#ifdef FFI_GO_CLOSURES + .align 4 +CNAME(ffi_go_closure_SYSV_V): + cfi_startproc + stp x29, x30, [sp, #-ffi_closure_SYSV_FS]! + cfi_adjust_cfa_offset (ffi_closure_SYSV_FS) + cfi_rel_offset (x29, 0) + cfi_rel_offset (x30, 8) + + /* Save the argument passing vector registers. */ + stp q0, q1, [sp, #16 + 0] + stp q2, q3, [sp, #16 + 32] + stp q4, q5, [sp, #16 + 64] + stp q6, q7, [sp, #16 + 96] + b 0f + cfi_endproc + + .globl CNAME(ffi_go_closure_SYSV_V) +#ifdef __ELF__ + .type CNAME(ffi_go_closure_SYSV_V), #function + .hidden CNAME(ffi_go_closure_SYSV_V) + .size CNAME(ffi_go_closure_SYSV_V), . - CNAME(ffi_go_closure_SYSV_V) +#endif + + .align 4 + cfi_startproc +CNAME(ffi_go_closure_SYSV): + stp x29, x30, [sp, #-ffi_closure_SYSV_FS]! + cfi_adjust_cfa_offset (ffi_closure_SYSV_FS) + cfi_rel_offset (x29, 0) + cfi_rel_offset (x30, 8) +0: + mov x29, sp + + /* Save the argument passing core registers. */ + stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0] + stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16] + stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32] + stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48] + + /* Load ffi_closure_inner arguments. */ + ldp x0, x1, [x18, #8] /* load cif, fn */ + mov x2, x18 /* load user_data */ + b .Ldo_closure + cfi_endproc + + .globl CNAME(ffi_go_closure_SYSV) +#ifdef __ELF__ + .type CNAME(ffi_go_closure_SYSV), #function + .hidden CNAME(ffi_go_closure_SYSV) + .size CNAME(ffi_go_closure_SYSV), . - CNAME(ffi_go_closure_SYSV) +#endif +#endif /* FFI_GO_CLOSURES */ + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",%progbits +#endif - On entry - - extern void - ffi_closure_SYSV (struct trampoline_data *); - - struct trampoline_data - { - UINT64 *ffi_closure; - UINT64 flags; - }; - - This function uses the following stack frame layout: - - == - saved x30(lr) - x29(fp)-> saved x29(fp) - saved x22 - saved x21 - ... - sp -> call_context - == - - Voila! */ - - .text - .globl ffi_closure_SYSV - .cfi_startproc -ffi_closure_SYSV: - stp x29, x30, [sp, #-16]! - cfi_adjust_cfa_offset (16) - cfi_rel_offset (x29, 0) - cfi_rel_offset (x30, 8) - - mov x29, sp - cfi_def_cfa_register (x29) - - sub sp, sp, #ffi_closure_SYSV_FS - - stp x21, x22, [x29, #-16] - cfi_rel_offset (x21, -16) - cfi_rel_offset (x22, -8) - - /* Load x21 with &call_context. */ - mov x21, sp - /* Preserve our struct trampoline_data * */ - mov x22, x17 - - /* Save the rest of the argument passing registers. */ - stp x0, x1, [x21, #0] - stp x2, x3, [x21, #16] - stp x4, x5, [x21, #32] - stp x6, x7, [x21, #48] - /* Don't forget we may have been given a result scratch pad address. - */ - str x8, [x21, #64] - - /* Figure out if we should touch the vector registers. */ - ldr x0, [x22, #8] - tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f - - /* Save the argument passing vector registers. */ - stp q0, q1, [x21, #8*32 + 0] - stp q2, q3, [x21, #8*32 + 32] - stp q4, q5, [x21, #8*32 + 64] - stp q6, q7, [x21, #8*32 + 96] -1: - /* Load &ffi_closure.. */ - ldr x0, [x22, #0] - mov x1, x21 - /* Compute the location of the stack at the point that the - trampoline was called. */ - add x2, x29, #16 - - bl ffi_closure_SYSV_inner - - /* Figure out if we should touch the vector registers. */ - ldr x0, [x22, #8] - tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f - - /* Load the result passing vector registers. */ - ldp q0, q1, [x21, #8*32 + 0] - ldp q2, q3, [x21, #8*32 + 32] - ldp q4, q5, [x21, #8*32 + 64] - ldp q6, q7, [x21, #8*32 + 96] -1: - /* Load the result passing core registers. */ - ldp x0, x1, [x21, #0] - ldp x2, x3, [x21, #16] - ldp x4, x5, [x21, #32] - ldp x6, x7, [x21, #48] - /* Note nothing usefull is returned in x8. */ - - /* We are done, unwind our frame. */ - ldp x21, x22, [x29, #-16] - cfi_restore (x21) - cfi_restore (x22) - - mov sp, x29 - cfi_def_cfa_register (sp) - - ldp x29, x30, [sp], #16 - cfi_adjust_cfa_offset (-16) - cfi_restore (x29) - cfi_restore (x30) - - ret - .cfi_endproc - .size ffi_closure_SYSV, .-ffi_closure_SYSV diff --git a/libffi/src/alpha/ffi.c b/libffi/src/alpha/ffi.c index cf0a730..efae4cc 100644 --- a/libffi/src/alpha/ffi.c +++ b/libffi/src/alpha/ffi.c @@ -1,8 +1,8 @@ /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2012 Anthony Green - Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc. - - Alpha Foreign Function Interface + Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc. + + Alpha Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -27,6 +27,8 @@ #include <ffi.h> #include <ffi_common.h> +#include <stdlib.h> +#include "internal.h" /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; all further uses in this file will refer to the 128-bit type. */ @@ -39,135 +41,286 @@ # define FFI_TYPE_LONGDOUBLE 4 #endif -extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void)) - FFI_HIDDEN; +extern void ffi_call_osf(void *stack, void *frame, unsigned flags, + void *raddr, void (*fn)(void), void *closure) + FFI_HIDDEN; extern void ffi_closure_osf(void) FFI_HIDDEN; +extern void ffi_go_closure_osf(void) FFI_HIDDEN; +/* Promote a float value to its in-register double representation. + Unlike actually casting to double, this does not trap on NaN. */ +static inline UINT64 lds(void *ptr) +{ + UINT64 ret; + asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr)); + return ret; +} -ffi_status +/* And the reverse. */ +static inline void sts(void *ptr, UINT64 val) +{ + asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val)); +} + +ffi_status FFI_HIDDEN ffi_prep_cif_machdep(ffi_cif *cif) { - /* Adjust cif->bytes to represent a minimum 6 words for the temporary - register argument loading area. */ - if (cif->bytes < 6*FFI_SIZEOF_ARG) - cif->bytes = 6*FFI_SIZEOF_ARG; + size_t bytes = 0; + int flags, i, avn; + ffi_type *rtype, *itype; + + if (cif->abi != FFI_OSF) + return FFI_BAD_ABI; + + /* Compute the size of the argument area. */ + for (i = 0, avn = cif->nargs; i < avn; i++) + { + itype = cif->arg_types[i]; + switch (itype->type) + { + case FFI_TYPE_INT: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + /* All take one 8 byte slot. */ + bytes += 8; + break; + + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + /* Passed by value in N slots. */ + bytes += ALIGN(itype->size, FFI_SIZEOF_ARG); + break; + + case FFI_TYPE_COMPLEX: + /* _Complex long double passed by reference; others in 2 slots. */ + if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE) + bytes += 8; + else + bytes += 16; + break; + + default: + abort(); + } + } /* Set the return type flag */ - switch (cif->rtype->type) + rtype = cif->rtype; + switch (rtype->type) { - case FFI_TYPE_STRUCT: + case FFI_TYPE_VOID: + flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID); + break; + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32); + break; case FFI_TYPE_FLOAT: + flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT); + break; case FFI_TYPE_DOUBLE: - cif->flags = cif->rtype->type; + flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE); + break; + case FFI_TYPE_UINT8: + flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8); + break; + case FFI_TYPE_SINT8: + flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8); + break; + case FFI_TYPE_UINT16: + flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16); + break; + case FFI_TYPE_SINT16: + flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16); + break; + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64); break; - case FFI_TYPE_LONGDOUBLE: - /* 128-bit long double is returned in memory, like a struct. */ - cif->flags = FFI_TYPE_STRUCT; + case FFI_TYPE_STRUCT: + /* Passed in memory, with a hidden pointer. */ + flags = ALPHA_RET_IN_MEM; break; - - default: - cif->flags = FFI_TYPE_INT; + case FFI_TYPE_COMPLEX: + itype = rtype->elements[0]; + switch (itype->type) + { + case FFI_TYPE_FLOAT: + flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF); + break; + case FFI_TYPE_DOUBLE: + flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD); + break; + default: + if (rtype->size <= 8) + flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64); + else + flags = ALPHA_RET_IN_MEM; + break; + } break; + default: + abort(); } - + cif->flags = flags; + + /* Include the hidden structure pointer in args requirement. */ + if (flags == ALPHA_RET_IN_MEM) + bytes += 8; + /* Minimum size is 6 slots, so that ffi_call_osf can pop them. */ + if (bytes < 6*8) + bytes = 6*8; + cif->bytes = bytes; + return FFI_OK; } +static unsigned long +extend_basic_type(void *valp, int type, int argn) +{ + switch (type) + { + case FFI_TYPE_SINT8: + return *(SINT8 *)valp; + case FFI_TYPE_UINT8: + return *(UINT8 *)valp; + case FFI_TYPE_SINT16: + return *(SINT16 *)valp; + case FFI_TYPE_UINT16: + return *(UINT16 *)valp; + + case FFI_TYPE_FLOAT: + if (argn < 6) + return lds(valp); + /* FALLTHRU */ + + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + /* Note that unsigned 32-bit quantities are sign extended. */ + return *(SINT32 *)valp; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + case FFI_TYPE_DOUBLE: + return *(UINT64 *)valp; -void -ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) + default: + abort(); + } +} + +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) { - unsigned long *stack, *argp; - long i, avn; + unsigned long *argp; + long i, avn, argn, flags = cif->flags; ffi_type **arg_types; - + void *frame; + /* If the return value is a struct and we don't have a return value address then we need to make one. */ - if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT) + if (rvalue == NULL && flags == ALPHA_RET_IN_MEM) rvalue = alloca(cif->rtype->size); /* Allocate the space for the arguments, plus 4 words of temp space for ffi_call_osf. */ - argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG); + argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG); + frame += cif->bytes; - if (cif->flags == FFI_TYPE_STRUCT) - *(void **) argp++ = rvalue; + argn = 0; + if (flags == ALPHA_RET_IN_MEM) + argp[argn++] = (unsigned long)rvalue; - i = 0; avn = cif->nargs; arg_types = cif->arg_types; - while (i < avn) + for (i = 0, avn = cif->nargs; i < avn; i++) { - size_t size = (*arg_types)->size; + ffi_type *ty = arg_types[i]; + void *valp = avalue[i]; + int type = ty->type; + size_t size; - switch ((*arg_types)->type) + switch (type) { + case FFI_TYPE_INT: case FFI_TYPE_SINT8: - *(SINT64 *) argp = *(SINT8 *)(* avalue); - break; - case FFI_TYPE_UINT8: - *(SINT64 *) argp = *(UINT8 *)(* avalue); - break; - case FFI_TYPE_SINT16: - *(SINT64 *) argp = *(SINT16 *)(* avalue); - break; - case FFI_TYPE_UINT16: - *(SINT64 *) argp = *(UINT16 *)(* avalue); - break; - case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: - /* Note that unsigned 32-bit quantities are sign extended. */ - *(SINT64 *) argp = *(SINT32 *)(* avalue); - break; - case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_POINTER: - *(UINT64 *) argp = *(UINT64 *)(* avalue); - break; - case FFI_TYPE_FLOAT: - if (argp - stack < 6) - { - /* Note the conversion -- all the fp regs are loaded as - doubles. The in-register format is the same. */ - *(double *) argp = *(float *)(* avalue); - } - else - *(float *) argp = *(float *)(* avalue); - break; - case FFI_TYPE_DOUBLE: - *(double *) argp = *(double *)(* avalue); + argp[argn] = extend_basic_type(valp, type, argn); + argn++; break; case FFI_TYPE_LONGDOUBLE: - /* 128-bit long double is passed by reference. */ - *(long double **) argp = (long double *)(* avalue); - size = sizeof (long double *); + by_reference: + /* Note that 128-bit long double is passed by reference. */ + argp[argn++] = (unsigned long)valp; break; + case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: - memcpy(argp, *avalue, (*arg_types)->size); + size = ty->size; + memcpy(argp + argn, valp, size); + argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + break; + + case FFI_TYPE_COMPLEX: + type = ty->elements[0]->type; + if (type == FFI_TYPE_LONGDOUBLE) + goto by_reference; + + /* Most complex types passed as two separate arguments. */ + size = ty->elements[0]->size; + argp[argn] = extend_basic_type(valp, type, argn); + argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1); + argn += 2; break; default: - FFI_ASSERT(0); + abort(); } - - argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - i++, arg_types++, avalue++; } - ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn); + flags = (flags >> ALPHA_ST_SHIFT) & 0xff; + ffi_call_osf(argp, frame, flags, rvalue, fn, closure); +} + +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + ffi_call_int(cif, fn, rvalue, avalue, NULL); } +void +ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int(cif, fn, rvalue, avalue, closure); +} ffi_status ffi_prep_closure_loc (ffi_closure* closure, @@ -203,39 +356,56 @@ ffi_prep_closure_loc (ffi_closure* closure, return FFI_OK; } +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*)) +{ + if (cif->abi != FFI_OSF) + return FFI_BAD_ABI; + + closure->tramp = (void *)ffi_go_closure_osf; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} long FFI_HIDDEN -ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) +ffi_closure_osf_inner (ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *rvalue, unsigned long *argp) { - ffi_cif *cif; void **avalue; ffi_type **arg_types; - long i, avn, argn; + long i, avn, argn, flags; - cif = closure->cif; avalue = alloca(cif->nargs * sizeof(void *)); - + flags = cif->flags; argn = 0; /* Copy the caller's structure return address to that the closure returns the data directly to the caller. */ - if (cif->flags == FFI_TYPE_STRUCT) + if (flags == ALPHA_RET_IN_MEM) { rvalue = (void *) argp[0]; argn = 1; } - i = 0; - avn = cif->nargs; arg_types = cif->arg_types; - + /* Grab the addresses of the arguments from the stack frame. */ - while (i < avn) + for (i = 0, avn = cif->nargs; i < avn; i++) { - size_t size = arg_types[i]->size; + ffi_type *ty = arg_types[i]; + int type = ty->type; + void *valp = &argp[argn]; + size_t size; - switch (arg_types[i]->type) + switch (type) { + case FFI_TYPE_INT: case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: case FFI_TYPE_SINT16: @@ -245,43 +415,107 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_POINTER: + argn += 1; + break; + + case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: - avalue[i] = &argp[argn]; + size = ty->size; + argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; break; case FFI_TYPE_FLOAT: + /* Floats coming from registers need conversion from double + back to float format. */ if (argn < 6) { - /* Floats coming from registers need conversion from double - back to float format. */ - *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6]; - avalue[i] = &argp[argn - 6]; + valp = &argp[argn - 6]; + sts(valp, argp[argn - 6]); } - else - avalue[i] = &argp[argn]; + argn += 1; break; case FFI_TYPE_DOUBLE: - avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)]; + if (argn < 6) + valp = &argp[argn - 6]; + argn += 1; break; case FFI_TYPE_LONGDOUBLE: + by_reference: /* 128-bit long double is passed by reference. */ - avalue[i] = (long double *) argp[argn]; - size = sizeof (long double *); + valp = (void *)argp[argn]; + argn += 1; + break; + + case FFI_TYPE_COMPLEX: + type = ty->elements[0]->type; + switch (type) + { + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + /* Passed as separate arguments, but they wind up sequential. */ + break; + + case FFI_TYPE_INT: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + /* Passed as separate arguments. Disjoint, but there's room + enough in one slot to hold the pair. */ + size = ty->elements[0]->size; + memcpy(valp + size, valp + 8, size); + break; + + case FFI_TYPE_FLOAT: + /* Passed as separate arguments. Disjoint, and each piece + may need conversion back to float. */ + if (argn < 6) + { + valp = &argp[argn - 6]; + sts(valp, argp[argn - 6]); + } + if (argn + 1 < 6) + sts(valp + 4, argp[argn + 1 - 6]); + else + *(UINT32 *)(valp + 4) = argp[argn + 1]; + break; + + case FFI_TYPE_DOUBLE: + /* Passed as separate arguments. Only disjoint if one part + is in fp regs and the other is on the stack. */ + if (argn < 5) + valp = &argp[argn - 6]; + else if (argn == 5) + { + valp = alloca(16); + ((UINT64 *)valp)[0] = argp[5 - 6]; + ((UINT64 *)valp)[1] = argp[6]; + } + break; + + case FFI_TYPE_LONGDOUBLE: + goto by_reference; + + default: + abort(); + } + argn += 2; break; default: - FFI_ASSERT (0); + abort (); } - argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - i++; + avalue[i] = valp; } /* Invoke the closure. */ - closure->fun (cif, rvalue, avalue, closure->user_data); + fun (cif, rvalue, avalue, user_data); /* Tell ffi_closure_osf how to perform return type promotions. */ - return cif->rtype->type; + return (flags >> ALPHA_LD_SHIFT) & 0xff; } diff --git a/libffi/src/alpha/ffitarget.h b/libffi/src/alpha/ffitarget.h index af145bc..a02dbd0 100644 --- a/libffi/src/alpha/ffitarget.h +++ b/libffi/src/alpha/ffitarget.h @@ -44,9 +44,13 @@ typedef enum ffi_abi { } ffi_abi; #endif +#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION +#define FFI_TARGET_HAS_COMPLEX_TYPE + /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 #define FFI_TRAMPOLINE_SIZE 24 #define FFI_NATIVE_RAW_API 0 diff --git a/libffi/src/alpha/internal.h b/libffi/src/alpha/internal.h new file mode 100644 index 0000000..44da192 --- /dev/null +++ b/libffi/src/alpha/internal.h @@ -0,0 +1,23 @@ +#define ALPHA_ST_VOID 0 +#define ALPHA_ST_INT 1 +#define ALPHA_ST_FLOAT 2 +#define ALPHA_ST_DOUBLE 3 +#define ALPHA_ST_CPLXF 4 +#define ALPHA_ST_CPLXD 5 + +#define ALPHA_LD_VOID 0 +#define ALPHA_LD_INT64 1 +#define ALPHA_LD_INT32 2 +#define ALPHA_LD_UINT16 3 +#define ALPHA_LD_SINT16 4 +#define ALPHA_LD_UINT8 5 +#define ALPHA_LD_SINT8 6 +#define ALPHA_LD_FLOAT 7 +#define ALPHA_LD_DOUBLE 8 +#define ALPHA_LD_CPLXF 9 +#define ALPHA_LD_CPLXD 10 + +#define ALPHA_ST_SHIFT 0 +#define ALPHA_LD_SHIFT 8 +#define ALPHA_RET_IN_MEM 0x10000 +#define ALPHA_FLAGS(S, L) (((L) << ALPHA_LD_SHIFT) | (S)) diff --git a/libffi/src/alpha/osf.S b/libffi/src/alpha/osf.S index 6b9f4df..b031828 100644 --- a/libffi/src/alpha/osf.S +++ b/libffi/src/alpha/osf.S @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- - osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011 Red Hat - - Alpha/OSF Foreign Function Interface + osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011, 2014 Red Hat + + Alpha/OSF Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -24,40 +24,49 @@ DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ -#define LIBFFI_ASM +#define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> +#include <ffi_cfi.h> +#include "internal.h" .arch ev6 .text -/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags, - void *raddr, void (*fnaddr)(void)); +/* Aid in building a direct addressed jump table, 4 insns per entry. */ +.macro E index + .align 4 + .org 99b + \index * 16 +.endm + +/* ffi_call_osf (void *stack, void *frame, unsigned flags, + void *raddr, void (*fnaddr)(void), void *closure) - Bit o trickiness here -- ARGS+BYTES is the base of the stack frame + Bit o trickiness here -- FRAME is the base of the stack frame for this function. This has been allocated by ffi_call. We also deallocate some of the stack that has been alloca'd. */ - .align 3 + .align 4 .globl ffi_call_osf .ent ffi_call_osf FFI_HIDDEN(ffi_call_osf) ffi_call_osf: - .frame $15, 32, $26, 0 - .mask 0x4008000, -32 -$LFB1: - addq $16,$17,$1 + cfi_startproc + cfi_def_cfa($17, 32) mov $16, $30 - stq $26, 0($1) - stq $15, 8($1) - stq $18, 16($1) - mov $1, $15 -$LCFI1: + stq $26, 0($17) + stq $15, 8($17) + mov $17, $15 .prologue 0 + cfi_def_cfa_register($15) + cfi_rel_offset($26, 0) + cfi_rel_offset($15, 8) - stq $19, 24($1) - mov $20, $27 + stq $18, 16($17) # save flags into frame + stq $19, 24($17) # save rvalue into frame + mov $20, $27 # fn into place for call + mov $21, $1 # closure into static chain # Load up all of the (potential) argument registers. ldq $16, 0($30) @@ -77,311 +86,197 @@ $LCFI1: lda $30, 48($30) jsr $26, ($27), 0 - ldgp $29, 0($26) - - # If the return value pointer is NULL, assume no return value. - ldq $19, 24($15) - ldq $18, 16($15) +0: + ldah $29, 0($26) !gpdisp!1 + ldq $2, 24($15) # reload rvalue + lda $29, 0($29) !gpdisp!1 + ldq $3, 16($15) # reload flags + lda $1, 99f-0b($26) ldq $26, 0($15) -$LCFI2: - beq $19, $noretval - - # Store the return value out in the proper type. - cmpeq $18, FFI_TYPE_INT, $1 - bne $1, $retint - cmpeq $18, FFI_TYPE_FLOAT, $2 - bne $2, $retfloat - cmpeq $18, FFI_TYPE_DOUBLE, $3 - bne $3, $retdouble - - .align 3 -$noretval: ldq $15, 8($15) - ret + cfi_restore($26) + cfi_restore($15) + cfi_def_cfa($sp, 0) + cmoveq $2, ALPHA_ST_VOID, $3 # mash null rvalue to void + addq $3, $3, $3 + s8addq $3, $1, $1 # 99f + stcode * 16 + jmp $31, ($1), $st_int .align 4 -$retint: - stq $0, 0($19) - nop - ldq $15, 8($15) +99: +E ALPHA_ST_VOID ret - - .align 4 -$retfloat: - sts $f0, 0($19) - nop - ldq $15, 8($15) +E ALPHA_ST_INT +$st_int: + stq $0, 0($2) ret - - .align 4 -$retdouble: - stt $f0, 0($19) - nop - ldq $15, 8($15) +E ALPHA_ST_FLOAT + sts $f0, 0($2) + ret +E ALPHA_ST_DOUBLE + stt $f0, 0($2) + ret +E ALPHA_ST_CPLXF + sts $f0, 0($2) + sts $f1, 4($2) + ret +E ALPHA_ST_CPLXD + stt $f0, 0($2) + stt $f1, 8($2) ret -$LFE1: + cfi_endproc .end ffi_call_osf /* ffi_closure_osf(...) Receives the closure argument in $1. */ - .align 3 +#define CLOSURE_FS (16*8) + + .align 4 + .globl ffi_go_closure_osf + .ent ffi_go_closure_osf + FFI_HIDDEN(ffi_go_closure_osf) + +ffi_go_closure_osf: + cfi_startproc + ldgp $29, 0($27) + subq $30, CLOSURE_FS, $30 + cfi_adjust_cfa_offset(CLOSURE_FS) + stq $26, 0($30) + .prologue 1 + cfi_rel_offset($26, 0) + + stq $16, 10*8($30) + stq $17, 11*8($30) + stq $18, 12*8($30) + + ldq $16, 8($1) # load cif + ldq $17, 16($1) # load fun + mov $1, $18 # closure is user_data + br $do_closure + + cfi_endproc + .end ffi_go_closure_osf + + .align 4 .globl ffi_closure_osf .ent ffi_closure_osf FFI_HIDDEN(ffi_closure_osf) ffi_closure_osf: - .frame $30, 16*8, $26, 0 - .mask 0x4000000, -16*8 -$LFB2: + cfi_startproc ldgp $29, 0($27) - subq $30, 16*8, $30 -$LCFI5: + subq $30, CLOSURE_FS, $30 + cfi_adjust_cfa_offset(CLOSURE_FS) stq $26, 0($30) -$LCFI6: .prologue 1 + cfi_rel_offset($26, 0) # Store all of the potential argument registers in va_list format. - stt $f16, 4*8($30) - stt $f17, 5*8($30) - stt $f18, 6*8($30) - stt $f19, 7*8($30) - stt $f20, 8*8($30) - stt $f21, 9*8($30) stq $16, 10*8($30) stq $17, 11*8($30) stq $18, 12*8($30) + + ldq $16, 24($1) # load cif + ldq $17, 32($1) # load fun + ldq $18, 40($1) # load user_data + +$do_closure: stq $19, 13*8($30) stq $20, 14*8($30) stq $21, 15*8($30) + stt $f16, 4*8($30) + stt $f17, 5*8($30) + stt $f18, 6*8($30) + stt $f19, 7*8($30) + stt $f20, 8*8($30) + stt $f21, 9*8($30) # Call ffi_closure_osf_inner to do the bulk of the work. - mov $1, $16 - lda $17, 2*8($30) - lda $18, 10*8($30) + lda $19, 2*8($30) + lda $20, 10*8($30) jsr $26, ffi_closure_osf_inner - ldgp $29, 0($26) +0: + ldah $29, 0($26) !gpdisp!2 + lda $2, 99f-0b($26) + s4addq $0, 0, $1 # ldcode * 4 + ldq $0, 16($30) # preload return value + s4addq $1, $2, $1 # 99f + ldcode * 16 + lda $29, 0($29) !gpdisp!2 ldq $26, 0($30) - - # Load up the return value in the proper type. - lda $1, $load_table - s4addq $0, $1, $1 - ldl $1, 0($1) - addq $1, $29, $1 + cfi_restore($26) jmp $31, ($1), $load_32 - .align 4 -$load_none: - addq $30, 16*8, $30 +.macro epilogue + addq $30, CLOSURE_FS, $30 + cfi_adjust_cfa_offset(-CLOSURE_FS) ret + .align 4 + cfi_adjust_cfa_offset(CLOSURE_FS) +.endm .align 4 -$load_float: - lds $f0, 16($30) - nop - addq $30, 16*8, $30 - ret +99: +E ALPHA_LD_VOID + epilogue - .align 4 -$load_double: - ldt $f0, 16($30) - nop - addq $30, 16*8, $30 - ret +E ALPHA_LD_INT64 + epilogue - .align 4 -$load_u8: +E ALPHA_LD_INT32 +$load_32: + sextl $0, $0 + epilogue + +E ALPHA_LD_UINT16 + zapnot $0, 3, $0 + epilogue + +E ALPHA_LD_SINT16 #ifdef __alpha_bwx__ - ldbu $0, 16($30) - nop + sextw $0, $0 #else - ldq $0, 16($30) - and $0, 255, $0 + sll $0, 48, $0 + sra $0, 48, $0 #endif - addq $30, 16*8, $30 - ret + epilogue - .align 4 -$load_s8: +E ALPHA_LD_UINT8 + and $0, 0xff, $0 + epilogue + +E ALPHA_LD_SINT8 #ifdef __alpha_bwx__ - ldbu $0, 16($30) sextb $0, $0 #else - ldq $0, 16($30) sll $0, 56, $0 sra $0, 56, $0 #endif - addq $30, 16*8, $30 - ret + epilogue - .align 4 -$load_u16: -#ifdef __alpha_bwx__ - ldwu $0, 16($30) - nop -#else - ldq $0, 16($30) - zapnot $0, 3, $0 -#endif - addq $30, 16*8, $30 - ret +E ALPHA_LD_FLOAT + lds $f0, 16($sp) + epilogue - .align 4 -$load_s16: -#ifdef __alpha_bwx__ - ldwu $0, 16($30) - sextw $0, $0 -#else - ldq $0, 16($30) - sll $0, 48, $0 - sra $0, 48, $0 -#endif - addq $30, 16*8, $30 - ret +E ALPHA_LD_DOUBLE + ldt $f0, 16($sp) + epilogue - .align 4 -$load_32: - ldl $0, 16($30) - nop - addq $30, 16*8, $30 - ret +E ALPHA_LD_CPLXF + lds $f0, 16($sp) + lds $f1, 20($sp) + epilogue - .align 4 -$load_64: - ldq $0, 16($30) - nop - addq $30, 16*8, $30 - ret -$LFE2: +E ALPHA_LD_CPLXD + ldt $f0, 16($sp) + ldt $f1, 24($sp) + epilogue + cfi_endproc .end ffi_closure_osf -#ifdef __ELF__ -.section .rodata -#else -.rdata -#endif -$load_table: - .gprel32 $load_none # FFI_TYPE_VOID - .gprel32 $load_32 # FFI_TYPE_INT - .gprel32 $load_float # FFI_TYPE_FLOAT - .gprel32 $load_double # FFI_TYPE_DOUBLE - .gprel32 $load_none # FFI_TYPE_LONGDOUBLE - .gprel32 $load_u8 # FFI_TYPE_UINT8 - .gprel32 $load_s8 # FFI_TYPE_SINT8 - .gprel32 $load_u16 # FFI_TYPE_UINT16 - .gprel32 $load_s16 # FFI_TYPE_SINT16 - .gprel32 $load_32 # FFI_TYPE_UINT32 - .gprel32 $load_32 # FFI_TYPE_SINT32 - .gprel32 $load_64 # FFI_TYPE_UINT64 - .gprel32 $load_64 # FFI_TYPE_SINT64 - .gprel32 $load_none # FFI_TYPE_STRUCT - .gprel32 $load_64 # FFI_TYPE_POINTER - -/* Assert that the table above is in sync with ffi.h. */ - -#if FFI_TYPE_FLOAT != 2 \ - || FFI_TYPE_DOUBLE != 3 \ - || FFI_TYPE_UINT8 != 5 \ - || FFI_TYPE_SINT8 != 6 \ - || FFI_TYPE_UINT16 != 7 \ - || FFI_TYPE_SINT16 != 8 \ - || FFI_TYPE_UINT32 != 9 \ - || FFI_TYPE_SINT32 != 10 \ - || FFI_TYPE_UINT64 != 11 \ - || FFI_TYPE_SINT64 != 12 \ - || FFI_TYPE_STRUCT != 13 \ - || FFI_TYPE_POINTER != 14 \ - || FFI_TYPE_LAST != 14 -#error "osf.S out of sync with ffi.h" -#endif - -#ifdef __ELF__ -# define UA_SI .4byte -# define FDE_ENCODING 0x1b /* pcrel sdata4 */ -# define FDE_ENCODE(X) .4byte X-. -# define FDE_ARANGE(X) .4byte X -#elif defined __osf__ -# define UA_SI .align 0; .long -# define FDE_ENCODING 0x50 /* aligned absolute */ -# define FDE_ENCODE(X) .align 3; .quad X -# define FDE_ARANGE(X) .align 0; .quad X -#endif - -#ifdef __ELF__ - .section .eh_frame,EH_FRAME_FLAGS,@progbits -#elif defined __osf__ - .data - .align 3 - .globl _GLOBAL__F_ffi_call_osf -_GLOBAL__F_ffi_call_osf: -#endif -__FRAME_BEGIN__: - UA_SI $LECIE1-$LSCIE1 # Length of Common Information Entry -$LSCIE1: - UA_SI 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor - .byte 0x78 # sleb128 -8; CIE Data Alignment Factor - .byte 26 # CIE RA Column - .byte 0x1 # uleb128 0x1; Augmentation size - .byte FDE_ENCODING # FDE Encoding - .byte 0xc # DW_CFA_def_cfa - .byte 30 # uleb128 column 30 - .byte 0 # uleb128 offset 0 - .align 3 -$LECIE1: -$LSFDE1: - UA_SI $LEFDE1-$LASFDE1 # FDE Length -$LASFDE1: - UA_SI $LASFDE1-__FRAME_BEGIN__ # FDE CIE offset - FDE_ENCODE($LFB1) # FDE initial location - FDE_ARANGE($LFE1-$LFB1) # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - - .byte 0x4 # DW_CFA_advance_loc4 - UA_SI $LCFI1-$LFB1 - .byte 0x9a # DW_CFA_offset, column 26 - .byte 4 # uleb128 4*-8 - .byte 0x8f # DW_CFA_offset, column 15 - .byte 0x3 # uleb128 3*-8 - .byte 0xc # DW_CFA_def_cfa - .byte 15 # uleb128 column 15 - .byte 32 # uleb128 offset 32 - - .byte 0x4 # DW_CFA_advance_loc4 - UA_SI $LCFI2-$LCFI1 - .byte 0xda # DW_CFA_restore, column 26 - .align 3 -$LEFDE1: - -$LSFDE3: - UA_SI $LEFDE3-$LASFDE3 # FDE Length -$LASFDE3: - UA_SI $LASFDE3-__FRAME_BEGIN__ # FDE CIE offset - FDE_ENCODE($LFB2) # FDE initial location - FDE_ARANGE($LFE2-$LFB2) # FDE address range - .byte 0x0 # uleb128 0x0; Augmentation size - - .byte 0x4 # DW_CFA_advance_loc4 - UA_SI $LCFI5-$LFB2 - .byte 0xe # DW_CFA_def_cfa_offset - .byte 0x80,0x1 # uleb128 128 - - .byte 0x4 # DW_CFA_advance_loc4 - UA_SI $LCFI6-$LCFI5 - .byte 0x9a # DW_CFA_offset, column 26 - .byte 16 # uleb128 offset 16*-8 - .align 3 -$LEFDE3: -#if defined __osf__ - .align 0 - .long 0 # End of Table -#endif - #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif diff --git a/libffi/src/arc/arcompact.S b/libffi/src/arc/arcompact.S new file mode 100644 index 0000000..03715fd --- /dev/null +++ b/libffi/src/arc/arcompact.S @@ -0,0 +1,135 @@ +/* ----------------------------------------------------------------------- + arcompact.S - Copyright (c) 2013 Synposys, Inc. (www.synopsys.com) + + ARCompact 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 RENESAS TECHNOLOGY 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> +#ifdef HAVE_MACHINE_ASM_H +#include <machine/asm.h> +#else +#define CNAME(x) x +#define ENTRY(x) .globl CNAME(x)` .type CNAME(x),%function` CNAME(x): +#endif + +.text + + /* R0: ffi_prep_args */ + /* R1: &ecif */ + /* R2: cif->bytes */ + /* R3: fig->flags */ + /* R4: ecif.rvalue */ + /* R5: fn */ +ENTRY(ffi_call_ARCompact) + /* 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 + + /* 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 + + 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 diff --git a/libffi/src/arc/ffi.c b/libffi/src/arc/ffi.c new file mode 100644 index 0000000..32f82a7d5 --- /dev/null +++ b/libffi/src/arc/ffi.c @@ -0,0 +1,268 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2013 Synopsys, Inc. (www.synopsys.com) + + ARC 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 RENESAS TECHNOLOGY 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 <sys/cachectl.h> + +/* for little endian ARC, the code is in fact stored as mixed endian for + performance reasons */ +#if __BIG_ENDIAN__ +#define CODE_ENDIAN(x) (x) +#else +#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; + int tmp; + void **p_argv; + char *argp; + ffi_type **p_arg; + + tmp = 0; + 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 *) 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) +{ + /* Set the return type flag. */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_STRUCT: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_DOUBLE: + cif->flags = FFI_TYPE_DOUBLE; + break; + + case FFI_TYPE_FLOAT: + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +extern void ffi_call_ARCompact (void (*)(char *, extended_cif *), + 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)) + { + ecif.rvalue = alloca (cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_ARCOMPACT: + ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; + + default: + FFI_ASSERT (0); + break; + } +} + +int +ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue, + ffi_arg * args) +{ + void **arg_area, **p_argv; + ffi_cif *cif = closure->cif; + char *argp = (char *) args; + ffi_type **p_argt; + int i; + + arg_area = (void **) alloca (cif->nargs * sizeof (void *)); + + /* handle hidden argument */ + if (cif->flags == FFI_TYPE_STRUCT) + { + rvalue = *(void **) argp; + argp += 4; + } + + p_argv = arg_area; + + for (i = 0, p_argt = cif->arg_types; i < cif->nargs; + i++, p_argt++, p_argv++) + { + size_t z; + int alignment; + + /* align alignment to 4 */ + alignment = (((*p_argt)->alignment - 1) | 3) + 1; + + /* Align if necessary. */ + if ((alignment - 1) & (unsigned) argp) + argp = (char *) ALIGN (argp, alignment); + + z = (*p_argt)->size; + *p_argv = (void *) argp; + argp += z; + } + + (closure->fun) (cif, rvalue, arg_area, closure->user_data); + + return cif->flags; +} + +extern void ffi_closure_ARCompact (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) +{ + uint32_t *tramp = (uint32_t *) & (closure->tramp[0]); + + switch (cif->abi) + { + 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); + break; + + default: + return FFI_BAD_ABI; + } + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + cacheflush (codeloc, FFI_TRAMPOLINE_SIZE, BCACHE); + + return FFI_OK; +} diff --git a/libffi/src/arc/ffitarget.h b/libffi/src/arc/ffitarget.h new file mode 100644 index 0000000..bf8311b --- /dev/null +++ b/libffi/src/arc/ffitarget.h @@ -0,0 +1,53 @@ +/* ----------------------------------------------------------------------- + ffitarget.h - Copyright (c) 2012 Anthony Green + Copyright (c) 2013 Synopsys, Inc. (www.synopsys.com) + Target configuration macros for ARC. + + 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 RENESAS TECHNOLOGY 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 ----------------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi +{ + FFI_FIRST_ABI = 0, + FFI_ARCOMPACT, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_ARCOMPACT +} ffi_abi; +#endif + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 12 +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/libffi/src/arm/ffi.c b/libffi/src/arm/ffi.c index 3ccceb9..9c8732d 100644 --- a/libffi/src/arm/ffi.c +++ b/libffi/src/arm/ffi.c @@ -4,8 +4,8 @@ Copyright (c) 2011 Anthony Green Copyright (c) 2011 Free Software Foundation Copyright (c) 1998, 2008, 2011 Red Hat, Inc. - - ARM Foreign Function Interface + + ARM Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -30,343 +30,505 @@ #include <ffi.h> #include <ffi_common.h> - #include <stdlib.h> +#include "internal.h" /* Forward declares. */ -static int vfp_type_p (ffi_type *); +static int vfp_type_p (const ffi_type *); static void layout_vfp_args (ffi_cif *); -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments - +static void * +ffi_align (ffi_type *ty, void *p) +{ + /* Align if necessary */ + size_t alignment; +#ifdef _WIN32_WCE + alignment = 4; +#else + alignment = ty->alignment; + if (alignment < 4) + alignment = 4; +#endif + return (void *) ALIGN (p, alignment); +} + +static size_t +ffi_put_arg (ffi_type *ty, void *src, void *dst) +{ + size_t z = ty->size; + + switch (ty->type) + { + case FFI_TYPE_SINT8: + *(UINT32 *)dst = *(SINT8 *)src; + break; + case FFI_TYPE_UINT8: + *(UINT32 *)dst = *(UINT8 *)src; + break; + case FFI_TYPE_SINT16: + *(UINT32 *)dst = *(SINT16 *)src; + break; + case FFI_TYPE_UINT16: + *(UINT32 *)dst = *(UINT16 *)src; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + case FFI_TYPE_FLOAT: + *(UINT32 *)dst = *(UINT32 *)src; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_DOUBLE: + *(UINT64 *)dst = *(UINT64 *)src; + break; + + case FFI_TYPE_STRUCT: + case FFI_TYPE_COMPLEX: + memcpy (dst, src, z); + break; + + default: + abort(); + } + + return ALIGN (z, 4); +} + +/* ffi_prep_args is called once stack space has been allocated + for the function's arguments. + The vfp_space parameter is the load area for VFP regs, the return value is cif->vfp_used (word bitset of VFP regs used for passing arguments). These are only used for the VFP hard-float ABI. */ -int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space) +static void +ffi_prep_args_SYSV (ffi_cif *cif, int flags, void *rvalue, + void **avalue, char *argp) { - register unsigned int i, vi = 0; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; + ffi_type **arg_types = cif->arg_types; + int i, n; - argp = stack; + if (flags == ARM_TYPE_STRUCT) + { + *(void **) argp = rvalue; + argp += 4; + } - if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { - *(void **) argp = ecif->rvalue; - argp += 4; - } + for (i = 0, n = cif->nargs; i < n; i++) + { + ffi_type *ty = arg_types[i]; + argp = ffi_align (ty, argp); + argp += ffi_put_arg (ty, avalue[i], argp); + } +} - p_argv = ecif->avalue; +static void +ffi_prep_args_VFP (ffi_cif *cif, int flags, void *rvalue, + void **avalue, char *stack, char *vfp_space) +{ + ffi_type **arg_types = cif->arg_types; + int i, n, vi = 0; + char *argp, *regp, *eo_regp; + char stack_used = 0; + char done_with_regs = 0; + + /* The first 4 words on the stack are used for values + passed in core registers. */ + regp = stack; + eo_regp = argp = regp + 16; + + /* If the function returns an FFI_TYPE_STRUCT in memory, + that address is passed in r0 to the function. */ + if (flags == ARM_TYPE_STRUCT) + { + *(void **) regp = rvalue; + regp += 4; + } - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - (i != 0); - i--, p_arg++) + for (i = 0, n = cif->nargs; i < n; i++) { - size_t z; - size_t alignment; + ffi_type *ty = arg_types[i]; + void *a = avalue[i]; + int is_vfp_type = vfp_type_p (ty); /* Allocated in VFP registers. */ - if (ecif->cif->abi == FFI_VFP - && vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg)) + if (vi < cif->vfp_nargs && is_vfp_type) { - float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++]; - if ((*p_arg)->type == FFI_TYPE_FLOAT) - *((float*)vfp_slot) = *((float*)*p_argv); - else if ((*p_arg)->type == FFI_TYPE_DOUBLE) - *((double*)vfp_slot) = *((double*)*p_argv); - else - memcpy(vfp_slot, *p_argv, (*p_arg)->size); - p_argv++; + char *vfp_slot = vfp_space + cif->vfp_args[vi++] * 4; + ffi_put_arg (ty, a, vfp_slot); continue; } - - /* Align if necessary */ - alignment = (*p_arg)->alignment; -#ifdef _WIN32_WCE - if (alignment > 4) - alignment = 4; -#endif - if ((alignment - 1) & (unsigned) argp) { - argp = (char *) ALIGN(argp, alignment); - } - - if ((*p_arg)->type == FFI_TYPE_STRUCT) - argp = (char *) ALIGN(argp, 4); - - 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)) + /* Try allocating in core registers. */ + else if (!done_with_regs && !is_vfp_type) + { + char *tregp = ffi_align (ty, regp); + size_t size = ty->size; + size = (size < 4) ? 4 : size; // pad + /* Check if there is space left in the aligned register + area to place the argument. */ + if (tregp + size <= eo_regp) { - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + regp = tregp + ffi_put_arg (ty, a, tregp); + done_with_regs = (regp == argp); + // ensure we did not write into the stack area + FFI_ASSERT (regp <= argp); + continue; } - else + /* In case there are no arguments in the stack area yet, + the argument is passed in the remaining core registers + and on the stack. */ + else if (!stack_used) { - memcpy(argp, *p_argv, z); + stack_used = 1; + done_with_regs = 1; + argp = tregp + ffi_put_arg (ty, a, tregp); + FFI_ASSERT (eo_regp < argp); + continue; } - p_argv++; - argp += z; + } + /* Base case, arguments are passed on the stack */ + stack_used = 1; + argp = ffi_align (ty, argp); + argp += ffi_put_arg (ty, a, argp); } - - /* Indicate the VFP registers used. */ - return ecif->cif->vfp_used; } /* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) { - int type_code; - /* Round the stack up to a multiple of 8 bytes. This isn't needed - everywhere, but it is on some platforms, and it doesn't harm anything - when it isn't needed. */ - cif->bytes = (cif->bytes + 7) & ~7; + int flags = 0, cabi = cif->abi; + size_t bytes = cif->bytes; + + /* Map out the register placements of VFP register args. The VFP + hard-float calling conventions are slightly more sophisticated + than the base calling conventions, so we do it here instead of + in ffi_prep_args(). */ + if (cabi == FFI_VFP) + layout_vfp_args (cif); /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_VOID: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - cif->flags = (unsigned) cif->rtype->type; + flags = ARM_TYPE_VOID; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + flags = ARM_TYPE_INT; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: - cif->flags = (unsigned) FFI_TYPE_SINT64; + flags = ARM_TYPE_INT64; + break; + + case FFI_TYPE_FLOAT: + flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_S : ARM_TYPE_INT); + break; + case FFI_TYPE_DOUBLE: + flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_D : ARM_TYPE_INT64); break; case FFI_TYPE_STRUCT: - if (cif->abi == FFI_VFP - && (type_code = vfp_type_p (cif->rtype)) != 0) + case FFI_TYPE_COMPLEX: + if (cabi == FFI_VFP) { - /* A Composite Type passed in VFP registers, either - FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */ - cif->flags = (unsigned) type_code; + int h = vfp_type_p (cif->rtype); + + flags = ARM_TYPE_VFP_N; + if (h == 0x100 + FFI_TYPE_FLOAT) + flags = ARM_TYPE_VFP_S; + if (h == 0x100 + FFI_TYPE_DOUBLE) + flags = ARM_TYPE_VFP_D; + if (h != 0) + break; } - else if (cif->rtype->size <= 4) - /* A Composite Type not larger than 4 bytes is returned in r0. */ - cif->flags = (unsigned)FFI_TYPE_INT; + + /* A Composite Type not larger than 4 bytes is returned in r0. + A Composite Type larger than 4 bytes, or whose size cannot + be determined statically ... is stored in memory at an + address passed [in r0]. */ + if (cif->rtype->size <= 4) + flags = ARM_TYPE_INT; else - /* A Composite Type larger than 4 bytes, or whose size cannot - be determined statically ... is stored in memory at an - address passed [in r0]. */ - cif->flags = (unsigned)FFI_TYPE_STRUCT; + { + flags = ARM_TYPE_STRUCT; + bytes += 4; + } break; default: - cif->flags = FFI_TYPE_INT; - break; + abort(); } - /* Map out the register placements of VFP register args. - The VFP hard-float calling conventions are slightly more sophisticated than - the base calling conventions, so we do it here instead of in ffi_prep_args(). */ - if (cif->abi == FFI_VFP) - layout_vfp_args (cif); + /* Round the stack up to a multiple of 8 bytes. This isn't needed + everywhere, but it is on some platforms, and it doesn't harm anything + when it isn't needed. */ + bytes = ALIGN (bytes, 8); + + /* Minimum stack space is the 4 register arguments that we pop. */ + if (bytes < 4*4) + bytes = 4*4; + + cif->bytes = bytes; + cif->flags = flags; return FFI_OK; } /* Perform machine dependent cif processing for variadic calls */ -ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, - unsigned int nfixedargs, - unsigned int ntotalargs) +ffi_status +ffi_prep_cif_machdep_var (ffi_cif * cif, + unsigned int nfixedargs, unsigned int ntotalargs) { /* VFP variadic calls actually use the SYSV ABI */ if (cif->abi == FFI_VFP) - cif->abi = FFI_SYSV; + cif->abi = FFI_SYSV; - return ffi_prep_cif_machdep(cif); + return ffi_prep_cif_machdep (cif); } -/* Prototypes for assembly functions, in sysv.S */ -extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *); -extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *); +/* Prototypes for assembly functions, in sysv.S. */ -void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +struct call_frame { - extended_cif ecif; - - int small_struct = (cif->flags == FFI_TYPE_INT - && cif->rtype->type == FFI_TYPE_STRUCT); - int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT - || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE); - - ecif.cif = cif; - ecif.avalue = avalue; + void *fp; + void *lr; + void *rvalue; + int flags; + void *closure; +}; - unsigned int temp; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ +extern void ffi_call_SYSV (void *stack, struct call_frame *, + void (*fn) (void)) FFI_HIDDEN; +extern void ffi_call_VFP (void *vfp_space, struct call_frame *, + void (*fn) (void), unsigned vfp_used) FFI_HIDDEN; - if ((rvalue == NULL) && - (cif->flags == FFI_TYPE_STRUCT)) +static void +ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue, + void **avalue, void *closure) +{ + int flags = cif->flags; + ffi_type *rtype = cif->rtype; + size_t bytes, rsize, vfp_size; + char *stack, *vfp_space, *new_rvalue; + struct call_frame *frame; + + rsize = 0; + if (rvalue == NULL) { - ecif.rvalue = alloca(cif->rtype->size); + /* If the return value is a struct and we don't have a return + value address then we need to make one. Otherwise the return + value is in registers and we can ignore them. */ + if (flags == ARM_TYPE_STRUCT) + rsize = rtype->size; + else + flags = ARM_TYPE_VOID; } - else if (small_struct) - ecif.rvalue = &temp; - else if (vfp_struct) + else if (flags == ARM_TYPE_VFP_N) { /* Largest case is double x 4. */ - ecif.rvalue = alloca(32); + rsize = 32; } - else - ecif.rvalue = rvalue; + else if (flags == ARM_TYPE_INT && rtype->type == FFI_TYPE_STRUCT) + rsize = 4; - switch (cif->abi) - { - case FFI_SYSV: - ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); - break; + /* Largest case. */ + vfp_size = (cif->abi == FFI_VFP && cif->vfp_used ? 8*8: 0); - case FFI_VFP: -#ifdef __ARM_EABI__ - ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); - break; -#endif + bytes = cif->bytes; + stack = alloca (vfp_size + bytes + sizeof(struct call_frame) + rsize); - default: - FFI_ASSERT(0); - break; + vfp_space = NULL; + if (vfp_size) + { + vfp_space = stack; + stack += vfp_size; } - if (small_struct) - memcpy (rvalue, &temp, cif->rtype->size); - else if (vfp_struct) - memcpy (rvalue, ecif.rvalue, cif->rtype->size); -} -/** private members **/ + frame = (struct call_frame *)(stack + bytes); -static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, - void** args, ffi_cif* cif, float *vfp_stack); + new_rvalue = rvalue; + if (rsize) + new_rvalue = (void *)(frame + 1); -void ffi_closure_SYSV (ffi_closure *); + frame->rvalue = new_rvalue; + frame->flags = flags; + frame->closure = closure; -void ffi_closure_VFP (ffi_closure *); + if (vfp_space) + { + ffi_prep_args_VFP (cif, flags, new_rvalue, avalue, stack, vfp_space); + ffi_call_VFP (vfp_space, frame, fn, cif->vfp_used); + } + else + { + ffi_prep_args_SYSV (cif, flags, new_rvalue, avalue, stack); + ffi_call_SYSV (stack, frame, fn); + } -/* This function is jumped to by the trampoline */ + if (rvalue && rvalue != new_rvalue) + memcpy (rvalue, new_rvalue, rtype->size); +} -unsigned int -ffi_closure_SYSV_inner (closure, respp, args, vfp_args) - ffi_closure *closure; - void **respp; - void *args; - void *vfp_args; +void +ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) { - // our various things... - ffi_cif *cif; - void **arg_area; + ffi_call_int (cif, fn, rvalue, avalue, NULL); +} - cif = closure->cif; - arg_area = (void**) alloca (cif->nargs * sizeof (void*)); +void +ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int (cif, fn, rvalue, avalue, closure); +} - /* this call will initialize ARG_AREA, such that each - * element in that array points to the corresponding - * value on the stack; and if the function returns - * a structure, it will re-set RESP to point to the - * structure return address. */ +static void * +ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue, + char *argp, void **avalue) +{ + ffi_type **arg_types = cif->arg_types; + int i, n; - ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args); + if (cif->flags == ARM_TYPE_STRUCT) + { + rvalue = *(void **) argp; + argp += 4; + } - (closure->fun) (cif, *respp, arg_area, closure->user_data); + for (i = 0, n = cif->nargs; i < n; i++) + { + ffi_type *ty = arg_types[i]; + size_t z = ty->size; - return cif->flags; + argp = ffi_align (ty, argp); + avalue[i] = (void *) argp; + argp += z; + } + + return rvalue; } -/*@-exportheader@*/ -static void -ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, - void **avalue, ffi_cif *cif, - /* Used only under VFP hard-float ABI. */ - float *vfp_stack) -/*@=exportheader@*/ +static void * +ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack, + char *vfp_space, void **avalue) { - register unsigned int i, vi = 0; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; + ffi_type **arg_types = cif->arg_types; + int i, n, vi = 0; + char *argp, *regp, *eo_regp; + char done_with_regs = 0; + char stack_used = 0; - argp = stack; + regp = stack; + eo_regp = argp = regp + 16; - if ( cif->flags == FFI_TYPE_STRUCT ) { - *rvalue = *(void **) argp; - argp += 4; - } - - p_argv = avalue; + if (cif->flags == ARM_TYPE_STRUCT) + { + rvalue = *(void **) regp; + regp += 4; + } - for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + for (i = 0, n = cif->nargs; i < n; i++) { - size_t z; - size_t alignment; - - if (cif->abi == FFI_VFP - && vi < cif->vfp_nargs && vfp_type_p (*p_arg)) + ffi_type *ty = arg_types[i]; + int is_vfp_type = vfp_type_p (ty); + size_t z = ty->size; + + if (vi < cif->vfp_nargs && is_vfp_type) { - *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]); + avalue[i] = vfp_space + cif->vfp_args[vi++] * 4; continue; } + else if (!done_with_regs && !is_vfp_type) + { + char *tregp = ffi_align (ty, regp); - alignment = (*p_arg)->alignment; - if (alignment < 4) - alignment = 4; -#ifdef _WIN32_WCE - else - if (alignment > 4) - alignment = 4; -#endif - /* Align if necessary */ - if ((alignment - 1) & (unsigned) argp) { - argp = (char *) ALIGN(argp, alignment); - } - - z = (*p_arg)->size; - - /* because we're little endian, this is what it turns into. */ + z = (z < 4) ? 4 : z; // pad - *p_argv = (void*) argp; + /* If the arguments either fits into the registers or uses registers + and stack, while we haven't read other things from the stack */ + if (tregp + z <= eo_regp || !stack_used) + { + /* Because we're little endian, this is what it turns into. */ + avalue[i] = (void *) tregp; + regp = tregp + z; + + /* If we read past the last core register, make sure we + have not read from the stack before and continue + reading after regp. */ + if (regp > eo_regp) + { + FFI_ASSERT (!stack_used); + argp = regp; + } + if (regp >= eo_regp) + { + done_with_regs = 1; + stack_used = 1; + } + continue; + } + } - p_argv++; + stack_used = 1; + argp = ffi_align (ty, argp); + avalue[i] = (void *) argp; argp += z; } - - return; + + return rvalue; } -/* How to make a trampoline. */ +struct closure_frame +{ + char vfp_space[8*8] __attribute__((aligned(8))); + char result[8*4]; + char argp[]; +}; + +int FFI_HIDDEN +ffi_closure_inner_SYSV (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + struct closure_frame *frame) +{ + void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); + void *rvalue = ffi_prep_incoming_args_SYSV (cif, frame->result, + frame->argp, avalue); + fun (cif, rvalue, avalue, user_data); + return cif->flags; +} + +int FFI_HIDDEN +ffi_closure_inner_VFP (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + struct closure_frame *frame) +{ + void **avalue = (void **) alloca (cif->nargs * sizeof (void *)); + void *rvalue = ffi_prep_incoming_args_VFP (cif, frame->result, frame->argp, + frame->vfp_space, avalue); + fun (cif, rvalue, avalue, user_data); + return cif->flags; +} -extern unsigned int ffi_arm_trampoline[3]; +void ffi_closure_SYSV (void) FFI_HIDDEN; +void ffi_closure_VFP (void) FFI_HIDDEN; +void ffi_go_closure_SYSV (void) FFI_HIDDEN; +void ffi_go_closure_VFP (void) FFI_HIDDEN; #if FFI_EXEC_TRAMPOLINE_TABLE @@ -380,8 +542,9 @@ extern void *ffi_closure_trampoline_table_page; typedef struct ffi_trampoline_table ffi_trampoline_table; typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry; -struct ffi_trampoline_table { - /* contigious writable and executable pages */ +struct ffi_trampoline_table +{ + /* contiguous writable and executable pages */ vm_address_t config_page; vm_address_t trampoline_page; @@ -394,8 +557,9 @@ struct ffi_trampoline_table { ffi_trampoline_table *next; }; -struct ffi_trampoline_table_entry { - void *(*trampoline)(); +struct ffi_trampoline_table_entry +{ + void *(*trampoline) (); ffi_trampoline_table_entry *next; }; @@ -421,64 +585,81 @@ ffi_trampoline_table_alloc () { ffi_trampoline_table *table = NULL; - /* Loop until we can allocate two contigious pages */ - while (table == NULL) { - vm_address_t config_page = 0x0; - kern_return_t kt; + /* Loop until we can allocate two contiguous pages */ + while (table == NULL) + { + vm_address_t config_page = 0x0; + kern_return_t kt; + + /* Try to allocate two pages */ + kt = + vm_allocate (mach_task_self (), &config_page, PAGE_SIZE * 2, + VM_FLAGS_ANYWHERE); + if (kt != KERN_SUCCESS) + { + fprintf (stderr, "vm_allocate() failure: %d at %s:%d\n", kt, + __FILE__, __LINE__); + break; + } - /* Try to allocate two pages */ - kt = vm_allocate (mach_task_self (), &config_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE); - if (kt != KERN_SUCCESS) { - fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); - break; - } + /* Now drop the second half of the allocation to make room for the trampoline table */ + vm_address_t trampoline_page = config_page + PAGE_SIZE; + kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE); + if (kt != KERN_SUCCESS) + { + fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, + __FILE__, __LINE__); + break; + } - /* Now drop the second half of the allocation to make room for the trampoline table */ - vm_address_t trampoline_page = config_page+PAGE_SIZE; - kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE); - if (kt != KERN_SUCCESS) { - fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); - break; - } + /* Remap the trampoline table to directly follow the config page */ + vm_prot_t cur_prot; + vm_prot_t max_prot; - /* Remap the trampoline table to directly follow the config page */ - vm_prot_t cur_prot; - vm_prot_t max_prot; + kt = + vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE, + mach_task_self (), + (vm_address_t) & ffi_closure_trampoline_table_page, FALSE, + &cur_prot, &max_prot, VM_INHERIT_SHARE); - kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE, mach_task_self (), (vm_address_t) &ffi_closure_trampoline_table_page, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE); + /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */ + if (kt != KERN_SUCCESS) + { + /* Log unexpected failures */ + if (kt != KERN_NO_SPACE) + { + fprintf (stderr, "vm_remap() failure: %d at %s:%d\n", kt, + __FILE__, __LINE__); + } - /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */ - if (kt != KERN_SUCCESS) { - /* Log unexpected failures */ - if (kt != KERN_NO_SPACE) { - fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); - } + vm_deallocate (mach_task_self (), config_page, PAGE_SIZE); + continue; + } - vm_deallocate (mach_task_self (), config_page, PAGE_SIZE); - continue; - } + /* We have valid trampoline and config pages */ + table = calloc (1, sizeof (ffi_trampoline_table)); + table->free_count = FFI_TRAMPOLINE_COUNT; + table->config_page = config_page; + table->trampoline_page = trampoline_page; - /* We have valid trampoline and config pages */ - table = calloc (1, sizeof(ffi_trampoline_table)); - table->free_count = FFI_TRAMPOLINE_COUNT; - table->config_page = config_page; - table->trampoline_page = trampoline_page; + /* Create and initialize the free list */ + table->free_list_pool = + calloc (FFI_TRAMPOLINE_COUNT, sizeof (ffi_trampoline_table_entry)); - /* Create and initialize the free list */ - table->free_list_pool = calloc(FFI_TRAMPOLINE_COUNT, sizeof(ffi_trampoline_table_entry)); + uint16_t i; + for (i = 0; i < table->free_count; i++) + { + ffi_trampoline_table_entry *entry = &table->free_list_pool[i]; + entry->trampoline = + (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE)); - uint16_t i; - for (i = 0; i < table->free_count; i++) { - ffi_trampoline_table_entry *entry = &table->free_list_pool[i]; - entry->trampoline = (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE)); + if (i < table->free_count - 1) + entry->next = &table->free_list_pool[i + 1]; + } - if (i < table->free_count - 1) - entry->next = &table->free_list_pool[i+1]; + table->free_list = table->free_list_pool; } - table->free_list = table->free_list_pool; - } - return table; } @@ -486,28 +667,30 @@ void * ffi_closure_alloc (size_t size, void **code) { /* Create the closure */ - ffi_closure *closure = malloc(size); + ffi_closure *closure = malloc (size); if (closure == NULL) return NULL; - pthread_mutex_lock(&ffi_trampoline_lock); + pthread_mutex_lock (&ffi_trampoline_lock); /* Check for an active trampoline table with available entries. */ ffi_trampoline_table *table = ffi_trampoline_tables; - if (table == NULL || table->free_list == NULL) { - table = ffi_trampoline_table_alloc (); - if (table == NULL) { - free(closure); - return NULL; - } + if (table == NULL || table->free_list == NULL) + { + table = ffi_trampoline_table_alloc (); + if (table == NULL) + { + free (closure); + return NULL; + } - /* Insert the new table at the top of the list */ - table->next = ffi_trampoline_tables; - if (table->next != NULL) - table->next->prev = table; + /* Insert the new table at the top of the list */ + table->next = ffi_trampoline_tables; + if (table->next != NULL) + table->next->prev = table; - ffi_trampoline_tables = table; - } + ffi_trampoline_tables = table; + } /* Claim the free entry */ ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list; @@ -515,7 +698,7 @@ ffi_closure_alloc (size_t size, void **code) ffi_trampoline_tables->free_count--; entry->next = NULL; - pthread_mutex_unlock(&ffi_trampoline_lock); + pthread_mutex_unlock (&ffi_trampoline_lock); /* Initialize the return values */ *code = entry->trampoline; @@ -530,7 +713,7 @@ ffi_closure_free (void *ptr) { ffi_closure *closure = ptr; - pthread_mutex_lock(&ffi_trampoline_lock); + pthread_mutex_lock (&ffi_trampoline_lock); /* Fetch the table and entry references */ ffi_trampoline_table *table = closure->trampoline_table; @@ -543,36 +726,43 @@ ffi_closure_free (void *ptr) /* If all trampolines within this table are free, and at least one other table exists, deallocate * the table */ - if (table->free_count == FFI_TRAMPOLINE_COUNT && ffi_trampoline_tables != table) { - /* Remove from the list */ - if (table->prev != NULL) - table->prev->next = table->next; - - if (table->next != NULL) - table->next->prev = table->prev; - - /* Deallocate pages */ - kern_return_t kt; - kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE); - if (kt != KERN_SUCCESS) - fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); - - kt = vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE); - if (kt != KERN_SUCCESS) - fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); - - /* Deallocate free list */ - free (table->free_list_pool); - free (table); - } else if (ffi_trampoline_tables != table) { - /* Otherwise, bump this table to the top of the list */ - table->prev = NULL; - table->next = ffi_trampoline_tables; - if (ffi_trampoline_tables != NULL) - ffi_trampoline_tables->prev = table; - - ffi_trampoline_tables = table; - } + if (table->free_count == FFI_TRAMPOLINE_COUNT + && ffi_trampoline_tables != table) + { + /* Remove from the list */ + if (table->prev != NULL) + table->prev->next = table->next; + + if (table->next != NULL) + table->next->prev = table->prev; + + /* Deallocate pages */ + kern_return_t kt; + kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE); + if (kt != KERN_SUCCESS) + fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, + __FILE__, __LINE__); + + kt = + vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE); + if (kt != KERN_SUCCESS) + fprintf (stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, + __FILE__, __LINE__); + + /* Deallocate free list */ + free (table->free_list_pool); + free (table); + } + else if (ffi_trampoline_tables != table) + { + /* Otherwise, bump this table to the top of the list */ + table->prev = NULL; + table->next = ffi_trampoline_tables; + if (ffi_trampoline_tables != NULL) + ffi_trampoline_tables->prev = table; + + ffi_trampoline_tables = table; + } pthread_mutex_unlock (&ffi_trampoline_lock); @@ -582,133 +772,225 @@ ffi_closure_free (void *ptr) #else -#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ -({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - unsigned int __fun = (unsigned int)(FUN); \ - unsigned int __ctx = (unsigned int)(CTX); \ - unsigned char *insns = (unsigned char *)(CTX); \ - memcpy (__tramp, ffi_arm_trampoline, sizeof ffi_arm_trampoline); \ - *(unsigned int*) &__tramp[12] = __ctx; \ - *(unsigned int*) &__tramp[16] = __fun; \ - __clear_cache((&__tramp[0]), (&__tramp[19])); /* Clear data mapping. */ \ - __clear_cache(insns, insns + 3 * sizeof (unsigned int)); \ - /* Clear instruction \ - mapping. */ \ - }) +extern unsigned int ffi_arm_trampoline[2] FFI_HIDDEN; #endif /* the cif must already be prep'ed */ ffi_status -ffi_prep_closure_loc (ffi_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void *codeloc) +ffi_prep_closure_loc (ffi_closure * closure, + ffi_cif * cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, void *codeloc) { - void (*closure_func)(ffi_closure*) = NULL; + void (*closure_func) (void) = ffi_closure_SYSV; - if (cif->abi == FFI_SYSV) - closure_func = &ffi_closure_SYSV; -#ifdef __ARM_EABI__ - else if (cif->abi == FFI_VFP) - closure_func = &ffi_closure_VFP; -#endif - else + if (cif->abi == FFI_VFP) + { + /* We only need take the vfp path if there are vfp arguments. */ + if (cif->vfp_used) + closure_func = ffi_closure_VFP; + } + else if (cif->abi != FFI_SYSV) return FFI_BAD_ABI; - + #if FFI_EXEC_TRAMPOLINE_TABLE - void **config = FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc); + void **config = FFI_TRAMPOLINE_CODELOC_CONFIG (codeloc); config[0] = closure; config[1] = closure_func; #else - FFI_INIT_TRAMPOLINE (&closure->tramp[0], \ - closure_func, \ - codeloc); + memcpy (closure->tramp, ffi_arm_trampoline, 8); + __clear_cache(closure->tramp, closure->tramp + 8); /* clear data map */ + __clear_cache(codeloc, codeloc + 8); /* clear insn map */ + *(void (**)(void))(closure->tramp + 8) = closure_func; #endif - closure->cif = cif; + closure->cif = cif; + closure->fun = fun; closure->user_data = user_data; - closure->fun = fun; + + return FFI_OK; +} + +ffi_status +ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *)) +{ + void (*closure_func) (void) = ffi_go_closure_SYSV; + + if (cif->abi == FFI_VFP) + { + /* We only need take the vfp path if there are vfp arguments. */ + if (cif->vfp_used) + closure_func = ffi_go_closure_VFP; + } + else if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; + + closure->tramp = closure_func; + closure->cif = cif; + closure->fun = fun; return FFI_OK; } /* Below are routines for VFP hard-float support. */ -static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum) +/* A subroutine of vfp_type_p. Given a structure type, return the type code + of the first non-structure element. Recurse for structure elements. + Return -1 if the structure is in fact empty, i.e. no nested elements. */ + +static int +is_hfa0 (const ffi_type *ty) { - switch (t->type) - { - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - *elt = (int) t->type; - *elnum = 1; - return 1; + ffi_type **elements = ty->elements; + int i, ret = -1; + + if (elements != NULL) + for (i = 0; elements[i]; ++i) + { + ret = elements[i]->type; + if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX) + { + ret = is_hfa0 (elements[i]); + if (ret < 0) + continue; + } + break; + } - case FFI_TYPE_STRUCT_VFP_FLOAT: - *elt = FFI_TYPE_FLOAT; - *elnum = t->size / sizeof (float); - return 1; + return ret; +} - case FFI_TYPE_STRUCT_VFP_DOUBLE: - *elt = FFI_TYPE_DOUBLE; - *elnum = t->size / sizeof (double); - return 1; +/* A subroutine of vfp_type_p. Given a structure type, return true if all + of the non-structure elements are the same as CANDIDATE. */ - case FFI_TYPE_STRUCT:; +static int +is_hfa1 (const ffi_type *ty, int candidate) +{ + ffi_type **elements = ty->elements; + int i; + + if (elements != NULL) + for (i = 0; elements[i]; ++i) { - int base_elt = 0, total_elnum = 0; - ffi_type **el = t->elements; - while (*el) - { - int el_elt = 0, el_elnum = 0; - if (! rec_vfp_type_p (*el, &el_elt, &el_elnum) - || (base_elt && base_elt != el_elt) - || total_elnum + el_elnum > 4) - return 0; - base_elt = el_elt; - total_elnum += el_elnum; - el++; - } - *elnum = total_elnum; - *elt = base_elt; - return 1; + int t = elements[i]->type; + if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) + { + if (!is_hfa1 (elements[i], candidate)) + return 0; + } + else if (t != candidate) + return 0; } - default: ; - } - return 0; + + return 1; } -static int vfp_type_p (ffi_type *t) +/* Determine if TY is an homogenous floating point aggregate (HFA). + That is, a structure consisting of 1 to 4 members of all the same type, + where that type is a floating point scalar. + + Returns non-zero iff TY is an HFA. The result is an encoded value where + bits 0-7 contain the type code, and bits 8-10 contain the element count. */ + +static int +vfp_type_p (const ffi_type *ty) { - int elt, elnum; - if (rec_vfp_type_p (t, &elt, &elnum)) + ffi_type **elements; + int candidate, i; + size_t size, ele_count; + + /* Quickest tests first. */ + candidate = ty->type; + switch (ty->type) { - if (t->type == FFI_TYPE_STRUCT) - { - if (elnum == 1) - t->type = elt; - else - t->type = (elt == FFI_TYPE_FLOAT - ? FFI_TYPE_STRUCT_VFP_FLOAT - : FFI_TYPE_STRUCT_VFP_DOUBLE); - } - return (int) t->type; + default: + return 0; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + ele_count = 1; + goto done; + case FFI_TYPE_COMPLEX: + candidate = ty->elements[0]->type; + if (candidate != FFI_TYPE_FLOAT && candidate != FFI_TYPE_DOUBLE) + return 0; + ele_count = 2; + goto done; + case FFI_TYPE_STRUCT: + break; } - return 0; + + /* No HFA types are smaller than 4 bytes, or larger than 32 bytes. */ + size = ty->size; + if (size < 4 || size > 32) + return 0; + + /* Find the type of the first non-structure member. */ + elements = ty->elements; + candidate = elements[0]->type; + if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX) + { + for (i = 0; ; ++i) + { + candidate = is_hfa0 (elements[i]); + if (candidate >= 0) + break; + } + } + + /* If the first member is not a floating point type, it's not an HFA. + Also quickly re-check the size of the structure. */ + switch (candidate) + { + case FFI_TYPE_FLOAT: + ele_count = size / sizeof(float); + if (size != ele_count * sizeof(float)) + return 0; + break; + case FFI_TYPE_DOUBLE: + ele_count = size / sizeof(double); + if (size != ele_count * sizeof(double)) + return 0; + break; + default: + return 0; + } + if (ele_count > 4) + return 0; + + /* Finally, make sure that all scalar elements are the same type. */ + for (i = 0; elements[i]; ++i) + { + int t = elements[i]->type; + if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX) + { + if (!is_hfa1 (elements[i], candidate)) + return 0; + } + else if (t != candidate) + return 0; + } + + /* All tests succeeded. Encode the result. */ + done: + return (ele_count << 8) | candidate; } -static void place_vfp_arg (ffi_cif *cif, ffi_type *t) +static int +place_vfp_arg (ffi_cif *cif, int h) { - int reg = cif->vfp_reg_free; - int nregs = t->size / sizeof (float); - int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT - || t->type == FFI_TYPE_FLOAT) ? 1 : 2); + unsigned short reg = cif->vfp_reg_free; + int align = 1, nregs = h >> 8; + + if ((h & 0xff) == FFI_TYPE_DOUBLE) + align = 2, nregs *= 2; + /* Align register number. */ if ((reg & 1) && align == 2) reg++; + while (reg + nregs <= 16) { int s, new_used = 0; @@ -733,24 +1015,29 @@ static void place_vfp_arg (ffi_cif *cif, ffi_type *t) reg += 1; cif->vfp_reg_free = reg; } - return; - next_reg: ; + return 0; + next_reg:; } + // done, mark all regs as used + cif->vfp_reg_free = 16; + cif->vfp_used = 0xFFFF; + return 1; } -static void layout_vfp_args (ffi_cif *cif) +static void +layout_vfp_args (ffi_cif * cif) { int i; /* Init VFP fields */ cif->vfp_used = 0; cif->vfp_nargs = 0; cif->vfp_reg_free = 0; - memset (cif->vfp_args, -1, 16); /* Init to -1. */ + memset (cif->vfp_args, -1, 16); /* Init to -1. */ for (i = 0; i < cif->nargs; i++) { - ffi_type *t = cif->arg_types[i]; - if (vfp_type_p (t)) - place_vfp_arg (cif, t); + int h = vfp_type_p (cif->arg_types[i]); + if (h && place_vfp_arg (cif, h) == 1) + break; } } diff --git a/libffi/src/arm/ffitarget.h b/libffi/src/arm/ffitarget.h index 26d494d..4f473f9 100644 --- a/libffi/src/arm/ffitarget.h +++ b/libffi/src/arm/ffitarget.h @@ -53,19 +53,17 @@ typedef enum ffi_abi { #define FFI_EXTRA_CIF_FIELDS \ int vfp_used; \ - short vfp_reg_free, vfp_nargs; \ + unsigned short vfp_reg_free, vfp_nargs; \ signed char vfp_args[16] \ -/* Internally used. */ -#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1) -#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2) - #define FFI_TARGET_SPECIFIC_VARIADIC +#define FFI_TARGET_HAS_COMPLEX_TYPE /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 -#define FFI_TRAMPOLINE_SIZE 20 +#define FFI_GO_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 12 #define FFI_NATIVE_RAW_API 0 #endif diff --git a/libffi/src/arm/gentramp.sh b/libffi/src/arm/gentramp.sh deleted file mode 100755 index 74f0b86..0000000 --- a/libffi/src/arm/gentramp.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/sh - -# ----------------------------------------------------------------------- -# gentramp.sh - Copyright (c) 2010, Plausible Labs Cooperative, Inc. -# -# ARM Trampoline Page Generator -# -# 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. -# ----------------------------------------------------------------------- - -PROGNAME=$0 - -# Each trampoline is exactly 3 instructions, or 12 bytes. If any of these values change, -# the entire arm trampoline implementation must be updated to match, too. - -# Size of an individual trampoline, in bytes -TRAMPOLINE_SIZE=12 - -# Page size, in bytes -PAGE_SIZE=4096 - -# Compute the size of the reachable config page; The first 16 bytes of the config page -# are unreachable due to our maximum pc-relative ldr offset. -PAGE_AVAIL=`expr $PAGE_SIZE - 16` - -# Compute the number of of available trampolines. -TRAMPOLINE_COUNT=`expr $PAGE_AVAIL / $TRAMPOLINE_SIZE` - -header () { - echo "# GENERATED CODE - DO NOT EDIT" - echo "# This file was generated by $PROGNAME" - echo "" - - # Write out the license header -cat << EOF -# Copyright (c) 2010, Plausible Labs Cooperative, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# ``Software''), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -# ----------------------------------------------------------------------- - -EOF - - # Write out the trampoline table, aligned to the page boundary - echo ".text" - echo ".align 12" - echo ".globl _ffi_closure_trampoline_table_page" - echo "_ffi_closure_trampoline_table_page:" -} - - -# WARNING - Don't modify the trampoline code size without also updating the relevent libffi code -trampoline () { - cat << END - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - -END -} - -main () { - # Write out the header - header - - # Write out the trampolines - local i=0 - while [ $i -lt ${TRAMPOLINE_COUNT} ]; do - trampoline - local i=`expr $i + 1` - done -} - -main diff --git a/libffi/src/arm/internal.h b/libffi/src/arm/internal.h new file mode 100644 index 0000000..6cf0b2a --- /dev/null +++ b/libffi/src/arm/internal.h @@ -0,0 +1,7 @@ +#define ARM_TYPE_VFP_S 0 +#define ARM_TYPE_VFP_D 1 +#define ARM_TYPE_VFP_N 2 +#define ARM_TYPE_INT64 3 +#define ARM_TYPE_INT 4 +#define ARM_TYPE_VOID 5 +#define ARM_TYPE_STRUCT 6 diff --git a/libffi/src/arm/sysv.S b/libffi/src/arm/sysv.S index fb38cd6..fd16589 100644 --- a/libffi/src/arm/sysv.S +++ b/libffi/src/arm/sysv.S @@ -1,8 +1,8 @@ /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc. Copyright (c) 2011 Plausible Labs Cooperative, Inc. - - ARM Foreign Function Interface + + ARM Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -28,477 +28,307 @@ #define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> -#ifdef HAVE_MACHINE_ASM_H -#include <machine/asm.h> -#else -#ifdef __USER_LABEL_PREFIX__ -#define CONCAT1(a, b) CONCAT2(a, b) -#define CONCAT2(a, b) a ## b - -/* Use the right prefix for global labels. */ -#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) -#else -#define CNAME(x) x -#endif -#ifdef __APPLE__ -#define ENTRY(x) .globl _##x; _##x: -#else -#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): -#endif /* __APPLE__ */ -#endif - -#ifdef __ELF__ -#define LSYM(x) .x -#else -#define LSYM(x) x -#endif - -/* Use the SOFTFP return value ABI on Mac OS X, as per the iOS ABI - Function Call Guide */ -#ifdef __APPLE__ -#define __SOFTFP__ -#endif - -/* We need a better way of testing for this, but for now, this is all - we can do. */ -@ This selects the minimum architecture level required. -#define __ARM_ARCH__ 3 - -#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) -# undef __ARM_ARCH__ -# define __ARM_ARCH__ 4 -#endif - -#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ - || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ - || defined(__ARM_ARCH_5TEJ__) -# undef __ARM_ARCH__ -# define __ARM_ARCH__ 5 -#endif - -#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ +#include <ffi_cfi.h> +#include "internal.h" + +/* GCC 4.8 provides __ARM_ARCH; construct it otherwise. */ +#ifndef __ARM_ARCH +# if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ + || defined(__ARM_ARCH_7EM__) +# define __ARM_ARCH 7 +# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \ || defined(__ARM_ARCH_6M__) -# undef __ARM_ARCH__ -# define __ARM_ARCH__ 6 -#endif - -#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ - || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ - || defined(__ARM_ARCH_7EM__) -# undef __ARM_ARCH__ -# define __ARM_ARCH__ 7 -#endif - -#if __ARM_ARCH__ >= 5 -# define call_reg(x) blx x -#elif defined (__ARM_ARCH_4T__) -# define call_reg(x) mov lr, pc ; bx x -# if defined(__thumb__) || defined(__THUMB_INTERWORK__) -# define __INTERWORKING__ +# define __ARM_ARCH 6 +# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH 5 +# else +# define __ARM_ARCH 4 # endif -#else -# define call_reg(x) mov lr, pc ; mov pc, x #endif /* Conditionally compile unwinder directives. */ +.macro UNWIND text:vararg #ifdef __ARM_EABI__ -#define UNWIND -#else -#define UNWIND @ + \text #endif - - -#if defined(__thumb__) && !defined(__THUMB_INTERWORK__) -.macro ARM_FUNC_START name - .text - .align 0 - .thumb - .thumb_func -#ifdef __APPLE__ - ENTRY($0) -#else - ENTRY(\name) -#endif - bx pc - nop - .arm - UNWIND .fnstart -/* A hook to tell gdb that we've switched to ARM mode. Also used to call - directly from other local arm routines. */ -#ifdef __APPLE__ -_L__$0: -#else -_L__\name: -#endif -.endm -#else -.macro ARM_FUNC_START name - .text - .align 0 - .arm -#ifdef __APPLE__ - ENTRY($0) -#else - ENTRY(\name) -#endif - UNWIND .fnstart .endm +#if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__) + .cfi_sections .debug_frame #endif -.macro RETLDM regs=, cond=, dirn=ia -#if defined (__INTERWORKING__) - .ifc "\regs","" - ldr\cond lr, [sp], #4 - .else - ldm\cond\dirn sp!, {\regs, lr} - .endif - bx\cond lr +#define CONCAT(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +#ifdef __USER_LABEL_PREFIX__ +# define CNAME(X) CONCAT (__USER_LABEL_PREFIX__, X) #else - .ifc "\regs","" - ldr\cond pc, [sp], #4 - .else - ldm\cond\dirn sp!, {\regs, pc} - .endif +# define CNAME(X) X +#endif +#ifdef __ELF__ +# define SIZE(X) .size CNAME(X), . - CNAME(X) +# define TYPE(X, Y) .type CNAME(X), Y +#else +# define SIZE(X) +# define TYPE(X, Y) #endif -.endm - - @ r0: ffi_prep_args - @ r1: &ecif - @ r2: cif->bytes - @ r3: fig->flags - @ sp+0: ecif.rvalue - - @ This assumes we are using gas. -ARM_FUNC_START ffi_call_SYSV - @ Save registers - stmfd sp!, {r0-r3, fp, lr} - UNWIND .save {r0-r3, fp, lr} - mov fp, sp - - UNWIND .setfp fp, sp - - @ Make room for all of the new args. - sub sp, fp, r2 - - @ Place all of the ffi_prep_args in position - mov r0, sp - @ r1 already set - - @ Call ffi_prep_args(stack, &ecif) - bl CNAME(ffi_prep_args) - - @ move first 4 parameters in registers - ldmia sp, {r0-r3} - - @ and adjust stack - sub lr, fp, sp @ cif->bytes == fp - sp - ldr ip, [fp] @ load fn() in advance - cmp lr, #16 - movhs lr, #16 - add sp, sp, lr - - @ call (fn) (...) - call_reg(ip) - - @ Remove the space we pushed for the args - mov sp, fp - - @ Load r2 with the pointer to storage for the return value - ldr r2, [sp, #24] - @ Load r3 with the return type code - ldr r3, [sp, #12] +#define ARM_FUNC_START(name, gl) \ + .align 3; \ + .ifne gl; .globl CNAME(name); FFI_HIDDEN(CNAME(name)); .endif; \ + TYPE(name, %function); \ + CNAME(name): - @ If the return value pointer is NULL, assume no return value. - cmp r2, #0 - beq LSYM(Lepilogue) +#define ARM_FUNC_END(name) \ + SIZE(name) -@ return INT - cmp r3, #FFI_TYPE_INT -#if defined(__SOFTFP__) || defined(__ARM_EABI__) - cmpne r3, #FFI_TYPE_FLOAT -#endif - streq r0, [r2] - beq LSYM(Lepilogue) +/* Aid in defining a jump table with 8 bytes between entries. */ +.macro E index + .if . - 0b - 8*\index + .error "type table out of sync" + .endif +.endm - @ return INT64 - cmp r3, #FFI_TYPE_SINT64 -#if defined(__SOFTFP__) || defined(__ARM_EABI__) - cmpne r3, #FFI_TYPE_DOUBLE -#endif - stmeqia r2, {r0, r1} + .text + .syntax unified + .arm -#if !defined(__SOFTFP__) && !defined(__ARM_EABI__) - beq LSYM(Lepilogue) + /* We require interworking on LDM, which implies ARMv5T, + which implies the existance of BLX. */ + .arch armv5t + + /* Note that we use STC and LDC to encode VFP instructions, + so that we do not need ".fpu vfp", nor get that added to + the object file attributes. These will not be executed + unless the FFI_VFP abi is used. */ + + @ r0: stack + @ r1: frame + @ r2: fn + @ r3: vfp_used + +ARM_FUNC_START(ffi_call_VFP, 1) + UNWIND .fnstart + cfi_startproc + + cmp r3, #3 @ load only d0 if possible + ldcle p11, cr0, [r0] @ vldrle d0, [sp] + ldcgt p11, cr0, [r0], {16} @ vldmgt sp, {d0-d7} + add r0, r0, #64 @ discard the vfp register args + /* FALLTHRU */ +ARM_FUNC_END(ffi_call_VFP) + +ARM_FUNC_START(ffi_call_SYSV, 1) + stm r1, {fp, lr} + mov fp, r1 + + @ This is a bit of a lie wrt the origin of the unwind info, but + @ now we've got the usual frame pointer and two saved registers. + UNWIND .save {fp,lr} + UNWIND .setfp fp, sp + cfi_def_cfa(fp, 8) + cfi_rel_offset(fp, 0) + cfi_rel_offset(lr, 4) + + mov sp, r0 @ install the stack pointer + mov lr, r2 @ move the fn pointer out of the way + ldr ip, [fp, #16] @ install the static chain + ldmia sp!, {r0-r3} @ move first 4 parameters in registers. + blx lr @ call fn -@ return FLOAT - cmp r3, #FFI_TYPE_FLOAT - stfeqs f0, [r2] - beq LSYM(Lepilogue) + @ Load r2 with the pointer to storage for the return value + @ Load r3 with the return type code + ldr r2, [fp, #8] + ldr r3, [fp, #12] -@ return DOUBLE or LONGDOUBLE - cmp r3, #FFI_TYPE_DOUBLE - stfeqd f0, [r2] -#endif + @ Deallocate the stack with the arguments. + mov sp, fp + cfi_def_cfa_register(sp) -LSYM(Lepilogue): -#if defined (__INTERWORKING__) - ldmia sp!, {r0-r3,fp, lr} - bx lr -#else - ldmia sp!, {r0-r3,fp, pc} -#endif + @ Store values stored in registers. + .align 3 + add pc, pc, r3, lsl #3 + nop +0: +E ARM_TYPE_VFP_S + stc p10, cr0, [r2] @ vstr s0, [r2] + pop {fp,pc} +E ARM_TYPE_VFP_D + stc p11, cr0, [r2] @ vstr d0, [r2] + pop {fp,pc} +E ARM_TYPE_VFP_N + stc p11, cr0, [r2], {8} @ vstm r2, {d0-d3} + pop {fp,pc} +E ARM_TYPE_INT64 + str r1, [r2, #4] + nop +E ARM_TYPE_INT + str r0, [r2] + pop {fp,pc} +E ARM_TYPE_VOID + pop {fp,pc} + nop +E ARM_TYPE_STRUCT + pop {fp,pc} -.ffi_call_SYSV_end: - UNWIND .fnend -#ifdef __ELF__ - .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) -#endif + cfi_endproc + UNWIND .fnend +ARM_FUNC_END(ffi_call_SYSV) /* - unsigned int FFI_HIDDEN - ffi_closure_SYSV_inner (closure, respp, args) - ffi_closure *closure; - void **respp; - void *args; + int ffi_closure_inner_* (cif, fun, user_data, frame) */ -ARM_FUNC_START ffi_closure_SYSV - UNWIND .pad #16 +ARM_FUNC_START(ffi_go_closure_SYSV, 1) + cfi_startproc + stmdb sp!, {r0-r3} @ save argument regs + cfi_adjust_cfa_offset(16) + ldr r0, [ip, #4] @ load cif + ldr r1, [ip, #8] @ load fun + mov r2, ip @ load user_data + b 0f + cfi_endproc +ARM_FUNC_END(ffi_go_closure_SYSV) + +ARM_FUNC_START(ffi_closure_SYSV, 1) + UNWIND .fnstart + cfi_startproc + stmdb sp!, {r0-r3} @ save argument regs + cfi_adjust_cfa_offset(16) + ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif + ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun + ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data +0: + add ip, sp, #16 @ compute entry sp + sub sp, sp, #64+32 @ allocate frame + cfi_adjust_cfa_offset(64+32) + stmdb sp!, {ip,lr} + + /* Remember that EABI unwind info only applies at call sites. + We need do nothing except note the save of the stack pointer + and the link registers. */ + UNWIND .save {sp,lr} + cfi_adjust_cfa_offset(8) + cfi_rel_offset(lr, 4) + + add r3, sp, #8 @ load frame + bl CNAME(ffi_closure_inner_SYSV) + + @ Load values returned in registers. + add r2, sp, #8+64 @ load result + adr r3, CNAME(ffi_closure_ret) + add pc, r3, r0, lsl #3 + cfi_endproc + UNWIND .fnend +ARM_FUNC_END(ffi_closure_SYSV) + +ARM_FUNC_START(ffi_go_closure_VFP, 1) + cfi_startproc + stmdb sp!, {r0-r3} @ save argument regs + cfi_adjust_cfa_offset(16) + ldr r0, [ip, #4] @ load cif + ldr r1, [ip, #8] @ load fun + mov r2, ip @ load user_data + b 0f + cfi_endproc +ARM_FUNC_END(ffi_go_closure_VFP) + +ARM_FUNC_START(ffi_closure_VFP, 1) + UNWIND .fnstart + cfi_startproc + stmdb sp!, {r0-r3} @ save argument regs + cfi_adjust_cfa_offset(16) + ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif + ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun + ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data +0: add ip, sp, #16 - stmfd sp!, {ip, lr} - UNWIND .save {r0, lr} - add r2, sp, #8 - UNWIND .pad #16 - sub sp, sp, #16 - str sp, [sp, #8] - add r1, sp, #8 - bl CNAME(ffi_closure_SYSV_inner) - cmp r0, #FFI_TYPE_INT - beq .Lretint - - cmp r0, #FFI_TYPE_FLOAT -#if defined(__SOFTFP__) || defined(__ARM_EABI__) - beq .Lretint -#else - beq .Lretfloat -#endif - - cmp r0, #FFI_TYPE_DOUBLE -#if defined(__SOFTFP__) || defined(__ARM_EABI__) - beq .Lretlonglong -#else - beq .Lretdouble -#endif + sub sp, sp, #64+32 @ allocate frame + cfi_adjust_cfa_offset(64+32) + stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7} + stmdb sp!, {ip,lr} + + /* See above. */ + UNWIND .save {sp,lr} + cfi_adjust_cfa_offset(8) + cfi_rel_offset(lr, 4) + + add r3, sp, #8 @ load frame + bl CNAME(ffi_closure_inner_VFP) + + @ Load values returned in registers. + add r2, sp, #8+64 @ load result + adr r3, CNAME(ffi_closure_ret) + add pc, r3, r0, lsl #3 + cfi_endproc + UNWIND .fnend +ARM_FUNC_END(ffi_closure_VFP) + +/* Load values returned in registers for both closure entry points. + Note that we use LDM with SP in the register set. This is deprecated + by ARM, but not yet unpredictable. */ + +ARM_FUNC_START(ffi_closure_ret, 0) + cfi_startproc + cfi_rel_offset(sp, 0) + cfi_rel_offset(lr, 4) +0: +E ARM_TYPE_VFP_S + ldc p10, cr0, [r2] @ vldr s0, [r2] + ldm sp, {sp,pc} +E ARM_TYPE_VFP_D + ldc p11, cr0, [r2] @ vldr d0, [r2] + ldm sp, {sp,pc} +E ARM_TYPE_VFP_N + ldc p11, cr0, [r2], {8} @ vldm r2, {d0-d3} + ldm sp, {sp,pc} +E ARM_TYPE_INT64 + ldr r1, [r2, #4] + nop +E ARM_TYPE_INT + ldr r0, [r2] + ldm sp, {sp,pc} +E ARM_TYPE_VOID + ldm sp, {sp,pc} + nop +E ARM_TYPE_STRUCT + ldm sp, {sp,pc} + cfi_endproc +ARM_FUNC_END(ffi_closure_ret) - cmp r0, #FFI_TYPE_LONGDOUBLE -#if defined(__SOFTFP__) || defined(__ARM_EABI__) - beq .Lretlonglong -#else - beq .Lretlongdouble -#endif +#if FFI_EXEC_TRAMPOLINE_TABLE - cmp r0, #FFI_TYPE_SINT64 - beq .Lretlonglong -.Lclosure_epilogue: - add sp, sp, #16 - ldmfd sp, {sp, pc} -.Lretint: - ldr r0, [sp] - b .Lclosure_epilogue -.Lretlonglong: - ldr r0, [sp] - ldr r1, [sp, #4] - b .Lclosure_epilogue - -#if !defined(__SOFTFP__) && !defined(__ARM_EABI__) -.Lretfloat: - ldfs f0, [sp] - b .Lclosure_epilogue -.Lretdouble: - ldfd f0, [sp] - b .Lclosure_epilogue -.Lretlongdouble: - ldfd f0, [sp] - b .Lclosure_epilogue -#endif +/* ??? The iOS support should be updated. The first insn used to + be STMFD, but that's been moved into ffi_closure_SYSV. If the + writable page is put after this one we can make use of the + pc+8 feature of the architecture. We can also reduce the size + of the thunk to 8 and pack more of these into the page. -.ffi_closure_SYSV_end: - UNWIND .fnend -#ifdef __ELF__ - .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) -#endif + In the meantime, simply replace the STMFD with a NOP so as to + keep all the magic numbers the same within ffi.c. */ + .align 12 +ARM_FUNC_START(ffi_closure_trampoline_table_page) +.rept 4096 / 12 + nop + ldr ip, [pc, #-4092] + ldr pc, [pc, #-4092] +.endr -/* Below are VFP hard-float ABI call and closure implementations. - Add VFP FPU directive here. This is only compiled into the library - under EABI. */ -#ifdef __ARM_EABI__ - .fpu vfp - - @ r0: fn - @ r1: &ecif - @ r2: cif->bytes - @ r3: fig->flags - @ sp+0: ecif.rvalue - -ARM_FUNC_START ffi_call_VFP - @ Save registers - stmfd sp!, {r0-r3, fp, lr} - UNWIND .save {r0-r3, fp, lr} - mov fp, sp - UNWIND .setfp fp, sp - - @ Make room for all of the new args. - sub sp, sp, r2 - - @ Make room for loading VFP args - sub sp, sp, #64 - - @ Place all of the ffi_prep_args in position - mov r0, sp - @ r1 already set - sub r2, fp, #64 @ VFP scratch space - - @ Call ffi_prep_args(stack, &ecif, vfp_space) - bl CNAME(ffi_prep_args) - - @ Load VFP register args if needed - cmp r0, #0 - beq LSYM(Lbase_args) - - @ Load only d0 if possible - cmp r0, #3 - sub ip, fp, #64 - flddle d0, [ip] - fldmiadgt ip, {d0-d7} - -LSYM(Lbase_args): - @ move first 4 parameters in registers - ldmia sp, {r0-r3} - - @ and adjust stack - sub lr, ip, sp @ cif->bytes == (fp - 64) - sp - ldr ip, [fp] @ load fn() in advance - cmp lr, #16 - movhs lr, #16 - add sp, sp, lr - - @ call (fn) (...) - call_reg(ip) - - @ Remove the space we pushed for the args - mov sp, fp +#else - @ Load r2 with the pointer to storage for - @ the return value - ldr r2, [sp, #24] - - @ Load r3 with the return type code - ldr r3, [sp, #12] - - @ If the return value pointer is NULL, - @ assume no return value. - cmp r2, #0 - beq LSYM(Lepilogue_vfp) - - cmp r3, #FFI_TYPE_INT - streq r0, [r2] - beq LSYM(Lepilogue_vfp) - - cmp r3, #FFI_TYPE_SINT64 - stmeqia r2, {r0, r1} - beq LSYM(Lepilogue_vfp) - - cmp r3, #FFI_TYPE_FLOAT - fstseq s0, [r2] - beq LSYM(Lepilogue_vfp) - - cmp r3, #FFI_TYPE_DOUBLE - fstdeq d0, [r2] - beq LSYM(Lepilogue_vfp) - - cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT - cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE - fstmiadeq r2, {d0-d3} - -LSYM(Lepilogue_vfp): - RETLDM "r0-r3,fp" - -.ffi_call_VFP_end: - UNWIND .fnend - .size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP) - - -ARM_FUNC_START ffi_closure_VFP - fstmfdd sp!, {d0-d7} - @ r0-r3, then d0-d7 - UNWIND .pad #80 - add ip, sp, #80 - stmfd sp!, {ip, lr} - UNWIND .save {r0, lr} - add r2, sp, #72 - add r3, sp, #8 - UNWIND .pad #72 - sub sp, sp, #72 - str sp, [sp, #64] - add r1, sp, #64 - bl CNAME(ffi_closure_SYSV_inner) - - cmp r0, #FFI_TYPE_INT - beq .Lretint_vfp - - cmp r0, #FFI_TYPE_FLOAT - beq .Lretfloat_vfp - - cmp r0, #FFI_TYPE_DOUBLE - cmpne r0, #FFI_TYPE_LONGDOUBLE - beq .Lretdouble_vfp - - cmp r0, #FFI_TYPE_SINT64 - beq .Lretlonglong_vfp - - cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT - beq .Lretfloat_struct_vfp - - cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE - beq .Lretdouble_struct_vfp - -.Lclosure_epilogue_vfp: - add sp, sp, #72 - ldmfd sp, {sp, pc} - -.Lretfloat_vfp: - flds s0, [sp] - b .Lclosure_epilogue_vfp -.Lretdouble_vfp: - fldd d0, [sp] - b .Lclosure_epilogue_vfp -.Lretint_vfp: - ldr r0, [sp] - b .Lclosure_epilogue_vfp -.Lretlonglong_vfp: - ldmia sp, {r0, r1} - b .Lclosure_epilogue_vfp -.Lretfloat_struct_vfp: - fldmiad sp, {d0-d1} - b .Lclosure_epilogue_vfp -.Lretdouble_struct_vfp: - fldmiad sp, {d0-d3} - b .Lclosure_epilogue_vfp - -.ffi_closure_VFP_end: - UNWIND .fnend - .size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP) -#endif +ARM_FUNC_START(ffi_arm_trampoline, 1) +0: adr ip, 0b + ldr pc, 1f +1: .long 0 +ARM_FUNC_END(ffi_arm_trampoline) -ENTRY(ffi_arm_trampoline) - stmfd sp!, {r0-r3} - ldr r0, [pc] - ldr pc, [pc] +#endif /* FFI_EXEC_TRAMPOLINE_TABLE */ #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",%progbits diff --git a/libffi/src/arm/trampoline.S b/libffi/src/arm/trampoline.S deleted file mode 100644 index 935e8de..0000000 --- a/libffi/src/arm/trampoline.S +++ /dev/null @@ -1,4450 +0,0 @@ -# GENERATED CODE - DO NOT EDIT -# This file was generated by src/arm/gentramp.sh - -# Copyright (c) 2010, Plausible Labs Cooperative, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# Software''), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED AS IS'', WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -# ----------------------------------------------------------------------- - -.text -.align 12 -.globl _ffi_closure_trampoline_table_page -_ffi_closure_trampoline_table_page: - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - - - // trampoline - // Save to stack - stmfd sp!, {r0-r3} - - // Load the context argument from the config page. - // This places the first usable config value at _ffi_closure_trampoline_table-4080 - // This accounts for the above 4-byte stmfd instruction, plus 8 bytes constant when loading from pc. - ldr r0, [pc, #-4092] - - // Load the jump address from the config page. - ldr pc, [pc, #-4092] - diff --git a/libffi/src/bfin/ffi.c b/libffi/src/bfin/ffi.c index 0beccc1..22a2acd 100644 --- a/libffi/src/bfin/ffi.c +++ b/libffi/src/bfin/ffi.c @@ -1,5 +1,6 @@ /* ----------------------------------------------------------------------- - ffi.c - Copyright (c) 2012 Alexandre K. I. de Mendonca <alexandre.keunecke@gmail.com> + ffi.c - Copyright (c) 2012 Alexandre K. I. de Mendonca <alexandre.keunecke@gmail.com>, + Paulo Pizarro <paulo.pizarro@gmail.com> Blackfin Foreign Function Interface diff --git a/libffi/src/bfin/sysv.S b/libffi/src/bfin/sysv.S index ae7a152..f4278be 100644 --- a/libffi/src/bfin/sysv.S +++ b/libffi/src/bfin/sysv.S @@ -1,5 +1,6 @@ /* ----------------------------------------------------------------------- - sysv.S - Copyright (c) 2012 Alexandre K. I. de Mendonca <alexandre.keunecke@gmail.com> + sysv.S - Copyright (c) 2012 Alexandre K. I. de Mendonca <alexandre.keunecke@gmail.com>, + Paulo Pizarro <paulo.pizarro@gmail.com> Blackfin Foreign Function Interface @@ -32,7 +33,7 @@ .align 4 /* - There is a "feature" in the bfin toolchain that it puts a _ before funcion names + There is a "feature" in the bfin toolchain that it puts a _ before function names that's why the function here it's called _ffi_call_SYSV and not ffi_call_SYSV */ .global _ffi_call_SYSV; @@ -40,25 +41,26 @@ .func ffi_call_SYSV /* - cif->bytes = R0 (fp+8) - &ecif = R1 (fp+12) - ffi_prep_args = R2 (fp+16) - ret_type = stack (fp+20) - ecif.rvalue = stack (fp+24) - fn = stack (fp+28) - got (fp+32) - There is room for improvement here (we can use temporary registers + cif->bytes = R0 (fp+8) + &ecif = R1 (fp+12) + ffi_prep_args = R2 (fp+16) + ret_type = stack (fp+20) + ecif.rvalue = stack (fp+24) + fn = stack (fp+28) + got (fp+32) + + There is room for improvement here (we can use temporary registers instead of saving the values in the memory) - REGS: - P5 => Stack pointer (function arguments) - R5 => cif->bytes - R4 => ret->type - - FP-20 = P3 - FP-16 = SP (parameters area) - FP-12 = SP (temp) - FP-08 = function return part 1 [R0] - FP-04 = function return part 2 [R1] + REGS: + P5 => Stack pointer (function arguments) + R5 => cif->bytes + R4 => ret->type + + FP-20 = P3 + FP-16 = SP (parameters area) + FP-12 = SP (temp) + FP-08 = function return part 1 [R0] + FP-04 = function return part 2 [R1] */ _ffi_call_SYSV: diff --git a/libffi/src/closures.c b/libffi/src/closures.c index 6298d6f..721ff00 100644 --- a/libffi/src/closures.c +++ b/libffi/src/closures.c @@ -34,7 +34,7 @@ #include <ffi_common.h> #if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE -# if __gnu_linux__ +# if __gnu_linux__ && !defined(__ANDROID__) /* This macro indicates it may be forbidden to map anonymous memory with both write and execute permission. Code compiled when this option is defined will attempt to map such pages once, but if it @@ -181,10 +181,26 @@ static int emutramp_enabled = -1; static int emutramp_enabled_check (void) { - if (getenv ("FFI_DISABLE_EMUTRAMP") == NULL) - return 1; - else + char *buf = NULL; + size_t len = 0; + FILE *f; + int ret; + f = fopen ("/proc/self/status", "r"); + if (f == NULL) return 0; + ret = 0; + + while (getline (&buf, &len, f) != -1) + if (!strncmp (buf, "PaX:", 4)) + { + char emutramp; + if (sscanf (buf, "%*s %*c%c", &emutramp) == 1) + ret = (emutramp == 'E'); + break; + } + free (buf); + fclose (f); + return ret; } #define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \ @@ -249,9 +265,15 @@ static size_t execsize = 0; /* Open a temporary file name, and immediately unlink it. */ static int -open_temp_exec_file_name (char *name) +open_temp_exec_file_name (char *name, int flags) { - int fd = mkstemp (name); + int fd; + +#ifdef HAVE_MKOSTEMP + fd = mkostemp (name, flags); +#else + fd = mkstemp (name); +#endif if (fd != -1) unlink (name); @@ -264,8 +286,30 @@ static int open_temp_exec_file_dir (const char *dir) { static const char suffix[] = "/ffiXXXXXX"; - int lendir = strlen (dir); - char *tempname = __builtin_alloca (lendir + sizeof (suffix)); + int lendir, flags; + char *tempname; +#ifdef O_TMPFILE + int fd; +#endif + +#ifdef O_CLOEXEC + flags = O_CLOEXEC; +#else + flags = 0; +#endif + +#ifdef O_TMPFILE + fd = open (dir, flags | O_RDWR | O_EXCL | O_TMPFILE, 0700); + /* If the running system does not support the O_TMPFILE flag then retry without it. */ + if (fd != -1 || (errno != EINVAL && errno != EISDIR && errno != EOPNOTSUPP)) { + return fd; + } else { + errno = 0; + } +#endif + + lendir = strlen (dir); + tempname = __builtin_alloca (lendir + sizeof (suffix)); if (!tempname) return -1; @@ -273,7 +317,7 @@ open_temp_exec_file_dir (const char *dir) memcpy (tempname, dir, lendir); memcpy (tempname + lendir, suffix, sizeof (suffix)); - return open_temp_exec_file_name (tempname); + return open_temp_exec_file_name (tempname, flags); } /* Open a temporary file in the directory in the named environment @@ -382,7 +426,7 @@ open_temp_exec_file_opts_next (void) } /* Return a file descriptor of a temporary zero-sized file in a - writable and exexutable filesystem. */ + writable and executable filesystem. */ static int open_temp_exec_file (void) { diff --git a/libffi/src/debug.c b/libffi/src/debug.c index 51dcfcf..f3172b1 100644 --- a/libffi/src/debug.c +++ b/libffi/src/debug.c @@ -54,6 +54,11 @@ void ffi_type_test(ffi_type *a, char *file, int line) FFI_ASSERT_AT(a->type <= FFI_TYPE_LAST, file, line); FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->size > 0, file, line); FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->alignment > 0, file, line); - FFI_ASSERT_AT(a->type != FFI_TYPE_STRUCT || a->elements != NULL, file, line); + FFI_ASSERT_AT((a->type != FFI_TYPE_STRUCT && a->type != FFI_TYPE_COMPLEX) + || a->elements != NULL, file, line); + FFI_ASSERT_AT(a->type != FFI_TYPE_COMPLEX + || (a->elements != NULL + && a->elements[0] != NULL && a->elements[1] == NULL), + file, line); } diff --git a/libffi/src/dlmalloc.c b/libffi/src/dlmalloc.c index 5c9f9c2..7e4ea83 100644 --- a/libffi/src/dlmalloc.c +++ b/libffi/src/dlmalloc.c @@ -1255,7 +1255,7 @@ extern void* sbrk(ptrdiff_t); #define SIZE_T_BITSIZE (sizeof(size_t) << 3) /* Some constants coerced to size_t */ -/* Annoying but necessary to avoid errors on some plaftorms */ +/* Annoying but necessary to avoid errors on some platforms */ #define SIZE_T_ZERO ((size_t)0) #define SIZE_T_ONE ((size_t)1) #define SIZE_T_TWO ((size_t)2) @@ -1409,7 +1409,7 @@ static int win32munmap(void* ptr, size_t size) { #define CALL_MORECORE(S) MFAIL #endif /* HAVE_MORECORE */ -/* mstate bit set if continguous morecore disabled or failed */ +/* mstate bit set if contiguous morecore disabled or failed */ #define USE_NONCONTIGUOUS_BIT (4U) /* segment bit set in create_mspace_with_base */ @@ -1661,7 +1661,7 @@ struct malloc_chunk { typedef struct malloc_chunk mchunk; typedef struct malloc_chunk* mchunkptr; typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ -typedef unsigned int bindex_t; /* Described below */ +typedef size_t bindex_t; /* Described below */ typedef unsigned int binmap_t; /* Described below */ typedef unsigned int flag_t; /* The type of various bit flag sets */ @@ -2291,7 +2291,7 @@ static size_t traverse_and_check(mstate m); #define treebin_at(M,i) (&((M)->treebins[i])) /* assign tree index for size S to variable I */ -#if defined(__GNUC__) && defined(i386) +#if defined(__GNUC__) && defined(__i386__) #define compute_tree_index(S, I)\ {\ size_t X = S >> TREEBIN_SHIFT;\ @@ -2356,7 +2356,7 @@ static size_t traverse_and_check(mstate m); /* index corresponding to given bit */ -#if defined(__GNUC__) && defined(i386) +#if defined(__GNUC__) && defined(__i386__) #define compute_bit2idx(X, I)\ {\ unsigned int J;\ @@ -3090,8 +3090,8 @@ static void internal_malloc_stats(mstate m) { and choose its bk node as its replacement. 2. If x was the last node of its size, but not a leaf node, it must be replaced with a leaf node (not merely one with an open left or - right), to make sure that lefts and rights of descendents - correspond properly to bit masks. We use the rightmost descendent + right), to make sure that lefts and rights of descendants + correspond properly to bit masks. We use the rightmost descendant of x. We could use any other leaf, but this is easy to locate and tends to counteract removal of leftmosts elsewhere, and so keeps paths shorter than minimally guaranteed. This doesn't loop much @@ -3388,7 +3388,7 @@ static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { *ss = m->seg; /* Push current record */ m->seg.base = tbase; m->seg.size = tsize; - set_segment_flags(&m->seg, mmapped); + (void)set_segment_flags(&m->seg, mmapped); m->seg.next = ss; /* Insert trailing fenceposts */ @@ -3548,7 +3548,7 @@ static void* sys_alloc(mstate m, size_t nb) { if (!is_initialized(m)) { /* first-time initialization */ m->seg.base = m->least_addr = tbase; m->seg.size = tsize; - set_segment_flags(&m->seg, mmap_flag); + (void)set_segment_flags(&m->seg, mmap_flag); m->magic = mparams.magic; init_bins(m); if (is_global(m)) @@ -5091,10 +5091,10 @@ History: Wolfram Gloger (Gloger@lrz.uni-muenchen.de). * Use last_remainder in more cases. * Pack bins using idea from colin@nyx10.cs.du.edu - * Use ordered bins instead of best-fit threshhold + * Use ordered bins instead of best-fit threshold * Eliminate block-local decls to simplify tracing and debugging. * Support another case of realloc via move into top - * Fix error occuring when initial sbrk_base not word-aligned. + * Fix error occurring when initial sbrk_base not word-aligned. * Rely on page size for units instead of SBRK_UNIT to avoid surprises about sbrk alignment conventions. * Add mallinfo, mallopt. Thanks to Raymond Nijssen diff --git a/libffi/src/ia64/ffi.c b/libffi/src/ia64/ffi.c index 9533ef6..b77a836 100644 --- a/libffi/src/ia64/ffi.c +++ b/libffi/src/ia64/ffi.c @@ -401,7 +401,7 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) the closure (in the "trampoline" area), but we replace the gp pointer with a pointer to the closure itself. We also add the real gp pointer to the closure. This allows the function entry code to - both retrieve the user data, and to restire the correct gp pointer. */ + both retrieve the user data, and to restore the correct gp pointer. */ extern void ffi_closure_unix (); diff --git a/libffi/src/java_raw_api.c b/libffi/src/java_raw_api.c index d8e79ea..127123d 100644 --- a/libffi/src/java_raw_api.c +++ b/libffi/src/java_raw_api.c @@ -60,6 +60,9 @@ ffi_java_raw_size (ffi_cif *cif) case FFI_TYPE_STRUCT: /* No structure parameters in Java. */ abort(); + case FFI_TYPE_COMPLEX: + /* Not supported yet. */ + abort(); default: result += FFI_SIZEOF_JAVA_RAW; } @@ -104,6 +107,10 @@ ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) *args = (void*) &(raw++)->ptr; break; + case FFI_TYPE_COMPLEX: + /* Not supported yet. */ + abort(); + default: *args = raw; raw += @@ -126,6 +133,9 @@ ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) *args = (void*) raw; raw += 2; break; + case FFI_TYPE_COMPLEX: + /* Not supported yet. */ + abort(); default: *args = (void*) raw++; } @@ -254,6 +264,10 @@ ffi_java_rvalue_to_raw (ffi_cif *cif, void *rvalue) *(SINT64 *)rvalue <<= 32; break; + case FFI_TYPE_COMPLEX: + /* Not supported yet. */ + abort(); + default: break; } @@ -279,6 +293,10 @@ ffi_java_raw_to_rvalue (ffi_cif *cif, void *rvalue) *(SINT64 *)rvalue >>= 32; break; + case FFI_TYPE_COMPLEX: + /* Not supported yet. */ + abort(); + default: break; } diff --git a/libffi/src/m68k/ffi.c b/libffi/src/m68k/ffi.c index 37a0784..0dee938 100644 --- a/libffi/src/m68k/ffi.c +++ b/libffi/src/m68k/ffi.c @@ -123,6 +123,8 @@ ffi_prep_args (void *stack, extended_cif *ecif) #define CIF_FLAGS_POINTER 32 #define CIF_FLAGS_STRUCT1 64 #define CIF_FLAGS_STRUCT2 128 +#define CIF_FLAGS_SINT8 256 +#define CIF_FLAGS_SINT16 512 /* Perform machine dependent cif processing */ ffi_status @@ -200,6 +202,14 @@ ffi_prep_cif_machdep (ffi_cif *cif) cif->flags = CIF_FLAGS_DINT; break; + case FFI_TYPE_SINT16: + cif->flags = CIF_FLAGS_SINT16; + break; + + case FFI_TYPE_SINT8: + cif->flags = CIF_FLAGS_SINT8; + break; + default: cif->flags = CIF_FLAGS_INT; break; diff --git a/libffi/src/m68k/sysv.S b/libffi/src/m68k/sysv.S index f6f4ef9..ec2b14f 100644 --- a/libffi/src/m68k/sysv.S +++ b/libffi/src/m68k/sysv.S @@ -2,9 +2,10 @@ sysv.S - Copyright (c) 2012 Alan Hourihane Copyright (c) 1998, 2012 Andreas Schwab - Copyright (c) 2008 Red Hat, Inc. - - m68k Foreign Function Interface + Copyright (c) 2008 Red Hat, Inc. + Copyright (c) 2012 Thorsten Glaser + + m68k Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -168,8 +169,28 @@ retstruct1: retstruct2: btst #7,%d2 - jbeq noretval + jbeq retsint8 move.w %d0,(%a1) + jbra epilogue + +retsint8: + btst #8,%d2 + jbeq retsint16 + | NOTE: On the mc68000, extb is not supported. 8->16, then 16->32. +#if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__) + ext.w %d0 + ext.l %d0 +#else + extb.l %d0 +#endif + move.l %d0,(%a1) + jbra epilogue + +retsint16: + btst #9,%d2 + jbeq noretval + ext.l %d0 + move.l %d0,(%a1) noretval: epilogue: @@ -201,8 +222,10 @@ CALLFUNC(ffi_closure_SYSV): lsr.l #1,%d0 jne 1f jcc .Lcls_epilogue + | CIF_FLAGS_INT move.l -12(%fp),%d0 .Lcls_epilogue: + | no CIF_FLAGS_* unlk %fp rts 1: @@ -210,6 +233,7 @@ CALLFUNC(ffi_closure_SYSV): lsr.l #2,%d0 jne 1f jcs .Lcls_ret_float + | CIF_FLAGS_DINT move.l (%a0)+,%d0 move.l (%a0),%d1 jra .Lcls_epilogue @@ -224,6 +248,7 @@ CALLFUNC(ffi_closure_SYSV): lsr.l #2,%d0 jne 1f jcs .Lcls_ret_ldouble + | CIF_FLAGS_DOUBLE #if defined(__MC68881__) || defined(__HAVE_68881__) fmove.d (%a0),%fp0 #else @@ -242,17 +267,37 @@ CALLFUNC(ffi_closure_SYSV): jra .Lcls_epilogue 1: lsr.l #2,%d0 - jne .Lcls_ret_struct2 + jne 1f jcs .Lcls_ret_struct1 + | CIF_FLAGS_POINTER move.l (%a0),%a0 move.l %a0,%d0 jra .Lcls_epilogue .Lcls_ret_struct1: move.b (%a0),%d0 jra .Lcls_epilogue -.Lcls_ret_struct2: +1: + lsr.l #2,%d0 + jne 1f + jcs .Lcls_ret_sint8 + | CIF_FLAGS_STRUCT2 move.w (%a0),%d0 jra .Lcls_epilogue +.Lcls_ret_sint8: + move.l (%a0),%d0 + | NOTE: On the mc68000, extb is not supported. 8->16, then 16->32. +#if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__) + ext.w %d0 + ext.l %d0 +#else + extb.l %d0 +#endif + jra .Lcls_epilogue +1: + | CIF_FLAGS_SINT16 + move.l (%a0),%d0 + ext.l %d0 + jra .Lcls_epilogue CFI_ENDPROC() .size CALLFUNC(ffi_closure_SYSV),.-CALLFUNC(ffi_closure_SYSV) diff --git a/libffi/src/m88k/ffi.c b/libffi/src/m88k/ffi.c new file mode 100644 index 0000000..68df494 --- /dev/null +++ b/libffi/src/m88k/ffi.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2013 Miodrag Vallat. <miod@openbsd.org> + * + * 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. + */ + +/* + * m88k Foreign Function Interface + * + * This file attempts to provide all the FFI entry points which can reliably + * be implemented in C. + * + * Only OpenBSD/m88k is currently supported; other platforms (such as + * Motorola's SysV/m88k) could be supported with the following tweaks: + * + * - non-OpenBSD systems use an `outgoing parameter area' as part of the + * 88BCS calling convention, which is not supported under OpenBSD from + * release 3.6 onwards. Supporting it should be as easy as taking it + * into account when adjusting the stack, in the assembly code. + * + * - the logic deciding whether a function argument gets passed through + * registers, or on the stack, has changed several times in OpenBSD in + * edge cases (especially for structs larger than 32 bytes being passed + * by value). The code below attemps to match the logic used by the + * system compiler of OpenBSD 5.3, i.e. gcc 3.3.6 with many m88k backend + * fixes. + */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> +#include <unistd.h> + +void ffi_call_OBSD (unsigned int, extended_cif *, unsigned int, void *, + void (*fn) ()); +void *ffi_prep_args (void *, extended_cif *); +void ffi_closure_OBSD (ffi_closure *); +void ffi_closure_struct_OBSD (ffi_closure *); +unsigned int ffi_closure_OBSD_inner (ffi_closure *, void *, unsigned int *, + char *); +void ffi_cacheflush_OBSD (unsigned int, unsigned int); + +#define CIF_FLAGS_INT (1 << 0) +#define CIF_FLAGS_DINT (1 << 1) + +/* + * Foreign Function Interface API + */ + +/* ffi_prep_args is called by the assembly routine once stack space has + been allocated for the function's arguments. */ + +void * +ffi_prep_args (void *stack, extended_cif *ecif) +{ + unsigned int i; + void **p_argv; + char *argp, *stackp; + unsigned int *regp; + unsigned int regused; + ffi_type **p_arg; + void *struct_value_ptr; + + regp = (unsigned int *)stack; + stackp = (char *)(regp + 8); + regused = 0; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT + && !ecif->cif->flags) + struct_value_ptr = ecif->rvalue; + else + struct_value_ptr = NULL; + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i != 0; i--, p_arg++) + { + size_t z; + unsigned short t, a; + + z = (*p_arg)->size; + t = (*p_arg)->type; + a = (*p_arg)->alignment; + + /* + * Figure out whether the argument can be passed through registers + * or on the stack. + * The rule is that registers can only receive simple types not larger + * than 64 bits, or structs the exact size of a register and aligned to + * the size of a register. + */ + if (t == FFI_TYPE_STRUCT) + { + if (z == sizeof (int) && a == sizeof (int) && regused < 8) + argp = (char *)regp; + else + argp = stackp; + } + else + { + if (z > sizeof (int) && regused < 8 - 1) + { + /* align to an even register pair */ + if (regused & 1) + { + regp++; + regused++; + } + } + if (regused < 8) + argp = (char *)regp; + else + argp = stackp; + } + + /* Enforce proper stack alignment of 64-bit types */ + if (argp == stackp && a > sizeof (int)) + { + stackp = (char *) ALIGN(stackp, a); + argp = stackp; + } + + switch (t) + { + 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_INT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + *(unsigned int *) argp = *(unsigned int *) *p_argv; + break; + + case FFI_TYPE_DOUBLE: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_STRUCT: + memcpy (argp, *p_argv, z); + break; + + default: + FFI_ASSERT (0); + } + + /* Align if necessary. */ + if ((sizeof (int) - 1) & z) + z = ALIGN(z, sizeof (int)); + + p_argv++; + + /* Be careful, once all registers are filled, and about to continue + on stack, regp == stackp. Therefore the check for regused as well. */ + if (argp == (char *)regp && regused < 8) + { + regp += z / sizeof (int); + regused += z / sizeof (int); + } + else + stackp += z; + } + + return struct_value_ptr; +} + +/* Perform machine dependent cif processing */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + cif->flags = 0; + break; + + case FFI_TYPE_STRUCT: + if (cif->rtype->size == sizeof (int) && + cif->rtype->alignment == sizeof (int)) + cif->flags = CIF_FLAGS_INT; + else + cif->flags = 0; + break; + + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = CIF_FLAGS_DINT; + break; + + default: + cif->flags = CIF_FLAGS_INT; + break; + } + + return FFI_OK; +} + +void +ffi_call (ffi_cif *cif, void (*fn) (), 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->size != sizeof (int) + || cif->rtype->alignment != sizeof (int))) + ecif.rvalue = alloca (cif->rtype->size); + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_OBSD: + ffi_call_OBSD (cif->bytes, &ecif, cif->flags, ecif.rvalue, fn); + break; + + default: + FFI_ASSERT (0); + break; + } +} + +/* + * Closure API + */ + +static void +ffi_prep_closure_args_OBSD (ffi_cif *cif, void **avalue, unsigned int *regp, + char *stackp) +{ + unsigned int i; + void **p_argv; + char *argp; + unsigned int regused; + ffi_type **p_arg; + + regused = 0; + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++) + { + size_t z; + unsigned short t, a; + + z = (*p_arg)->size; + t = (*p_arg)->type; + a = (*p_arg)->alignment; + + /* + * Figure out whether the argument has been passed through registers + * or on the stack. + * The rule is that registers can only receive simple types not larger + * than 64 bits, or structs the exact size of a register and aligned to + * the size of a register. + */ + if (t == FFI_TYPE_STRUCT) + { + if (z == sizeof (int) && a == sizeof (int) && regused < 8) + argp = (char *)regp; + else + argp = stackp; + } + else + { + if (z > sizeof (int) && regused < 8 - 1) + { + /* align to an even register pair */ + if (regused & 1) + { + regp++; + regused++; + } + } + if (regused < 8) + argp = (char *)regp; + else + argp = stackp; + } + + /* Enforce proper stack alignment of 64-bit types */ + if (argp == stackp && a > sizeof (int)) + { + stackp = (char *) ALIGN(stackp, a); + argp = stackp; + } + + if (z < sizeof (int) && t != FFI_TYPE_STRUCT) + *p_argv = (void *) (argp + sizeof (int) - z); + else + *p_argv = (void *) argp; + + /* Align if necessary */ + if ((sizeof (int) - 1) & z) + z = ALIGN(z, sizeof (int)); + + p_argv++; + + /* Be careful, once all registers are exhausted, and about to fetch from + stack, regp == stackp. Therefore the check for regused as well. */ + if (argp == (char *)regp && regused < 8) + { + regp += z / sizeof (int); + regused += z / sizeof (int); + } + else + stackp += z; + } +} + +unsigned int +ffi_closure_OBSD_inner (ffi_closure *closure, void *resp, unsigned int *regp, + char *stackp) +{ + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void *)); + + ffi_prep_closure_args_OBSD(cif, arg_area, regp, stackp); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + return cif->flags; +} + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, void *codeloc) +{ + unsigned int *tramp = (unsigned int *) codeloc; + void *fn; + + FFI_ASSERT (cif->abi == FFI_OBSD); + + if (cif->rtype->type == FFI_TYPE_STRUCT && !cif->flags) + fn = &ffi_closure_struct_OBSD; + else + fn = &ffi_closure_OBSD; + + /* or.u %r10, %r0, %hi16(fn) */ + tramp[0] = 0x5d400000 | (((unsigned int)fn) >> 16); + /* or.u %r13, %r0, %hi16(closure) */ + tramp[1] = 0x5da00000 | ((unsigned int)closure >> 16); + /* or %r10, %r10, %lo16(fn) */ + tramp[2] = 0x594a0000 | (((unsigned int)fn) & 0xffff); + /* jmp.n %r10 */ + tramp[3] = 0xf400c40a; + /* or %r13, %r13, %lo16(closure) */ + tramp[4] = 0x59ad0000 | ((unsigned int)closure & 0xffff); + + ffi_cacheflush_OBSD((unsigned int)codeloc, FFI_TRAMPOLINE_SIZE); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} diff --git a/libffi/src/m88k/ffitarget.h b/libffi/src/m88k/ffitarget.h new file mode 100644 index 0000000..e52bf9f --- /dev/null +++ b/libffi/src/m88k/ffitarget.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013 Miodrag Vallat. <miod@openbsd.org> + * + * 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. + */ + +/* + * m88k Foreign Function Interface + */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_OBSD, + FFI_DEFAULT_ABI = FFI_OBSD, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 0x14 +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/libffi/src/m88k/obsd.S b/libffi/src/m88k/obsd.S new file mode 100644 index 0000000..1944a23 --- /dev/null +++ b/libffi/src/m88k/obsd.S @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2013 Miodrag Vallat. <miod@openbsd.org> + * + * 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. + */ + +/* + * m88k Foreign Function Interface + */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .text + +/* + * ffi_cacheflush_OBSD(unsigned int addr, %r2 + * unsigned int size); %r3 + */ + .align 4 + .globl ffi_cacheflush_OBSD + .type ffi_cacheflush_OBSD,@function +ffi_cacheflush_OBSD: + tb0 0, %r0, 451 + or %r0, %r0, %r0 + jmp %r1 + .size ffi_cacheflush_OBSD, . - ffi_cacheflush_OBSD + +/* + * ffi_call_OBSD(unsigned bytes, %r2 + * extended_cif *ecif, %r3 + * unsigned flags, %r4 + * void *rvalue, %r5 + * void (*fn)()); %r6 + */ + .align 4 + .globl ffi_call_OBSD + .type ffi_call_OBSD,@function +ffi_call_OBSD: + subu %r31, %r31, 32 + st %r30, %r31, 4 + st %r1, %r31, 0 + addu %r30, %r31, 32 + + | Save the few arguments we'll need after ffi_prep_args() + st.d %r4, %r31, 8 + st %r6, %r31, 16 + + | Allocate room for the image of r2-r9, and the stack space for + | the args (rounded to a 16-byte boundary) + addu %r2, %r2, (8 * 4) + 15 + clr %r2, %r2, 4<0> + subu %r31, %r31, %r2 + + | Fill register and stack image + or %r2, %r31, %r0 +#ifdef PIC + bsr ffi_prep_args#plt +#else + bsr ffi_prep_args +#endif + + | Save pointer to return struct address, if any + or %r12, %r2, %r0 + + | Get function pointer + subu %r4, %r30, 32 + ld %r1, %r4, 16 + + | Fetch the register arguments + ld.d %r2, %r31, (0 * 4) + ld.d %r4, %r31, (2 * 4) + ld.d %r6, %r31, (4 * 4) + ld.d %r8, %r31, (6 * 4) + addu %r31, %r31, (8 * 4) + + | Invoke the function + jsr %r1 + + | Restore stack now that we don't need the args anymore + subu %r31, %r30, 32 + + | Figure out what to return as the function's return value + ld %r5, %r31, 12 | rvalue + ld %r4, %r31, 8 | flags + + bcnd eq0, %r5, 9f + + bb0 0, %r4, 1f | CIF_FLAGS_INT + st %r2, %r5, 0 + br 9f + +1: + bb0 1, %r4, 1f | CIF_FLAGS_DINT + st.d %r2, %r5, 0 + br 9f + +1: +9: + ld %r1, %r31, 0 + ld %r30, %r31, 4 + jmp.n %r1 + addu %r31, %r31, 32 + .size ffi_call_OBSD, . - ffi_call_OBSD + +/* + * ffi_closure_OBSD(ffi_closure *closure); %r13 + */ + .align 4 + .globl ffi_closure_OBSD + .type ffi_closure_OBSD, @function +ffi_closure_OBSD: + subu %r31, %r31, 16 + st %r30, %r31, 4 + st %r1, %r31, 0 + addu %r30, %r31, 16 + + | Make room on the stack for saved register arguments and return + | value + subu %r31, %r31, (8 * 4) + (2 * 4) + st.d %r2, %r31, (0 * 4) + st.d %r4, %r31, (2 * 4) + st.d %r6, %r31, (4 * 4) + st.d %r8, %r31, (6 * 4) + + | Invoke the closure function + or %r5, %r30, 0 | calling stack + addu %r4, %r31, 0 | saved registers + addu %r3, %r31, (8 * 4) | return value + or %r2, %r13, %r0 | closure +#ifdef PIC + bsr ffi_closure_OBSD_inner#plt +#else + bsr ffi_closure_OBSD_inner +#endif + + | Figure out what to return as the function's return value + bb0 0, %r2, 1f | CIF_FLAGS_INT + ld %r2, %r31, (8 * 4) + br 9f + +1: + bb0 1, %r2, 1f | CIF_FLAGS_DINT + ld.d %r2, %r31, (8 * 4) + br 9f + +1: +9: + subu %r31, %r30, 16 + ld %r1, %r31, 0 + ld %r30, %r31, 4 + jmp.n %r1 + addu %r31, %r31, 16 + .size ffi_closure_OBSD,.-ffi_closure_OBSD + +/* + * ffi_closure_struct_OBSD(ffi_closure *closure); %r13 + */ + .align 4 + .globl ffi_closure_struct_OBSD + .type ffi_closure_struct_OBSD, @function +ffi_closure_struct_OBSD: + subu %r31, %r31, 16 + st %r30, %r31, 4 + st %r1, %r31, 0 + addu %r30, %r31, 16 + + | Make room on the stack for saved register arguments + subu %r31, %r31, (8 * 4) + st.d %r2, %r31, (0 * 4) + st.d %r4, %r31, (2 * 4) + st.d %r6, %r31, (4 * 4) + st.d %r8, %r31, (6 * 4) + + | Invoke the closure function + or %r5, %r30, 0 | calling stack + addu %r4, %r31, 0 | saved registers + or %r3, %r12, 0 | return value + or %r2, %r13, %r0 | closure +#ifdef PIC + bsr ffi_closure_OBSD_inner#plt +#else + bsr ffi_closure_OBSD_inner +#endif + + subu %r31, %r30, 16 + ld %r1, %r31, 0 + ld %r30, %r31, 4 + jmp.n %r1 + addu %r31, %r31, 16 + .size ffi_closure_struct_OBSD,.-ffi_closure_struct_OBSD diff --git a/libffi/src/metag/ffi.c b/libffi/src/metag/ffi.c new file mode 100644 index 0000000..46b383e --- /dev/null +++ b/libffi/src/metag/ffi.c @@ -0,0 +1,330 @@ +/* ---------------------------------------------------------------------- + ffi.c - Copyright (c) 2013 Imagination Technologies + + Meta 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 SIMON POSNJAK 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> + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +/* + * ffi_prep_args is called by the assembly routine once stack space has been + * allocated for the function's arguments + */ + +unsigned int ffi_prep_args(char *stack, extended_cif *ecif) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + /* Store return value */ + if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { + argp -= 4; + *(void **) argp = ecif->rvalue; + } + + p_argv = ecif->avalue; + + /* point to next location */ + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++, p_argv++) + { + size_t z; + + /* Move argp to address of argument */ + z = (*p_arg)->size; + argp -= z; + + /* Align if necessary */ + argp = (char *) ALIGN_DOWN(ALIGN_DOWN(argp, (*p_arg)->alignment), 4); + + 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); + 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 { + memcpy(argp, *p_argv, z); + } + } + + /* return the size of the arguments to be passed in registers, + padded to an 8 byte boundary to preserve stack alignment */ + return ALIGN(MIN(stack - argp, 6*4), 8); +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + ffi_type **ptr; + unsigned i, bytes = 0; + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) { + if ((*ptr)->size == 0) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type, do this + check after the initialization. */ + FFI_ASSERT_VALID_TYPE(*ptr); + + /* Add any padding if necessary */ + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN(bytes, (*ptr)->alignment); + + bytes += ALIGN((*ptr)->size, 4); + } + + /* Ensure arg space is aligned to an 8-byte boundary */ + bytes = ALIGN(bytes, 8); + + /* Make space for the return structure pointer */ + if (cif->rtype->type == FFI_TYPE_STRUCT) { + bytes += sizeof(void*); + + /* Ensure stack is aligned to an 8-byte boundary */ + bytes = ALIGN(bytes, 8); + } + + cif->bytes = bytes; + + /* Set the return type flag */ + switch (cif->rtype->type) { + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = (unsigned) FFI_TYPE_SINT64; + break; + case FFI_TYPE_STRUCT: + /* Meta can store return values which are <= 64 bits */ + if (cif->rtype->size <= 4) + /* Returned to D0Re0 as 32-bit value */ + cif->flags = (unsigned)FFI_TYPE_INT; + else if ((cif->rtype->size > 4) && (cif->rtype->size <= 8)) + /* Returned valued is stored to D1Re0|R0Re0 */ + cif->flags = (unsigned)FFI_TYPE_DOUBLE; + else + /* value stored in memory */ + cif->flags = (unsigned)FFI_TYPE_STRUCT; + break; + default: + cif->flags = (unsigned)FFI_TYPE_INT; + break; + } + return FFI_OK; +} + +extern void ffi_call_SYSV(void (*fn)(void), extended_cif *, unsigned, unsigned, double *); + +/* + * Exported in API. Entry point + * cif -> ffi_cif object + * fn -> function pointer + * rvalue -> pointer to return value + * avalue -> vector of void * pointers pointing to memory locations holding the + * arguments + */ +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + int small_struct = (((cif->flags == FFI_TYPE_INT) || (cif->flags == FFI_TYPE_DOUBLE)) && (cif->rtype->type == FFI_TYPE_STRUCT)); + ecif.cif = cif; + ecif.avalue = avalue; + + double temp; + + /* + * If the return value is a struct and we don't have a return value address + * then we need to make one + */ + + if ((rvalue == NULL ) && (cif->flags == FFI_TYPE_STRUCT)) + ecif.rvalue = alloca(cif->rtype->size); + else if (small_struct) + ecif.rvalue = &temp; + else + ecif.rvalue = rvalue; + + switch (cif->abi) { + case FFI_SYSV: + ffi_call_SYSV(fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); + break; + default: + FFI_ASSERT(0); + break; + } + + if (small_struct) + memcpy (rvalue, &temp, cif->rtype->size); +} + +/* private members */ + +static void ffi_prep_incoming_args_SYSV (char *, void **, void **, + ffi_cif*, float *); + +void ffi_closure_SYSV (ffi_closure *); + +/* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */ +extern unsigned int ffi_metag_trampoline[10]; /* 10 instructions */ + +/* end of private members */ + +/* + * __tramp: trampoline memory location + * __fun: assembly routine + * __ctx: memory location for wrapper + * + * At this point, tramp[0] == __ctx ! + */ +void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx) { + memcpy (__tramp, ffi_metag_trampoline, sizeof(ffi_metag_trampoline)); + *(unsigned int*) &__tramp[40] = __ctx; + *(unsigned int*) &__tramp[44] = __fun; + /* This will flush the instruction cache */ + __builtin_meta2_cachewd(&__tramp[0], 1); + __builtin_meta2_cachewd(&__tramp[47], 1); +} + + + +/* the cif must already be prepared */ + +ffi_status +ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + void (*closure_func)(ffi_closure*) = NULL; + + if (cif->abi == FFI_SYSV) + closure_func = &ffi_closure_SYSV; + else + return FFI_BAD_ABI; + + ffi_init_trampoline( + (unsigned char*)&closure->tramp[0], + (unsigned int)closure_func, + (unsigned int)codeloc); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + + +/* This function is jumped to by the trampoline */ +unsigned int ffi_closure_SYSV_inner (closure, respp, args, vfp_args) + ffi_closure *closure; + void **respp; + void *args; + void *vfp_args; +{ + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* + * This call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will re-set RESP to point to the + * structure return address. + */ + ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args); + + (closure->fun) ( cif, *respp, arg_area, closure->user_data); + + return cif->flags; +} + +static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif, + float *vfp_stack) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + /* stack points to original arguments */ + argp = stack; + + /* Store return value */ + if ( cif->flags == FFI_TYPE_STRUCT ) { + argp -= 4; + *rvalue = *(void **) argp; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) { + size_t z; + size_t alignment; + + alignment = (*p_arg)->alignment; + if (alignment < 4) + alignment = 4; + if ((alignment - 1) & (unsigned)argp) + argp = (char *) ALIGN(argp, alignment); + + z = (*p_arg)->size; + *p_argv = (void*) argp; + p_argv++; + argp -= z; + } + return; +} diff --git a/libffi/src/metag/ffitarget.h b/libffi/src/metag/ffitarget.h new file mode 100644 index 0000000..7b9dbeb --- /dev/null +++ b/libffi/src/metag/ffitarget.h @@ -0,0 +1,53 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2013 Imagination Technologies Ltd. + Target configuration macros for Meta + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_H +#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1, +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 48 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/libffi/src/metag/sysv.S b/libffi/src/metag/sysv.S new file mode 100644 index 0000000..b4b2a3b --- /dev/null +++ b/libffi/src/metag/sysv.S @@ -0,0 +1,311 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2013 Imagination Technologies Ltd. + + Meta Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#ifdef HAVE_MACHINE_ASM_H +#include <machine/asm.h> +#else +#ifdef __USER_LABEL_PREFIX__ +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ +#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) +#else +#define CNAME(x) x +#endif +#define ENTRY(x) .globl CNAME(x); .type CNAME(x), %function; CNAME(x): +#endif + +#ifdef __ELF__ +#define LSYM(x) .x +#else +#define LSYM(x) x +#endif + +.macro call_reg x= + .text + .balign 4 + mov D1RtP, \x + swap D1RtP, PC +.endm + +! Save register arguments +.macro SAVE_ARGS + .text + .balign 4 + setl [A0StP++], D0Ar6, D1Ar5 + setl [A0StP++], D0Ar4, D1Ar3 + setl [A0StP++], D0Ar2, D1Ar1 +.endm + +! Save retrun, frame pointer and other regs +.macro SAVE_REGS regs= + .text + .balign 4 + setl [A0StP++], D0FrT, D1RtP + ! Needs to be a pair of regs + .ifnc "\regs","" + setl [A0StP++], \regs + .endif +.endm + +! Declare a global function +.macro METAG_FUNC_START name + .text + .balign 4 + ENTRY(\name) +.endm + +! Return registers from the stack. Reverse SAVE_REGS operation +.macro RET_REGS regs=, cond= + .ifnc "\regs", "" + getl \regs, [--A0StP] + .endif + getl D0FrT, D1RtP, [--A0StP] +.endm + +! Return arguments +.macro RET_ARGS + getl D0Ar2, D1Ar1, [--A0StP] + getl D0Ar4, D1Ar3, [--A0StP] + getl D0Ar6, D1Ar5, [--A0StP] +.endm + + + ! D1Ar1: fn + ! D0Ar2: &ecif + ! D1Ar3: cif->bytes + ! D0Ar4: fig->flags + ! D1Ar5: ecif.rvalue + + ! This assumes we are using GNU as +METAG_FUNC_START ffi_call_SYSV + ! Save argument registers + + SAVE_ARGS + + ! new frame + mov D0FrT, A0FrP + add A0FrP, A0StP, #0 + + ! Preserve the old frame pointer + SAVE_REGS "D1.5, D0.5" + + ! Make room for new args. cifs->bytes is the total space for input + ! and return arguments + + add A0StP, A0StP, D1Ar3 + + ! Preserve cifs->bytes & fn + mov D0.5, D1Ar3 + mov D1.5, D1Ar1 + + ! Place all of the ffi_prep_args in position + mov D1Ar1, A0StP + + ! Call ffi_prep_args(stack, &ecif) +#ifdef __PIC__ + callr D1RtP, CNAME(ffi_prep_args@PLT) +#else + callr D1RtP, CNAME(ffi_prep_args) +#endif + + ! Restore fn pointer + + ! The foreign stack should look like this + ! XXXXX XXXXXX <--- stack pointer + ! FnArgN rvalue + ! FnArgN+2 FnArgN+1 + ! FnArgN+4 FnArgN+3 + ! .... + ! + + ! A0StP now points to the first (or return) argument + 4 + + ! Preserve cif->bytes + getl D0Ar2, D1Ar1, [--A0StP] + getl D0Ar4, D1Ar3, [--A0StP] + getl D0Ar6, D1Ar5, [--A0StP] + + ! Place A0StP to the first argument again + add A0StP, A0StP, #24 ! That's because we loaded 6 regs x 4 byte each + + ! A0FrP points to the initial stack without the reserved space for the + ! cifs->bytes, whilst A0StP points to the stack after the space allocation + + ! fn was the first argument of ffi_call_SYSV. + ! The stack at this point looks like this: + ! + ! A0StP(on entry to _SYSV) -> Arg6 Arg5 | low + ! Arg4 Arg3 | + ! Arg2 Arg1 | + ! A0FrP ----> D0FrtP D1RtP | + ! D1.5 D0.5 | + ! A0StP(bf prep_args) -> FnArgn FnArgn-1 | + ! FnArgn-2FnArgn-3 | + ! ................ | <= cifs->bytes + ! FnArg4 FnArg3 | + ! A0StP (prv_A0StP+cifs->bytes) FnArg2 FnArg1 | high + ! + ! fn was in Arg1 so it's located in in A0FrP+#-0xC + ! + + ! D0Re0 contains the size of arguments stored in registers + sub A0StP, A0StP, D0Re0 + + ! Arg1 is the function pointer for the foreign call. This has been + ! preserved in D1.5 + + ! Time to call (fn). Arguments should be like this: + ! Arg1-Arg6 are loaded to regs + ! The rest of the arguments are stored in stack pointed by A0StP + + call_reg D1.5 + + ! Reset stack. + + mov A0StP, A0FrP + + ! Load Arg1 with the pointer to storage for the return type + ! This was stored in Arg5 + + getd D1Ar1, [A0FrP+#-20] + + ! Load D0Ar2 with the return type code. This was stored in Arg4 (flags) + + getd D0Ar2, [A0FrP+#-16] + + ! We are ready to start processing the return value + ! D0Re0 (and D1Re0) hold the return value + + ! If the return value is NULL, assume no return value + cmp D1Ar1, #0 + beq LSYM(Lepilogue) + + ! return INT + cmp D0Ar2, #FFI_TYPE_INT + ! Sadly, there is no setd{cc} instruction so we need to workaround that + bne .INT64 + setd [D1Ar1], D0Re0 + b LSYM(Lepilogue) + + ! return INT64 +.INT64: + cmp D0Ar2, #FFI_TYPE_SINT64 + setleq [D1Ar1], D0Re0, D1Re0 + + ! return DOUBLE + cmp D0Ar2, #FFI_TYPE_DOUBLE + setl [D1AR1++], D0Re0, D1Re0 + +LSYM(Lepilogue): + ! At this point, the stack pointer points right after the argument + ! saved area. We need to restore 4 regs, therefore we need to move + ! 16 bytes ahead. + add A0StP, A0StP, #16 + RET_REGS "D1.5, D0.5" + RET_ARGS + getd D0Re0, [A0StP] + mov A0FrP, D0FrT + swap D1RtP, PC + +.ffi_call_SYSV_end: + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + + +/* + (called by ffi_metag_trampoline) + void ffi_closure_SYSV (ffi_closure*) + + (called by ffi_closure_SYSV) + unsigned int FFI_HIDDEN + ffi_closure_SYSV_inner (closure,respp, args) + ffi_closure *closure; + void **respp; + void *args; +*/ + +METAG_FUNC_START ffi_closure_SYSV + ! We assume that D1Ar1 holds the address of the + ! ffi_closure struct. We will use that to fetch the + ! arguments. The stack pointer points to an empty space + ! and it is ready to store more data. + + ! D1Ar1 is ready + ! Allocate stack space for return value + add A0StP, A0StP, #8 + ! Store it to D0Ar2 + sub D0Ar2, A0StP, #8 + + sub D1Ar3, A0FrP, #4 + + ! D1Ar3 contains the address of the original D1Ar1 argument + ! We need to subtract #4 later on + + ! Preverve D0Ar2 + mov D0.5, D0Ar2 + +#ifdef __PIC__ + callr D1RtP, CNAME(ffi_closure_SYSV_inner@PLT) +#else + callr D1RtP, CNAME(ffi_closure_SYSV_inner) +#endif + + ! Check the return value and store it to D0.5 + cmp D0Re0, #FFI_TYPE_INT + beq .Lretint + cmp D0Re0, #FFI_TYPE_DOUBLE + beq .Lretdouble +.Lclosure_epilogue: + sub A0StP, A0StP, #8 + RET_REGS "D1.5, D0.5" + RET_ARGS + swap D1RtP, PC + +.Lretint: + setd [D0.5], D0Re0 + b .Lclosure_epilogue +.Lretdouble: + setl [D0.5++], D0Re0, D1Re0 + b .Lclosure_epilogue +.ffi_closure_SYSV_end: +.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) + + +ENTRY(ffi_metag_trampoline) + SAVE_ARGS + ! New frame + mov A0FrP, A0StP + SAVE_REGS "D1.5, D0.5" + mov D0.5, PC + ! Load D1Ar1 the value of ffi_metag_trampoline + getd D1Ar1, [D0.5 + #8] + ! Jump to ffi_closure_SYSV + getd PC, [D0.5 + #12] diff --git a/libffi/src/microblaze/ffi.c b/libffi/src/microblaze/ffi.c new file mode 100644 index 0000000..ea962ea --- /dev/null +++ b/libffi/src/microblaze/ffi.c @@ -0,0 +1,321 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2012, 2013 Xilinx, Inc + + MicroBlaze 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> + +extern void ffi_call_SYSV(void (*)(void*, extended_cif*), extended_cif*, + unsigned int, unsigned int, unsigned int*, void (*fn)(void), + unsigned int, unsigned int); + +extern void ffi_closure_SYSV(void); + +#define WORD_SIZE sizeof(unsigned int) +#define ARGS_REGISTER_SIZE (WORD_SIZE * 6) +#define WORD_ALIGN(x) ALIGN(x, WORD_SIZE) + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ +void ffi_prep_args(void* stack, extended_cif* ecif) +{ + unsigned int i; + ffi_type** p_arg; + void** p_argv; + void* stack_args_p = stack; + + p_argv = ecif->avalue; + + if (ecif == NULL || ecif->cif == NULL) { + return; /* no description to prepare */ + } + + if ((ecif->cif->rtype != NULL) && + (ecif->cif->rtype->type == FFI_TYPE_STRUCT)) + { + /* if return type is a struct which is referenced on the stack/reg5, + * by a pointer. Stored the return value pointer in r5. + */ + char* addr = stack_args_p; + memcpy(addr, &(ecif->rvalue), WORD_SIZE); + stack_args_p += WORD_SIZE; + } + + if (ecif->avalue == NULL) { + return; /* no arguments to prepare */ + } + + for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; + i++, p_arg++) + { + size_t size = (*p_arg)->size; + int type = (*p_arg)->type; + void* value = p_argv[i]; + char* addr = stack_args_p; + int aligned_size = WORD_ALIGN(size); + + /* force word alignment on the stack */ + stack_args_p += aligned_size; + + switch (type) + { + case FFI_TYPE_UINT8: + *(unsigned int *)addr = (unsigned int)*(UINT8*)(value); + break; + case FFI_TYPE_SINT8: + *(signed int *)addr = (signed int)*(SINT8*)(value); + break; + case FFI_TYPE_UINT16: + *(unsigned int *)addr = (unsigned int)*(UINT16*)(value); + break; + case FFI_TYPE_SINT16: + *(signed int *)addr = (signed int)*(SINT16*)(value); + break; + case FFI_TYPE_STRUCT: +#if __BIG_ENDIAN__ + /* + * MicroBlaze toolchain appears to emit: + * bsrli r5, r5, 8 (caller) + * ... + * <branch to callee> + * ... + * bslli r5, r5, 8 (callee) + * + * For structs like "struct a { uint8_t a[3]; };", when passed + * by value. + * + * Structs like "struct b { uint16_t a; };" are also expected + * to be packed strangely in registers. + * + * This appears to be because the microblaze toolchain expects + * "struct b == uint16_t", which is only any issue for big + * endian. + * + * The following is a work around for big-endian only, for the + * above mentioned case, it will re-align the contents of a + * <= 3-byte struct value. + */ + if (size < WORD_SIZE) + { + memcpy (addr + (WORD_SIZE - size), value, size); + break; + } +#endif + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_DOUBLE: + default: + memcpy(addr, value, aligned_size); + } + } +} + +ffi_status ffi_prep_cif_machdep(ffi_cif* cif) +{ + /* check ABI */ + switch (cif->abi) + { + case FFI_SYSV: + break; + default: + return FFI_BAD_ABI; + } + return FFI_OK; +} + +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)) { + ecif.rvalue = alloca(cif->rtype->size); + } else { + ecif.rvalue = rvalue; + } + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, + ecif.rvalue, fn, cif->rtype->type, cif->rtype->size); + break; + default: + FFI_ASSERT(0); + break; + } +} + +void ffi_closure_call_SYSV(void* register_args, void* stack_args, + ffi_closure* closure, void* rvalue, + unsigned int* rtype, unsigned int* rsize) +{ + /* prepare arguments for closure call */ + ffi_cif* cif = closure->cif; + ffi_type** arg_types = cif->arg_types; + + /* re-allocate data for the args. This needs to be done in order to keep + * multi-word objects (e.g. structs) in contiguous memory. Callers are not + * required to store the value of args in the lower 6 words in the stack + * (although they are allocated in the stack). + */ + char* stackclone = alloca(cif->bytes); + void** avalue = alloca(cif->nargs * sizeof(void*)); + void* struct_rvalue = NULL; + char* ptr = stackclone; + int i; + + /* copy registers into stack clone */ + int registers_used = cif->bytes; + if (registers_used > ARGS_REGISTER_SIZE) { + registers_used = ARGS_REGISTER_SIZE; + } + memcpy(stackclone, register_args, registers_used); + + /* copy stack allocated args into stack clone */ + if (cif->bytes > ARGS_REGISTER_SIZE) { + int stack_used = cif->bytes - ARGS_REGISTER_SIZE; + memcpy(stackclone + ARGS_REGISTER_SIZE, stack_args, stack_used); + } + + /* preserve struct type return pointer passing */ + if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { + struct_rvalue = *((void**)ptr); + ptr += WORD_SIZE; + } + + /* populate arg pointer list */ + for (i = 0; i < cif->nargs; i++) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: +#ifdef __BIG_ENDIAN__ + avalue[i] = ptr + 3; +#else + avalue[i] = ptr; +#endif + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: +#ifdef __BIG_ENDIAN__ + avalue[i] = ptr + 2; +#else + avalue[i] = ptr; +#endif + break; + case FFI_TYPE_STRUCT: +#if __BIG_ENDIAN__ + /* + * Work around strange ABI behaviour. + * (see info in ffi_prep_args) + */ + if (arg_types[i]->size < WORD_SIZE) + { + memcpy (ptr, ptr + (WORD_SIZE - arg_types[i]->size), arg_types[i]->size); + } +#endif + avalue[i] = (void*)ptr; + break; + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_DOUBLE: + avalue[i] = ptr; + break; + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + default: + /* default 4-byte argument */ + avalue[i] = ptr; + break; + } + ptr += WORD_ALIGN(arg_types[i]->size); + } + + /* set the return type info passed back to the wrapper */ + *rsize = cif->rtype->size; + *rtype = cif->rtype->type; + if (struct_rvalue != NULL) { + closure->fun(cif, struct_rvalue, avalue, closure->user_data); + /* copy struct return pointer value into function return value */ + *((void**)rvalue) = struct_rvalue; + } else { + closure->fun(cif, rvalue, avalue, closure->user_data); + } +} + +ffi_status ffi_prep_closure_loc( + ffi_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void* user_data, void* codeloc) +{ + unsigned long* tramp = (unsigned long*)&(closure->tramp[0]); + unsigned long cls = (unsigned long)codeloc; + unsigned long fn = 0; + unsigned long fn_closure_call_sysv = (unsigned long)ffi_closure_call_SYSV; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + switch (cif->abi) + { + case FFI_SYSV: + fn = (unsigned long)ffi_closure_SYSV; + + /* load r11 (temp) with fn */ + /* imm fn(upper) */ + tramp[0] = 0xb0000000 | ((fn >> 16) & 0xffff); + /* addik r11, r0, fn(lower) */ + tramp[1] = 0x31600000 | (fn & 0xffff); + + /* load r12 (temp) with cls */ + /* imm cls(upper) */ + tramp[2] = 0xb0000000 | ((cls >> 16) & 0xffff); + /* addik r12, r0, cls(lower) */ + tramp[3] = 0x31800000 | (cls & 0xffff); + + /* load r3 (temp) with ffi_closure_call_SYSV */ + /* imm fn_closure_call_sysv(upper) */ + tramp[4] = 0xb0000000 | ((fn_closure_call_sysv >> 16) & 0xffff); + /* addik r3, r0, fn_closure_call_sysv(lower) */ + tramp[5] = 0x30600000 | (fn_closure_call_sysv & 0xffff); + /* branch/jump to address stored in r11 (fn) */ + tramp[6] = 0x98085800; /* bra r11 */ + + break; + default: + return FFI_BAD_ABI; + } + return FFI_OK; +} diff --git a/libffi/src/microblaze/ffitarget.h b/libffi/src/microblaze/ffitarget.h new file mode 100644 index 0000000..c6fa5a4 --- /dev/null +++ b/libffi/src/microblaze/ffitarget.h @@ -0,0 +1,53 @@ +/* ----------------------------------------------------------------------- + ffitarget.h - Copyright (c) 2012, 2013 Xilinx, Inc + + Target configuration macros for MicroBlaze. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_H +#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; +#endif + +/* Definitions for closures */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +#define FFI_TRAMPOLINE_SIZE (4*8) + +#endif diff --git a/libffi/src/microblaze/sysv.S b/libffi/src/microblaze/sysv.S new file mode 100644 index 0000000..ea43e9d --- /dev/null +++ b/libffi/src/microblaze/sysv.S @@ -0,0 +1,302 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2012, 2013 Xilinx, Inc + + MicroBlaze Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + /* + * arg[0] (r5) = ffi_prep_args, + * arg[1] (r6) = &ecif, + * arg[2] (r7) = cif->bytes, + * arg[3] (r8) = cif->flags, + * arg[4] (r9) = ecif.rvalue, + * arg[5] (r10) = fn + * arg[6] (sp[0]) = cif->rtype->type + * arg[7] (sp[4]) = cif->rtype->size + */ + .text + .globl ffi_call_SYSV + .type ffi_call_SYSV, @function +ffi_call_SYSV: + /* push callee saves */ + addik r1, r1, -20 + swi r19, r1, 0 /* Frame Pointer */ + swi r20, r1, 4 /* PIC register */ + swi r21, r1, 8 /* PIC register */ + swi r22, r1, 12 /* save for locals */ + swi r23, r1, 16 /* save for locals */ + + /* save the r5-r10 registers in the stack */ + addik r1, r1, -24 /* increment sp to store 6x 32-bit words */ + swi r5, r1, 0 + swi r6, r1, 4 + swi r7, r1, 8 + swi r8, r1, 12 + swi r9, r1, 16 + swi r10, r1, 20 + + /* save function pointer */ + addik r3, r5, 0 /* copy ffi_prep_args into r3 */ + addik r22, r1, 0 /* save sp for unallocated args into r22 (callee-saved) */ + addik r23, r10, 0 /* save function address into r23 (callee-saved) */ + + /* prepare stack with allocation for n (bytes = r7) args */ + rsub r1, r7, r1 /* subtract bytes from sp */ + + /* prep args for ffi_prep_args call */ + addik r5, r1, 0 /* store stack pointer into arg[0] */ + /* r6 still holds ecif for arg[1] */ + + /* Call ffi_prep_args(stack, &ecif). */ + addik r1, r1, -4 + swi r15, r1, 0 /* store the link register in the frame */ + brald r15, r3 + nop /* branch has delay slot */ + lwi r15, r1, 0 + addik r1, r1, 4 /* restore the link register from the frame */ + /* returns calling stack pointer location */ + + /* prepare args for fn call, prep_args populates them onto the stack */ + lwi r5, r1, 0 /* arg[0] */ + lwi r6, r1, 4 /* arg[1] */ + lwi r7, r1, 8 /* arg[2] */ + lwi r8, r1, 12 /* arg[3] */ + lwi r9, r1, 16 /* arg[4] */ + lwi r10, r1, 20 /* arg[5] */ + + /* call (fn) (...). */ + addik r1, r1, -4 + swi r15, r1, 0 /* store the link register in the frame */ + brald r15, r23 + nop /* branch has delay slot */ + lwi r15, r1, 0 + addik r1, r1, 4 /* restore the link register from the frame */ + + /* Remove the space we pushed for the args. */ + addik r1, r22, 0 /* restore old SP */ + + /* restore this functions parameters */ + lwi r5, r1, 0 /* arg[0] */ + lwi r6, r1, 4 /* arg[1] */ + lwi r7, r1, 8 /* arg[2] */ + lwi r8, r1, 12 /* arg[3] */ + lwi r9, r1, 16 /* arg[4] */ + lwi r10, r1, 20 /* arg[5] */ + addik r1, r1, 24 /* decrement sp to de-allocate 6x 32-bit words */ + + /* If the return value pointer is NULL, assume no return value. */ + beqi r9, ffi_call_SYSV_end + + lwi r22, r1, 48 /* get return type (20 for locals + 28 for arg[6]) */ + lwi r23, r1, 52 /* get return size (20 for locals + 32 for arg[7]) */ + + /* Check if return type is actually a struct, do nothing */ + rsubi r11, r22, FFI_TYPE_STRUCT + beqi r11, ffi_call_SYSV_end + + /* Return 8bit */ + rsubi r11, r23, 1 + beqi r11, ffi_call_SYSV_store8 + + /* Return 16bit */ + rsubi r11, r23, 2 + beqi r11, ffi_call_SYSV_store16 + + /* Return 32bit */ + rsubi r11, r23, 4 + beqi r11, ffi_call_SYSV_store32 + + /* Return 64bit */ + rsubi r11, r23, 8 + beqi r11, ffi_call_SYSV_store64 + + /* Didn't match anything */ + bri ffi_call_SYSV_end + +ffi_call_SYSV_store64: + swi r3, r9, 0 /* store word r3 into return value */ + swi r4, r9, 4 /* store word r4 into return value */ + bri ffi_call_SYSV_end + +ffi_call_SYSV_store32: + swi r3, r9, 0 /* store word r3 into return value */ + bri ffi_call_SYSV_end + +ffi_call_SYSV_store16: +#ifdef __BIG_ENDIAN__ + shi r3, r9, 2 /* store half-word r3 into return value */ +#else + shi r3, r9, 0 /* store half-word r3 into return value */ +#endif + bri ffi_call_SYSV_end + +ffi_call_SYSV_store8: +#ifdef __BIG_ENDIAN__ + sbi r3, r9, 3 /* store byte r3 into return value */ +#else + sbi r3, r9, 0 /* store byte r3 into return value */ +#endif + bri ffi_call_SYSV_end + +ffi_call_SYSV_end: + /* callee restores */ + lwi r19, r1, 0 /* frame pointer */ + lwi r20, r1, 4 /* PIC register */ + lwi r21, r1, 8 /* PIC register */ + lwi r22, r1, 12 + lwi r23, r1, 16 + addik r1, r1, 20 + + /* return from sub-routine (with delay slot) */ + rtsd r15, 8 + nop + + .size ffi_call_SYSV, . - ffi_call_SYSV + +/* ------------------------------------------------------------------------- */ + + /* + * args passed into this function, are passed down to the callee. + * this function is the target of the closure trampoline, as such r12 is + * a pointer to the closure object. + */ + .text + .globl ffi_closure_SYSV + .type ffi_closure_SYSV, @function +ffi_closure_SYSV: + /* push callee saves */ + addik r11, r1, 28 /* save stack args start location (excluding regs/link) */ + addik r1, r1, -12 + swi r19, r1, 0 /* Frame Pointer */ + swi r20, r1, 4 /* PIC register */ + swi r21, r1, 8 /* PIC register */ + + /* store register args on stack */ + addik r1, r1, -24 + swi r5, r1, 0 + swi r6, r1, 4 + swi r7, r1, 8 + swi r8, r1, 12 + swi r9, r1, 16 + swi r10, r1, 20 + + /* setup args */ + addik r5, r1, 0 /* register_args */ + addik r6, r11, 0 /* stack_args */ + addik r7, r12, 0 /* closure object */ + addik r1, r1, -8 /* allocate return value */ + addik r8, r1, 0 /* void* rvalue */ + addik r1, r1, -8 /* allocate for return type/size values */ + addik r9, r1, 0 /* void* rtype */ + addik r10, r1, 4 /* void* rsize */ + + /* call the wrap_call function */ + addik r1, r1, -28 /* allocate args + link reg */ + swi r15, r1, 0 /* store the link register in the frame */ + brald r15, r3 + nop /* branch has delay slot */ + lwi r15, r1, 0 + addik r1, r1, 28 /* restore the link register from the frame */ + +ffi_closure_SYSV_prepare_return: + lwi r9, r1, 0 /* rtype */ + lwi r10, r1, 4 /* rsize */ + addik r1, r1, 8 /* de-allocate return info values */ + + /* Check if return type is actually a struct, store 4 bytes */ + rsubi r11, r9, FFI_TYPE_STRUCT + beqi r11, ffi_closure_SYSV_store32 + + /* Return 8bit */ + rsubi r11, r10, 1 + beqi r11, ffi_closure_SYSV_store8 + + /* Return 16bit */ + rsubi r11, r10, 2 + beqi r11, ffi_closure_SYSV_store16 + + /* Return 32bit */ + rsubi r11, r10, 4 + beqi r11, ffi_closure_SYSV_store32 + + /* Return 64bit */ + rsubi r11, r10, 8 + beqi r11, ffi_closure_SYSV_store64 + + /* Didn't match anything */ + bri ffi_closure_SYSV_end + +ffi_closure_SYSV_store64: + lwi r3, r1, 0 /* store word r3 into return value */ + lwi r4, r1, 4 /* store word r4 into return value */ + /* 64 bits == 2 words, no sign extend occurs */ + bri ffi_closure_SYSV_end + +ffi_closure_SYSV_store32: + lwi r3, r1, 0 /* store word r3 into return value */ + /* 32 bits == 1 word, no sign extend occurs */ + bri ffi_closure_SYSV_end + +ffi_closure_SYSV_store16: +#ifdef __BIG_ENDIAN__ + lhui r3, r1, 2 /* store half-word r3 into return value */ +#else + lhui r3, r1, 0 /* store half-word r3 into return value */ +#endif + rsubi r11, r9, FFI_TYPE_SINT16 + bnei r11, ffi_closure_SYSV_end + sext16 r3, r3 /* fix sign extend of sint8 */ + bri ffi_closure_SYSV_end + +ffi_closure_SYSV_store8: +#ifdef __BIG_ENDIAN__ + lbui r3, r1, 3 /* store byte r3 into return value */ +#else + lbui r3, r1, 0 /* store byte r3 into return value */ +#endif + rsubi r11, r9, FFI_TYPE_SINT8 + bnei r11, ffi_closure_SYSV_end + sext8 r3, r3 /* fix sign extend of sint8 */ + bri ffi_closure_SYSV_end + +ffi_closure_SYSV_end: + addik r1, r1, 8 /* de-allocate return value */ + + /* de-allocate stored args */ + addik r1, r1, 24 + + /* callee restores */ + lwi r19, r1, 0 /* frame pointer */ + lwi r20, r1, 4 /* PIC register */ + lwi r21, r1, 8 /* PIC register */ + addik r1, r1, 12 + + /* return from sub-routine (with delay slot) */ + rtsd r15, 8 + nop + + .size ffi_closure_SYSV, . - ffi_closure_SYSV diff --git a/libffi/src/mips/ffi.c b/libffi/src/mips/ffi.c index 03121e3..5d0dd70 100644 --- a/libffi/src/mips/ffi.c +++ b/libffi/src/mips/ffi.c @@ -170,7 +170,14 @@ static void ffi_prep_args(char *stack, break; case FFI_TYPE_UINT32: +#ifdef FFI_MIPS_N32 + /* The N32 ABI requires that 32-bit integers + be sign-extended to 64-bits, regardless of + whether they are signed or unsigned. */ + *(ffi_arg *)argp = *(SINT32 *)(* p_argv); +#else *(ffi_arg *)argp = *(UINT32 *)(* p_argv); +#endif break; /* This can only happen with 64bit slots. */ diff --git a/libffi/src/mips/n32.S b/libffi/src/mips/n32.S index ff4bbce..c6985d3 100644 --- a/libffi/src/mips/n32.S +++ b/libffi/src/mips/n32.S @@ -108,10 +108,8 @@ loadregs: REG_L t6, 3*FFI_SIZEOF_ARG($fp) # load the flags word into t6. and t4, t6, ((1<<FFI_FLAG_BITS)-1) - bnez t4, arg1_floatp REG_L a0, 0*FFI_SIZEOF_ARG(t9) - b arg1_next -arg1_floatp: + beqz t4, arg1_next bne t4, FFI_TYPE_FLOAT, arg1_doublep l.s $f12, 0*FFI_SIZEOF_ARG(t9) b arg1_next @@ -121,10 +119,8 @@ arg1_next: SRL t4, t6, 1*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) - bnez t4, arg2_floatp REG_L a1, 1*FFI_SIZEOF_ARG(t9) - b arg2_next -arg2_floatp: + beqz t4, arg2_next bne t4, FFI_TYPE_FLOAT, arg2_doublep l.s $f13, 1*FFI_SIZEOF_ARG(t9) b arg2_next @@ -134,10 +130,8 @@ arg2_next: SRL t4, t6, 2*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) - bnez t4, arg3_floatp REG_L a2, 2*FFI_SIZEOF_ARG(t9) - b arg3_next -arg3_floatp: + beqz t4, arg3_next bne t4, FFI_TYPE_FLOAT, arg3_doublep l.s $f14, 2*FFI_SIZEOF_ARG(t9) b arg3_next @@ -147,10 +141,8 @@ arg3_next: SRL t4, t6, 3*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) - bnez t4, arg4_floatp REG_L a3, 3*FFI_SIZEOF_ARG(t9) - b arg4_next -arg4_floatp: + beqz t4, arg4_next bne t4, FFI_TYPE_FLOAT, arg4_doublep l.s $f15, 3*FFI_SIZEOF_ARG(t9) b arg4_next @@ -160,10 +152,8 @@ arg4_next: SRL t4, t6, 4*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) - bnez t4, arg5_floatp REG_L a4, 4*FFI_SIZEOF_ARG(t9) - b arg5_next -arg5_floatp: + beqz t4, arg5_next bne t4, FFI_TYPE_FLOAT, arg5_doublep l.s $f16, 4*FFI_SIZEOF_ARG(t9) b arg5_next @@ -173,10 +163,8 @@ arg5_next: SRL t4, t6, 5*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) - bnez t4, arg6_floatp REG_L a5, 5*FFI_SIZEOF_ARG(t9) - b arg6_next -arg6_floatp: + beqz t4, arg6_next bne t4, FFI_TYPE_FLOAT, arg6_doublep l.s $f17, 5*FFI_SIZEOF_ARG(t9) b arg6_next @@ -186,10 +174,8 @@ arg6_next: SRL t4, t6, 6*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) - bnez t4, arg7_floatp REG_L a6, 6*FFI_SIZEOF_ARG(t9) - b arg7_next -arg7_floatp: + beqz t4, arg7_next bne t4, FFI_TYPE_FLOAT, arg7_doublep l.s $f18, 6*FFI_SIZEOF_ARG(t9) b arg7_next @@ -199,10 +185,8 @@ arg7_next: SRL t4, t6, 7*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) - bnez t4, arg8_floatp REG_L a7, 7*FFI_SIZEOF_ARG(t9) - b arg8_next -arg8_floatp: + beqz t4, arg8_next bne t4, FFI_TYPE_FLOAT, arg8_doublep l.s $f19, 7*FFI_SIZEOF_ARG(t9) b arg8_next diff --git a/libffi/src/moxie/eabi.S b/libffi/src/moxie/eabi.S new file mode 100644 index 0000000..ac7aceb --- /dev/null +++ b/libffi/src/moxie/eabi.S @@ -0,0 +1,101 @@ +/* ----------------------------------------------------------------------- + eabi.S - Copyright (c) 2012, 2013 Anthony Green + + Moxie Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .globl ffi_prep_args_EABI + + .text + .p2align 4 + .globl ffi_call_EABI + .type ffi_call_EABI, @function + + # $r0 : ffi_prep_args + # $r1 : &ecif + # $r2 : cif->bytes + # $r3 : fig->flags + # $r4 : ecif.rvalue + # $r5 : fn + +ffi_call_EABI: + push $sp, $r6 + push $sp, $r7 + push $sp, $r8 + dec $sp, 24 + + /* Store incoming args on stack. */ + sto.l 0($sp), $r0 /* ffi_prep_args */ + sto.l 4($sp), $r1 /* ecif */ + sto.l 8($sp), $r2 /* bytes */ + sto.l 12($sp), $r3 /* flags */ + sto.l 16($sp), $r4 /* &rvalue */ + sto.l 20($sp), $r5 /* fn */ + + /* Call ffi_prep_args. */ + mov $r6, $r4 /* Save result buffer */ + mov $r7, $r5 /* Save the target fn */ + mov $r8, $r3 /* Save the flags */ + sub.l $sp, $r2 /* Allocate stack space */ + mov $r0, $sp /* We can stomp over $r0 */ + /* $r1 is already set up */ + jsra ffi_prep_args + + /* Load register arguments. */ + ldo.l $r0, 0($sp) + ldo.l $r1, 4($sp) + ldo.l $r2, 8($sp) + ldo.l $r3, 12($sp) + ldo.l $r4, 16($sp) + ldo.l $r5, 20($sp) + + /* Call the target function. */ + jsr $r7 + + ldi.l $r7, 0xffffffff + cmp $r8, $r7 + beq retstruct + + ldi.l $r7, 4 + cmp $r8, $r7 + bgt ret2reg + + st.l ($r6), $r0 + jmpa retdone + +ret2reg: + st.l ($r6), $r0 + sto.l 4($r6), $r1 + +retstruct: +retdone: + /* Return. */ + ldo.l $r6, -4($fp) + ldo.l $r7, -8($fp) + ldo.l $r8, -12($fp) + ret + .size ffi_call_EABI, .-ffi_call_EABI + diff --git a/libffi/src/moxie/ffi.c b/libffi/src/moxie/ffi.c new file mode 100644 index 0000000..540a042 --- /dev/null +++ b/libffi/src/moxie/ffi.c @@ -0,0 +1,272 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (C) 2012, 2013 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 + ``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> + +/* 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) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + register int count = 0; + + p_argv = ecif->avalue; + argp = stack; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT) + { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); + 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); + 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; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof(int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + count += z; + } + + return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8))); +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + if (cif->rtype->type == FFI_TYPE_STRUCT) + cif->flags = -1; + else + cif->flags = cif->rtype->size; + + cif->bytes = ALIGN (cif->bytes, 8); + + return FFI_OK; +} + +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 **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)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_EABI: + ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; + default: + FFI_ASSERT(0); + break; + } +} + +void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3, + unsigned arg4, unsigned arg5, unsigned arg6) +{ + /* This function is called by a trampoline. The trampoline stows a + pointer to the ffi_closure object in $r7. We must save this + pointer in a place that will persist while we do our work. */ + register ffi_closure *creg __asm__ ("$r12"); + ffi_closure *closure = creg; + + /* Arguments that don't fit in registers are found on the stack + at a fixed offset above the current frame pointer. */ + register char *frame_pointer __asm__ ("$fp"); + + /* Pointer to a struct return value. */ + void *struct_rvalue = (void *) arg1; + + /* 6 words reserved for register args + 3 words from jsr */ + char *stack_args = frame_pointer + 9*4; + + /* Lay the register arguments down in a continuous chunk of memory. */ + unsigned register_args[6] = + { arg1, arg2, arg3, arg4, arg5, arg6 }; + char *register_args_ptr = (char *) register_args; + + ffi_cif *cif = closure->cif; + ffi_type **arg_types = cif->arg_types; + void **avalue = alloca (cif->nargs * sizeof(void *)); + char *ptr = (char *) register_args; + int i; + + /* preserve struct type return pointer passing */ + if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { + ptr += 4; + register_args_ptr = (char *)®ister_args[1]; + } + + /* Find the address of each argument. */ + for (i = 0; i < cif->nargs; i++) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = ptr + 3; + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = ptr + 2; + break; + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + case FFI_TYPE_POINTER: + avalue[i] = ptr; + break; + case FFI_TYPE_STRUCT: + avalue[i] = *(void**)ptr; + break; + default: + /* This is an 8-byte value. */ + avalue[i] = ptr; + ptr += 4; + break; + } + ptr += 4; + + /* If we've handled more arguments than fit in registers, + start looking at the those passed on the stack. */ + if (ptr == ®ister_args[6]) + ptr = stack_args; + } + + /* Invoke the closure. */ + if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT)) + { + (closure->fun) (cif, struct_rvalue, avalue, closure->user_data); + } + else + { + /* Allocate space for the return value and call the function. */ + long long rvalue; + (closure->fun) (cif, &rvalue, avalue, closure->user_data); + asm ("mov $r12, %0\n ld.l $r0, ($r12)\n ldo.l $r1, 4($r12)" : : "r" (&rvalue)); + } +} + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned short *tramp = (unsigned short *) &closure->tramp[0]; + unsigned long fn = (long) ffi_closure_eabi; + unsigned long cls = (long) codeloc; + + if (cif->abi != FFI_EABI) + return FFI_BAD_ABI; + + fn = (unsigned long) ffi_closure_eabi; + + tramp[0] = 0x01e0; /* ldi.l $r7, .... */ + tramp[1] = cls >> 16; + tramp[2] = cls & 0xffff; + tramp[3] = 0x1a00; /* jmpa .... */ + tramp[4] = fn >> 16; + tramp[5] = fn & 0xffff; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} diff --git a/libffi/src/moxie/ffitarget.h b/libffi/src/moxie/ffitarget.h new file mode 100644 index 0000000..623e3ece --- /dev/null +++ b/libffi/src/moxie/ffitarget.h @@ -0,0 +1,52 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2012, 2013 Anthony Green + Target configuration macros for Moxie + + 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 + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_EABI, + FFI_DEFAULT_ABI = FFI_EABI, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +/* Trampolines are 12-bytes long. See ffi_prep_closure_loc. */ +#define FFI_TRAMPOLINE_SIZE (12) + +#endif diff --git a/libffi/src/nios2/ffi.c b/libffi/src/nios2/ffi.c new file mode 100644 index 0000000..2efa033 --- /dev/null +++ b/libffi/src/nios2/ffi.c @@ -0,0 +1,304 @@ +/* libffi support for Altera Nios II. + + Copyright (c) 2013 Mentor Graphics. + + 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> + +/* The Nios II Processor Reference Handbook defines the procedure call + ABI as follows. + + Arguments are passed as if a structure containing the types of + the arguments were constructed. The first 16 bytes are passed in r4 + through r7, the remainder on the stack. The first 16 bytes of a function + taking variable arguments are passed in r4-r7 in the same way. + + Return values of types up to 8 bytes are returned in r2 and r3. For + return values greater than 8 bytes, the caller must allocate memory for + the result and pass the address as if it were argument 0. + + While this isn't specified explicitly in the ABI documentation, GCC + promotes integral arguments smaller than int size to 32 bits. + + Also of note, the ABI specifies that all structure objects are + aligned to 32 bits even if all their fields have a smaller natural + alignment. See FFI_AGGREGATE_ALIGNMENT. */ + + +/* Declare the assembly language hooks. */ + +extern UINT64 ffi_call_sysv (void (*) (char *, extended_cif *), + extended_cif *, + unsigned, + void (*fn) (void)); +extern void ffi_closure_sysv (void); + +/* Perform machine-dependent cif processing. */ + +ffi_status ffi_prep_cif_machdep (ffi_cif *cif) +{ + /* We always want at least 16 bytes in the parameter block since it + simplifies the low-level call function. Also round the parameter + block size up to a multiple of 4 bytes to preserve + 32-bit alignment of the stack pointer. */ + if (cif->bytes < 16) + cif->bytes = 16; + else + cif->bytes = (cif->bytes + 3) & ~3; + + return FFI_OK; +} + + +/* ffi_prep_args is called by the assembly routine to transfer arguments + to the stack using the pointers in the ecif array. + Note that the stack buffer is big enough to fit all the arguments, + but the first 16 bytes will be copied to registers for the actual + call. */ + +void ffi_prep_args (char *stack, extended_cif *ecif) +{ + char *argp = stack; + unsigned int i; + + /* The implicit return value pointer is passed as if it were a hidden + first argument. */ + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT + && ecif->cif->rtype->size > 8) + { + (*(void **) argp) = ecif->rvalue; + argp += 4; + } + + for (i = 0; i < ecif->cif->nargs; i++) + { + void *avalue = ecif->avalue[i]; + ffi_type *atype = ecif->cif->arg_types[i]; + size_t size = atype->size; + size_t alignment = atype->alignment; + + /* Align argp as appropriate for the argument type. */ + if ((alignment - 1) & (unsigned) argp) + argp = (char *) ALIGN (argp, alignment); + + /* Copy the argument, promoting integral types smaller than a + word to word size. */ + if (size < sizeof (int)) + { + size = sizeof (int); + switch (atype->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int) *(SINT8 *) avalue; + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int) *(UINT8 *) avalue; + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int) *(SINT16 *) avalue; + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int) *(UINT16 *) avalue; + break; + + case FFI_TYPE_STRUCT: + memcpy (argp, avalue, atype->size); + break; + + default: + FFI_ASSERT(0); + } + } + else if (size == sizeof (int)) + *(unsigned int *) argp = (unsigned int) *(UINT32 *) avalue; + else + memcpy (argp, avalue, size); + argp += size; + } +} + + +/* Call FN using the prepared CIF. RVALUE points to space allocated by + the caller for the return value, and AVALUE is an array of argument + pointers. */ + +void ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) +{ + + extended_cif ecif; + UINT64 result; + + /* If bigret is true, this is the case where a return value of larger + than 8 bytes is handled by being passed by reference as an implicit + argument. */ + int bigret = (cif->rtype->type == FFI_TYPE_STRUCT + && cif->rtype->size > 8); + + ecif.cif = cif; + ecif.avalue = avalue; + + /* Allocate space for return value if this is the pass-by-reference case + and the caller did not provide a buffer. */ + if (rvalue == NULL && bigret) + ecif.rvalue = alloca (cif->rtype->size); + else + ecif.rvalue = rvalue; + + result = ffi_call_sysv (ffi_prep_args, &ecif, cif->bytes, fn); + + /* Now result contains the 64 bit contents returned from fn in + r2 and r3. Copy the value of the appropriate size to the user-provided + rvalue buffer. */ + if (rvalue && !bigret) + switch (cif->rtype->size) + { + case 1: + *(UINT8 *)rvalue = (UINT8) result; + break; + case 2: + *(UINT16 *)rvalue = (UINT16) result; + break; + case 4: + *(UINT32 *)rvalue = (UINT32) result; + break; + case 8: + *(UINT64 *)rvalue = (UINT64) result; + break; + default: + memcpy (rvalue, (void *)&result, cif->rtype->size); + break; + } +} + +/* This function is invoked from the closure trampoline to invoke + CLOSURE with argument block ARGS. Parse ARGS according to + CLOSURE->cfi and invoke CLOSURE->fun. */ + +static UINT64 +ffi_closure_helper (unsigned char *args, + ffi_closure *closure) +{ + ffi_cif *cif = closure->cif; + unsigned char *argp = args; + void **parsed_args = alloca (cif->nargs * sizeof (void *)); + UINT64 result; + void *retptr; + unsigned int i; + + /* First figure out what to do about the return type. If this is the + big-structure-return case, the first arg is the hidden return buffer + allocated by the caller. */ + if (cif->rtype->type == FFI_TYPE_STRUCT + && cif->rtype->size > 8) + { + retptr = *((void **) argp); + argp += 4; + } + else + retptr = (void *) &result; + + /* Fill in the array of argument pointers. */ + for (i = 0; i < cif->nargs; i++) + { + size_t size = cif->arg_types[i]->size; + size_t alignment = cif->arg_types[i]->alignment; + + /* Align argp as appropriate for the argument type. */ + if ((alignment - 1) & (unsigned) argp) + argp = (char *) ALIGN (argp, alignment); + + /* Arguments smaller than an int are promoted to int. */ + if (size < sizeof (int)) + size = sizeof (int); + + /* Store the pointer. */ + parsed_args[i] = argp; + argp += size; + } + + /* Call the user-supplied function. */ + (closure->fun) (cif, retptr, parsed_args, closure->user_data); + return result; +} + + +/* Initialize CLOSURE with a trampoline to call FUN with + CIF and USER_DATA. */ +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun) (ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + int i; + + if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; + + /* The trampoline looks like: + movhi r8, %hi(ffi_closure_sysv) + ori r8, r8, %lo(ffi_closure_sysv) + movhi r9, %hi(ffi_closure_helper) + ori r0, r9, %lo(ffi_closure_helper) + movhi r10, %hi(closure) + ori r10, r10, %lo(closure) + jmp r8 + and then ffi_closure_sysv retrieves the closure pointer out of r10 + in addition to the arguments passed in the normal way for the call, + and invokes ffi_closure_helper. We encode the pointer to + ffi_closure_helper in the trampoline because making a PIC call + to it in ffi_closure_sysv would be messy (it would have to indirect + through the GOT). */ + +#define HI(x) ((((unsigned int) (x)) >> 16) & 0xffff) +#define LO(x) (((unsigned int) (x)) & 0xffff) + tramp[0] = (0 << 27) | (8 << 22) | (HI (ffi_closure_sysv) << 6) | 0x34; + tramp[1] = (8 << 27) | (8 << 22) | (LO (ffi_closure_sysv) << 6) | 0x14; + tramp[2] = (0 << 27) | (9 << 22) | (HI (ffi_closure_helper) << 6) | 0x34; + tramp[3] = (9 << 27) | (9 << 22) | (LO (ffi_closure_helper) << 6) | 0x14; + tramp[4] = (0 << 27) | (10 << 22) | (HI (closure) << 6) | 0x34; + tramp[5] = (10 << 27) | (10 << 22) | (LO (closure) << 6) | 0x14; + tramp[6] = (8 << 27) | (0x0d << 11) | 0x3a; +#undef HI +#undef LO + + /* Flush the caches. + See Example 9-4 in the Nios II Software Developer's Handbook. */ + for (i = 0; i < 7; i++) + asm volatile ("flushd 0(%0); flushi %0" :: "r"(tramp + i) : "memory"); + asm volatile ("flushp" ::: "memory"); + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + diff --git a/libffi/src/nios2/ffitarget.h b/libffi/src/nios2/ffitarget.h new file mode 100644 index 0000000..134d118 --- /dev/null +++ b/libffi/src/nios2/ffitarget.h @@ -0,0 +1,52 @@ +/* libffi target includes for Altera Nios II. + + Copyright (c) 2013 Mentor Graphics. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_H +#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; +#endif + +/* Structures have a 4-byte alignment even if all the fields have lesser + alignment requirements. */ +#define FFI_AGGREGATE_ALIGNMENT 4 + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 28 /* 7 instructions */ +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/libffi/src/nios2/sysv.S b/libffi/src/nios2/sysv.S new file mode 100644 index 0000000..75f442b --- /dev/null +++ b/libffi/src/nios2/sysv.S @@ -0,0 +1,136 @@ +/* Low-level libffi support for Altera Nios II. + + Copyright (c) 2013 Mentor Graphics. + + 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. */ + +/* This function is declared on the C side as + + extern UINT64 ffi_call_sysv (void (*arghook) (char *, extended_cif *), + extended_cif *ecif, + unsigned nbytes, + void (*fn) (void)); + + On input, the arguments appear as + r4 = arghook + r5 = ecif + r6 = nbytes + r7 = fn +*/ + + .section .text + .align 2 + .global ffi_call_sysv + .type ffi_call_sysv, @function + +ffi_call_sysv: + .cfi_startproc + + /* Create the stack frame, saving r16 so we can use it locally. */ + addi sp, sp, -12 + .cfi_def_cfa_offset 12 + stw ra, 8(sp) + stw fp, 4(sp) + stw r16, 0(sp) + .cfi_offset 31, -4 + .cfi_offset 28, -8 + .cfi_offset 16, -12 + mov fp, sp + .cfi_def_cfa_register 28 + mov r16, r7 + + /* Adjust the stack pointer to create the argument buffer + nbytes long. */ + sub sp, sp, r6 + + /* Call the arghook function. */ + mov r2, r4 /* fn */ + mov r4, sp /* argbuffer */ + callr r2 /* r5 already contains ecif */ + + /* Pop off the first 16 bytes of the argument buffer on the stack, + transferring the contents to the argument registers. */ + ldw r4, 0(sp) + ldw r5, 4(sp) + ldw r6, 8(sp) + ldw r7, 12(sp) + addi sp, sp, 16 + + /* Call the user function, which leaves its result in r2 and r3. */ + callr r16 + + /* Pop off the stack frame. */ + mov sp, fp + ldw ra, 8(sp) + ldw fp, 4(sp) + ldw r16, 0(sp) + addi sp, sp, 12 + ret + .cfi_endproc + .size ffi_call_sysv, .-ffi_call_sysv + + +/* Closure trampolines jump here after putting the C helper address + in r9 and the closure pointer in r10. The user-supplied arguments + to the closure are in the normal places, in r4-r7 and on the + stack. Push the register arguments on the stack too and then call the + C helper function to deal with them. */ + + .section .text + .align 2 + .global ffi_closure_sysv + .type ffi_closure_sysv, @function + +ffi_closure_sysv: + .cfi_startproc + + /* Create the stack frame, pushing the register args on the stack + just below the stack args. This is the same trick illustrated + in Figure 7-3 in the Nios II Processor Reference Handbook, used + for variable arguments and structures passed by value. */ + addi sp, sp, -20 + .cfi_def_cfa_offset 20 + stw ra, 0(sp) + .cfi_offset 31, -20 + stw r4, 4(sp) + .cfi_offset 4, -16 + stw r5, 8(sp) + .cfi_offset 5, -12 + stw r6, 12(sp) + .cfi_offset 6, -8 + stw r7, 16(sp) + .cfi_offset 7, -4 + + /* Call the helper. + r4 = pointer to arguments on stack + r5 = closure pointer (loaded in r10 by the trampoline) + r9 = address of helper function (loaded by trampoline) */ + addi r4, sp, 4 + mov r5, r10 + callr r9 + + /* Pop the stack and return. */ + ldw ra, 0(sp) + addi sp, sp, 20 + .cfi_def_cfa_offset -20 + ret + .cfi_endproc + .size ffi_closure_sysv, .-ffi_closure_sysv + diff --git a/libffi/src/or1k/ffi.c b/libffi/src/or1k/ffi.c new file mode 100644 index 0000000..2bad938 --- /dev/null +++ b/libffi/src/or1k/ffi.c @@ -0,0 +1,328 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de> + + OpenRISC 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" + +/* 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) +{ + char *stacktemp = stack; + int i, s; + ffi_type **arg; + int count = 0; + int nfixedargs; + + nfixedargs = ecif->cif->nfixedargs; + arg = ecif->cif->arg_types; + void **argv = ecif->avalue; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT) + { + *(void **) stack = ecif->rvalue; + stack += 4; + count = 4; + } + for(i=0; i<ecif->cif->nargs; i++) + { + + /* variadic args are saved on stack */ + if ((nfixedargs == 0) && (count < 24)) + { + count = 24; + stack = stacktemp + 24; + } + nfixedargs--; + + s = 4; + switch((*arg)->type) + { + case FFI_TYPE_STRUCT: + *(void **)stack = *argv; + break; + + case FFI_TYPE_SINT8: + *(signed int *) stack = (signed int)*(SINT8 *)(* argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) stack = (unsigned int)*(UINT8 *)(* argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) stack = (signed int)*(SINT16 *)(* argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) stack = (unsigned int)*(UINT16 *)(* argv); + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + case FFI_TYPE_POINTER: + *(int *)stack = *(int*)(*argv); + break; + + default: /* 8 byte types */ + if (count == 20) /* never split arguments */ + { + stack += 4; + count += 4; + } + s = (*arg)->size; + memcpy(stack, *argv, s); + break; + } + + stack += s; + count += s; + argv++; + arg++; + } + return stacktemp + ((count>24)?24:0); +} + +extern void ffi_call_SYSV(unsigned, + extended_cif *, + void *(*)(int *, extended_cif *), + unsigned *, + void (*fn)(void), + unsigned); + + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + int i; + int size; + ffi_type **arg; + + /* Calculate size to allocate on stack */ + + for(i = 0, arg = cif->arg_types, size=0; i < cif->nargs; i++, arg++) + { + if ((*arg)->type == FFI_TYPE_STRUCT) + size += 4; + else + if ((*arg)->size <= 4) + size += 4; + else + size += 8; + } + + /* for variadic functions more space is needed on the stack */ + if (cif->nargs != cif->nfixedargs) + size += 24; + + if (cif->rtype->type == FFI_TYPE_STRUCT) + size += 4; + + + extended_cif ecif; + ecif.cif = cif; + ecif.avalue = avalue; + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV(size, &ecif, ffi_prep_args, rvalue, fn, cif->flags); + break; + default: + FFI_ASSERT(0); + break; + } +} + + +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; + + /* Lay the register arguments down in a continuous chunk of memory. */ + unsigned register_args[6] = + { r3, r4, r5, r6, r7, r8 }; + + /* Pointer to a struct return value. */ + void *struct_rvalue = (void *) r3; + + ffi_cif *cif = closure->cif; + ffi_type **arg_types = cif->arg_types; + void **avalue = alloca (cif->nargs * sizeof(void *)); + char *ptr = (char *) register_args; + int count = 0; + int nfixedargs = cif->nfixedargs; + int i; + + /* preserve struct type return pointer passing */ + + if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ptr += 4; + count = 4; + } + + /* Find the address of each argument. */ + for (i = 0; i < cif->nargs; i++) + { + + /* variadic args are saved on stack */ + if ((nfixedargs == 0) && (count < 24)) + { + ptr = stack_args; + count = 24; + } + nfixedargs--; + + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = ptr + 3; + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = ptr + 2; + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + case FFI_TYPE_POINTER: + avalue[i] = ptr; + break; + + case FFI_TYPE_STRUCT: + avalue[i] = *(void**)ptr; + break; + + default: + /* 8-byte values */ + + /* arguments are never splitted */ + if (ptr == ®ister_args[5]) + ptr = stack_args; + avalue[i] = ptr; + ptr += 4; + count += 4; + break; + } + ptr += 4; + count += 4; + + /* If we've handled more arguments than fit in registers, + start looking at the those passed on the stack. */ + + if (count == 24) + ptr = stack_args; + } + + if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT)) + { + (closure->fun) (cif, struct_rvalue, avalue, closure->user_data); + } else + { + 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)); + } +} + + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + unsigned short *tramp = (unsigned short *) closure->tramp; + unsigned long fn = (unsigned long) ffi_closure_SYSV; + unsigned long cls = (unsigned long) codeloc; + + if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + /* write pointers to temporary registers */ + tramp[0] = (0x6 << 10) | (13 << 5); /* l.movhi r13, ... */ + tramp[1] = cls >> 16; + tramp[2] = (0x2a << 10) | (13 << 5) | 13; /* l.ori r13, r13, ... */ + tramp[3] = cls & 0xFFFF; + + tramp[4] = (0x6 << 10) | (15 << 5); /* l.movhi r15, ... */ + tramp[5] = fn >> 16; + tramp[6] = (0x2a << 10) | (15 << 5) | 15; /* l.ori r15, r15 ... */ + tramp[7] = fn & 0xFFFF; + + tramp[8] = (0x11 << 10); /* l.jr r15 */ + tramp[9] = 15 << 11; + + tramp[10] = (0x2a << 10) | (17 << 5) | 1; /* l.ori r17, r1, ... */ + tramp[11] = 0x0; + + return FFI_OK; +} + + +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 + if (cif->rtype->size > 4) + cif->flags = FFI_TYPE_UINT64; + + cif->nfixedargs = cif->nargs; + + return FFI_OK; +} + + +ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, + unsigned int nfixedargs, unsigned int ntotalargs) +{ + ffi_status status; + + status = ffi_prep_cif_machdep (cif); + cif->nfixedargs = nfixedargs; + return status; +} diff --git a/libffi/src/or1k/ffitarget.h b/libffi/src/or1k/ffitarget.h new file mode 100644 index 0000000..e55da28 --- /dev/null +++ b/libffi/src/or1k/ffitarget.h @@ -0,0 +1,58 @@ +/* ----------------------------------------------------------------------- + ffitarget.h - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de> + + OpenRISC Target configuration macros + + 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 + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 +#define FFI_TRAMPOLINE_SIZE (24) + +#define FFI_TARGET_SPECIFIC_VARIADIC 1 +#define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs; + +#endif + diff --git a/libffi/src/or1k/sysv.S b/libffi/src/or1k/sysv.S new file mode 100644 index 0000000..df6570b --- /dev/null +++ b/libffi/src/or1k/sysv.S @@ -0,0 +1,107 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de> + + OpenRISC Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +.text + .globl ffi_call_SYSV + .type ffi_call_SYSV, @function +/* + r3: size to allocate on stack + r4: extended cif structure + r5: function pointer ffi_prep_args + r6: ret address + r7: function to call + r8: flag for return type +*/ + +ffi_call_SYSV: + /* Store registers used on stack */ + l.sw -4(r1), r9 /* return address */ + l.sw -8(r1), r1 /* stack address */ + l.sw -12(r1), r14 /* callee saved registers */ + l.sw -16(r1), r16 + l.sw -20(r1), r18 + l.sw -24(r1), r20 + + l.ori r14, r1, 0x0 /* save stack pointer */ + l.addi r1, r1, -24 + + l.ori r16, r7, 0x0 /* save function address */ + l.ori r18, r6, 0x0 /* save ret address */ + l.ori r20, r8, 0x0 /* save flag */ + + l.sub r1, r1, r3 /* reserve space on stack */ + + /* Call ffi_prep_args */ + l.ori r3, r1, 0x0 /* first argument stack address, second already ecif */ + l.jalr r5 + l.nop + + /* Load register arguments and call*/ + + l.lwz r3, 0(r1) + l.lwz r4, 4(r1) + l.lwz r5, 8(r1) + l.lwz r6, 12(r1) + l.lwz r7, 16(r1) + l.lwz r8, 20(r1) + l.ori r1, r11, 0x0 /* new stack pointer */ + l.jalr r16 + l.nop + + /* handle return values */ + + l.sfeqi r20, FFI_TYPE_STRUCT + l.bf ret /* structs don't return an rvalue */ + l.nop + + /* copy ret address */ + + l.sfeqi r20, FFI_TYPE_UINT64 + l.bnf four_byte_ret /* 8 byte value is returned */ + l.nop + + l.sw 4(r18), r12 + +four_byte_ret: + l.sw 0(r18), r11 + +ret: + /* return */ + l.ori r1, r14, 0x0 /* reset stack pointer */ + l.lwz r9, -4(r1) + l.lwz r1, -8(r1) + l.lwz r14, -12(r1) + l.lwz r16, -16(r1) + l.lwz r18, -20(r1) + l.lwz r20, -24(r1) + l.jr r9 + l.nop + +.size ffi_call_SYSV, .-ffi_call_SYSV diff --git a/libffi/src/pa/ffitarget.h b/libffi/src/pa/ffitarget.h index 5e364d3..fff4c6b 100644 --- a/libffi/src/pa/ffitarget.h +++ b/libffi/src/pa/ffitarget.h @@ -62,6 +62,8 @@ typedef enum ffi_abi { } ffi_abi; #endif +#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION + /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 diff --git a/libffi/src/powerpc/aix.S b/libffi/src/powerpc/aix.S index 213f2db..349e78c 100644 --- a/libffi/src/powerpc/aix.S +++ b/libffi/src/powerpc/aix.S @@ -137,7 +137,7 @@ ffi_call_AIX: mtcrf 0x40, r31 mtctr r0 /* Load all those argument registers. */ - // We have set up a nice stack frame, just load it into registers. + /* We have set up a nice stack frame, just load it into registers. */ ld r3, 40+(1*8)(r1) ld r4, 40+(2*8)(r1) ld r5, 40+(3*8)(r1) @@ -150,7 +150,7 @@ ffi_call_AIX: L1: /* Load all the FP registers. */ - bf 6,L2 // 2f + 0x18 + bf 6,L2 /* 2f + 0x18 */ lfd f1,-32-(13*8)(r28) lfd f2,-32-(12*8)(r28) lfd f3,-32-(11*8)(r28) @@ -239,7 +239,7 @@ L(float_return_value): mtcrf 0x40, r31 mtctr r0 /* Load all those argument registers. */ - // We have set up a nice stack frame, just load it into registers. + /* We have set up a nice stack frame, just load it into registers. */ lwz r3, 20+(1*4)(r1) lwz r4, 20+(2*4)(r1) lwz r5, 20+(3*4)(r1) @@ -252,7 +252,7 @@ L(float_return_value): L1: /* Load all the FP registers. */ - bf 6,L2 // 2f + 0x18 + bf 6,L2 /* 2f + 0x18 */ lfd f1,-16-(13*8)(r28) lfd f2,-16-(12*8)(r28) lfd f3,-16-(11*8)(r28) @@ -307,7 +307,7 @@ L(float_return_value): #endif .long 0 .byte 0,0,0,1,128,4,0,0 -//END(ffi_call_AIX) +/* END(ffi_call_AIX) */ .csect .text[PR] .align 2 @@ -325,4 +325,4 @@ ffi_call_DARWIN: blr .long 0 .byte 0,0,0,0,0,0,0,0 -//END(ffi_call_DARWIN) +/* END(ffi_call_DARWIN) */ diff --git a/libffi/src/powerpc/darwin.S b/libffi/src/powerpc/darwin.S index 4f987dc..066eb82 100644 --- a/libffi/src/powerpc/darwin.S +++ b/libffi/src/powerpc/darwin.S @@ -318,11 +318,6 @@ _ffi_call_AIX: #define EH_DATA_ALIGN_FACT MODE_CHOICE(0x7c,0x78) - .static_data - .align LOG2_GPR_BYTES -LLFB0$non_lazy_ptr: - .g_long Lstartcode - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support EH_frame1: .set L$set$0,LECIE1-LSCIE1 @@ -335,7 +330,7 @@ LSCIE1: .byte EH_DATA_ALIGN_FACT ; sleb128 -4; CIE Data Alignment Factor .byte 0x41 ; CIE RA Column .byte 0x1 ; uleb128 0x1; Augmentation size - .byte 0x10 ; FDE Encoding (indirect pcrel) + .byte 0x10 ; FDE Encoding (pcrel) .byte 0xc ; DW_CFA_def_cfa .byte 0x1 ; uleb128 0x1 .byte 0x0 ; uleb128 0x0 @@ -349,7 +344,7 @@ LSFDE1: .long L$set$1 ; FDE Length LASFDE1: .long LASFDE1-EH_frame1 ; FDE CIE offset - .g_long LLFB0$non_lazy_ptr-. ; FDE initial location + .g_long Lstartcode-. ; FDE initial location .set L$set$3,LFE1-Lstartcode .g_long L$set$3 ; FDE address range .byte 0x0 ; uleb128 0x0; Augmentation size diff --git a/libffi/src/powerpc/darwin_closure.S b/libffi/src/powerpc/darwin_closure.S index 3f6790f..c7734d4 100644 --- a/libffi/src/powerpc/darwin_closure.S +++ b/libffi/src/powerpc/darwin_closure.S @@ -192,7 +192,7 @@ LCFI1: lg r0,0(r3) ; size => r0 lhz r3,FFI_TYPE_TYPE(r3) ; type => r3 - /* The helper will have intercepted struture returns and inserted + /* The helper will have intercepted structure returns and inserted the caller`s destination address for structs returned by ref. */ /* r3 contains the return type so use it to look up in a table @@ -467,11 +467,6 @@ Lendcode: #define EH_FRAME_OFFSETA MODE_CHOICE(176,0x90) #define EH_FRAME_OFFSETB MODE_CHOICE(1,3) - .static_data - .align LOG2_GPR_BYTES -LLFB1$non_lazy_ptr: - .g_long Lstartcode - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support EH_frame1: .set L$set$0,LECIE1-LSCIE1 @@ -484,7 +479,7 @@ LSCIE1: .byte EH_DATA_ALIGN_FACT ; sleb128 -4; CIE Data Alignment Factor .byte 0x41 ; CIE RA Column .byte 0x1 ; uleb128 0x1; Augmentation size - .byte 0x10 ; FDE Encoding (indirect pcrel) + .byte 0x10 ; FDE Encoding (pcrel) .byte 0xc ; DW_CFA_def_cfa .byte 0x1 ; uleb128 0x1 .byte 0x0 ; uleb128 0x0 @@ -498,7 +493,7 @@ LSFDE1: LASFDE1: .long LASFDE1-EH_frame1 ; FDE CIE offset - .g_long LLFB1$non_lazy_ptr-. ; FDE initial location + .g_long Lstartcode-. ; FDE initial location .set L$set$3,LFE1-Lstartcode .g_long L$set$3 ; FDE address range .byte 0x0 ; uleb128 0x0; Augmentation size @@ -523,12 +518,12 @@ LEFDE1: L_ffi_closure_helper_DARWIN$stub: .indirect_symbol _ffi_closure_helper_DARWIN mflr r0 - bcl 20,31,"L00000000001$spb" -"L00000000001$spb": + bcl 20,31,"L1$spb" +"L1$spb": mflr r11 - addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L00000000001$spb") + addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L1$spb") mtlr r0 - lwzu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L00000000001$spb")(r11) + lwzu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L1$spb")(r11) mtctr r12 bctr .lazy_symbol_pointer @@ -542,12 +537,12 @@ L_ffi_closure_helper_DARWIN$lazy_ptr: L_darwin64_struct_ret_by_value_p$stub: .indirect_symbol _darwin64_struct_ret_by_value_p mflr r0 - bcl 20,31,"L00000000002$spb" -"L00000000002$spb": + bcl 20,31,"L2$spb" +"L2$spb": mflr r11 - addis r11,r11,ha16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L00000000002$spb") + addis r11,r11,ha16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L2$spb") mtlr r0 - lwzu r12,lo16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L00000000002$spb")(r11) + lwzu r12,lo16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L2$spb")(r11) mtctr r12 bctr .lazy_symbol_pointer @@ -560,12 +555,12 @@ L_darwin64_struct_ret_by_value_p$lazy_ptr: L_darwin64_pass_struct_floats$stub: .indirect_symbol _darwin64_pass_struct_floats mflr r0 - bcl 20,31,"L00000000003$spb" -"L00000000003$spb": + bcl 20,31,"L3$spb" +"L3$spb": mflr r11 - addis r11,r11,ha16(L_darwin64_pass_struct_floats$lazy_ptr-"L00000000003$spb") + addis r11,r11,ha16(L_darwin64_pass_struct_floats$lazy_ptr-"L3$spb") mtlr r0 - lwzu r12,lo16(L_darwin64_pass_struct_floats$lazy_ptr-"L00000000003$spb")(r11) + lwzu r12,lo16(L_darwin64_pass_struct_floats$lazy_ptr-"L3$spb")(r11) mtctr r12 bctr .lazy_symbol_pointer diff --git a/libffi/src/powerpc/ffi.c b/libffi/src/powerpc/ffi.c index efb441b..7eb543e 100644 --- a/libffi/src/powerpc/ffi.c +++ b/libffi/src/powerpc/ffi.c @@ -70,8 +70,12 @@ ffi_prep_cif_machdep_var (ffi_cif *cif, #endif } -void -ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +static void +ffi_call_int (ffi_cif *cif, + void (*fn) (void), + void *rvalue, + void **avalue, + void *closure) { /* The final SYSV ABI says that structures smaller or equal 8 bytes are returned in r3/r4. A draft ABI used by linux instead returns @@ -97,9 +101,10 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) ecif.rvalue = alloca (cif->rtype->size); #ifdef POWERPC64 - ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn); + ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure, + -(long) cif->bytes); #else - ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); + ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes); #endif /* Check for a bounce-buffered return value */ @@ -125,6 +130,18 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) } } +void +ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) +{ + ffi_call_int (cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, + void *closure) +{ + ffi_call_int (cif, fn, rvalue, avalue, closure); +} ffi_status ffi_prep_closure_loc (ffi_closure *closure, @@ -139,3 +156,18 @@ ffi_prep_closure_loc (ffi_closure *closure, return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc); #endif } + +ffi_status +ffi_prep_go_closure (ffi_go_closure *closure, + ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *)) +{ +#ifdef POWERPC64 + closure->tramp = ffi_go_closure_linux64; +#else + closure->tramp = ffi_go_closure_sysv; +#endif + closure->cif = cif; + closure->fun = fun; + return FFI_OK; +} diff --git a/libffi/src/powerpc/ffi_darwin.c b/libffi/src/powerpc/ffi_darwin.c index dd897f4..cf6fb6d4 100644 --- a/libffi/src/powerpc/ffi_darwin.c +++ b/libffi/src/powerpc/ffi_darwin.c @@ -302,10 +302,10 @@ ffi_prep_args (extended_cif *ecif, unsigned long *const stack) } /* Check that we didn't overrun the stack... */ - //FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS); - //FFI_ASSERT((unsigned *)fpr_base - // <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); - //FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); + /* FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS); + FFI_ASSERT((unsigned *)fpr_base + <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); + FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); */ } #if defined(POWERPC_DARWIN64) @@ -593,7 +593,7 @@ darwin_adjust_aggregate_sizes (ffi_type *s) /* Natural alignment for all items. */ align = p->alignment; #else - /* Natrual alignment for the first item... */ + /* Natural alignment for the first item... */ if (i == 0) align = p->alignment; else if (p->alignment == 16 || p->alignment < 4) diff --git a/libffi/src/powerpc/ffi_linux64.c b/libffi/src/powerpc/ffi_linux64.c index 33f24b3..b84b91f 100644 --- a/libffi/src/powerpc/ffi_linux64.c +++ b/libffi/src/powerpc/ffi_linux64.c @@ -667,7 +667,8 @@ flush_icache (char *wraddr, char *xaddr, int size) } #endif -ffi_status + +ffi_status FFI_HIDDEN ffi_prep_closure_loc_linux64 (ffi_closure *closure, ffi_cif *cif, void (*fun) (ffi_cif *, void *, void **, void *), @@ -688,16 +689,17 @@ ffi_prep_closure_loc_linux64 (ffi_closure *closure, /* 2: .quad context */ *(void **) &tramp[4] = (void *) ffi_closure_LINUX64; *(void **) &tramp[6] = codeloc; - flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE); + flush_icache ((char *) tramp, (char *) codeloc, 4 * 4); #else void **tramp = (void **) &closure->tramp[0]; if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI) return FFI_BAD_ABI; - /* Copy function address and TOC from ffi_closure_LINUX64. */ - memcpy (tramp, (char *) ffi_closure_LINUX64, 16); - tramp[2] = codeloc; + /* Copy function address and TOC from ffi_closure_LINUX64 OPD. */ + memcpy (&tramp[0], (void **) ffi_closure_LINUX64, sizeof (void *)); + tramp[1] = codeloc; + memcpy (&tramp[2], (void **) ffi_closure_LINUX64 + 1, sizeof (void *)); #endif closure->cif = cif; @@ -709,8 +711,12 @@ ffi_prep_closure_loc_linux64 (ffi_closure *closure, int FFI_HIDDEN -ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, - unsigned long *pst, ffi_dblfl *pfr) +ffi_closure_helper_LINUX64 (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + void *rvalue, + unsigned long *pst, + ffi_dblfl *pfr) { /* rvalue is the pointer to space for return value in closure assembly */ /* pst is the pointer to parameter save area @@ -720,11 +726,9 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, void **avalue; ffi_type **arg_types; unsigned long i, avn, nfixedargs; - ffi_cif *cif; ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; unsigned long align; - cif = closure->cif; avalue = alloca (cif->nargs * sizeof (void *)); /* Copy the caller's structure return value address so that the @@ -924,8 +928,7 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, i++; } - - (closure->fun) (cif, rvalue, avalue, closure->user_data); + (*fun) (cif, rvalue, avalue, user_data); /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ if ((cif->flags & FLAG_RETURNS_SMST) != 0) diff --git a/libffi/src/powerpc/ffi_powerpc.h b/libffi/src/powerpc/ffi_powerpc.h index 2e61653..3dcd6b5 100644 --- a/libffi/src/powerpc/ffi_powerpc.h +++ b/libffi/src/powerpc/ffi_powerpc.h @@ -56,22 +56,39 @@ typedef union } ffi_dblfl; void FFI_HIDDEN ffi_closure_SYSV (void); -void FFI_HIDDEN ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *, - void (*)(void)); +void FFI_HIDDEN ffi_go_closure_sysv (void); +void FFI_HIDDEN ffi_call_SYSV(extended_cif *, void (*)(void), void *, + unsigned, void *, int); void FFI_HIDDEN ffi_prep_types_sysv (ffi_abi); ffi_status FFI_HIDDEN ffi_prep_cif_sysv (ffi_cif *); -int FFI_HIDDEN ffi_closure_helper_SYSV (ffi_closure *, void *, unsigned long *, +ffi_status FFI_HIDDEN ffi_prep_closure_loc_sysv (ffi_closure *, + ffi_cif *, + void (*) (ffi_cif *, void *, + void **, void *), + void *, void *); +int FFI_HIDDEN ffi_closure_helper_SYSV (ffi_cif *, + void (*) (ffi_cif *, void *, + void **, void *), + void *, void *, unsigned long *, ffi_dblfl *, unsigned long *); -void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long, unsigned long, - unsigned long *, void (*)(void)); +void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, void (*) (void), void *, + unsigned long, void *, long); void FFI_HIDDEN ffi_closure_LINUX64 (void); +void FFI_HIDDEN ffi_go_closure_linux64 (void); void FFI_HIDDEN ffi_prep_types_linux64 (ffi_abi); ffi_status FFI_HIDDEN ffi_prep_cif_linux64 (ffi_cif *); ffi_status FFI_HIDDEN ffi_prep_cif_linux64_var (ffi_cif *, unsigned int, unsigned int); void FFI_HIDDEN ffi_prep_args64 (extended_cif *, unsigned long *const); -int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *, +ffi_status FFI_HIDDEN ffi_prep_closure_loc_linux64 (ffi_closure *, ffi_cif *, + void (*) (ffi_cif *, void *, + void **, void *), + void *, void *); +int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_cif *, + void (*) (ffi_cif *, void *, + void **, void *), + void *, void *, unsigned long *, ffi_dblfl *); diff --git a/libffi/src/powerpc/ffi_sysv.c b/libffi/src/powerpc/ffi_sysv.c index fbe85fe..646c340 100644 --- a/libffi/src/powerpc/ffi_sysv.c +++ b/libffi/src/powerpc/ffi_sysv.c @@ -36,7 +36,7 @@ /* About the SYSV ABI. */ -#define ASM_NEEDS_REGISTERS 4 +#define ASM_NEEDS_REGISTERS 6 #define NUM_GPR_ARG_REGISTERS 8 #define NUM_FPR_ARG_REGISTERS 8 @@ -654,18 +654,18 @@ ffi_prep_closure_loc_sysv (ffi_closure *closure, tramp = (unsigned int *) &closure->tramp[0]; tramp[0] = 0x7c0802a6; /* mflr r0 */ - tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */ - tramp[4] = 0x7d6802a6; /* mflr r11 */ - tramp[5] = 0x7c0803a6; /* mtlr r0 */ - tramp[6] = 0x800b0000; /* lwz r0,0(r11) */ - tramp[7] = 0x816b0004; /* lwz r11,4(r11) */ - tramp[8] = 0x7c0903a6; /* mtctr r0 */ - tramp[9] = 0x4e800420; /* bctr */ - *(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */ - *(void **) &tramp[3] = codeloc; /* context */ + tramp[1] = 0x429f0005; /* bcl 20,31,.+4 */ + tramp[2] = 0x7d6802a6; /* mflr r11 */ + tramp[3] = 0x7c0803a6; /* mtlr r0 */ + tramp[4] = 0x800b0018; /* lwz r0,24(r11) */ + tramp[5] = 0x816b001c; /* lwz r11,28(r11) */ + tramp[6] = 0x7c0903a6; /* mtctr r0 */ + tramp[7] = 0x4e800420; /* bctr */ + *(void **) &tramp[8] = (void *) ffi_closure_SYSV; /* function */ + *(void **) &tramp[9] = codeloc; /* context */ /* Flush the icache. */ - flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE); + flush_icache ((char *)tramp, (char *)codeloc, 8 * 4); closure->cif = cif; closure->fun = fun; @@ -682,8 +682,12 @@ ffi_prep_closure_loc_sysv (ffi_closure *closure, following helper function to do most of the work. */ int -ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, - unsigned long *pgr, ffi_dblfl *pfr, +ffi_closure_helper_SYSV (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + void *rvalue, + unsigned long *pgr, + ffi_dblfl *pfr, unsigned long *pst) { /* rvalue is the pointer to space for return value in closure assembly */ @@ -699,7 +703,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, #endif long ng = 0; /* number of general registers already used */ - ffi_cif *cif = closure->cif; unsigned size = cif->rtype->size; unsigned short rtypenum = cif->rtype->type; @@ -915,7 +918,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, i++; } - (closure->fun) (cif, rvalue, avalue, closure->user_data); + (*fun) (cif, rvalue, avalue, user_data); /* Tell ffi_closure_SYSV how to perform return type promotions. Because the FFI_SYSV ABI returns the structures <= 8 bytes in diff --git a/libffi/src/powerpc/ffitarget.h b/libffi/src/powerpc/ffitarget.h index b47b0f5..0f66d31 100644 --- a/libffi/src/powerpc/ffitarget.h +++ b/libffi/src/powerpc/ffitarget.h @@ -138,23 +138,35 @@ typedef enum ffi_abi { #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #if defined (POWERPC) || defined (POWERPC_FREEBSD) +# define FFI_GO_CLOSURES 1 # define FFI_TARGET_SPECIFIC_VARIADIC 1 # define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs #endif -/* For additional types like the below, take care about the order in - ppc_closures.S. They must follow after the FFI_TYPE_LAST. */ +/* ppc_closure.S and linux64_closure.S expect this. */ +#define FFI_PPC_TYPE_LAST FFI_TYPE_POINTER + +/* We define additional types below. If generic types are added that + must be supported by powerpc libffi then it is likely that + FFI_PPC_TYPE_LAST needs increasing *and* the jump tables in + ppc_closure.S and linux64_closure.S be extended. */ + +#if !(FFI_TYPE_LAST == FFI_PPC_TYPE_LAST \ + || (FFI_TYPE_LAST == FFI_TYPE_COMPLEX \ + && !defined FFI_TARGET_HAS_COMPLEX_TYPE)) +# error "You likely have a broken powerpc libffi" +#endif /* Needed for soft-float long-double-128 support. */ -#define FFI_TYPE_UINT128 (FFI_TYPE_LAST + 1) +#define FFI_TYPE_UINT128 (FFI_PPC_TYPE_LAST + 1) /* Needed for FFI_SYSV small structure returns. */ -#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2) +#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2) /* Used by ELFv2 for homogenous structure returns. */ -#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_TYPE_LAST + 1) -#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_TYPE_LAST + 2) -#define FFI_V2_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 3) +#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 1) +#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 2) +#define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 3) #if _CALL_ELF == 2 # define FFI_TRAMPOLINE_SIZE 32 diff --git a/libffi/src/powerpc/linux64.S b/libffi/src/powerpc/linux64.S index d2acb70..b2ae60e 100644 --- a/libffi/src/powerpc/linux64.S +++ b/libffi/src/powerpc/linux64.S @@ -32,8 +32,9 @@ #ifdef POWERPC64 .hidden ffi_call_LINUX64 .globl ffi_call_LINUX64 -# if _CALL_ELF == 2 .text + .cfi_startproc +# if _CALL_ELF == 2 ffi_call_LINUX64: addis %r2, %r12, .TOC.-ffi_call_LINUX64@ha addi %r2, %r2, .TOC.-ffi_call_LINUX64@l @@ -57,20 +58,26 @@ ffi_call_LINUX64: .ffi_call_LINUX64: # endif # endif -.LFB1: mflr %r0 std %r28, -32(%r1) std %r29, -24(%r1) std %r30, -16(%r1) std %r31, -8(%r1) + std %r7, 8(%r1) /* closure, saved in cr field. */ std %r0, 16(%r1) mr %r28, %r1 /* our AP. */ -.LCFI0: - stdux %r1, %r1, %r4 - mr %r31, %r5 /* flags, */ - mr %r30, %r6 /* rvalue, */ - mr %r29, %r7 /* function address. */ + .cfi_def_cfa_register 28 + .cfi_offset 65, 16 + .cfi_offset 31, -8 + .cfi_offset 30, -16 + .cfi_offset 29, -24 + .cfi_offset 28, -32 + + stdux %r1, %r1, %r8 + mr %r31, %r6 /* flags, */ + mr %r30, %r5 /* rvalue, */ + mr %r29, %r4 /* function address. */ /* Save toc pointer, not for the ffi_prep_args64 call, but for the later bctrl function call. */ # if _CALL_ELF == 2 @@ -92,7 +99,6 @@ ffi_call_LINUX64: # else ld %r12, 0(%r29) ld %r2, 8(%r29) - ld %r11, 16(%r29) # endif /* Now do the call. */ /* Set up cr1 with bits 4-7 of the flags. */ @@ -130,6 +136,7 @@ ffi_call_LINUX64: 2: /* Make the call. */ + ld %r11, 8(%r28) bctrl /* This must follow the call immediately, the unwinder @@ -151,6 +158,7 @@ ffi_call_LINUX64: .Ldone_return_value: /* Restore the registers we used and return. */ mr %r1, %r28 + .cfi_def_cfa_register 1 ld %r0, 16(%r28) ld %r28, -32(%r28) mtlr %r0 @@ -160,6 +168,7 @@ ffi_call_LINUX64: blr .Lfp_return_value: + .cfi_def_cfa_register 28 bf 28, .Lfloat_return_value stfd %f1, 0(%r30) mtcrf 0x02, %r31 /* cr6 */ @@ -199,61 +208,19 @@ ffi_call_LINUX64: std %r4, 8(%r30) b .Ldone_return_value -.LFE1: - .long 0 - .byte 0,12,0,1,128,4,0,0 + .cfi_endproc # if _CALL_ELF == 2 .size ffi_call_LINUX64,.-ffi_call_LINUX64 # else # ifdef _CALL_LINUX .size ffi_call_LINUX64,.-.L.ffi_call_LINUX64 # else + .long 0 + .byte 0,12,0,1,128,4,0,0 .size .ffi_call_LINUX64,.-.ffi_call_LINUX64 # endif # endif - .section .eh_frame,EH_FRAME_FLAGS,@progbits -.Lframe1: - .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry -.LSCIE1: - .4byte 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .uleb128 0x1 # CIE Code Alignment Factor - .sleb128 -8 # CIE Data Alignment Factor - .byte 0x41 # CIE RA Column - .uleb128 0x1 # Augmentation size - .byte 0x14 # FDE Encoding (pcrel udata8) - .byte 0xc # DW_CFA_def_cfa - .uleb128 0x1 - .uleb128 0x0 - .align 3 -.LECIE1: -.LSFDE1: - .4byte .LEFDE1-.LASFDE1 # FDE Length -.LASFDE1: - .4byte .LASFDE1-.Lframe1 # FDE CIE offset - .8byte .LFB1-. # FDE initial location - .8byte .LFE1-.LFB1 # FDE address range - .uleb128 0x0 # Augmentation size - .byte 0x2 # DW_CFA_advance_loc1 - .byte .LCFI0-.LFB1 - .byte 0xd # DW_CFA_def_cfa_register - .uleb128 0x1c - .byte 0x11 # DW_CFA_offset_extended_sf - .uleb128 0x41 - .sleb128 -2 - .byte 0x9f # DW_CFA_offset, column 0x1f - .uleb128 0x1 - .byte 0x9e # DW_CFA_offset, column 0x1e - .uleb128 0x2 - .byte 0x9d # DW_CFA_offset, column 0x1d - .uleb128 0x3 - .byte 0x9c # DW_CFA_offset, column 0x1c - .uleb128 0x4 - .align 3 -.LEFDE1: - #endif #if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 diff --git a/libffi/src/powerpc/linux64_closure.S b/libffi/src/powerpc/linux64_closure.S index 1d80a39..6487d2a 100644 --- a/libffi/src/powerpc/linux64_closure.S +++ b/libffi/src/powerpc/linux64_closure.S @@ -33,8 +33,9 @@ #ifdef POWERPC64 FFI_HIDDEN (ffi_closure_LINUX64) .globl ffi_closure_LINUX64 -# if _CALL_ELF == 2 .text + .cfi_startproc +# if _CALL_ELF == 2 ffi_closure_LINUX64: addis %r2, %r12, .TOC.-ffi_closure_LINUX64@ha addi %r2, %r2, .TOC.-ffi_closure_LINUX64@l @@ -73,20 +74,18 @@ ffi_closure_LINUX64: # define RETVAL PARMSAVE+64 # endif -.LFB1: # if _CALL_ELF == 2 ld %r12, FFI_TRAMPOLINE_SIZE(%r11) # closure->cif mflr %r0 lwz %r12, 28(%r12) # cif->flags mtcrf 0x40, %r12 addi %r12, %r1, PARMSAVE - bt 7, .Lparmsave + bt 7, 0f # Our caller has not allocated a parameter save area. # We need to allocate one here and use it to pass gprs to # ffi_closure_helper_LINUX64. addi %r12, %r1, -STACKFRAME+PARMSAVE -.Lparmsave: - std %r0, 16(%r1) +0: # Save general regs into parm save area std %r3, 0(%r12) std %r4, 8(%r12) @@ -98,8 +97,12 @@ ffi_closure_LINUX64: std %r10, 56(%r12) # load up the pointer to the parm save area - mr %r5, %r12 + mr %r7, %r12 # else + # copy r2 to r11 and load TOC into r2 + mr %r11, %r2 + ld %r2, 16(%r2) + mflr %r0 # Save general regs into parm save area # This is the parameter save area set up by our caller. @@ -112,12 +115,19 @@ ffi_closure_LINUX64: std %r9, PARMSAVE+48(%r1) std %r10, PARMSAVE+56(%r1) - std %r0, 16(%r1) - # load up the pointer to the parm save area - addi %r5, %r1, PARMSAVE + addi %r7, %r1, PARMSAVE # endif + std %r0, 16(%r1) + # closure->cif + ld %r3, FFI_TRAMPOLINE_SIZE(%r11) + # closure->fun + ld %r4, FFI_TRAMPOLINE_SIZE+8(%r11) + # closure->user_data + ld %r5, FFI_TRAMPOLINE_SIZE+16(%r11) + +.Ldoclosure: # next save fpr 1 to fpr 13 stfd %f1, -104+(0*8)(%r1) stfd %f2, -104+(1*8)(%r1) @@ -134,16 +144,14 @@ ffi_closure_LINUX64: stfd %f13, -104+(12*8)(%r1) # load up the pointer to the saved fpr registers */ - addi %r6, %r1, -104 + addi %r8, %r1, -104 # load up the pointer to the result storage - addi %r4, %r1, -STACKFRAME+RETVAL + addi %r6, %r1, -STACKFRAME+RETVAL stdu %r1, -STACKFRAME(%r1) -.LCFI0: - - # get the context pointer from the trampoline - mr %r3, %r11 + .cfi_def_cfa_offset STACKFRAME + .cfi_offset 65, 16 # make the call # if defined _CALL_LINUX || _CALL_ELF == 2 @@ -178,7 +186,9 @@ ffi_closure_LINUX64: # case FFI_TYPE_VOID mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME nop # case FFI_TYPE_INT # ifdef __LITTLE_ENDIAN__ @@ -188,17 +198,23 @@ ffi_closure_LINUX64: # endif mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_FLOAT lfs %f1, RETVAL+0(%r1) mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_DOUBLE lfd %f1, RETVAL+0(%r1) mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_LONGDOUBLE lfd %f1, RETVAL+0(%r1) mtlr %r0 @@ -212,7 +228,9 @@ ffi_closure_LINUX64: # endif mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_SINT8 # ifdef __LITTLE_ENDIAN__ lbz %r3, RETVAL+0(%r1) @@ -231,7 +249,9 @@ ffi_closure_LINUX64: mtlr %r0 .Lfinish: addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_SINT16 # ifdef __LITTLE_ENDIAN__ lha %r3, RETVAL+0(%r1) @@ -240,7 +260,9 @@ ffi_closure_LINUX64: # endif mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_UINT32 # ifdef __LITTLE_ENDIAN__ lwz %r3, RETVAL+0(%r1) @@ -249,7 +271,9 @@ ffi_closure_LINUX64: # endif mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_SINT32 # ifdef __LITTLE_ENDIAN__ lwa %r3, RETVAL+0(%r1) @@ -258,27 +282,37 @@ ffi_closure_LINUX64: # endif mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_UINT64 ld %r3, RETVAL+0(%r1) mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_SINT64 ld %r3, RETVAL+0(%r1) mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_TYPE_STRUCT mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME nop # case FFI_TYPE_POINTER ld %r3, RETVAL+0(%r1) mtlr %r0 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME # case FFI_V2_TYPE_FLOAT_HOMOG lfs %f1, RETVAL+0(%r1) lfs %f2, RETVAL+4(%r1) @@ -295,7 +329,9 @@ ffi_closure_LINUX64: lfd %f7, RETVAL+48(%r1) lfd %f8, RETVAL+56(%r1) addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME .Lmorefloat: lfs %f4, RETVAL+12(%r1) mtlr %r0 @@ -304,13 +340,16 @@ ffi_closure_LINUX64: lfs %f7, RETVAL+24(%r1) lfs %f8, RETVAL+28(%r1) addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME .Lsmall: # ifdef __LITTLE_ENDIAN__ ld %r3,RETVAL+0(%r1) mtlr %r0 ld %r4,RETVAL+8(%r1) addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr # else # A struct smaller than a dword is returned in the low bits of r3 @@ -324,63 +363,124 @@ ffi_closure_LINUX64: mtlr %r0 ld %r4,RETVAL+8(%r1) addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset STACKFRAME .Lsmalldown: addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7 mtlr %r0 sldi %r5, %r5, 3 addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 srd %r3, %r3, %r5 blr # endif -.LFE1: - .long 0 - .byte 0,12,0,1,128,0,0,0 + .cfi_endproc # if _CALL_ELF == 2 .size ffi_closure_LINUX64,.-ffi_closure_LINUX64 # else # ifdef _CALL_LINUX .size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64 # else + .long 0 + .byte 0,12,0,1,128,0,0,0 .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 # endif # endif - .section .eh_frame,EH_FRAME_FLAGS,@progbits -.Lframe1: - .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry -.LSCIE1: - .4byte 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .uleb128 0x1 # CIE Code Alignment Factor - .sleb128 -8 # CIE Data Alignment Factor - .byte 0x41 # CIE RA Column - .uleb128 0x1 # Augmentation size - .byte 0x14 # FDE Encoding (pcrel udata8) - .byte 0xc # DW_CFA_def_cfa - .uleb128 0x1 - .uleb128 0x0 - .align 3 -.LECIE1: -.LSFDE1: - .4byte .LEFDE1-.LASFDE1 # FDE Length -.LASFDE1: - .4byte .LASFDE1-.Lframe1 # FDE CIE offset - .8byte .LFB1-. # FDE initial location - .8byte .LFE1-.LFB1 # FDE address range - .uleb128 0x0 # Augmentation size - .byte 0x2 # DW_CFA_advance_loc1 - .byte .LCFI0-.LFB1 - .byte 0xe # DW_CFA_def_cfa_offset - .uleb128 STACKFRAME - .byte 0x11 # DW_CFA_offset_extended_sf - .uleb128 0x41 - .sleb128 -2 - .align 3 -.LEFDE1: + FFI_HIDDEN (ffi_go_closure_linux64) + .globl ffi_go_closure_linux64 + .text + .cfi_startproc +# if _CALL_ELF == 2 +ffi_go_closure_linux64: + addis %r2, %r12, .TOC.-ffi_go_closure_linux64@ha + addi %r2, %r2, .TOC.-ffi_go_closure_linux64@l + .localentry ffi_go_closure_linux64, . - ffi_go_closure_linux64 +# else + .section ".opd","aw" + .align 3 +ffi_go_closure_linux64: +# ifdef _CALL_LINUX + .quad .L.ffi_go_closure_linux64,.TOC.@tocbase,0 + .type ffi_go_closure_linux64,@function + .text +.L.ffi_go_closure_linux64: +# else + FFI_HIDDEN (.ffi_go_closure_linux64) + .globl .ffi_go_closure_linux64 + .quad .ffi_go_closure_linux64,.TOC.@tocbase,0 + .size ffi_go_closure_linux64,24 + .type .ffi_go_closure_linux64,@function + .text +.ffi_go_closure_linux64: +# endif +# endif + +# if _CALL_ELF == 2 + ld %r12, 8(%r11) # closure->cif + mflr %r0 + lwz %r12, 28(%r12) # cif->flags + mtcrf 0x40, %r12 + addi %r12, %r1, PARMSAVE + bt 7, 0f + # Our caller has not allocated a parameter save area. + # We need to allocate one here and use it to pass gprs to + # ffi_closure_helper_LINUX64. + addi %r12, %r1, -STACKFRAME+PARMSAVE +0: + # Save general regs into parm save area + std %r3, 0(%r12) + std %r4, 8(%r12) + std %r5, 16(%r12) + std %r6, 24(%r12) + std %r7, 32(%r12) + std %r8, 40(%r12) + std %r9, 48(%r12) + std %r10, 56(%r12) + + # load up the pointer to the parm save area + mr %r7, %r12 +# else + mflr %r0 + # Save general regs into parm save area + # This is the parameter save area set up by our caller. + std %r3, PARMSAVE+0(%r1) + std %r4, PARMSAVE+8(%r1) + std %r5, PARMSAVE+16(%r1) + std %r6, PARMSAVE+24(%r1) + std %r7, PARMSAVE+32(%r1) + std %r8, PARMSAVE+40(%r1) + std %r9, PARMSAVE+48(%r1) + std %r10, PARMSAVE+56(%r1) + + # load up the pointer to the parm save area + addi %r7, %r1, PARMSAVE +# endif + std %r0, 16(%r1) + + # closure->cif + ld %r3, 8(%r11) + # closure->fun + ld %r4, 16(%r11) + # user_data + mr %r5, %r11 + b .Ldoclosure + + .cfi_endproc +# if _CALL_ELF == 2 + .size ffi_go_closure_linux64,.-ffi_go_closure_linux64 +# else +# ifdef _CALL_LINUX + .size ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64 +# else + .long 0 + .byte 0,12,0,1,128,0,0,0 + .size .ffi_go_closure_linux64,.-.ffi_go_closure_linux64 +# endif +# endif #endif #if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 diff --git a/libffi/src/powerpc/ppc_closure.S b/libffi/src/powerpc/ppc_closure.S index 0507128..b6d209d 100644 --- a/libffi/src/powerpc/ppc_closure.S +++ b/libffi/src/powerpc/ppc_closure.S @@ -33,13 +33,14 @@ #ifndef POWERPC64 +FFI_HIDDEN(ffi_closure_SYSV) ENTRY(ffi_closure_SYSV) -.LFB1: + .cfi_startproc stwu %r1,-144(%r1) -.LCFI0: + .cfi_def_cfa_offset 144 mflr %r0 -.LCFI1: stw %r0,148(%r1) + .cfi_offset 65, 4 # we want to build up an areas for the parameters passed # in registers (both floating point and integer) @@ -48,6 +49,17 @@ ENTRY(ffi_closure_SYSV) stw %r3, 16(%r1) stw %r4, 20(%r1) stw %r5, 24(%r1) + + # set up registers for the routine that does the work + + # closure->cif + lwz %r3,FFI_TRAMPOLINE_SIZE(%r11) + # closure->fun + lwz %r4,FFI_TRAMPOLINE_SIZE+4(%r11) + # closure->user_data + lwz %r5,FFI_TRAMPOLINE_SIZE+8(%r11) + +.Ldoclosure: stw %r6, 28(%r1) stw %r7, 32(%r1) stw %r8, 36(%r1) @@ -66,23 +78,18 @@ ENTRY(ffi_closure_SYSV) stfd %f8, 104(%r1) #endif - # set up registers for the routine that actually does the work - # get the context pointer from the trampoline - mr %r3,%r11 + # pointer to the result storage + addi %r6,%r1,112 - # now load up the pointer to the result storage - addi %r4,%r1,112 + # pointer to the saved gpr registers + addi %r7,%r1,16 - # now load up the pointer to the saved gpr registers - addi %r5,%r1,16 + # pointer to the saved fpr registers + addi %r8,%r1,48 - # now load up the pointer to the saved fpr registers */ - addi %r6,%r1,48 - - # now load up the pointer to the outgoing parameter - # stack in the previous frame + # pointer to the outgoing parameter save area in the previous frame # i.e. the previous frame pointer + 8 - addi %r7,%r1,152 + addi %r9,%r1,152 # make the call bl ffi_closure_helper_SYSV@local @@ -101,7 +108,6 @@ ENTRY(ffi_closure_SYSV) add %r3,%r3,%r4 # add contents of table to table address mtctr %r3 bctr # jump to it -.LFE1: # Each of the ret_typeX code fragments has to be exactly 16 bytes long # (4 instructions). For cache effectiveness we align to a 16 byte boundary @@ -111,7 +117,9 @@ ENTRY(ffi_closure_SYSV) .Lret_type0: mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 nop # case FFI_TYPE_INT @@ -119,31 +127,33 @@ ENTRY(ffi_closure_SYSV) mtlr %r0 .Lfinish: addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_TYPE_FLOAT #ifndef __NO_FPRS__ lfs %f1,112+0(%r1) - mtlr %r0 - addi %r1,%r1,144 #else nop - nop - nop #endif + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_TYPE_DOUBLE #ifndef __NO_FPRS__ lfd %f1,112+0(%r1) - mtlr %r0 - addi %r1,%r1,144 #else nop - nop - nop #endif + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_TYPE_LONGDOUBLE #ifndef __NO_FPRS__ @@ -152,10 +162,12 @@ ENTRY(ffi_closure_SYSV) mtlr %r0 b .Lfinish #else - nop - nop - nop + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 + nop #endif # case FFI_TYPE_UINT8 @@ -166,7 +178,9 @@ ENTRY(ffi_closure_SYSV) #endif mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_TYPE_SINT8 #ifdef __LITTLE_ENDIAN__ @@ -186,7 +200,9 @@ ENTRY(ffi_closure_SYSV) #endif mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_TYPE_SINT16 #ifdef __LITTLE_ENDIAN__ @@ -196,19 +212,25 @@ ENTRY(ffi_closure_SYSV) #endif mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_TYPE_UINT32 lwz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_TYPE_SINT32 lwz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_TYPE_UINT64 lwz %r3,112+0(%r1) @@ -225,14 +247,18 @@ ENTRY(ffi_closure_SYSV) # case FFI_TYPE_STRUCT mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 nop # case FFI_TYPE_POINTER lwz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_TYPE_UINT128 lwz %r3,112+0(%r1) @@ -245,20 +271,26 @@ ENTRY(ffi_closure_SYSV) lbz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct. lhz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct. lwz %r3,112+0(%r1) #ifdef __LITTLE_ENDIAN__ mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 #else srwi %r3,%r3,8 mtlr %r0 @@ -269,7 +301,9 @@ ENTRY(ffi_closure_SYSV) lwz %r3,112+0(%r1) mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 # case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct. lwz %r3,112+0(%r1) @@ -319,64 +353,43 @@ ENTRY(ffi_closure_SYSV) or %r4,%r6,%r4 mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr + .cfi_def_cfa_offset 144 #endif .Luint128: lwz %r6,112+12(%r1) mtlr %r0 addi %r1,%r1,144 + .cfi_def_cfa_offset 0 blr - + .cfi_endproc END(ffi_closure_SYSV) - .section ".eh_frame",EH_FRAME_FLAGS,@progbits -.Lframe1: - .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry -.LSCIE1: - .4byte 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version -#if defined _RELOCATABLE || defined __PIC__ - .ascii "zR\0" # CIE Augmentation -#else - .ascii "\0" # CIE Augmentation -#endif - .uleb128 0x1 # CIE Code Alignment Factor - .sleb128 -4 # CIE Data Alignment Factor - .byte 0x41 # CIE RA Column -#if defined _RELOCATABLE || defined __PIC__ - .uleb128 0x1 # Augmentation size - .byte 0x1b # FDE Encoding (pcrel sdata4) -#endif - .byte 0xc # DW_CFA_def_cfa - .uleb128 0x1 - .uleb128 0x0 - .align 2 -.LECIE1: -.LSFDE1: - .4byte .LEFDE1-.LASFDE1 # FDE Length -.LASFDE1: - .4byte .LASFDE1-.Lframe1 # FDE CIE offset -#if defined _RELOCATABLE || defined __PIC__ - .4byte .LFB1-. # FDE initial location -#else - .4byte .LFB1 # FDE initial location -#endif - .4byte .LFE1-.LFB1 # FDE address range -#if defined _RELOCATABLE || defined __PIC__ - .uleb128 0x0 # Augmentation size -#endif - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI0-.LFB1 - .byte 0xe # DW_CFA_def_cfa_offset - .uleb128 144 - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI1-.LCFI0 - .byte 0x11 # DW_CFA_offset_extended_sf - .uleb128 0x41 - .sleb128 -1 - .align 2 -.LEFDE1: + +FFI_HIDDEN(ffi_go_closure_sysv) +ENTRY(ffi_go_closure_sysv) + .cfi_startproc + stwu %r1,-144(%r1) + .cfi_def_cfa_offset 144 + mflr %r0 + stw %r0,148(%r1) + .cfi_offset 65, 4 + + stw %r3, 16(%r1) + stw %r4, 20(%r1) + stw %r5, 24(%r1) + + # closure->cif + lwz %r3,4(%r11) + # closure->fun + lwz %r4,8(%r11) + # user_data + mr %r5,%r11 + b .Ldoclosure + .cfi_endproc +END(ffi_go_closure_sysv) #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits diff --git a/libffi/src/powerpc/sysv.S b/libffi/src/powerpc/sysv.S index fed2380..1474ce7 100644 --- a/libffi/src/powerpc/sysv.S +++ b/libffi/src/powerpc/sysv.S @@ -31,34 +31,35 @@ #include <powerpc/asm.h> #ifndef POWERPC64 - .globl ffi_prep_args_SYSV +FFI_HIDDEN(ffi_call_SYSV) ENTRY(ffi_call_SYSV) -.LFB1: + .cfi_startproc /* Save the old stack pointer as AP. */ - mr %r8,%r1 + mr %r10,%r1 + .cfi_def_cfa_register 10 -.LCFI0: /* Allocate the stack space we need. */ - stwux %r1,%r1,%r4 + stwux %r1,%r1,%r8 /* Save registers we use. */ mflr %r9 - stw %r28,-16(%r8) -.LCFI1: - stw %r29,-12(%r8) -.LCFI2: - stw %r30, -8(%r8) -.LCFI3: - stw %r31, -4(%r8) -.LCFI4: - stw %r9, 4(%r8) -.LCFI5: + stw %r28,-16(%r10) + stw %r29,-12(%r10) + stw %r30, -8(%r10) + stw %r31, -4(%r10) + stw %r9, 4(%r10) + .cfi_offset 65, 4 + .cfi_offset 31, -4 + .cfi_offset 30, -8 + .cfi_offset 29, -12 + .cfi_offset 28, -16 /* Save arguments over call... */ - mr %r31,%r5 /* flags, */ - mr %r30,%r6 /* rvalue, */ - mr %r29,%r7 /* function address, */ - mr %r28,%r8 /* our AP. */ -.LCFI6: + stw %r7, -20(%r10) /* closure, */ + mr %r31,%r6 /* flags, */ + mr %r30,%r5 /* rvalue, */ + mr %r29,%r4 /* function address, */ + mr %r28,%r10 /* our AP. */ + .cfi_def_cfa_register 28 /* Call ffi_prep_args_SYSV. */ mr %r4,%r1 @@ -70,35 +71,36 @@ ENTRY(ffi_call_SYSV) /* Get the address to call into CTR. */ mtctr %r29 /* Load all those argument registers. */ - lwz %r3,-16-(8*4)(%r28) - lwz %r4,-16-(7*4)(%r28) - lwz %r5,-16-(6*4)(%r28) - lwz %r6,-16-(5*4)(%r28) + lwz %r3,-24-(8*4)(%r28) + lwz %r4,-24-(7*4)(%r28) + lwz %r5,-24-(6*4)(%r28) + lwz %r6,-24-(5*4)(%r28) bf- 5,1f nop - lwz %r7,-16-(4*4)(%r28) - lwz %r8,-16-(3*4)(%r28) - lwz %r9,-16-(2*4)(%r28) - lwz %r10,-16-(1*4)(%r28) + lwz %r7,-24-(4*4)(%r28) + lwz %r8,-24-(3*4)(%r28) + lwz %r9,-24-(2*4)(%r28) + lwz %r10,-24-(1*4)(%r28) nop 1: #ifndef __NO_FPRS__ /* Load all the FP registers. */ bf- 6,2f - lfd %f1,-16-(8*4)-(8*8)(%r28) - lfd %f2,-16-(8*4)-(7*8)(%r28) - lfd %f3,-16-(8*4)-(6*8)(%r28) - lfd %f4,-16-(8*4)-(5*8)(%r28) + lfd %f1,-24-(8*4)-(8*8)(%r28) + lfd %f2,-24-(8*4)-(7*8)(%r28) + lfd %f3,-24-(8*4)-(6*8)(%r28) + lfd %f4,-24-(8*4)-(5*8)(%r28) nop - lfd %f5,-16-(8*4)-(4*8)(%r28) - lfd %f6,-16-(8*4)-(3*8)(%r28) - lfd %f7,-16-(8*4)-(2*8)(%r28) - lfd %f8,-16-(8*4)-(1*8)(%r28) + lfd %f5,-24-(8*4)-(4*8)(%r28) + lfd %f6,-24-(8*4)-(3*8)(%r28) + lfd %f7,-24-(8*4)-(2*8)(%r28) + lfd %f8,-24-(8*4)-(1*8)(%r28) #endif 2: /* Make the call. */ + lwz %r11, -20(%r28) bctrl /* Now, deal with the return value. */ @@ -125,11 +127,24 @@ L(done_return_value): lwz %r30, -8(%r28) lwz %r29,-12(%r28) lwz %r28,-16(%r28) + .cfi_remember_state + /* At this point we don't have a cfa register. Say all our + saved regs have been restored. */ + .cfi_same_value 65 + .cfi_same_value 31 + .cfi_same_value 30 + .cfi_same_value 29 + .cfi_same_value 28 + /* Hopefully this works.. */ + .cfi_def_cfa_register 1 + .cfi_offset 1, 0 lwz %r1,0(%r1) + .cfi_same_value 1 blr #ifndef __NO_FPRS__ L(fp_return_value): + .cfi_restore_state bf 28,L(float_return_value) stfd %f1,0(%r30) mtcrf 0x02,%r31 /* cr6 */ @@ -150,70 +165,10 @@ L(small_struct_return_value): stw %r3, 0(%r30) stw %r4, 4(%r30) b L(done_return_value) + .cfi_endproc -.LFE1: END(ffi_call_SYSV) - .section ".eh_frame",EH_FRAME_FLAGS,@progbits -.Lframe1: - .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */ -.LSCIE1: - .4byte 0x0 /* CIE Identifier Tag */ - .byte 0x1 /* CIE Version */ -#if defined _RELOCATABLE || defined __PIC__ - .ascii "zR\0" /* CIE Augmentation */ -#else - .ascii "\0" /* CIE Augmentation */ -#endif - .uleb128 0x1 /* CIE Code Alignment Factor */ - .sleb128 -4 /* CIE Data Alignment Factor */ - .byte 0x41 /* CIE RA Column */ -#if defined _RELOCATABLE || defined __PIC__ - .uleb128 0x1 /* Augmentation size */ - .byte 0x1b /* FDE Encoding (pcrel sdata4) */ -#endif - .byte 0xc /* DW_CFA_def_cfa */ - .uleb128 0x1 - .uleb128 0x0 - .align 2 -.LECIE1: -.LSFDE1: - .4byte .LEFDE1-.LASFDE1 /* FDE Length */ -.LASFDE1: - .4byte .LASFDE1-.Lframe1 /* FDE CIE offset */ -#if defined _RELOCATABLE || defined __PIC__ - .4byte .LFB1-. /* FDE initial location */ -#else - .4byte .LFB1 /* FDE initial location */ -#endif - .4byte .LFE1-.LFB1 /* FDE address range */ -#if defined _RELOCATABLE || defined __PIC__ - .uleb128 0x0 /* Augmentation size */ -#endif - .byte 0x4 /* DW_CFA_advance_loc4 */ - .4byte .LCFI0-.LFB1 - .byte 0xd /* DW_CFA_def_cfa_register */ - .uleb128 0x08 - .byte 0x4 /* DW_CFA_advance_loc4 */ - .4byte .LCFI5-.LCFI0 - .byte 0x11 /* DW_CFA_offset_extended_sf */ - .uleb128 0x41 - .sleb128 -1 - .byte 0x9f /* DW_CFA_offset, column 0x1f */ - .uleb128 0x1 - .byte 0x9e /* DW_CFA_offset, column 0x1e */ - .uleb128 0x2 - .byte 0x9d /* DW_CFA_offset, column 0x1d */ - .uleb128 0x3 - .byte 0x9c /* DW_CFA_offset, column 0x1c */ - .uleb128 0x4 - .byte 0x4 /* DW_CFA_advance_loc4 */ - .4byte .LCFI6-.LCFI5 - .byte 0xd /* DW_CFA_def_cfa_register */ - .uleb128 0x1c - .align 2 -.LEFDE1: - #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif diff --git a/libffi/src/prep_cif.c b/libffi/src/prep_cif.c index 866ed34..5881ceb 100644 --- a/libffi/src/prep_cif.c +++ b/libffi/src/prep_cif.c @@ -76,6 +76,13 @@ static ffi_status initialize_aggregate(ffi_type *arg) total size of 3*sizeof(long). */ arg->size = ALIGN (arg->size, arg->alignment); + /* On some targets, the ABI defines that structures have an additional + alignment beyond the "natural" one based on their elements. */ +#ifdef FFI_AGGREGATE_ALIGNMENT + if (FFI_AGGREGATE_ALIGNMENT > arg->alignment) + arg->alignment = FFI_AGGREGATE_ALIGNMENT; +#endif + if (arg->size == 0) return FFI_BAD_TYPEDEF; else @@ -111,13 +118,8 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi, FFI_ASSERT((!isvariadic) || (nfixedargs >= 1)); FFI_ASSERT(nfixedargs <= ntotalargs); -#ifndef X86_WIN32 if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)) return FFI_BAD_ABI; -#else - if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI || abi == FFI_THISCALL)) - return FFI_BAD_ABI; -#endif cif->abi = abi; cif->arg_types = atypes; @@ -134,19 +136,26 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi, if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) return FFI_BAD_TYPEDEF; +#ifndef FFI_TARGET_HAS_COMPLEX_TYPE + if (rtype->type == FFI_TYPE_COMPLEX) + abort(); +#endif /* Perform a sanity check on the return type */ FFI_ASSERT_VALID_TYPE(cif->rtype); /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */ -#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA +#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT -#ifdef SPARC - && (cif->abi != FFI_V9 || cif->rtype->size > 32) -#endif #ifdef TILE && (cif->rtype->size > 10 * FFI_SIZEOF_ARG) #endif +#ifdef XTENSA + && (cif->rtype->size > 16) +#endif +#ifdef NIOS2 + && (cif->rtype->size > 8) +#endif ) bytes = STACK_ARG_SIZE(sizeof(void*)); #endif @@ -158,23 +167,19 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi, if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; +#ifndef FFI_TARGET_HAS_COMPLEX_TYPE + if ((*ptr)->type == FFI_TYPE_COMPLEX) + abort(); +#endif /* Perform a sanity check on the argument type, do this check after the initialization. */ FFI_ASSERT_VALID_TYPE(*ptr); -#if !defined X86_ANY && !defined S390 && !defined PA -#ifdef SPARC - if (((*ptr)->type == FFI_TYPE_STRUCT - && ((*ptr)->size > 16 || cif->abi != FFI_V9)) - || ((*ptr)->type == FFI_TYPE_LONGDOUBLE - && cif->abi != FFI_V9)) - bytes += sizeof(void*); - else -#endif +#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION { /* Add any padding if necessary */ if (((*ptr)->alignment - 1) & bytes) - bytes = ALIGN(bytes, (*ptr)->alignment); + bytes = (unsigned)ALIGN(bytes, (*ptr)->alignment); #ifdef TILE if (bytes < 10 * FFI_SIZEOF_ARG && @@ -185,6 +190,10 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi, bytes = 10 * FFI_SIZEOF_ARG; } #endif +#ifdef XTENSA + if (bytes <= 6*4 && bytes + STACK_ARG_SIZE((*ptr)->size) > 6*4) + bytes = 6*4; +#endif bytes += STACK_ARG_SIZE((*ptr)->size); } diff --git a/libffi/src/raw_api.c b/libffi/src/raw_api.c index ce21372..276cb22 100644 --- a/libffi/src/raw_api.c +++ b/libffi/src/raw_api.c @@ -88,6 +88,10 @@ ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args) break; #endif + case FFI_TYPE_COMPLEX: + *args = (raw++)->ptr; + break; + case FFI_TYPE_POINTER: *args = (void*) &(raw++)->ptr; break; @@ -112,6 +116,11 @@ ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args) } else #endif + if ((*tp)->type == FFI_TYPE_COMPLEX) + { + *args = (raw++)->ptr; + } + else { *args = (void*) raw; raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*); @@ -167,6 +176,10 @@ ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw) break; #endif + case FFI_TYPE_COMPLEX: + (raw++)->ptr = *args; + break; + case FFI_TYPE_POINTER: (raw++)->ptr = **(void***) args; break; diff --git a/libffi/src/s390/ffi.c b/libffi/src/s390/ffi.c index 8adb5bc..4035b6e 100644 --- a/libffi/src/s390/ffi.c +++ b/libffi/src/s390/ffi.c @@ -1,9 +1,9 @@ /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2000, 2007 Software AG Copyright (c) 2008 Red Hat, Inc - + S390 Foreign Function Interface - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including @@ -11,10 +11,10 @@ distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,24 +27,23 @@ /* Includes */ /* -------- */ /*====================================================================*/ - + #include <ffi.h> #include <ffi_common.h> - -#include <stdlib.h> -#include <stdio.h> - +#include <stdint.h> +#include "internal.h" + /*====================== End of Includes =============================*/ - + /*====================================================================*/ /* Defines */ /* ------- */ /*====================================================================*/ -/* Maximum number of GPRs available for argument passing. */ +/* Maximum number of GPRs available for argument passing. */ #define MAX_GPRARGS 5 -/* Maximum number of FPRs available for argument passing. */ +/* Maximum number of FPRs available for argument passing. */ #ifdef __s390x__ #define MAX_FPRARGS 4 #else @@ -54,47 +53,30 @@ /* Round to multiple of 16. */ #define ROUND_SIZE(size) (((size) + 15) & ~15) -/* If these values change, sysv.S must be adapted! */ -#define FFI390_RET_VOID 0 -#define FFI390_RET_STRUCT 1 -#define FFI390_RET_FLOAT 2 -#define FFI390_RET_DOUBLE 3 -#define FFI390_RET_INT32 4 -#define FFI390_RET_INT64 5 - /*===================== End of Defines ===============================*/ - -/*====================================================================*/ -/* Prototypes */ -/* ---------- */ -/*====================================================================*/ - -static void ffi_prep_args (unsigned char *, extended_cif *); -void -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) -__attribute__ ((visibility ("hidden"))) -#endif -ffi_closure_helper_SYSV (ffi_closure *, unsigned long *, - unsigned long long *, unsigned long *); -/*====================== End of Prototypes ===========================*/ - /*====================================================================*/ /* Externals */ /* --------- */ /*====================================================================*/ - -extern void ffi_call_SYSV(unsigned, - extended_cif *, - void (*)(unsigned char *, extended_cif *), - unsigned, - void *, - void (*fn)(void)); + +struct call_frame +{ + void *back_chain; + void *eos; + unsigned long gpr_args[5]; + unsigned long gpr_save[9]; + unsigned long long fpr_args[4]; +}; + +extern void FFI_HIDDEN ffi_call_SYSV(struct call_frame *, unsigned, void *, + void (*fn)(void), void *); extern void ffi_closure_SYSV(void); - +extern void ffi_go_closure_SYSV(void); + /*====================== End of Externals ============================*/ - + /*====================================================================*/ /* */ /* Name - ffi_check_struct_type. */ @@ -103,7 +85,7 @@ extern void ffi_closure_SYSV(void); /* general purpose or floating point register. */ /* */ /*====================================================================*/ - + static int ffi_check_struct_type (ffi_type *arg) { @@ -111,7 +93,7 @@ ffi_check_struct_type (ffi_type *arg) /* If the struct has just one element, look at that element to find out whether to consider the struct as floating point. */ - while (arg->type == FFI_TYPE_STRUCT + while (arg->type == FFI_TYPE_STRUCT && arg->elements[0] && !arg->elements[1]) arg = arg->elements[0]; @@ -144,190 +126,9 @@ ffi_check_struct_type (ffi_type *arg) /* Other structs are passed via a pointer to the data. */ return FFI_TYPE_POINTER; } - -/*======================== End of Routine ============================*/ - -/*====================================================================*/ -/* */ -/* Name - ffi_prep_args. */ -/* */ -/* Function - Prepare parameters for call to function. */ -/* */ -/* ffi_prep_args is called by the assembly routine once stack space */ -/* has been allocated for the function's arguments. */ -/* */ -/*====================================================================*/ - -static void -ffi_prep_args (unsigned char *stack, extended_cif *ecif) -{ - /* The stack space will be filled with those areas: - - FPR argument register save area (highest addresses) - GPR argument register save area - temporary struct copies - overflow argument area (lowest addresses) - - We set up the following pointers: - - p_fpr: bottom of the FPR area (growing upwards) - p_gpr: bottom of the GPR area (growing upwards) - p_ov: bottom of the overflow area (growing upwards) - p_struct: top of the struct copy area (growing downwards) - - All areas are kept aligned to twice the word size. */ - - int gpr_off = ecif->cif->bytes; - int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long)); - - unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off); - unsigned long *p_gpr = (unsigned long *)(stack + gpr_off); - unsigned char *p_struct = (unsigned char *)p_gpr; - unsigned long *p_ov = (unsigned long *)stack; - - int n_fpr = 0; - int n_gpr = 0; - int n_ov = 0; - - ffi_type **ptr; - void **p_argv = ecif->avalue; - int i; - - /* If we returning a structure then we set the first parameter register - to the address of where we are returning this structure. */ - - if (ecif->cif->flags == FFI390_RET_STRUCT) - p_gpr[n_gpr++] = (unsigned long) ecif->rvalue; - - /* Now for the arguments. */ - - for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; - i > 0; - i--, ptr++, p_argv++) - { - void *arg = *p_argv; - int type = (*ptr)->type; - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - /* 16-byte long double is passed like a struct. */ - if (type == FFI_TYPE_LONGDOUBLE) - type = FFI_TYPE_STRUCT; -#endif - - /* Check how a structure type is passed. */ - if (type == FFI_TYPE_STRUCT) - { - type = ffi_check_struct_type (*ptr); - - /* If we pass the struct via pointer, copy the data. */ - if (type == FFI_TYPE_POINTER) - { - p_struct -= ROUND_SIZE ((*ptr)->size); - memcpy (p_struct, (char *)arg, (*ptr)->size); - arg = &p_struct; - } - } - - /* Now handle all primitive int/pointer/float data types. */ - switch (type) - { - case FFI_TYPE_DOUBLE: - if (n_fpr < MAX_FPRARGS) - p_fpr[n_fpr++] = *(unsigned long long *) arg; - else -#ifdef __s390x__ - p_ov[n_ov++] = *(unsigned long *) arg; -#else - p_ov[n_ov++] = ((unsigned long *) arg)[0], - p_ov[n_ov++] = ((unsigned long *) arg)[1]; -#endif - break; - - case FFI_TYPE_FLOAT: - if (n_fpr < MAX_FPRARGS) - p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32; - else - p_ov[n_ov++] = *(unsigned int *) arg; - break; - - case FFI_TYPE_POINTER: - if (n_gpr < MAX_GPRARGS) - p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg; - else - p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg; - break; - - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: -#ifdef __s390x__ - if (n_gpr < MAX_GPRARGS) - p_gpr[n_gpr++] = *(unsigned long *) arg; - else - p_ov[n_ov++] = *(unsigned long *) arg; -#else - if (n_gpr == MAX_GPRARGS-1) - n_gpr = MAX_GPRARGS; - if (n_gpr < MAX_GPRARGS) - p_gpr[n_gpr++] = ((unsigned long *) arg)[0], - p_gpr[n_gpr++] = ((unsigned long *) arg)[1]; - else - p_ov[n_ov++] = ((unsigned long *) arg)[0], - p_ov[n_ov++] = ((unsigned long *) arg)[1]; -#endif - break; - - case FFI_TYPE_UINT32: - if (n_gpr < MAX_GPRARGS) - p_gpr[n_gpr++] = *(unsigned int *) arg; - else - p_ov[n_ov++] = *(unsigned int *) arg; - break; - - case FFI_TYPE_INT: - case FFI_TYPE_SINT32: - if (n_gpr < MAX_GPRARGS) - p_gpr[n_gpr++] = *(signed int *) arg; - else - p_ov[n_ov++] = *(signed int *) arg; - break; - - case FFI_TYPE_UINT16: - if (n_gpr < MAX_GPRARGS) - p_gpr[n_gpr++] = *(unsigned short *) arg; - else - p_ov[n_ov++] = *(unsigned short *) arg; - break; - - case FFI_TYPE_SINT16: - if (n_gpr < MAX_GPRARGS) - p_gpr[n_gpr++] = *(signed short *) arg; - else - p_ov[n_ov++] = *(signed short *) arg; - break; - - case FFI_TYPE_UINT8: - if (n_gpr < MAX_GPRARGS) - p_gpr[n_gpr++] = *(unsigned char *) arg; - else - p_ov[n_ov++] = *(unsigned char *) arg; - break; - - case FFI_TYPE_SINT8: - if (n_gpr < MAX_GPRARGS) - p_gpr[n_gpr++] = *(signed char *) arg; - else - p_ov[n_ov++] = *(signed char *) arg; - break; - - default: - FFI_ASSERT (0); - break; - } - } -} /*======================== End of Routine ============================*/ - + /*====================================================================*/ /* */ /* Name - ffi_prep_cif_machdep. */ @@ -335,8 +136,8 @@ ffi_prep_args (unsigned char *stack, extended_cif *ecif) /* Function - Perform machine dependent CIF processing. */ /* */ /*====================================================================*/ - -ffi_status + +ffi_status FFI_HIDDEN ffi_prep_cif_machdep(ffi_cif *cif) { size_t struct_size = 0; @@ -347,7 +148,7 @@ ffi_prep_cif_machdep(ffi_cif *cif) ffi_type **ptr; int i; - /* Determine return value handling. */ + /* Determine return value handling. */ switch (cif->rtype->type) { @@ -356,11 +157,12 @@ ffi_prep_cif_machdep(ffi_cif *cif) cif->flags = FFI390_RET_VOID; break; - /* Structures are returned via a hidden pointer. */ + /* Structures and complex are returned via a hidden pointer. */ case FFI_TYPE_STRUCT: + case FFI_TYPE_COMPLEX: cif->flags = FFI390_RET_STRUCT; n_gpr++; /* We need one GPR to pass the pointer. */ - break; + break; /* Floating point values are returned in fpr 0. */ case FFI_TYPE_FLOAT: @@ -399,14 +201,14 @@ ffi_prep_cif_machdep(ffi_cif *cif) cif->flags = FFI390_RET_INT32; #endif break; - + default: FFI_ASSERT (0); break; } /* Now for the arguments. */ - + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) @@ -420,9 +222,12 @@ ffi_prep_cif_machdep(ffi_cif *cif) #endif /* Check how a structure type is passed. */ - if (type == FFI_TYPE_STRUCT) + if (type == FFI_TYPE_STRUCT || type == FFI_TYPE_COMPLEX) { - type = ffi_check_struct_type (*ptr); + if (type == FFI_TYPE_COMPLEX) + type = FFI_TYPE_POINTER; + else + type = ffi_check_struct_type (*ptr); /* If we pass the struct via pointer, we must reserve space to copy its data for proper call-by-value semantics. */ @@ -431,7 +236,7 @@ ffi_prep_cif_machdep(ffi_cif *cif) } /* Now handle all primitive int/float data types. */ - switch (type) + switch (type) { /* The first MAX_FPRARGS floating point arguments go in FPRs, the rest overflow to the stack. */ @@ -442,7 +247,7 @@ ffi_prep_cif_machdep(ffi_cif *cif) else n_ov += sizeof (double) / sizeof (long); break; - + case FFI_TYPE_FLOAT: if (n_fpr < MAX_FPRARGS) n_fpr++; @@ -452,9 +257,9 @@ ffi_prep_cif_machdep(ffi_cif *cif) /* On 31-bit machines, 64-bit integers are passed in GPR pairs, if one is still available, or else on the stack. If only one - register is free, skip the register (it won't be used for any + register is free, skip the register (it won't be used for any subsequent argument either). */ - + #ifndef __s390x__ case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: @@ -470,7 +275,7 @@ ffi_prep_cif_machdep(ffi_cif *cif) /* Everything else is passed in GPRs (until MAX_GPRARGS have been used) or overflows to the stack. */ - default: + default: if (n_gpr < MAX_GPRARGS) n_gpr++; else @@ -483,12 +288,12 @@ ffi_prep_cif_machdep(ffi_cif *cif) and temporary structure copies. */ cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size; - + return FFI_OK; } - + /*======================== End of Routine ============================*/ - + /*====================================================================*/ /* */ /* Name - ffi_call. */ @@ -496,42 +301,195 @@ ffi_prep_cif_machdep(ffi_cif *cif) /* Function - Call the FFI routine. */ /* */ /*====================================================================*/ - -void -ffi_call(ffi_cif *cif, - void (*fn)(void), - void *rvalue, - void **avalue) + +static void +ffi_call_int(ffi_cif *cif, + void (*fn)(void), + void *rvalue, + void **avalue, + void *closure) { int ret_type = cif->flags; - extended_cif ecif; - - ecif.cif = cif; - ecif.avalue = avalue; - ecif.rvalue = rvalue; + size_t rsize = 0, bytes = cif->bytes; + unsigned char *stack, *p_struct; + struct call_frame *frame; + unsigned long *p_ov, *p_gpr; + unsigned long long *p_fpr; + int n_fpr, n_gpr, n_ov, i, n; + ffi_type **arg_types; + + FFI_ASSERT (cif->abi == FFI_SYSV); /* If we don't have a return value, we need to fake one. */ if (rvalue == NULL) { - if (ret_type == FFI390_RET_STRUCT) - ecif.rvalue = alloca (cif->rtype->size); + if (ret_type & FFI390_RET_IN_MEM) + rsize = cif->rtype->size; else ret_type = FFI390_RET_VOID; - } + } - switch (cif->abi) + /* The stack space will be filled with those areas: + + dummy structure return (highest addresses) + FPR argument register save area + GPR argument register save area + stack frame for ffi_call_SYSV + temporary struct copies + overflow argument area (lowest addresses) + + We set up the following pointers: + + p_fpr: bottom of the FPR area (growing upwards) + p_gpr: bottom of the GPR area (growing upwards) + p_ov: bottom of the overflow area (growing upwards) + p_struct: top of the struct copy area (growing downwards) + + All areas are kept aligned to twice the word size. + + Note that we're going to create the stack frame for both + ffi_call_SYSV _and_ the target function right here. This + works because we don't make any function calls with more + than 5 arguments (indeed only memcpy and ffi_call_SYSV), + and thus we don't have any stacked outgoing parameters. */ + + stack = alloca (bytes + sizeof(struct call_frame) + rsize); + frame = (struct call_frame *)(stack + bytes); + if (rsize) + rvalue = frame + 1; + + /* Link the new frame back to the one from this function. */ + frame->back_chain = __builtin_frame_address (0); + + /* Fill in all of the argument stuff. */ + p_ov = (unsigned long *)stack; + p_struct = (unsigned char *)frame; + p_gpr = frame->gpr_args; + p_fpr = frame->fpr_args; + n_fpr = n_gpr = n_ov = 0; + + /* If we returning a structure then we set the first parameter register + to the address of where we are returning this structure. */ + if (cif->flags & FFI390_RET_IN_MEM) + p_gpr[n_gpr++] = (uintptr_t) rvalue; + + /* Now for the arguments. */ + arg_types = cif->arg_types; + for (i = 0, n = cif->nargs; i < n; ++i) { - case FFI_SYSV: - ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args, - ret_type, ecif.rvalue, fn); - break; - - default: - FFI_ASSERT (0); - break; + ffi_type *ty = arg_types[i]; + void *arg = avalue[i]; + int type = ty->type; + ffi_arg val; + + restart: + switch (type) + { + case FFI_TYPE_SINT8: + val = *(SINT8 *)arg; + goto do_int; + case FFI_TYPE_UINT8: + val = *(UINT8 *)arg; + goto do_int; + case FFI_TYPE_SINT16: + val = *(SINT16 *)arg; + goto do_int; + case FFI_TYPE_UINT16: + val = *(UINT16 *)arg; + goto do_int; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + val = *(SINT32 *)arg; + goto do_int; + case FFI_TYPE_UINT32: + val = *(UINT32 *)arg; + goto do_int; + case FFI_TYPE_POINTER: + val = *(uintptr_t *)arg; + do_int: + *(n_gpr < MAX_GPRARGS ? p_gpr + n_gpr++ : p_ov + n_ov++) = val; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef __s390x__ + val = *(UINT64 *)arg; + goto do_int; +#else + if (n_gpr == MAX_GPRARGS-1) + n_gpr = MAX_GPRARGS; + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = ((UINT32 *) arg)[0], + p_gpr[n_gpr++] = ((UINT32 *) arg)[1]; + else + p_ov[n_ov++] = ((UINT32 *) arg)[0], + p_ov[n_ov++] = ((UINT32 *) arg)[1]; +#endif + break; + + case FFI_TYPE_DOUBLE: + if (n_fpr < MAX_FPRARGS) + p_fpr[n_fpr++] = *(UINT64 *) arg; + else + { +#ifdef __s390x__ + p_ov[n_ov++] = *(UINT64 *) arg; +#else + p_ov[n_ov++] = ((UINT32 *) arg)[0], + p_ov[n_ov++] = ((UINT32 *) arg)[1]; +#endif + } + break; + + case FFI_TYPE_FLOAT: + val = *(UINT32 *)arg; + if (n_fpr < MAX_FPRARGS) + p_fpr[n_fpr++] = (UINT64)val << 32; + else + p_ov[n_ov++] = val; + break; + + case FFI_TYPE_STRUCT: + /* Check how a structure type is passed. */ + type = ffi_check_struct_type (ty); + /* Some structures are passed via a type they contain. */ + if (type != FFI_TYPE_POINTER) + goto restart; + /* ... otherwise, passed by reference. fallthru. */ + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + /* 16-byte long double is passed via reference. */ +#endif + case FFI_TYPE_COMPLEX: + /* Complex types are passed via reference. */ + p_struct -= ROUND_SIZE (ty->size); + memcpy (p_struct, arg, ty->size); + val = (uintptr_t)p_struct; + goto do_int; + + default: + FFI_ASSERT (0); + break; + } } + + ffi_call_SYSV (frame, ret_type & FFI360_RET_MASK, rvalue, fn, closure); +} + +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + ffi_call_int(cif, fn, rvalue, avalue, NULL); } - + +void +ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int(cif, fn, rvalue, avalue, closure); +} + /*======================== End of Routine ============================*/ /*====================================================================*/ @@ -541,9 +499,11 @@ ffi_call(ffi_cif *cif, /* Function - Call a FFI closure target function. */ /* */ /*====================================================================*/ - -void -ffi_closure_helper_SYSV (ffi_closure *closure, + +void FFI_HIDDEN +ffi_closure_helper_SYSV (ffi_cif *cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, unsigned long *p_gpr, unsigned long long *p_fpr, unsigned long *p_ov) @@ -562,21 +522,16 @@ ffi_closure_helper_SYSV (ffi_closure *closure, int i; /* Allocate buffer for argument list pointers. */ + p_arg = avalue = alloca (cif->nargs * sizeof (void *)); - p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *)); - - /* If we returning a structure, pass the structure address - directly to the target function. Otherwise, have the target + /* If we returning a structure, pass the structure address + directly to the target function. Otherwise, have the target function store the return value to the GPR save area. */ - - if (closure->cif->flags == FFI390_RET_STRUCT) + if (cif->flags & FFI390_RET_IN_MEM) rvalue = (void *) p_gpr[n_gpr++]; /* Now for the arguments. */ - - for (ptr = closure->cif->arg_types, i = closure->cif->nargs; - i > 0; - i--, p_arg++, ptr++) + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, p_arg++, ptr++) { int deref_struct_pointer = 0; int type = (*ptr)->type; @@ -588,11 +543,14 @@ ffi_closure_helper_SYSV (ffi_closure *closure, #endif /* Check how a structure type is passed. */ - if (type == FFI_TYPE_STRUCT) + if (type == FFI_TYPE_STRUCT || type == FFI_TYPE_COMPLEX) { - type = ffi_check_struct_type (*ptr); + if (type == FFI_TYPE_COMPLEX) + type = FFI_TYPE_POINTER; + else + type = ffi_check_struct_type (*ptr); - /* If we pass the struct via pointer, remember to + /* If we pass the struct via pointer, remember to retrieve the pointer later. */ if (type == FFI_TYPE_POINTER) deref_struct_pointer = 1; @@ -600,30 +558,32 @@ ffi_closure_helper_SYSV (ffi_closure *closure, /* Pointers are passed like UINTs of the same size. */ if (type == FFI_TYPE_POINTER) + { #ifdef __s390x__ - type = FFI_TYPE_UINT64; + type = FFI_TYPE_UINT64; #else - type = FFI_TYPE_UINT32; + type = FFI_TYPE_UINT32; #endif + } /* Now handle all primitive int/float data types. */ - switch (type) + switch (type) { case FFI_TYPE_DOUBLE: if (n_fpr < MAX_FPRARGS) *p_arg = &p_fpr[n_fpr++]; else - *p_arg = &p_ov[n_ov], + *p_arg = &p_ov[n_ov], n_ov += sizeof (double) / sizeof (long); break; - + case FFI_TYPE_FLOAT: if (n_fpr < MAX_FPRARGS) *p_arg = &p_fpr[n_fpr++]; else *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4; break; - + case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: #ifdef __s390x__ @@ -640,7 +600,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, *p_arg = &p_ov[n_ov], n_ov += 2; #endif break; - + case FFI_TYPE_INT: case FFI_TYPE_UINT32: case FFI_TYPE_SINT32: @@ -649,7 +609,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, else *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4; break; - + case FFI_TYPE_UINT16: case FFI_TYPE_SINT16: if (n_gpr < MAX_GPRARGS) @@ -665,7 +625,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, else *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1; break; - + default: FFI_ASSERT (0); break; @@ -679,14 +639,15 @@ ffi_closure_helper_SYSV (ffi_closure *closure, /* Call the target function. */ - (closure->fun) (closure->cif, rvalue, avalue, closure->user_data); + (fun) (cif, rvalue, avalue, user_data); /* Convert the return value. */ - switch (closure->cif->rtype->type) + switch (cif->rtype->type) { /* Void is easy, and so is struct. */ case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: + case FFI_TYPE_COMPLEX: #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: #endif @@ -732,7 +693,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, break; } } - + /*======================== End of Routine ============================*/ /*====================================================================*/ @@ -742,7 +703,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, /* Function - Prepare a FFI closure. */ /* */ /*====================================================================*/ - + ffi_status ffi_prep_closure_loc (ffi_closure *closure, ffi_cif *cif, @@ -750,32 +711,46 @@ ffi_prep_closure_loc (ffi_closure *closure, void *user_data, void *codeloc) { + static unsigned short const template[] = { + 0x0d10, /* basr %r1,0 */ +#ifndef __s390x__ + 0x9801, 0x1006, /* lm %r0,%r1,6(%r1) */ +#else + 0xeb01, 0x100e, 0x0004, /* lmg %r0,%r1,14(%r1) */ +#endif + 0x07f1 /* br %r1 */ + }; + + unsigned long *tramp = (unsigned long *)&closure->tramp; + if (cif->abi != FFI_SYSV) return FFI_BAD_ABI; -#ifndef __s390x__ - *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */ - *(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */ - *(short *)&closure->tramp [4] = 0x1006; - *(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */ - *(long *)&closure->tramp [8] = (long)codeloc; - *(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV; -#else - *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */ - *(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */ - *(short *)&closure->tramp [4] = 0x100e; - *(short *)&closure->tramp [6] = 0x0004; - *(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */ - *(long *)&closure->tramp[16] = (long)codeloc; - *(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV; -#endif - + memcpy (tramp, template, sizeof(template)); + tramp[2] = (unsigned long)codeloc; + tramp[3] = (unsigned long)&ffi_closure_SYSV; + closure->cif = cif; - closure->user_data = user_data; closure->fun = fun; - + closure->user_data = user_data; + return FFI_OK; } /*======================== End of Routine ============================*/ - + +/* Build a Go language closure. */ + +ffi_status +ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, + void (*fun)(ffi_cif*,void*,void**,void*)) +{ + if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; + + closure->tramp = ffi_go_closure_SYSV; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} diff --git a/libffi/src/s390/ffitarget.h b/libffi/src/s390/ffitarget.h index 97fa5c4..d8a4ee4 100644 --- a/libffi/src/s390/ffitarget.h +++ b/libffi/src/s390/ffitarget.h @@ -52,10 +52,13 @@ typedef enum ffi_abi { } ffi_abi; #endif +#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION +#define FFI_TARGET_HAS_COMPLEX_TYPE /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 #ifdef S390X #define FFI_TRAMPOLINE_SIZE 32 #else diff --git a/libffi/src/s390/internal.h b/libffi/src/s390/internal.h new file mode 100644 index 0000000..b875578 --- /dev/null +++ b/libffi/src/s390/internal.h @@ -0,0 +1,11 @@ +/* If these values change, sysv.S must be adapted! */ +#define FFI390_RET_DOUBLE 0 +#define FFI390_RET_FLOAT 1 +#define FFI390_RET_INT64 2 +#define FFI390_RET_INT32 3 +#define FFI390_RET_VOID 4 + +#define FFI360_RET_MASK 7 +#define FFI390_RET_IN_MEM 8 + +#define FFI390_RET_STRUCT (FFI390_RET_VOID | FFI390_RET_IN_MEM) diff --git a/libffi/src/s390/sysv.S b/libffi/src/s390/sysv.S index 4731a31..c4b5006 100644 --- a/libffi/src/s390/sysv.S +++ b/libffi/src/s390/sysv.S @@ -1,9 +1,9 @@ /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 2000 Software AG Copyright (c) 2008 Red Hat, Inc. - + S390 Foreign Function Interface - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including @@ -11,10 +11,10 @@ distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -29,405 +29,296 @@ #include <fficonfig.h> #include <ffi.h> + .text + #ifndef __s390x__ - -.text - - # r2: cif->bytes - # r3: &ecif - # r4: ffi_prep_args - # r5: ret_type - # r6: ecif.rvalue - # ov: fn - + + # r2: frame + # r3: ret_type + # r4: ret_addr + # r5: fun + # r6: closure + # This assumes we are using gas. + .balign 8 .globl ffi_call_SYSV + FFI_HIDDEN(ffi_call_SYSV) .type ffi_call_SYSV,%function ffi_call_SYSV: -.LFB1: - stm %r6,%r15,24(%r15) # Save registers -.LCFI0: - basr %r13,0 # Set up base register -.Lbase: - lr %r11,%r15 # Set up frame pointer -.LCFI1: - sr %r15,%r2 - ahi %r15,-96-48 # Allocate stack - lr %r8,%r6 # Save ecif.rvalue - sr %r9,%r9 - ic %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address - l %r7,96(%r11) # Load function address - st %r11,0(%r15) # Set up back chain - ahi %r11,-48 # Register save area -.LCFI2: - - la %r2,96(%r15) # Save area - # r3 already holds &ecif - basr %r14,%r4 # Call ffi_prep_args - - lm %r2,%r6,0(%r11) # Load arguments - ld %f0,32(%r11) - ld %f2,40(%r11) - la %r14,0(%r13,%r9) # Set return address - br %r7 # ... and call function - -.LretNone: # Return void - l %r4,48+56(%r11) - lm %r6,%r15,48+24(%r11) - br %r4 - -.LretFloat: - l %r4,48+56(%r11) - ste %f0,0(%r8) # Return float - lm %r6,%r15,48+24(%r11) - br %r4 - -.LretDouble: - l %r4,48+56(%r11) - std %f0,0(%r8) # Return double - lm %r6,%r15,48+24(%r11) - br %r4 - -.LretInt32: - l %r4,48+56(%r11) - st %r2,0(%r8) # Return int - lm %r6,%r15,48+24(%r11) - br %r4 - -.LretInt64: - l %r4,48+56(%r11) - stm %r2,%r3,0(%r8) # Return long long - lm %r6,%r15,48+24(%r11) - br %r4 - + .cfi_startproc + st %r6,44(%r2) # Save registers + stm %r12,%r14,48(%r2) + lr %r13,%r2 # Install frame pointer + .cfi_rel_offset r6, 44 + .cfi_rel_offset r12, 48 + .cfi_rel_offset r13, 52 + .cfi_rel_offset r14, 56 + .cfi_def_cfa_register r13 + st %r2,0(%r15) # Set up back chain + sla %r3,3 # ret_type *= 8 + lr %r12,%r4 # Save ret_addr + lr %r1,%r5 # Save fun + lr %r0,%r6 # Install static chain + + # Set return address, so that there is only one indirect jump. +#ifdef HAVE_AS_S390_ZARCH + larl %r14,.Ltable + ar %r14,%r3 +#else + basr %r14,0 +0: la %r14,.Ltable-0b(%r14,%r3) +#endif + + lm %r2,%r6,8(%r13) # Load arguments + ld %f0,64(%r13) + ld %f2,72(%r13) + br %r1 # ... and call function + + .balign 8 .Ltable: - .byte .LretNone-.Lbase # FFI390_RET_VOID - .byte .LretNone-.Lbase # FFI390_RET_STRUCT - .byte .LretFloat-.Lbase # FFI390_RET_FLOAT - .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE - .byte .LretInt32-.Lbase # FFI390_RET_INT32 - .byte .LretInt64-.Lbase # FFI390_RET_INT64 +# FFI390_RET_DOUBLE + std %f0,0(%r12) + j .Ldone + + .balign 8 +# FFI390_RET_FLOAT + ste %f0,0(%r12) + j .Ldone + + .balign 8 +# FFI390_RET_INT64 + st %r3,4(%r12) + nop + # fallthru + + .balign 8 +# FFI390_RET_INT32 + st %r2,0(%r12) + nop + # fallthru + + .balign 8 +# FFI390_RET_VOID +.Ldone: + l %r14,56(%r13) + l %r12,48(%r13) + l %r6,44(%r13) + l %r13,52(%r13) + .cfi_restore 14 + .cfi_restore 13 + .cfi_restore 12 + .cfi_restore 6 + .cfi_def_cfa r15, 96 + br %r14 + .cfi_endproc + .size ffi_call_SYSV,.-ffi_call_SYSV -.LFE1: -.ffi_call_SYSV_end: - .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + .balign 8 + .globl ffi_go_closure_SYSV + FFI_HIDDEN(ffi_go_closure_SYSV) + .type ffi_go_closure_SYSV,%function +ffi_go_closure_SYSV: + .cfi_startproc + stm %r2,%r6,8(%r15) # Save arguments + lr %r4,%r0 # Load closure -> user_data + l %r2,4(%r4) # ->cif + l %r3,8(%r4) # ->fun + j .Ldoclosure + .cfi_endproc + .balign 8 .globl ffi_closure_SYSV + FFI_HIDDEN(ffi_closure_SYSV) .type ffi_closure_SYSV,%function ffi_closure_SYSV: -.LFB2: + .cfi_startproc + stm %r2,%r6,8(%r15) # Save arguments + lr %r4,%r0 # Closure + l %r2,16(%r4) # ->cif + l %r3,20(%r4) # ->fun + l %r4,24(%r4) # ->user_data +.Ldoclosure: stm %r12,%r15,48(%r15) # Save registers -.LCFI10: + lr %r12,%r15 + .cfi_def_cfa_register r12 + .cfi_rel_offset r6, 24 + .cfi_rel_offset r12, 48 + .cfi_rel_offset r13, 52 + .cfi_rel_offset r14, 56 + .cfi_rel_offset r15, 60 +#ifndef HAVE_AS_S390_ZARCH basr %r13,0 # Set up base register .Lcbase: - stm %r2,%r6,8(%r15) # Save arguments - std %f0,64(%r15) - std %f2,72(%r15) - lr %r1,%r15 # Set up stack frame - ahi %r15,-96 -.LCFI11: - l %r12,.Lchelper-.Lcbase(%r13) # Get helper function - lr %r2,%r0 # Closure - la %r3,8(%r1) # GPRs - la %r4,64(%r1) # FPRs - la %r5,96(%r1) # Overflow - st %r1,0(%r15) # Set up back chain - - bas %r14,0(%r12,%r13) # Call helper - - l %r4,96+56(%r15) - ld %f0,96+64(%r15) # Load return registers - lm %r2,%r3,96+8(%r15) - lm %r12,%r15,96+48(%r15) - br %r4 + l %r1,.Lchelper-.Lcbase(%r13) # Get helper function +#endif + ahi %r15,-96-8 # Set up stack frame + st %r12,0(%r15) # Set up back chain + + std %f0,64(%r12) # Save fp arguments + std %f2,72(%r12) + + la %r5,96(%r12) # Overflow + st %r5,96(%r15) + la %r6,64(%r12) # FPRs + la %r5,8(%r12) # GPRs +#ifdef HAVE_AS_S390_ZARCH + brasl %r14,ffi_closure_helper_SYSV +#else + bas %r14,0(%r1,%r13) # Call helper +#endif + lr %r15,%r12 + .cfi_def_cfa_register r15 + lm %r12,%r14,48(%r12) # Restore saved registers + l %r6,24(%r15) + ld %f0,64(%r15) # Load return registers + lm %r2,%r3,8(%r15) + br %r14 + .cfi_endproc + +#ifndef HAVE_AS_S390_ZARCH .align 4 .Lchelper: .long ffi_closure_helper_SYSV-.Lcbase +#endif -.LFE2: - -.ffi_closure_SYSV_end: - .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV - - - .section .eh_frame,EH_FRAME_FLAGS,@progbits -.Lframe1: - .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry -.LSCIE1: - .4byte 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .uleb128 0x1 # CIE Code Alignment Factor - .sleb128 -4 # CIE Data Alignment Factor - .byte 0xe # CIE RA Column - .uleb128 0x1 # Augmentation size - .byte 0x1b # FDE Encoding (pcrel sdata4) - .byte 0xc # DW_CFA_def_cfa - .uleb128 0xf - .uleb128 0x60 - .align 4 -.LECIE1: -.LSFDE1: - .4byte .LEFDE1-.LASFDE1 # FDE Length -.LASFDE1: - .4byte .LASFDE1-.Lframe1 # FDE CIE offset - .4byte .LFB1-. # FDE initial location - .4byte .LFE1-.LFB1 # FDE address range - .uleb128 0x0 # Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI0-.LFB1 - .byte 0x8f # DW_CFA_offset, column 0xf - .uleb128 0x9 - .byte 0x8e # DW_CFA_offset, column 0xe - .uleb128 0xa - .byte 0x8d # DW_CFA_offset, column 0xd - .uleb128 0xb - .byte 0x8c # DW_CFA_offset, column 0xc - .uleb128 0xc - .byte 0x8b # DW_CFA_offset, column 0xb - .uleb128 0xd - .byte 0x8a # DW_CFA_offset, column 0xa - .uleb128 0xe - .byte 0x89 # DW_CFA_offset, column 0x9 - .uleb128 0xf - .byte 0x88 # DW_CFA_offset, column 0x8 - .uleb128 0x10 - .byte 0x87 # DW_CFA_offset, column 0x7 - .uleb128 0x11 - .byte 0x86 # DW_CFA_offset, column 0x6 - .uleb128 0x12 - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI1-.LCFI0 - .byte 0xd # DW_CFA_def_cfa_register - .uleb128 0xb - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI2-.LCFI1 - .byte 0xe # DW_CFA_def_cfa_offset - .uleb128 0x90 - .align 4 -.LEFDE1: -.LSFDE2: - .4byte .LEFDE2-.LASFDE2 # FDE Length -.LASFDE2: - .4byte .LASFDE2-.Lframe1 # FDE CIE offset - .4byte .LFB2-. # FDE initial location - .4byte .LFE2-.LFB2 # FDE address range - .uleb128 0x0 # Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI10-.LFB2 - .byte 0x8f # DW_CFA_offset, column 0xf - .uleb128 0x9 - .byte 0x8e # DW_CFA_offset, column 0xe - .uleb128 0xa - .byte 0x8d # DW_CFA_offset, column 0xd - .uleb128 0xb - .byte 0x8c # DW_CFA_offset, column 0xc - .uleb128 0xc - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI11-.LCFI10 - .byte 0xe # DW_CFA_def_cfa_offset - .uleb128 0xc0 - .align 4 -.LEFDE2: + .size ffi_closure_SYSV,.-ffi_closure_SYSV #else - -.text - - # r2: cif->bytes - # r3: &ecif - # r4: ffi_prep_args - # r5: ret_type - # r6: ecif.rvalue - # ov: fn - + + # r2: frame + # r3: ret_type + # r4: ret_addr + # r5: fun + # r6: closure + # This assumes we are using gas. + .balign 8 .globl ffi_call_SYSV + FFI_HIDDEN(ffi_call_SYSV) .type ffi_call_SYSV,%function ffi_call_SYSV: -.LFB1: - stmg %r6,%r15,48(%r15) # Save registers -.LCFI0: - larl %r13,.Lbase # Set up base register - lgr %r11,%r15 # Set up frame pointer -.LCFI1: - sgr %r15,%r2 - aghi %r15,-160-80 # Allocate stack - lgr %r8,%r6 # Save ecif.rvalue - llgc %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address - lg %r7,160(%r11) # Load function address - stg %r11,0(%r15) # Set up back chain - aghi %r11,-80 # Register save area -.LCFI2: - - la %r2,160(%r15) # Save area - # r3 already holds &ecif - basr %r14,%r4 # Call ffi_prep_args - - lmg %r2,%r6,0(%r11) # Load arguments - ld %f0,48(%r11) - ld %f2,56(%r11) - ld %f4,64(%r11) - ld %f6,72(%r11) - la %r14,0(%r13,%r9) # Set return address - br %r7 # ... and call function - -.Lbase: -.LretNone: # Return void - lg %r4,80+112(%r11) - lmg %r6,%r15,80+48(%r11) - br %r4 - -.LretFloat: - lg %r4,80+112(%r11) - ste %f0,0(%r8) # Return float - lmg %r6,%r15,80+48(%r11) - br %r4 - -.LretDouble: - lg %r4,80+112(%r11) - std %f0,0(%r8) # Return double - lmg %r6,%r15,80+48(%r11) - br %r4 - -.LretInt32: - lg %r4,80+112(%r11) - st %r2,0(%r8) # Return int - lmg %r6,%r15,80+48(%r11) - br %r4 - -.LretInt64: - lg %r4,80+112(%r11) - stg %r2,0(%r8) # Return long - lmg %r6,%r15,80+48(%r11) - br %r4 - + .cfi_startproc + stg %r6,88(%r2) # Save registers + stmg %r12,%r14,96(%r2) + lgr %r13,%r2 # Install frame pointer + .cfi_rel_offset r6, 88 + .cfi_rel_offset r12, 96 + .cfi_rel_offset r13, 104 + .cfi_rel_offset r14, 112 + .cfi_def_cfa_register r13 + stg %r2,0(%r15) # Set up back chain + larl %r14,.Ltable # Set up return address + slag %r3,%r3,3 # ret_type *= 8 + lgr %r12,%r4 # Save ret_addr + lgr %r1,%r5 # Save fun + lgr %r0,%r6 # Install static chain + agr %r14,%r3 + lmg %r2,%r6,16(%r13) # Load arguments + ld %f0,128(%r13) + ld %f2,136(%r13) + ld %f4,144(%r13) + ld %f6,152(%r13) + br %r1 # ... and call function + + .balign 8 .Ltable: - .byte .LretNone-.Lbase # FFI390_RET_VOID - .byte .LretNone-.Lbase # FFI390_RET_STRUCT - .byte .LretFloat-.Lbase # FFI390_RET_FLOAT - .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE - .byte .LretInt32-.Lbase # FFI390_RET_INT32 - .byte .LretInt64-.Lbase # FFI390_RET_INT64 +# FFI390_RET_DOUBLE + std %f0,0(%r12) + j .Ldone + + .balign 8 +# FFI390_RET_DOUBLE + ste %f0,0(%r12) + j .Ldone + + .balign 8 +# FFI390_RET_INT64 + stg %r2,0(%r12) + + .balign 8 +# FFI390_RET_INT32 + # Never used, as we always store type ffi_arg. + # But the stg above is 6 bytes and we cannot + # jump around this case, so fall through. + nop + nop + + .balign 8 +# FFI390_RET_VOID +.Ldone: + lg %r14,112(%r13) + lg %r12,96(%r13) + lg %r6,88(%r13) + lg %r13,104(%r13) + .cfi_restore r14 + .cfi_restore r13 + .cfi_restore r12 + .cfi_restore r6 + .cfi_def_cfa r15, 160 + br %r14 + .cfi_endproc + .size ffi_call_SYSV,.-ffi_call_SYSV -.LFE1: -.ffi_call_SYSV_end: - .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + + .balign 8 + .globl ffi_go_closure_SYSV + FFI_HIDDEN(ffi_go_closure_SYSV) + .type ffi_go_closure_SYSV,%function +ffi_go_closure_SYSV: + .cfi_startproc + stmg %r2,%r6,16(%r15) # Save arguments + lgr %r4,%r0 # Load closure -> user_data + lg %r2,8(%r4) # ->cif + lg %r3,16(%r4) # ->fun + j .Ldoclosure + .cfi_endproc + .size ffi_go_closure_SYSV,.-ffi_go_closure_SYSV + .balign 8 .globl ffi_closure_SYSV + FFI_HIDDEN(ffi_closure_SYSV) .type ffi_closure_SYSV,%function ffi_closure_SYSV: -.LFB2: - stmg %r14,%r15,112(%r15) # Save registers -.LCFI10: + .cfi_startproc stmg %r2,%r6,16(%r15) # Save arguments - std %f0,128(%r15) - std %f2,136(%r15) - std %f4,144(%r15) - std %f6,152(%r15) - lgr %r1,%r15 # Set up stack frame - aghi %r15,-160 -.LCFI11: - lgr %r2,%r0 # Closure - la %r3,16(%r1) # GPRs - la %r4,128(%r1) # FPRs - la %r5,160(%r1) # Overflow - stg %r1,0(%r15) # Set up back chain - + lgr %r4,%r0 # Load closure + lg %r2,32(%r4) # ->cif + lg %r3,40(%r4) # ->fun + lg %r4,48(%r4) # ->user_data +.Ldoclosure: + stmg %r13,%r15,104(%r15) # Save registers + lgr %r13,%r15 + .cfi_def_cfa_register r13 + .cfi_rel_offset r6, 48 + .cfi_rel_offset r13, 104 + .cfi_rel_offset r14, 112 + .cfi_rel_offset r15, 120 + aghi %r15,-160-16 # Set up stack frame + stg %r13,0(%r15) # Set up back chain + + std %f0,128(%r13) # Save fp arguments + std %f2,136(%r13) + std %f4,144(%r13) + std %f6,152(%r13) + la %r5,160(%r13) # Overflow + stg %r5,160(%r15) + la %r6,128(%r13) # FPRs + la %r5,16(%r13) # GPRs brasl %r14,ffi_closure_helper_SYSV # Call helper - lg %r14,160+112(%r15) - ld %f0,160+128(%r15) # Load return registers - lg %r2,160+16(%r15) - la %r15,160(%r15) + lgr %r15,%r13 + .cfi_def_cfa_register r15 + lmg %r13,%r14,104(%r13) # Restore saved registers + lg %r6,48(%r15) + ld %f0,128(%r15) # Load return registers + lg %r2,16(%r15) br %r14 -.LFE2: - -.ffi_closure_SYSV_end: - .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV - - - - .section .eh_frame,EH_FRAME_FLAGS,@progbits -.Lframe1: - .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry -.LSCIE1: - .4byte 0x0 # CIE Identifier Tag - .byte 0x1 # CIE Version - .ascii "zR\0" # CIE Augmentation - .uleb128 0x1 # CIE Code Alignment Factor - .sleb128 -8 # CIE Data Alignment Factor - .byte 0xe # CIE RA Column - .uleb128 0x1 # Augmentation size - .byte 0x1b # FDE Encoding (pcrel sdata4) - .byte 0xc # DW_CFA_def_cfa - .uleb128 0xf - .uleb128 0xa0 - .align 8 -.LECIE1: -.LSFDE1: - .4byte .LEFDE1-.LASFDE1 # FDE Length -.LASFDE1: - .4byte .LASFDE1-.Lframe1 # FDE CIE offset - .4byte .LFB1-. # FDE initial location - .4byte .LFE1-.LFB1 # FDE address range - .uleb128 0x0 # Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI0-.LFB1 - .byte 0x8f # DW_CFA_offset, column 0xf - .uleb128 0x5 - .byte 0x8e # DW_CFA_offset, column 0xe - .uleb128 0x6 - .byte 0x8d # DW_CFA_offset, column 0xd - .uleb128 0x7 - .byte 0x8c # DW_CFA_offset, column 0xc - .uleb128 0x8 - .byte 0x8b # DW_CFA_offset, column 0xb - .uleb128 0x9 - .byte 0x8a # DW_CFA_offset, column 0xa - .uleb128 0xa - .byte 0x89 # DW_CFA_offset, column 0x9 - .uleb128 0xb - .byte 0x88 # DW_CFA_offset, column 0x8 - .uleb128 0xc - .byte 0x87 # DW_CFA_offset, column 0x7 - .uleb128 0xd - .byte 0x86 # DW_CFA_offset, column 0x6 - .uleb128 0xe - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI1-.LCFI0 - .byte 0xd # DW_CFA_def_cfa_register - .uleb128 0xb - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI2-.LCFI1 - .byte 0xe # DW_CFA_def_cfa_offset - .uleb128 0xf0 - .align 8 -.LEFDE1: -.LSFDE2: - .4byte .LEFDE2-.LASFDE2 # FDE Length -.LASFDE2: - .4byte .LASFDE2-.Lframe1 # FDE CIE offset - .4byte .LFB2-. # FDE initial location - .4byte .LFE2-.LFB2 # FDE address range - .uleb128 0x0 # Augmentation size - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI10-.LFB2 - .byte 0x8f # DW_CFA_offset, column 0xf - .uleb128 0x5 - .byte 0x8e # DW_CFA_offset, column 0xe - .uleb128 0x6 - .byte 0x4 # DW_CFA_advance_loc4 - .4byte .LCFI11-.LCFI10 - .byte 0xe # DW_CFA_def_cfa_offset - .uleb128 0x140 - .align 8 -.LEFDE2: - -#endif + .cfi_endproc + .size ffi_closure_SYSV,.-ffi_closure_SYSV +#endif /* !s390x */ #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits diff --git a/libffi/src/sh/ffi.c b/libffi/src/sh/ffi.c index 3515b91..9ec86bf 100644 --- a/libffi/src/sh/ffi.c +++ b/libffi/src/sh/ffi.c @@ -41,7 +41,7 @@ #define STRUCT_VALUE_ADDRESS_WITH_ARG 0 #endif -/* If the structure has essentialy an unique element, return its type. */ +/* If the structure has essentially an unique element, return its type. */ static int simple_type (ffi_type *arg) { diff --git a/libffi/src/sparc/ffi.c b/libffi/src/sparc/ffi.c index 77e3822..d5212d8 100644 --- a/libffi/src/sparc/ffi.c +++ b/libffi/src/sparc/ffi.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- - ffi.c - Copyright (c) 2011 Anthony Green + ffi.c - Copyright (c) 2011, 2013 Anthony Green Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc. - + SPARC Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining @@ -27,697 +27,442 @@ #include <ffi.h> #include <ffi_common.h> - #include <stdlib.h> +#include "internal.h" +#ifndef SPARC64 -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments */ - -#ifdef SPARC64 - -int -ffi_prep_args_v9(char *stack, extended_cif *ecif) -{ - int i, ret = 0; - int tmp; - void **p_argv; - char *argp; - ffi_type **p_arg; - - tmp = 0; - - /* Skip 16 words for the window save area */ - argp = stack + 16*sizeof(long long); - -#ifdef USING_PURIFY - /* Purify will probably complain in our assembly routine, unless we - zero out this memory. */ - - ((long long*)argp)[0] = 0; - ((long long*)argp)[1] = 0; - ((long long*)argp)[2] = 0; - ((long long*)argp)[3] = 0; - ((long long*)argp)[4] = 0; - ((long long*)argp)[5] = 0; +/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; + all further uses in this file will refer to the 128-bit type. */ +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +# if FFI_TYPE_LONGDOUBLE != 4 +# error FFI_TYPE_LONGDOUBLE out of date +# endif +#else +# undef FFI_TYPE_LONGDOUBLE +# define FFI_TYPE_LONGDOUBLE 4 #endif - p_argv = ecif->avalue; +/* Perform machine dependent cif processing */ +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep(ffi_cif *cif) +{ + ffi_type *rtype = cif->rtype; + int rtt = rtype->type; + size_t bytes; + int i, n, flags; - if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && - ecif->cif->rtype->size > 32) + /* Set the return type flag */ + switch (rtt) { - *(unsigned long long *) argp = (unsigned long)ecif->rvalue; - argp += sizeof(long long); - tmp = 1; + case FFI_TYPE_VOID: + flags = SPARC_RET_VOID; + break; + case FFI_TYPE_FLOAT: + flags = SPARC_RET_F_1; + break; + case FFI_TYPE_DOUBLE: + flags = SPARC_RET_F_2; + break; + case FFI_TYPE_LONGDOUBLE: + case FFI_TYPE_STRUCT: + flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT; + flags |= SPARC_RET_STRUCT; + break; + case FFI_TYPE_SINT8: + flags = SPARC_RET_SINT8; + break; + case FFI_TYPE_UINT8: + flags = SPARC_RET_UINT8; + break; + case FFI_TYPE_SINT16: + flags = SPARC_RET_SINT16; + break; + case FFI_TYPE_UINT16: + flags = SPARC_RET_UINT16; + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + flags = SPARC_RET_UINT32; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + flags = SPARC_RET_INT64; + break; + case FFI_TYPE_COMPLEX: + rtt = rtype->elements[0]->type; + switch (rtt) + { + case FFI_TYPE_FLOAT: + flags = SPARC_RET_F_2; + break; + case FFI_TYPE_DOUBLE: + flags = SPARC_RET_F_4; + break; + case FFI_TYPE_LONGDOUBLE: + flags = SPARC_RET_F_8; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + flags = SPARC_RET_INT128; + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + flags = SPARC_RET_INT64; + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + flags = SP_V8_RET_CPLX16; + break; + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + flags = SP_V8_RET_CPLX8; + break; + default: + abort(); + } + break; + default: + abort(); } + cif->flags = flags; - for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; - i++, p_arg++) + bytes = 0; + for (i = 0, n = cif->nargs; i < n; ++i) { - size_t z; + ffi_type *ty = cif->arg_types[i]; + size_t z = ty->size; + int tt = ty->type; - z = (*p_arg)->size; - switch ((*p_arg)->type) + switch (tt) { case FFI_TYPE_STRUCT: - if (z > 16) - { - /* For structures larger than 16 bytes we pass reference. */ - *(unsigned long long *) argp = (unsigned long)* p_argv; - argp += sizeof(long long); - tmp++; - p_argv++; - continue; - } - /* FALLTHROUGH */ - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: -#endif - ret = 1; /* We should promote into FP regs as well as integer. */ + by_reference: + /* Passed by reference. */ + z = 4; break; + + case FFI_TYPE_COMPLEX: + tt = ty->elements[0]->type; + if (tt == FFI_TYPE_FLOAT || z > 8) + goto by_reference; + /* FALLTHRU */ + + default: + z = ALIGN(z, 4); } - if (z < sizeof(long long)) - { - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed long long *) argp = *(SINT8 *)(* p_argv); - break; + bytes += z; + } - case FFI_TYPE_UINT8: - *(unsigned long long *) argp = *(UINT8 *)(* p_argv); - break; + /* Sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + if (bytes < 6 * 4) + bytes = 6 * 4; - case FFI_TYPE_SINT16: - *(signed long long *) argp = *(SINT16 *)(* p_argv); - break; + /* The ABI always requires space for the struct return pointer. */ + bytes += 4; - case FFI_TYPE_UINT16: - *(unsigned long long *) argp = *(UINT16 *)(* p_argv); - break; + /* The stack must be 2 word aligned, so round bytes up appropriately. */ + bytes = ALIGN(bytes, 2 * 4); - case FFI_TYPE_SINT32: - *(signed long long *) argp = *(SINT32 *)(* p_argv); - break; + /* Include the call frame to prep_args. */ + bytes += 4*16 + 4*8; + cif->bytes = bytes; - case FFI_TYPE_UINT32: - *(unsigned long long *) argp = *(UINT32 *)(* p_argv); - break; + return FFI_OK; +} - case FFI_TYPE_FLOAT: - *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */ - break; +extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, size_t bytes, void *closure) FFI_HIDDEN; - case FFI_TYPE_STRUCT: - memcpy(argp, *p_argv, z); - break; +int FFI_HIDDEN +ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue) +{ + ffi_type **p_arg; + int flags = cif->flags; + int i, nargs; - default: - FFI_ASSERT(0); - } - z = sizeof(long long); - tmp++; - } - else if (z == sizeof(long long)) + if (rvalue == NULL) + { + if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT) { - memcpy(argp, *p_argv, z); - z = sizeof(long long); - tmp++; + /* Since we pass the pointer to the callee, we need a value. + We allowed for this space in ffi_call, before ffi_call_v8 + alloca'd the space. */ + rvalue = (char *)argp + cif->bytes; } else { - if ((tmp & 1) && (*p_arg)->alignment > 8) - { - tmp++; - argp += sizeof(long long); - } - memcpy(argp, *p_argv, z); - z = 2 * sizeof(long long); - tmp += 2; + /* Otherwise, we can ignore the return value. */ + flags = SPARC_RET_VOID; } - p_argv++; - argp += z; } - return ret; -} - -#else - -void -ffi_prep_args_v8(char *stack, extended_cif *ecif) -{ - int i; - void **p_argv; - char *argp; - ffi_type **p_arg; - - /* Skip 16 words for the window save area */ - argp = stack + 16*sizeof(int); - - /* This should only really be done when we are returning a structure, - however, it's faster just to do it all the time... - - if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */ - *(int *) argp = (long)ecif->rvalue; - - /* And 1 word for the structure return value. */ - argp += sizeof(int); + /* This could only really be done when we are returning a structure. + However, the space is reserved so we can do it unconditionally. */ + *argp++ = (unsigned long)rvalue; #ifdef USING_PURIFY - /* Purify will probably complain in our assembly routine, unless we - zero out this memory. */ - - ((int*)argp)[0] = 0; - ((int*)argp)[1] = 0; - ((int*)argp)[2] = 0; - ((int*)argp)[3] = 0; - ((int*)argp)[4] = 0; - ((int*)argp)[5] = 0; + /* Purify will probably complain in our assembly routine, + unless we zero out this memory. */ + memset(argp, 0, 6*4); #endif - p_argv = ecif->avalue; - - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) + p_arg = cif->arg_types; + for (i = 0, nargs = cif->nargs; i < nargs; i++) { + ffi_type *ty = p_arg[i]; + void *a = avalue[i]; + int tt = ty->type; size_t z; - if ((*p_arg)->type == FFI_TYPE_STRUCT -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || (*p_arg)->type == FFI_TYPE_LONGDOUBLE -#endif - ) + switch (tt) + { + case FFI_TYPE_STRUCT: + case FFI_TYPE_LONGDOUBLE: + by_reference: + *argp++ = (unsigned long)a; + break; + + case FFI_TYPE_DOUBLE: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + memcpy(argp, a, 8); + argp += 2; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + *argp++ = *(unsigned *)a; + break; + + case FFI_TYPE_UINT8: + *argp++ = *(UINT8 *)a; + break; + case FFI_TYPE_SINT8: + *argp++ = *(SINT8 *)a; + break; + case FFI_TYPE_UINT16: + *argp++ = *(UINT16 *)a; + break; + case FFI_TYPE_SINT16: + *argp++ = *(SINT16 *)a; + break; + + case FFI_TYPE_COMPLEX: + tt = ty->elements[0]->type; + z = ty->size; + if (tt == FFI_TYPE_FLOAT || z > 8) + goto by_reference; + if (z < 4) { - *(unsigned int *) argp = (unsigned long)(* p_argv); - z = sizeof(int); + memcpy((char *)argp + 4 - z, a, z); + argp++; } else { - z = (*p_arg)->size; - if (z < sizeof(int)) - { - z = sizeof(int); - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = *(SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = *(UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = *(SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = *(UINT16 *)(* p_argv); - break; - - default: - FFI_ASSERT(0); - } - } - else - { - memcpy(argp, *p_argv, z); - } + memcpy(argp, a, z); + argp += z / 4; } - p_argv++; - argp += z; - } - - return; -} - -#endif - -/* Perform machine dependent cif processing */ - -static -ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif) -{ - int wordsize; - - if (!V9_ABI_P (cif->abi)) - { - wordsize = 4; - - /* If we are returning a struct, this will already have been added. - Otherwise we need to add it because it's always got to be there! */ - - if (cif->rtype->type != FFI_TYPE_STRUCT) - cif->bytes += wordsize; - - /* sparc call frames require that space is allocated for 6 args, - even if they aren't used. Make that space if necessary. */ - - if (cif->bytes < 4*6+4) - cif->bytes = 4*6+4; - } - else - { - wordsize = 8; + break; - /* sparc call frames require that space is allocated for 6 args, - even if they aren't used. Make that space if necessary. */ - - if (cif->bytes < 8*6) - cif->bytes = 8*6; + default: + abort(); + } } - /* Adjust cif->bytes. to include 16 words for the window save area, - and maybe the struct/union return pointer area, */ - - cif->bytes += 16 * wordsize; - - /* The stack must be 2 word aligned, so round bytes up - appropriately. */ - - cif->bytes = ALIGN(cif->bytes, 2 * wordsize); + return flags; +} - /* Set the return type flag */ - switch (cif->rtype->type) - { - case FFI_TYPE_VOID: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: -#endif - cif->flags = cif->rtype->type; - break; +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + size_t bytes = cif->bytes; - case FFI_TYPE_STRUCT: - if (V9_ABI_P (cif->abi) && cif->rtype->size > 32) - cif->flags = FFI_TYPE_VOID; - else - cif->flags = FFI_TYPE_STRUCT; - break; + FFI_ASSERT (cif->abi == FFI_V8); - case FFI_TYPE_SINT8: - case FFI_TYPE_UINT8: - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT16: - if (V9_ABI_P (cif->abi)) - cif->flags = FFI_TYPE_INT; - else - cif->flags = cif->rtype->type; - break; + /* If we've not got a return value, we need to create one if we've + got to pass the return value to the callee. Otherwise ignore it. */ + if (rvalue == NULL + && (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT) + bytes += ALIGN (cif->rtype->size, 8); - case FFI_TYPE_SINT64: - case FFI_TYPE_UINT64: - if (V9_ABI_P (cif->abi)) - cif->flags = FFI_TYPE_INT; - else - cif->flags = FFI_TYPE_SINT64; - break; - - default: - cif->flags = FFI_TYPE_INT; - break; - } - return FFI_OK; + ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure); } -ffi_status -ffi_prep_cif_machdep(ffi_cif *cif) +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { -#ifdef SPARC64 - if (cif->abi != FFI_COMPAT_V9) - cif->nfixedargs = cif->nargs; -#endif - return ffi_prep_cif_machdep_core (cif); + ffi_call_int (cif, fn, rvalue, avalue, NULL); } -ffi_status -ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, - unsigned int ntotalargs) +void +ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) { -#ifdef SPARC64 - if (cif->abi != FFI_COMPAT_V9) - cif->nfixedargs = nfixedargs; -#endif - return ffi_prep_cif_machdep_core (cif); + ffi_call_int (cif, fn, rvalue, avalue, closure); } -#ifdef SPARC64 - -int -ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) +#ifdef __GNUC__ +static inline void +ffi_flush_icache (void *p) { - ffi_type **ptr = &arg->elements[0]; - - while (*ptr != NULL) - { - if (off & ((*ptr)->alignment - 1)) - off = ALIGN(off, (*ptr)->alignment); - - switch ((*ptr)->type) - { - case FFI_TYPE_STRUCT: - off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt); - off = ALIGN(off, FFI_SIZEOF_ARG); - break; - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: -#endif - memmove(ret + off, flt + off, (*ptr)->size); - off += (*ptr)->size; - break; - default: - memmove(ret + off, intg + off, (*ptr)->size); - off += (*ptr)->size; - break; - } - ptr++; - } - return off; + /* SPARC v8 requires 5 instructions for flush to be visible */ + asm volatile ("iflush %0; iflush %0+8; nop; nop; nop; nop; nop" + : : "r" (p) : "memory"); } - -#endif - -#ifdef SPARC64 -extern int ffi_call_v9(void *, extended_cif *, unsigned, - unsigned, unsigned *, void (*fn)(void)); -#else -extern int ffi_call_v8(void *, extended_cif *, unsigned, - unsigned, unsigned *, void (*fn)(void)); -#endif - -void -ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) -{ - extended_cif ecif; -#ifdef SPARC64 - void *rval = rvalue; -#endif - - ecif.cif = cif; - ecif.avalue = avalue; - ecif.rvalue = rvalue; - - /* If the return value is a struct and we don't have a return value address, - then we need to make one. */ - if (cif->rtype->type == FFI_TYPE_STRUCT) - { - if (ecif.rvalue == NULL) - ecif.rvalue = alloca(cif->rtype->size); - -#ifdef SPARC64 - if (cif->rtype->size <= 32) - rval = alloca(64); - else - rval = NULL; -#endif - } - - switch (cif->abi) - { - case FFI_V8: - case FFI_V8PLUS: -#ifdef SPARC64 - /* We don't yet support calling 32bit code from 64bit */ - FFI_ASSERT(0); #else - if (rvalue && (cif->rtype->type == FFI_TYPE_STRUCT -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || cif->flags == FFI_TYPE_LONGDOUBLE +extern void ffi_flush_icache (void *) FFI_HIDDEN; #endif - )) - { - /* For v8, we need an "unimp" with size of returning struct */ - /* behind "call", so we alloc some executable space for it. */ - /* l7 is used, we need to make sure v8.S doesn't use %l7. */ - unsigned int *call_struct = NULL; - ffi_closure_alloc(32, (void **)&call_struct); - if (call_struct) - { - unsigned long f = (unsigned long)fn; - call_struct[0] = 0xae10001f; /* mov %i7, %l7 */ - call_struct[1] = 0xbe10000f; /* mov %o7, %i7 */ - call_struct[2] = 0x03000000 | f >> 10; /* sethi %hi(fn), %g1 */ - call_struct[3] = 0x9fc06000 | (f & 0x3ff); /* jmp %g1+%lo(fn), %o7 */ - call_struct[4] = 0x01000000; /* nop */ - if (cif->rtype->size < 0x7f) - call_struct[5] = cif->rtype->size; /* unimp */ - else - call_struct[5] = 0x01000000; /* nop */ - call_struct[6] = 0x81c7e008; /* ret */ - call_struct[7] = 0xbe100017; /* mov %l7, %i7 */ - asm volatile ("iflush %0; iflush %0+8; iflush %0+16; iflush %0+24" : : - "r" (call_struct) : "memory"); - /* SPARC v8 requires 5 instructions for flush to be visible */ - asm volatile ("nop; nop; nop; nop; nop"); - ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, - cif->flags, rvalue, (void (*)(void)) call_struct); - ffi_closure_free(call_struct); - } - else - { - ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, - cif->flags, rvalue, fn); - } - } - else - { - ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, - cif->flags, rvalue, fn); - } -#endif - break; - case FFI_COMPAT_V9: - case FFI_V9: -#ifdef SPARC64 - ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes, cif->flags, rval, fn); - if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT) - ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, - ((char *)rval)+32); -#else - /* And vice versa */ - FFI_ASSERT(0); -#endif - break; - default: - FFI_ASSERT(0); - break; - } -} - -#ifdef SPARC64 -extern void ffi_closure_v9(void); -#else -extern void ffi_closure_v8(void); -#endif +extern void ffi_closure_v8(void) FFI_HIDDEN; +extern void ffi_go_closure_v8(void) FFI_HIDDEN; ffi_status -ffi_prep_closure_loc (ffi_closure* closure, - ffi_cif* cif, +ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif *cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data, void *codeloc) { unsigned int *tramp = (unsigned int *) &closure->tramp[0]; - unsigned long fn; -#ifdef SPARC64 - /* Trampoline address is equal to the closure address. We take advantage - of that to reduce the trampoline size by 8 bytes. */ - if (!V9_ABI_P (cif->abi)) - return FFI_BAD_ABI; - fn = (unsigned long) ffi_closure_v9; - tramp[0] = 0x83414000; /* rd %pc, %g1 */ - tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */ - tramp[2] = 0x81c14000; /* jmp %g5 */ - tramp[3] = 0x01000000; /* nop */ - *((unsigned long *) &tramp[4]) = fn; -#else - unsigned long ctx = (unsigned long) codeloc; - if (!V8_ABI_P (cif->abi)) + unsigned long ctx = (unsigned long) closure; + unsigned long fn = (unsigned long) ffi_closure_v8; + + if (cif->abi != FFI_V8) return FFI_BAD_ABI; - fn = (unsigned long) ffi_closure_v8; + tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */ tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */ tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */ tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */ -#endif closure->cif = cif; closure->fun = fun; closure->user_data = user_data; - /* Flush the Icache. closure is 8 bytes aligned. */ -#ifdef SPARC64 - asm volatile ("flush %0; flush %0+8" : : "r" (closure) : "memory"); -#else - asm volatile ("iflush %0; iflush %0+8" : : "r" (closure) : "memory"); - /* SPARC v8 requires 5 instructions for flush to be visible */ - asm volatile ("nop; nop; nop; nop; nop"); -#endif + ffi_flush_icache (closure); return FFI_OK; } -#ifdef SPARC64 +ffi_status +ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*)) +{ + if (cif->abi != FFI_V8) + return FFI_BAD_ABI; -int -ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue, - unsigned long *gpr, double *fpr) + closure->tramp = ffi_go_closure_v8; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + +int FFI_HIDDEN +ffi_closure_sparc_inner_v8(ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, void *rvalue, + unsigned long *argp) { - ffi_cif *cif; ffi_type **arg_types; void **avalue; - int i, argn, fp_slot_max; + int i, nargs, flags; - cif = closure->cif; arg_types = cif->arg_types; - avalue = alloca(cif->nargs * sizeof(void *)); + nargs = cif->nargs; + flags = cif->flags; + avalue = alloca(nargs * sizeof(void *)); /* Copy the caller's structure return address so that the closure - returns the data directly to the caller. */ - if (cif->flags == FFI_TYPE_VOID && cif->rtype->type == FFI_TYPE_STRUCT) + returns the data directly to the caller. Also install it so we + can return the address in %o0. */ + if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT) { - rvalue = (void *) gpr[0]; - /* Skip the structure return address. */ - argn = 1; + void *new_rvalue = (void *)*argp; + *(void **)rvalue = new_rvalue; + rvalue = new_rvalue; } - else - argn = 0; - fp_slot_max = 16 - argn; + /* Always skip the structure return address. */ + argp++; /* Grab the addresses of the arguments from the stack frame. */ - for (i = 0; i < cif->nargs; i++) + for (i = 0; i < nargs; i++) { - /* If the function is variadic, FP arguments are passed in FP - registers only if the corresponding parameter is named. */ - const int named - = (cif->abi == FFI_COMPAT_V9 ? 1 : i < cif->nfixedargs); + ffi_type *ty = arg_types[i]; + int tt = ty->type; + void *a = argp; + size_t z; - if (arg_types[i]->type == FFI_TYPE_STRUCT) + switch (tt) { - if (arg_types[i]->size > 16) - { - /* Straight copy of invisible reference. */ - avalue[i] = (void *)gpr[argn++]; - } - else + case FFI_TYPE_STRUCT: + case FFI_TYPE_LONGDOUBLE: + by_reference: + /* Straight copy of invisible reference. */ + a = (void *)*argp; + break; + + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + if ((unsigned long)a & 7) { - /* Left-justify. */ - ffi_v9_layout_struct(arg_types[i], - 0, - (char *) &gpr[argn], - (char *) &gpr[argn], - named - ? (char *) &fpr[argn] - : (char *) &gpr[argn]); - avalue[i] = &gpr[argn]; - argn - += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + /* Align on a 8-byte boundary. */ + UINT64 *tmp = alloca(8); + *tmp = ((UINT64)argp[0] << 32) | argp[1]; + a = tmp; } - } - else - { - /* Right-justify. */ - argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - - /* Align on a 16-byte boundary. */ -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - if (arg_types[i]->type == FFI_TYPE_LONGDOUBLE && (argn % 2) != 0) - argn++; -#endif - if (i < fp_slot_max - && named - && (arg_types[i]->type == FFI_TYPE_FLOAT - || arg_types[i]->type == FFI_TYPE_DOUBLE -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || arg_types[i]->type == FFI_TYPE_LONGDOUBLE -#endif - )) - avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size; - else - avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; - } - } - - /* Invoke the closure. */ - closure->fun (cif, rvalue, avalue, closure->user_data); - - /* Tell ffi_closure_sparc how to perform return type promotions. */ - return cif->rtype->type; -} - -#else - -int -ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue, - unsigned long *gpr, unsigned long *scratch) -{ - ffi_cif *cif; - ffi_type **arg_types; - void **avalue; - int i, argn; - - cif = closure->cif; - arg_types = cif->arg_types; - avalue = alloca(cif->nargs * sizeof(void *)); + argp++; + break; - /* Copy the caller's structure return address so that the closure - returns the data directly to the caller. */ - if (cif->flags == FFI_TYPE_STRUCT -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || cif->flags == FFI_TYPE_LONGDOUBLE -#endif - ) - rvalue = (void *) gpr[0]; + case FFI_TYPE_INT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + break; + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + a += 2; + break; + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + a += 3; + break; - /* Always skip the structure return address. */ - argn = 1; + case FFI_TYPE_COMPLEX: + tt = ty->elements[0]->type; + z = ty->size; + if (tt == FFI_TYPE_FLOAT || z > 8) + goto by_reference; + if (z < 4) + a += 4 - z; + else if (z > 4) + argp++; + break; - /* Grab the addresses of the arguments from the stack frame. */ - for (i = 0; i < cif->nargs; i++) - { - if (arg_types[i]->type == FFI_TYPE_STRUCT -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || arg_types[i]->type == FFI_TYPE_LONGDOUBLE -#endif - ) - { - /* Straight copy of invisible reference. */ - avalue[i] = (void *)gpr[argn++]; - } - else if ((arg_types[i]->type == FFI_TYPE_DOUBLE - || arg_types[i]->type == FFI_TYPE_SINT64 - || arg_types[i]->type == FFI_TYPE_UINT64) - /* gpr is 8-byte aligned. */ - && (argn % 2) != 0) - { - /* Align on a 8-byte boundary. */ - scratch[0] = gpr[argn]; - scratch[1] = gpr[argn+1]; - avalue[i] = scratch; - scratch -= 2; - argn += 2; - } - else - { - /* Always right-justify. */ - argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; + default: + abort(); } + argp++; + avalue[i] = a; } /* Invoke the closure. */ - closure->fun (cif, rvalue, avalue, closure->user_data); + fun (cif, rvalue, avalue, user_data); /* Tell ffi_closure_sparc how to perform return type promotions. */ - return cif->rtype->type; + return flags; } - -#endif +#endif /* !SPARC64 */ diff --git a/libffi/src/sparc/ffi64.c b/libffi/src/sparc/ffi64.c new file mode 100644 index 0000000..340b198 --- /dev/null +++ b/libffi/src/sparc/ffi64.c @@ -0,0 +1,608 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2011, 2013 Anthony Green + Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc. + + SPARC Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> +#include <stdlib.h> +#include "internal.h" + +/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; + all further uses in this file will refer to the 128-bit type. */ +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +# if FFI_TYPE_LONGDOUBLE != 4 +# error FFI_TYPE_LONGDOUBLE out of date +# endif +#else +# undef FFI_TYPE_LONGDOUBLE +# define FFI_TYPE_LONGDOUBLE 4 +#endif + +#ifdef SPARC64 + +/* Flatten the contents of a structure to the parts that are passed in + floating point registers. The return is a bit mask wherein bit N + set means bytes [4*n, 4*n+3] are passed in %fN. + + We encode both the (running) size (maximum 32) and mask (maxumum 255) + into one integer. The size is placed in the low byte, so that align + and addition work correctly. The mask is placed in the second byte. */ + +static int +ffi_struct_float_mask (ffi_type *outer_type, int size_mask) +{ + ffi_type **elts; + ffi_type *t; + + if (outer_type->type == FFI_TYPE_COMPLEX) + { + int m = 0, tt = outer_type->elements[0]->type; + size_t z = outer_type->size; + + if (tt == FFI_TYPE_FLOAT + || tt == FFI_TYPE_DOUBLE + || tt == FFI_TYPE_LONGDOUBLE) + m = (1 << (z / 4)) - 1; + return (m << 8) | z; + } + FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT); + + for (elts = outer_type->elements; (t = *elts) != NULL; elts++) + { + size_t z = t->size; + int o, m, tt; + + size_mask = ALIGN(size_mask, t->alignment); + switch (t->type) + { + case FFI_TYPE_STRUCT: + size_mask = ffi_struct_float_mask (t, size_mask); + continue; + case FFI_TYPE_COMPLEX: + tt = t->elements[0]->type; + if (tt != FFI_TYPE_FLOAT + && tt != FFI_TYPE_DOUBLE + && tt != FFI_TYPE_LONGDOUBLE) + break; + /* FALLTHRU */ + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + m = (1 << (z / 4)) - 1; /* compute mask for type */ + o = (size_mask >> 2) & 0x3f; /* extract word offset */ + size_mask |= m << (o + 8); /* insert mask into place */ + break; + } + size_mask += z; + } + + size_mask = ALIGN(size_mask, outer_type->alignment); + FFI_ASSERT ((size_mask & 0xff) == outer_type->size); + + return size_mask; +} + +/* Merge floating point data into integer data. If the structure is + entirely floating point, simply return a pointer to the fp data. */ + +static void * +ffi_struct_float_merge (int size_mask, void *vi, void *vf) +{ + int size = size_mask & 0xff; + int mask = size_mask >> 8; + int n = size >> 2; + + if (mask == 0) + return vi; + else if (mask == (1 << n) - 1) + return vf; + else + { + unsigned int *wi = vi, *wf = vf; + int i; + + for (i = 0; i < n; ++i) + if ((mask >> i) & 1) + wi[i] = wf[i]; + + return vi; + } +} + +/* Similar, but place the data into VD in the end. */ + +void FFI_HIDDEN +ffi_struct_float_copy (int size_mask, void *vd, void *vi, void *vf) +{ + int size = size_mask & 0xff; + int mask = size_mask >> 8; + int n = size >> 2; + + if (mask == 0) + ; + else if (mask == (1 << n) - 1) + vi = vf; + else + { + unsigned int *wd = vd, *wi = vi, *wf = vf; + int i; + + for (i = 0; i < n; ++i) + wd[i] = ((mask >> i) & 1 ? wf : wi)[i]; + return; + } + memcpy (vd, vi, size); +} + +/* Perform machine dependent cif processing */ + +static ffi_status +ffi_prep_cif_machdep_core(ffi_cif *cif) +{ + ffi_type *rtype = cif->rtype; + int rtt = rtype->type; + size_t bytes = 0; + int i, n, flags; + + /* Set the return type flag */ + switch (rtt) + { + case FFI_TYPE_VOID: + flags = SPARC_RET_VOID; + break; + case FFI_TYPE_FLOAT: + flags = SPARC_RET_F_1; + break; + case FFI_TYPE_DOUBLE: + flags = SPARC_RET_F_2; + break; + case FFI_TYPE_LONGDOUBLE: + flags = SPARC_RET_F_4; + break; + + case FFI_TYPE_COMPLEX: + case FFI_TYPE_STRUCT: + if (rtype->size > 32) + { + flags = SPARC_RET_VOID | SPARC_FLAG_RET_IN_MEM; + bytes = 8; + } + else + { + int size_mask = ffi_struct_float_mask (rtype, 0); + int word_size = (size_mask >> 2) & 0x3f; + int all_mask = (1 << word_size) - 1; + int fp_mask = size_mask >> 8; + + flags = (size_mask << SPARC_SIZEMASK_SHIFT) | SPARC_RET_STRUCT; + + /* For special cases of all-int or all-fp, we can return + the value directly without popping through a struct copy. */ + if (fp_mask == 0) + { + if (rtype->alignment >= 8) + { + if (rtype->size == 8) + flags = SPARC_RET_INT64; + else if (rtype->size == 16) + flags = SPARC_RET_INT128; + } + } + else if (fp_mask == all_mask) + switch (word_size) + { + case 1: flags = SPARC_RET_F_1; break; + case 2: flags = SPARC_RET_F_2; break; + case 3: flags = SP_V9_RET_F_3; break; + case 4: flags = SPARC_RET_F_4; break; + /* 5 word structures skipped; handled via RET_STRUCT. */ + case 6: flags = SPARC_RET_F_6; break; + /* 7 word structures skipped; handled via RET_STRUCT. */ + case 8: flags = SPARC_RET_F_8; break; + } + } + break; + + case FFI_TYPE_SINT8: + flags = SPARC_RET_SINT8; + break; + case FFI_TYPE_UINT8: + flags = SPARC_RET_UINT8; + break; + case FFI_TYPE_SINT16: + flags = SPARC_RET_SINT16; + break; + case FFI_TYPE_UINT16: + flags = SPARC_RET_UINT16; + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + flags = SP_V9_RET_SINT32; + break; + case FFI_TYPE_UINT32: + flags = SPARC_RET_UINT32; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + flags = SPARC_RET_INT64; + break; + + default: + abort(); + } + + bytes = 0; + for (i = 0, n = cif->nargs; i < n; ++i) + { + ffi_type *ty = cif->arg_types[i]; + size_t z = ty->size; + size_t a = ty->alignment; + + switch (ty->type) + { + case FFI_TYPE_COMPLEX: + case FFI_TYPE_STRUCT: + /* Large structs passed by reference. */ + if (z > 16) + { + a = z = 8; + break; + } + /* Small structs may be passed in integer or fp regs or both. */ + if (bytes >= 16*8) + break; + if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0) + break; + /* FALLTHRU */ + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + flags |= SPARC_FLAG_FP_ARGS; + break; + } + bytes = ALIGN(bytes, a); + bytes += ALIGN(z, 8); + } + + /* Sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + if (bytes < 6 * 8) + bytes = 6 * 8; + + /* The stack must be 2 word aligned, so round bytes up appropriately. */ + bytes = ALIGN(bytes, 16); + + /* Include the call frame to prep_args. */ + bytes += 8*16 + 8*8; + + cif->bytes = bytes; + cif->flags = flags; + return FFI_OK; +} + +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep(ffi_cif *cif) +{ + cif->nfixedargs = cif->nargs; + return ffi_prep_cif_machdep_core(cif); +} + +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs) +{ + cif->nfixedargs = nfixedargs; + return ffi_prep_cif_machdep_core(cif); +} + +extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, size_t bytes, void *closure) FFI_HIDDEN; + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +int FFI_HIDDEN +ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue) +{ + ffi_type **p_arg; + int flags = cif->flags; + int i, nargs; + + if (rvalue == NULL) + { + if (flags & SPARC_FLAG_RET_IN_MEM) + { + /* Since we pass the pointer to the callee, we need a value. + We allowed for this space in ffi_call, before ffi_call_v8 + alloca'd the space. */ + rvalue = (char *)argp + cif->bytes; + } + else + { + /* Otherwise, we can ignore the return value. */ + flags = SPARC_RET_VOID; + } + } + +#ifdef USING_PURIFY + /* Purify will probably complain in our assembly routine, + unless we zero out this memory. */ + memset(argp, 0, 6*8); +#endif + + if (flags & SPARC_FLAG_RET_IN_MEM) + *argp++ = (unsigned long)rvalue; + + p_arg = cif->arg_types; + for (i = 0, nargs = cif->nargs; i < nargs; i++) + { + ffi_type *ty = p_arg[i]; + void *a = avalue[i]; + size_t z; + + switch (ty->type) + { + case FFI_TYPE_SINT8: + *argp++ = *(SINT8 *)a; + break; + case FFI_TYPE_UINT8: + *argp++ = *(UINT8 *)a; + break; + case FFI_TYPE_SINT16: + *argp++ = *(SINT16 *)a; + break; + case FFI_TYPE_UINT16: + *argp++ = *(UINT16 *)a; + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + *argp++ = *(SINT32 *)a; + break; + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + *argp++ = *(UINT32 *)a; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + case FFI_TYPE_DOUBLE: + *argp++ = *(UINT64 *)a; + break; + + case FFI_TYPE_LONGDOUBLE: + case FFI_TYPE_COMPLEX: + case FFI_TYPE_STRUCT: + z = ty->size; + if (z > 16) + { + /* For structures larger than 16 bytes we pass reference. */ + *argp++ = (unsigned long)a; + break; + } + if (((unsigned long)argp & 15) && ty->alignment > 8) + argp++; + memcpy(argp, a, z); + argp += ALIGN(z, 8) / 8; + break; + + default: + abort(); + } + } + + return flags; +} + +static void +ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + size_t bytes = cif->bytes; + + FFI_ASSERT (cif->abi == FFI_V9); + + if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM)) + bytes += ALIGN (cif->rtype->size, 16); + + ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure); +} + +void +ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + ffi_call_int(cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go(ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int(cif, fn, rvalue, avalue, closure); +} + +#ifdef __GNUC__ +static inline void +ffi_flush_icache (void *p) +{ + asm volatile ("flush %0; flush %0+8" : : "r" (p) : "memory"); +} +#else +extern void ffi_flush_icache (void *) FFI_HIDDEN; +#endif + +extern void ffi_closure_v9(void) FFI_HIDDEN; +extern void ffi_go_closure_v9(void) FFI_HIDDEN; + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + unsigned long fn; + + if (cif->abi != FFI_V9) + return FFI_BAD_ABI; + + /* Trampoline address is equal to the closure address. We take advantage + of that to reduce the trampoline size by 8 bytes. */ + fn = (unsigned long) ffi_closure_v9; + tramp[0] = 0x83414000; /* rd %pc, %g1 */ + tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */ + tramp[2] = 0x81c14000; /* jmp %g5 */ + tramp[3] = 0x01000000; /* nop */ + *((unsigned long *) &tramp[4]) = fn; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + ffi_flush_icache (closure); + + return FFI_OK; +} + +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*)) +{ + if (cif->abi != FFI_V9) + return FFI_BAD_ABI; + + closure->tramp = ffi_go_closure_v9; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + +int FFI_HIDDEN +ffi_closure_sparc_inner_v9(ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, void *rvalue, + unsigned long *gpr, unsigned long *fpr) +{ + ffi_type **arg_types; + void **avalue; + int i, argn, argx, nargs, flags, nfixedargs; + + arg_types = cif->arg_types; + nargs = cif->nargs; + flags = cif->flags; + nfixedargs = cif->nfixedargs; + + avalue = alloca(nargs * sizeof(void *)); + + /* Copy the caller's structure return address so that the closure + returns the data directly to the caller. */ + if (flags & SPARC_FLAG_RET_IN_MEM) + { + rvalue = (void *) gpr[0]; + /* Skip the structure return address. */ + argn = 1; + } + else + argn = 0; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0; i < nargs; i++, argn = argx) + { + int named = i < nfixedargs; + ffi_type *ty = arg_types[i]; + void *a = &gpr[argn]; + size_t z; + + argx = argn + 1; + switch (ty->type) + { + case FFI_TYPE_COMPLEX: + case FFI_TYPE_STRUCT: + z = ty->size; + if (z > 16) + a = *(void **)a; + else + { + argx = argn + ALIGN (z, 8) / 8; + if (named && argn < 16) + { + int size_mask = ffi_struct_float_mask (ty, 0); + int argn_mask = (0xffff00 >> argn) & 0xff00; + + /* Eliminate fp registers off the end. */ + size_mask = (size_mask & 0xff) | (size_mask & argn_mask); + a = ffi_struct_float_merge (size_mask, gpr+argn, fpr+argn); + } + } + break; + + case FFI_TYPE_LONGDOUBLE: + argn = ALIGN (argn, 2); + a = (named && argn < 16 ? fpr : gpr) + argn; + argx = argn + 2; + break; + case FFI_TYPE_DOUBLE: + if (named && argn < 16) + a = fpr + argn; + break; + case FFI_TYPE_FLOAT: + if (named && argn < 16) + a = fpr + argn; + a += 4; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + break; + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + a += 4; + break; + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + a += 6; + break; + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + a += 7; + break; + + default: + abort(); + } + avalue[i] = a; + } + + /* Invoke the closure. */ + fun (cif, rvalue, avalue, user_data); + + /* Tell ffi_closure_sparc how to perform return type promotions. */ + return flags; +} +#endif /* SPARC64 */ diff --git a/libffi/src/sparc/ffitarget.h b/libffi/src/sparc/ffitarget.h index 6489ac0..2f4cd9a 100644 --- a/libffi/src/sparc/ffitarget.h +++ b/libffi/src/sparc/ffitarget.h @@ -46,42 +46,36 @@ typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, - FFI_V8, - FFI_V8PLUS, - /* See below for the COMPAT_V9 rationale. */ - FFI_COMPAT_V9, - FFI_V9, - FFI_LAST_ABI, #ifdef SPARC64 - FFI_DEFAULT_ABI = FFI_V9 + FFI_V9, + FFI_DEFAULT_ABI = FFI_V9, #else - FFI_DEFAULT_ABI = FFI_V8 + FFI_V8, + FFI_DEFAULT_ABI = FFI_V8, #endif + FFI_LAST_ABI } ffi_abi; #endif -#define V8_ABI_P(abi) ((abi) == FFI_V8 || (abi) == FFI_V8PLUS) -#define V9_ABI_P(abi) ((abi) == FFI_COMPAT_V9 || (abi) == FFI_V9) - -#define FFI_TARGET_SPECIFIC_VARIADIC 1 +#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION 1 +#define FFI_TARGET_HAS_COMPLEX_TYPE 1 -/* The support of variadic functions was broken in the original implementation - of the FFI_V9 ABI. This has been fixed by adding one extra field to the - CIF structure (nfixedargs field), which means that the ABI of libffi itself - has changed. In order to support applications using the original ABI, we - have renamed FFI_V9 into FFI_COMPAT_V9 and defined a new FFI_V9 value. */ #ifdef SPARC64 -#define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs +# define FFI_TARGET_SPECIFIC_VARIADIC 1 +# define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + #ifdef SPARC64 #define FFI_TRAMPOLINE_SIZE 24 #else #define FFI_TRAMPOLINE_SIZE 16 #endif -#define FFI_NATIVE_RAW_API 0 #endif + diff --git a/libffi/src/sparc/internal.h b/libffi/src/sparc/internal.h new file mode 100644 index 0000000..0a66472 --- /dev/null +++ b/libffi/src/sparc/internal.h @@ -0,0 +1,26 @@ +#define SPARC_RET_VOID 0 +#define SPARC_RET_STRUCT 1 +#define SPARC_RET_UINT8 2 +#define SPARC_RET_SINT8 3 +#define SPARC_RET_UINT16 4 +#define SPARC_RET_SINT16 5 +#define SPARC_RET_UINT32 6 +#define SP_V9_RET_SINT32 7 /* v9 only */ +#define SP_V8_RET_CPLX16 7 /* v8 only */ +#define SPARC_RET_INT64 8 +#define SPARC_RET_INT128 9 + +/* Note that F_7 is missing, and is handled by SPARC_RET_STRUCT. */ +#define SPARC_RET_F_8 10 +#define SPARC_RET_F_6 11 +#define SPARC_RET_F_4 12 +#define SPARC_RET_F_2 13 +#define SP_V9_RET_F_3 14 /* v9 only */ +#define SP_V8_RET_CPLX8 14 /* v8 only */ +#define SPARC_RET_F_1 15 + +#define SPARC_FLAG_RET_MASK 15 +#define SPARC_FLAG_RET_IN_MEM 32 +#define SPARC_FLAG_FP_ARGS 64 + +#define SPARC_SIZEMASK_SHIFT 8 diff --git a/libffi/src/sparc/v8.S b/libffi/src/sparc/v8.S index 7ec6e1c..3a811ef 100644 --- a/libffi/src/sparc/v8.S +++ b/libffi/src/sparc/v8.S @@ -1,7 +1,8 @@ /* ----------------------------------------------------------------------- - v8.S - Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc. + v8.S - Copyright (c) 2013 The Written Word, Inc. + Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc. - SPARC Foreign Function Interface + SPARC Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -24,153 +25,243 @@ DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ -#define LIBFFI_ASM +#define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> +#include <ffi_cfi.h> +#include "internal.h" #ifndef SPARC64 -#define STACKFRAME 96 /* Minimum stack framesize for SPARC */ -#define ARGS (64+4) /* Offset of register area in frame */ +#define C2(X, Y) X ## Y +#define C1(X, Y) C2(X, Y) -.text - .align 8 -.globl ffi_call_v8 -.globl _ffi_call_v8 - -ffi_call_v8: -_ffi_call_v8: -.LLFB1: - save %sp, -STACKFRAME, %sp -.LLCFI0: - - sub %sp, %i2, %sp ! alloca() space in stack for frame to set up - add %sp, STACKFRAME, %l0 ! %l0 has start of - ! frame to set up - - mov %l0, %o0 ! call routine to set up frame - call %i0 - mov %i1, %o1 ! (delay) - - ld [%l0+ARGS], %o0 ! call foreign function - ld [%l0+ARGS+4], %o1 - ld [%l0+ARGS+8], %o2 - ld [%l0+ARGS+12], %o3 - ld [%l0+ARGS+16], %o4 - ld [%l0+ARGS+20], %o5 - call %i5 - mov %l0, %sp ! (delay) switch to frame - nop ! STRUCT returning functions skip 12 instead of 8 bytes - - ! If the return value pointer is NULL, assume no return value. - tst %i4 - bz done - nop - - cmp %i3, FFI_TYPE_INT - be,a done - st %o0, [%i4] ! (delay) - - cmp %i3, FFI_TYPE_FLOAT - be,a done - st %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_DOUBLE - be,a double - st %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_SINT8 - be,a sint8 - sll %o0, 24, %o0 ! (delay) +#ifdef __USER_LABEL_PREFIX__ +# define C(Y) C1(__USER_LABEL_PREFIX__, Y) +#else +# define C(Y) Y +#endif +#define L(Y) C1(.L, Y) - cmp %i3, FFI_TYPE_UINT8 - be,a uint8 - sll %o0, 24, %o0 ! (delay) + .text - cmp %i3, FFI_TYPE_SINT16 - be,a sint16 - sll %o0, 16, %o0 ! (delay) +#ifndef __GNUC__ + .align 8 + .globl C(ffi_flush_icache) + .type C(ffi_flush_icache),@function + FFI_HIDDEN(C(ffi_flush_icache)) + +C(ffi_flush_icache): + cfi_startproc +1: iflush %o0 + iflush %o+8 + nop + nop + nop + nop + nop + retl + nop + cfi_endproc + .size C(ffi_flush_icache), . - C(ffi_flush_icache) +#endif - cmp %i3, FFI_TYPE_UINT16 - be,a uint16 - sll %o0, 16, %o0 ! (delay) +.macro E index + .align 16 + .org 2b + \index * 16 +.endm - cmp %i3, FFI_TYPE_SINT64 - be,a longlong - st %o0, [%i4+0] ! (delay) -done: + .align 8 + .globl C(ffi_call_v8) + .type C(ffi_call_v8),@function + FFI_HIDDEN(C(ffi_call_v8)) + +C(ffi_call_v8): + cfi_startproc + ! Allocate a stack frame sized by ffi_call. + save %sp, %o4, %sp + cfi_def_cfa_register(%fp) + cfi_window_save + + mov %i0, %o0 ! copy cif + add %sp, 64+32, %o1 ! load args area + mov %i2, %o2 ! copy rvalue + call C(ffi_prep_args_v8) + mov %i3, %o3 ! copy avalue + + add %sp, 32, %sp ! deallocate prep frame + and %o0, SPARC_FLAG_RET_MASK, %l0 ! save return type + srl %o0, SPARC_SIZEMASK_SHIFT, %l1 ! save return size + ld [%sp+64+4], %o0 ! load all argument registers + ld [%sp+64+8], %o1 + ld [%sp+64+12], %o2 + ld [%sp+64+16], %o3 + cmp %l0, SPARC_RET_STRUCT ! struct return needs an unimp 4 + ld [%sp+64+20], %o4 + be 8f + ld [%sp+64+24], %o5 + + ! Call foreign function + call %i1 + mov %i5, %g2 ! load static chain + +0: call 1f ! load pc in %o7 + sll %l0, 4, %l0 +1: add %o7, %l0, %o7 ! o7 = 0b + ret_type*16 + jmp %o7+(2f-0b) + nop + + ! Note that each entry is 4 insns, enforced by the E macro. + .align 16 +2: +E SPARC_RET_VOID ret - restore - -double: - st %f1, [%i4+4] + restore +E SPARC_RET_STRUCT + unimp +E SPARC_RET_UINT8 + and %o0, 0xff, %o0 + st %o0, [%i2] ret - restore - -sint8: - sra %o0, 24, %o0 - st %o0, [%i4+0] + restore +E SPARC_RET_SINT8 + sll %o0, 24, %o0 + b 7f + sra %o0, 24, %o0 +E SPARC_RET_UINT16 + sll %o0, 16, %o0 + b 7f + srl %o0, 16, %o0 +E SPARC_RET_SINT16 + sll %o0, 16, %o0 + b 7f + sra %o0, 16, %o0 +E SPARC_RET_UINT32 +7: st %o0, [%i2] ret - restore - -uint8: - srl %o0, 24, %o0 - st %o0, [%i4+0] + restore +E SP_V8_RET_CPLX16 + sth %o0, [%i2+2] + b 9f + srl %o0, 16, %o0 +E SPARC_RET_INT64 + st %o0, [%i2] + st %o1, [%i2+4] ret - restore - -sint16: - sra %o0, 16, %o0 - st %o0, [%i4+0] + restore +E SPARC_RET_INT128 + std %o0, [%i2] + std %o2, [%i2+8] ret - restore + restore +E SPARC_RET_F_8 + st %f7, [%i2+7*4] + nop + st %f6, [%i2+6*4] + nop +E SPARC_RET_F_6 + st %f5, [%i2+5*4] + nop + st %f4, [%i2+4*4] + nop +E SPARC_RET_F_4 + st %f3, [%i2+3*4] + nop + st %f2, [%i2+2*4] + nop +E SPARC_RET_F_2 + st %f1, [%i2+4] + st %f0, [%i2] + ret + restore +E SP_V8_RET_CPLX8 + stb %o0, [%i2+1] + b 10f + srl %o0, 8, %o0 +E SPARC_RET_F_1 + st %f0, [%i2] + ret + restore -uint16: - srl %o0, 16, %o0 - st %o0, [%i4+0] + .align 8 +9: sth %o0, [%i2] + ret + restore + .align 8 +10: stb %o0, [%i2] ret - restore + restore -longlong: - st %o1, [%i4+4] + ! Struct returning functions expect and skip the unimp here. + ! To make it worse, conforming callees examine the unimp and + ! make sure the low 12 bits of the unimp match the size of + ! the struct being returned. + .align 8 +8: call 1f ! load pc in %o7 + sll %l1, 2, %l0 ! size * 4 +1: sll %l1, 4, %l1 ! size * 16 + add %l0, %l1, %l0 ! size * 20 + add %o7, %l0, %o7 ! o7 = 0b + size*20 + jmp %o7+(2f-8b) + mov %i5, %g2 ! load static chain +2: +.rept 0x1000 + call %i1 + nop + unimp (. - 2b) / 20 ret - restore -.LLFE1: + restore +.endr -.ffi_call_v8_end: - .size ffi_call_v8,.ffi_call_v8_end-ffi_call_v8 + cfi_endproc + .size C(ffi_call_v8),. - C(ffi_call_v8) -#undef STACKFRAME -#define STACKFRAME 104 /* 16*4 register window + - 1*4 struct return + - 6*4 args backing store + - 3*4 locals */ +/* 16*4 register window + 1*4 struct return + 6*4 args backing store + + 8*4 return storage + 1*4 alignment. */ +#define STACKFRAME (16*4 + 4 + 6*4 + 8*4 + 4) /* ffi_closure_v8(...) Receives the closure argument in %g2. */ - .text - .align 8 - .globl ffi_closure_v8 - -ffi_closure_v8: #ifdef HAVE_AS_REGISTER_PSEUDO_OP - .register %g2, #scratch + .register %g2, #scratch #endif -.LLFB2: - ! Reserve frame space for all arguments in case - ! we need to align them on a 8-byte boundary. - ld [%g2+FFI_TRAMPOLINE_SIZE], %g1 - ld [%g1+4], %g1 - sll %g1, 3, %g1 - add %g1, STACKFRAME, %g1 - ! %g1 == STACKFRAME + 8*nargs - neg %g1 - save %sp, %g1, %sp -.LLCFI1: + .align 8 + .globl C(ffi_go_closure_v8) + .type C(ffi_go_closure_v8),@function + FFI_HIDDEN(C(ffi_go_closure_v8)) + +C(ffi_go_closure_v8): + cfi_startproc + save %sp, -STACKFRAME, %sp + cfi_def_cfa_register(%fp) + cfi_window_save + + ld [%g2+4], %o0 ! load cif + ld [%g2+8], %o1 ! load fun + b 0f + mov %g2, %o2 ! load user_data + cfi_endproc + .size C(ffi_go_closure_v8), . - C(ffi_go_closure_v8) + + .align 8 + .globl C(ffi_closure_v8) + .type C(ffi_closure_v8),@function + FFI_HIDDEN(C(ffi_closure_v8)) + +C(ffi_closure_v8): + cfi_startproc + save %sp, -STACKFRAME, %sp + cfi_def_cfa_register(%fp) + cfi_window_save + + ld [%g2+FFI_TRAMPOLINE_SIZE], %o0 ! load cif + ld [%g2+FFI_TRAMPOLINE_SIZE+4], %o1 ! load fun + ld [%g2+FFI_TRAMPOLINE_SIZE+8], %o2 ! load user_data +0: ! Store all of the potential argument registers in va_list format. st %i0, [%fp+68+0] st %i1, [%fp+68+4] @@ -180,137 +271,91 @@ ffi_closure_v8: st %i5, [%fp+68+20] ! Call ffi_closure_sparc_inner to do the bulk of the work. - mov %g2, %o0 - add %fp, -8, %o1 - add %fp, 64, %o2 + add %fp, -8*4, %o3 call ffi_closure_sparc_inner_v8 - add %fp, -16, %o3 - - ! Load up the return value in the proper type. - ! See ffi_prep_cif_machdep for the list of cases. - cmp %o0, FFI_TYPE_VOID - be done1 - - cmp %o0, FFI_TYPE_INT - be done1 - ld [%fp-8], %i0 - - cmp %o0, FFI_TYPE_FLOAT - be,a done1 - ld [%fp-8], %f0 - - cmp %o0, FFI_TYPE_DOUBLE - be,a done1 - ldd [%fp-8], %f0 - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - cmp %o0, FFI_TYPE_LONGDOUBLE - be done2 -#endif - - cmp %o0, FFI_TYPE_STRUCT - be done2 - - cmp %o0, FFI_TYPE_SINT64 - be,a done1 - ldd [%fp-8], %i0 - - ld [%fp-8], %i0 -done1: - jmp %i7+8 + add %fp, 64, %o4 + +0: call 1f + and %o0, SPARC_FLAG_RET_MASK, %o0 +1: sll %o0, 4, %o0 ! o0 = o0 * 16 + add %o7, %o0, %o7 ! o7 = 0b + o0*16 + jmp %o7+(2f-0b) + add %fp, -8*4, %i2 + + ! Note that each entry is 4 insns, enforced by the E macro. + .align 16 +2: +E SPARC_RET_VOID + ret restore -done2: - ! Skip 'unimp'. +E SPARC_RET_STRUCT + ld [%i2], %i0 jmp %i7+12 restore -.LLFE2: - -.ffi_closure_v8_end: - .size ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8 - -#ifdef SPARC64 -#define WS 8 -#define nword xword -#define uanword uaxword -#else -#define WS 4 -#define nword long -#define uanword uaword -#endif - -#ifdef HAVE_RO_EH_FRAME - .section ".eh_frame",#alloc -#else - .section ".eh_frame",#alloc,#write -#endif -.LLframe1: - .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry -.LLSCIE1: - .uaword 0x0 ! CIE Identifier Tag - .byte 0x1 ! CIE Version - .ascii "zR\0" ! CIE Augmentation - .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor - .byte 0x80-WS ! sleb128 -WS; CIE Data Alignment Factor - .byte 0xf ! CIE RA Column - .byte 0x1 ! uleb128 0x1; Augmentation size -#ifdef HAVE_AS_SPARC_UA_PCREL - .byte 0x1b ! FDE Encoding (pcrel sdata4) -#else - .byte 0x50 ! FDE Encoding (aligned absolute) -#endif - .byte 0xc ! DW_CFA_def_cfa - .byte 0xe ! uleb128 0xe - .byte 0x0 ! uleb128 0x0 - .align WS -.LLECIE1: -.LLSFDE1: - .uaword .LLEFDE1-.LLASFDE1 ! FDE Length -.LLASFDE1: - .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset -#ifdef HAVE_AS_SPARC_UA_PCREL - .uaword %r_disp32(.LLFB1) - .uaword .LLFE1-.LLFB1 ! FDE address range -#else - .align WS - .nword .LLFB1 - .uanword .LLFE1-.LLFB1 ! FDE address range -#endif - .byte 0x0 ! uleb128 0x0; Augmentation size - .byte 0x4 ! DW_CFA_advance_loc4 - .uaword .LLCFI0-.LLFB1 - .byte 0xd ! DW_CFA_def_cfa_register - .byte 0x1e ! uleb128 0x1e - .byte 0x2d ! DW_CFA_GNU_window_save - .byte 0x9 ! DW_CFA_register - .byte 0xf ! uleb128 0xf - .byte 0x1f ! uleb128 0x1f - .align WS -.LLEFDE1: -.LLSFDE2: - .uaword .LLEFDE2-.LLASFDE2 ! FDE Length -.LLASFDE2: - .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset -#ifdef HAVE_AS_SPARC_UA_PCREL - .uaword %r_disp32(.LLFB2) - .uaword .LLFE2-.LLFB2 ! FDE address range -#else - .align WS - .nword .LLFB2 - .uanword .LLFE2-.LLFB2 ! FDE address range -#endif - .byte 0x0 ! uleb128 0x0; Augmentation size - .byte 0x4 ! DW_CFA_advance_loc4 - .uaword .LLCFI1-.LLFB2 - .byte 0xd ! DW_CFA_def_cfa_register - .byte 0x1e ! uleb128 0x1e - .byte 0x2d ! DW_CFA_GNU_window_save - .byte 0x9 ! DW_CFA_register - .byte 0xf ! uleb128 0xf - .byte 0x1f ! uleb128 0x1f - .align WS -.LLEFDE2: -#endif +E SPARC_RET_UINT8 + ldub [%i2+3], %i0 + ret + restore +E SPARC_RET_SINT8 + ldsb [%i2+3], %i0 + ret + restore +E SPARC_RET_UINT16 + lduh [%i2+2], %i0 + ret + restore +E SPARC_RET_SINT16 + ldsh [%i2+2], %i0 + ret + restore +E SPARC_RET_UINT32 + ld [%i2], %i0 + ret + restore +E SP_V8_RET_CPLX16 + ld [%i2], %i0 + ret + restore +E SPARC_RET_INT64 + ldd [%i2], %i0 + ret + restore +E SPARC_RET_INT128 + ldd [%i2], %i0 + ldd [%i2+8], %i2 + ret + restore +E SPARC_RET_F_8 + ld [%i2+7*4], %f7 + nop + ld [%i2+6*4], %f6 + nop +E SPARC_RET_F_6 + ld [%i2+5*4], %f5 + nop + ld [%i2+4*4], %f4 + nop +E SPARC_RET_F_4 + ld [%i2+3*4], %f3 + nop + ld [%i2+2*4], %f2 + nop +E SPARC_RET_F_2 + ldd [%i2], %f0 + ret + restore +E SP_V8_RET_CPLX8 + lduh [%i2], %i0 + ret + restore +E SPARC_RET_F_1 + ld [%i2], %f0 + ret + restore + cfi_endproc + .size C(ffi_closure_v8), . - C(ffi_closure_v8) +#endif /* !SPARC64 */ #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif diff --git a/libffi/src/sparc/v9.S b/libffi/src/sparc/v9.S index 2c97673..52732d3 100644 --- a/libffi/src/sparc/v9.S +++ b/libffi/src/sparc/v9.S @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- v9.S - Copyright (c) 2000, 2003, 2004, 2008 Red Hat, Inc. - + SPARC 64-bit Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining @@ -27,103 +27,178 @@ #define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> +#include <ffi_cfi.h> +#include "internal.h" #ifdef SPARC64 -#define STACKFRAME 176 /* Minimum stack framesize for SPARC 64-bit */ +#define C2(X, Y) X ## Y +#define C1(X, Y) C2(X, Y) + +#ifdef __USER_LABEL_PREFIX__ +# define C(Y) C1(__USER_LABEL_PREFIX__, Y) +#else +# define C(Y) Y +#endif +#define L(Y) C1(.L, Y) + +.macro E index + .align 16 + .org 2b + \index * 16 +.endm + #define STACK_BIAS 2047 -#define ARGS (128) /* Offset of register area in frame */ -.text + .text .align 8 -.globl ffi_call_v9 -.globl _ffi_call_v9 - -ffi_call_v9: -_ffi_call_v9: -.LLFB1: - save %sp, -STACKFRAME, %sp -.LLCFI0: + .globl C(ffi_call_v9) + .type C(ffi_call_v9),@function + FFI_HIDDEN(C(ffi_call_v9)) + +C(ffi_call_v9): + cfi_startproc + save %sp, %o4, %sp + cfi_def_cfa_register(%fp) + cfi_window_save - sub %sp, %i2, %sp ! alloca() space in stack for frame to set up - add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of - ! frame to set up - - mov %l0, %o0 ! call routine to set up frame - call %i0 - mov %i1, %o1 ! (delay) - brz,pt %o0, 1f - ldx [%l0+ARGS], %o0 ! call foreign function - - ldd [%l0+ARGS], %f0 - ldd [%l0+ARGS+8], %f2 - ldd [%l0+ARGS+16], %f4 - ldd [%l0+ARGS+24], %f6 - ldd [%l0+ARGS+32], %f8 - ldd [%l0+ARGS+40], %f10 - ldd [%l0+ARGS+48], %f12 - ldd [%l0+ARGS+56], %f14 - ldd [%l0+ARGS+64], %f16 - ldd [%l0+ARGS+72], %f18 - ldd [%l0+ARGS+80], %f20 - ldd [%l0+ARGS+88], %f22 - ldd [%l0+ARGS+96], %f24 - ldd [%l0+ARGS+104], %f26 - ldd [%l0+ARGS+112], %f28 - ldd [%l0+ARGS+120], %f30 - -1: ldx [%l0+ARGS+8], %o1 - ldx [%l0+ARGS+16], %o2 - ldx [%l0+ARGS+24], %o3 - ldx [%l0+ARGS+32], %o4 - ldx [%l0+ARGS+40], %o5 - call %i5 - sub %l0, STACK_BIAS, %sp ! (delay) switch to frame - - ! If the return value pointer is NULL, assume no return value. - brz,pn %i4, done + mov %i0, %o0 ! copy cif + add %sp, STACK_BIAS+128+48, %o1 ! load args area + mov %i2, %o2 ! copy rvalue + call C(ffi_prep_args_v9) + mov %i3, %o3 ! copy avalue + + andcc %o0, SPARC_FLAG_FP_ARGS, %g0 ! need fp regs? + add %sp, 48, %sp ! deallocate prep frame + be,pt %xcc, 1f + mov %o0, %l0 ! save flags + + ldd [%sp+STACK_BIAS+128], %f0 ! load all fp arg regs + ldd [%sp+STACK_BIAS+128+8], %f2 + ldd [%sp+STACK_BIAS+128+16], %f4 + ldd [%sp+STACK_BIAS+128+24], %f6 + ldd [%sp+STACK_BIAS+128+32], %f8 + ldd [%sp+STACK_BIAS+128+40], %f10 + ldd [%sp+STACK_BIAS+128+48], %f12 + ldd [%sp+STACK_BIAS+128+56], %f14 + ldd [%sp+STACK_BIAS+128+64], %f16 + ldd [%sp+STACK_BIAS+128+72], %f18 + ldd [%sp+STACK_BIAS+128+80], %f20 + ldd [%sp+STACK_BIAS+128+88], %f22 + ldd [%sp+STACK_BIAS+128+96], %f24 + ldd [%sp+STACK_BIAS+128+104], %f26 + ldd [%sp+STACK_BIAS+128+112], %f28 + ldd [%sp+STACK_BIAS+128+120], %f30 + +1: ldx [%sp+STACK_BIAS+128], %o0 ! load all int arg regs + ldx [%sp+STACK_BIAS+128+8], %o1 + ldx [%sp+STACK_BIAS+128+16], %o2 + ldx [%sp+STACK_BIAS+128+24], %o3 + ldx [%sp+STACK_BIAS+128+32], %o4 + ldx [%sp+STACK_BIAS+128+40], %o5 + call %i1 + mov %i5, %g5 ! load static chain + +0: call 1f ! load pc in %o7 + and %l0, SPARC_FLAG_RET_MASK, %l1 +1: sll %l1, 4, %l1 + add %o7, %l1, %o7 ! o7 = 0b + ret_type*16 + jmp %o7+(2f-0b) nop - cmp %i3, FFI_TYPE_INT - be,a,pt %icc, done - stx %o0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_FLOAT - be,a,pn %icc, done - st %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_DOUBLE - be,a,pn %icc, done - std %f0, [%i4+0] ! (delay) - - cmp %i3, FFI_TYPE_STRUCT - be,pn %icc, dostruct - - cmp %i3, FFI_TYPE_LONGDOUBLE - bne,pt %icc, done + .align 16 +2: +E SPARC_RET_VOID + return %i7+8 + nop +E SPARC_RET_STRUCT + add %sp, STACK_BIAS-64+128+48, %l2 + sub %sp, 64, %sp + b 8f + stx %o0, [%l2] +E SPARC_RET_UINT8 + and %o0, 0xff, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_SINT8 + sll %o0, 24, %o0 + sra %o0, 24, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_UINT16 + sll %o0, 16, %o0 + srl %o0, 16, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_SINT16 + sll %o0, 16, %o0 + sra %o0, 16, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_UINT32 + srl %o0, 0, %i0 + return %i7+8 + stx %o0, [%o2] +E SP_V9_RET_SINT32 + sra %o0, 0, %i0 + return %i7+8 + stx %o0, [%o2] +E SPARC_RET_INT64 + stx %o0, [%i2] + return %i7+8 + nop +E SPARC_RET_INT128 + stx %o0, [%i2] + stx %o1, [%i2+8] + return %i7+8 + nop +E SPARC_RET_F_8 + st %f7, [%i2+7*4] + nop + st %f6, [%i2+6*4] + nop +E SPARC_RET_F_6 + st %f5, [%i2+5*4] + nop + st %f4, [%i2+4*4] + nop +E SPARC_RET_F_4 + std %f2, [%i2+2*4] + return %i7+8 + std %f0, [%o2] +E SPARC_RET_F_2 + return %i7+8 + std %f0, [%o2] +E SP_V9_RET_F_3 + st %f2, [%i2+2*4] + nop + st %f1, [%i2+1*4] + nop +E SPARC_RET_F_1 + return %i7+8 + st %f0, [%o2] + + ! Finish the SPARC_RET_STRUCT sequence. + .align 8 +8: stx %o1, [%l2+8] + stx %o2, [%l2+16] + stx %o3, [%l2+24] + std %f0, [%l2+32] + std %f2, [%l2+40] + std %f4, [%l2+48] + std %f6, [%l2+56] + + ! Copy the structure into place. + srl %l0, SPARC_SIZEMASK_SHIFT, %o0 ! load size_mask + mov %i2, %o1 ! load dst + mov %l2, %o2 ! load src_gp + call C(ffi_struct_float_copy) + add %l2, 32, %o3 ! load src_fp + + return %i7+8 nop - std %f0, [%i4+0] - std %f2, [%i4+8] - -done: ret - restore - -dostruct: - /* This will not work correctly for unions. */ - stx %o0, [%i4+0] - stx %o1, [%i4+8] - stx %o2, [%i4+16] - stx %o3, [%i4+24] - std %f0, [%i4+32] - std %f2, [%i4+40] - std %f4, [%i4+48] - std %f6, [%i4+56] - ret - restore -.LLFE1: - -.ffi_call_v9_end: - .size ffi_call_v9,.ffi_call_v9_end-ffi_call_v9 + + cfi_endproc + .size C(ffi_call_v9), . - C(ffi_call_v9) #undef STACKFRAME @@ -136,15 +211,40 @@ dostruct: Receives the closure argument in %g1. */ - .text .align 8 - .globl ffi_closure_v9 + .globl C(ffi_go_closure_v9) + .type C(ffi_go_closure_v9),@function + FFI_HIDDEN(C(ffi_go_closure_v9)) -ffi_closure_v9: -.LLFB2: +C(ffi_go_closure_v9): + cfi_startproc save %sp, -STACKFRAME, %sp -.LLCFI1: + cfi_def_cfa_register(%fp) + cfi_window_save + ldx [%g5+8], %o0 + ldx [%g5+16], %o1 + b 0f + mov %g5, %o2 + + cfi_endproc + .size C(ffi_go_closure_v9), . - C(ffi_go_closure_v9) + + .align 8 + .globl C(ffi_closure_v9) + .type C(ffi_closure_v9),@function + FFI_HIDDEN(C(ffi_closure_v9)) + +C(ffi_closure_v9): + cfi_startproc + save %sp, -STACKFRAME, %sp + cfi_def_cfa_register(%fp) + cfi_window_save + + ldx [%g1+FFI_TRAMPOLINE_SIZE], %o0 + ldx [%g1+FFI_TRAMPOLINE_SIZE+8], %o1 + ldx [%g1+FFI_TRAMPOLINE_SIZE+16], %o2 +0: ! Store all of the potential argument registers in va_list format. stx %i0, [FP+128+0] stx %i1, [FP+128+8] @@ -172,134 +272,106 @@ ffi_closure_v9: std %f30, [FP-8] ! Call ffi_closure_sparc_inner to do the bulk of the work. - mov %g1, %o0 - add %fp, STACK_BIAS-160, %o1 - add %fp, STACK_BIAS+128, %o2 - call ffi_closure_sparc_inner_v9 - add %fp, STACK_BIAS-128, %o3 - - ! Load up the return value in the proper type. - ! See ffi_prep_cif_machdep for the list of cases. - cmp %o0, FFI_TYPE_VOID - be,pn %icc, done1 - - cmp %o0, FFI_TYPE_INT - be,pn %icc, integer - - cmp %o0, FFI_TYPE_FLOAT - be,a,pn %icc, done1 - ld [FP-160], %f0 - - cmp %o0, FFI_TYPE_DOUBLE - be,a,pn %icc, done1 - ldd [FP-160], %f0 - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - cmp %o0, FFI_TYPE_LONGDOUBLE - be,a,pn %icc, longdouble1 - ldd [FP-160], %f0 -#endif + add %fp, STACK_BIAS-160, %o3 + add %fp, STACK_BIAS+128, %o4 + call C(ffi_closure_sparc_inner_v9) + add %fp, STACK_BIAS-128, %o5 + +0: call 1f ! load pc in %o7 + and %o0, SPARC_FLAG_RET_MASK, %o0 +1: sll %o0, 4, %o0 ! o2 = i2 * 16 + add %o7, %o0, %o7 ! o7 = 0b + i2*16 + jmp %o7+(2f-0b) + nop - ! FFI_TYPE_STRUCT - ldx [FP-152], %i1 - ldx [FP-144], %i2 - ldx [FP-136], %i3 + ! Note that we cannot load the data in the delay slot of + ! the return insn because the data is in the stack frame + ! that is deallocated by the return. + .align 16 +2: +E SPARC_RET_VOID + return %i7+8 + nop +E SPARC_RET_STRUCT + ldx [FP-160], %i0 ldd [FP-160], %f0 - ldd [FP-152], %f2 - ldd [FP-144], %f4 - ldd [FP-136], %f6 - -integer: + b 8f + ldx [FP-152], %i1 +E SPARC_RET_UINT8 + ldub [FP-160+7], %i0 + return %i7+8 + nop +E SPARC_RET_SINT8 + ldsb [FP-160+7], %i0 + return %i7+8 + nop +E SPARC_RET_UINT16 + lduh [FP-160+6], %i0 + return %i7+8 + nop +E SPARC_RET_SINT16 + ldsh [FP-160+6], %i0 + return %i7+8 + nop +E SPARC_RET_UINT32 + lduw [FP-160+4], %i0 + return %i7+8 + nop +E SP_V9_RET_SINT32 + ldsw [FP-160+4], %i0 + return %i7+8 + nop +E SPARC_RET_INT64 ldx [FP-160], %i0 + return %i7+8 + nop +E SPARC_RET_INT128 + ldx [FP-160], %i0 + ldx [FP-160+8], %i1 + return %i7+8 + nop +E SPARC_RET_F_8 + ld [FP-160+7*4], %f7 + nop + ld [FP-160+6*4], %f6 + nop +E SPARC_RET_F_6 + ld [FP-160+5*4], %f5 + nop + ld [FP-160+4*4], %f4 + nop +E SPARC_RET_F_4 + ldd [FP-160], %f0 + ldd [FP-160+8], %f2 + return %i7+8 + nop +E SPARC_RET_F_2 + ldd [FP-160], %f0 + return %i7+8 + nop +E SP_V9_RET_F_3 + ld [FP-160+2*4], %f2 + nop + ld [FP-160+1*4], %f1 + nop +E SPARC_RET_F_1 + ld [FP-160], %f0 + return %i7+8 + nop -done1: - ret - restore - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE -longdouble1: - ldd [FP-152], %f2 - ret - restore -#endif -.LLFE2: - -.ffi_closure_v9_end: - .size ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9 - -#ifdef HAVE_RO_EH_FRAME - .section ".eh_frame",#alloc -#else - .section ".eh_frame",#alloc,#write -#endif -.LLframe1: - .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry -.LLSCIE1: - .uaword 0x0 ! CIE Identifier Tag - .byte 0x1 ! CIE Version - .ascii "zR\0" ! CIE Augmentation - .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor - .byte 0x78 ! sleb128 -8; CIE Data Alignment Factor - .byte 0xf ! CIE RA Column - .byte 0x1 ! uleb128 0x1; Augmentation size -#ifdef HAVE_AS_SPARC_UA_PCREL - .byte 0x1b ! FDE Encoding (pcrel sdata4) -#else - .byte 0x50 ! FDE Encoding (aligned absolute) -#endif - .byte 0xc ! DW_CFA_def_cfa - .byte 0xe ! uleb128 0xe - .byte 0xff,0xf ! uleb128 0x7ff - .align 8 -.LLECIE1: -.LLSFDE1: - .uaword .LLEFDE1-.LLASFDE1 ! FDE Length -.LLASFDE1: - .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset -#ifdef HAVE_AS_SPARC_UA_PCREL - .uaword %r_disp32(.LLFB1) - .uaword .LLFE1-.LLFB1 ! FDE address range -#else - .align 8 - .xword .LLFB1 - .uaxword .LLFE1-.LLFB1 ! FDE address range -#endif - .byte 0x0 ! uleb128 0x0; Augmentation size - .byte 0x4 ! DW_CFA_advance_loc4 - .uaword .LLCFI0-.LLFB1 - .byte 0xd ! DW_CFA_def_cfa_register - .byte 0x1e ! uleb128 0x1e - .byte 0x2d ! DW_CFA_GNU_window_save - .byte 0x9 ! DW_CFA_register - .byte 0xf ! uleb128 0xf - .byte 0x1f ! uleb128 0x1f - .align 8 -.LLEFDE1: -.LLSFDE2: - .uaword .LLEFDE2-.LLASFDE2 ! FDE Length -.LLASFDE2: - .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset -#ifdef HAVE_AS_SPARC_UA_PCREL - .uaword %r_disp32(.LLFB2) - .uaword .LLFE2-.LLFB2 ! FDE address range -#else - .align 8 - .xword .LLFB2 - .uaxword .LLFE2-.LLFB2 ! FDE address range -#endif - .byte 0x0 ! uleb128 0x0; Augmentation size - .byte 0x4 ! DW_CFA_advance_loc4 - .uaword .LLCFI1-.LLFB2 - .byte 0xd ! DW_CFA_def_cfa_register - .byte 0x1e ! uleb128 0x1e - .byte 0x2d ! DW_CFA_GNU_window_save - .byte 0x9 ! DW_CFA_register - .byte 0xf ! uleb128 0xf - .byte 0x1f ! uleb128 0x1f - .align 8 -.LLEFDE2: -#endif + ! Finish the SPARC_RET_STRUCT sequence. + .align 8 +8: ldd [FP-152], %f2 + ldx [FP-144], %i2 + ldd [FP-144], %f4 + ldx [FP-136], %i3 + ldd [FP-136], %f6 + return %i7+8 + nop + cfi_endproc + .size C(ffi_closure_v9), . - C(ffi_closure_v9) +#endif /* SPARC64 */ #ifdef __linux__ .section .note.GNU-stack,"",@progbits #endif diff --git a/libffi/src/tile/tile.S b/libffi/src/tile/tile.S index a186e1f..d1f82cb 100644 --- a/libffi/src/tile/tile.S +++ b/libffi/src/tile/tile.S @@ -60,7 +60,7 @@ void (*fnaddr)(void)); On entry, REG_ARGS contain the outgoing register values, - and STACK_ARGS containts STACK_ARG_BYTES of additional values + and STACK_ARGS contains STACK_ARG_BYTES of additional values to be passed on the stack. If STACK_ARG_BYTES is zero, then STACK_ARGS is ignored. diff --git a/libffi/src/types.c b/libffi/src/types.c index 0de5994..7e80aec 100644 --- a/libffi/src/types.c +++ b/libffi/src/types.c @@ -33,26 +33,30 @@ /* Type definitions */ -#define FFI_TYPEDEF(name, type, id) \ +#define FFI_TYPEDEF(name, type, id, maybe_const)\ struct struct_align_##name { \ char c; \ type x; \ }; \ -const ffi_type ffi_type_##name = { \ +maybe_const ffi_type ffi_type_##name = { \ sizeof(type), \ offsetof(struct struct_align_##name, x), \ id, NULL \ } -#define FFI_NONCONST_TYPEDEF(name, type, id) \ -struct struct_align_##name { \ - char c; \ - type x; \ -}; \ -ffi_type ffi_type_##name = { \ - sizeof(type), \ - offsetof(struct struct_align_##name, x), \ - id, NULL \ +#define FFI_COMPLEX_TYPEDEF(name, type, maybe_const) \ +static ffi_type *ffi_elements_complex_##name [2] = { \ + (ffi_type *)(&ffi_type_##name), NULL \ +}; \ +struct struct_align_complex_##name { \ + char c; \ + _Complex type x; \ +}; \ +maybe_const ffi_type ffi_type_complex_##name = { \ + sizeof(_Complex type), \ + offsetof(struct struct_align_complex_##name, x), \ + FFI_TYPE_COMPLEX, \ + (ffi_type **)ffi_elements_complex_##name \ } /* Size and alignment are fake here. They must not be 0. */ @@ -60,19 +64,25 @@ const ffi_type ffi_type_void = { 1, 1, FFI_TYPE_VOID, NULL }; -FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8); -FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8); -FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16); -FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16); -FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32); -FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32); -FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64); -FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64); +FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8, const); +FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8, const); +FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16, const); +FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16, const); +FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32, const); +FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32, const); +FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64, const); +FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64, const); -FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER); +FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER, const); -FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT); -FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE); +FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT, const); +FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE, const); + +#if !defined HAVE_LONG_DOUBLE_VARIANT || defined __alpha__ +#define FFI_LDBL_CONST const +#else +#define FFI_LDBL_CONST +#endif #ifdef __alpha__ /* Even if we're not configured to default to 128-bit long double, @@ -84,9 +94,13 @@ FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE); # endif const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL }; #elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE -# if HAVE_LONG_DOUBLE_VARIANT -FFI_NONCONST_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE); -# else -FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE); -# endif +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/vax/elfbsd.S b/libffi/src/vax/elfbsd.S new file mode 100644 index 0000000..01ca313 --- /dev/null +++ b/libffi/src/vax/elfbsd.S @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2013 Miodrag Vallat. <miod@openbsd.org> + * + * 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. + */ + +/* + * vax Foreign Function Interface + */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .text + +/* + * void * %r0 + * ffi_call_elfbsd(extended_cif *ecif, 4(%ap) + * unsigned bytes, 8(%ap) + * unsigned flags, 12(%ap) + * void *rvalue, 16(%ap) + * void (*fn)()); 20(%ap) + */ + .globl ffi_call_elfbsd + .type ffi_call_elfbsd,@function + .align 2 +ffi_call_elfbsd: + .word 0x00c # save R2 and R3 + + # Allocate stack space for the args + subl2 8(%ap), %sp + + # Call ffi_prep_args + pushl %sp + pushl 4(%ap) + calls $2, ffi_prep_args + + # Get function pointer + movl 20(%ap), %r1 + + # Build a CALLS frame + ashl $-2, 8(%ap), %r0 + pushl %r0 # argument stack usage + movl %sp, %r0 # future %ap + # saved registers + bbc $11, 0(%r1), 1f + pushl %r11 +1: bbc $10, 0(%r1), 1f + pushl %r10 +1: bbc $9, 0(%r1), 1f + pushl %r9 +1: bbc $8, 0(%r1), 1f + pushl %r8 +1: bbc $7, 0(%r1), 1f + pushl %r7 +1: bbc $6, 0(%r1), 1f + pushl %r6 +1: bbc $5, 0(%r1), 1f + pushl %r5 +1: bbc $4, 0(%r1), 1f + pushl %r4 +1: bbc $3, 0(%r1), 1f + pushl %r3 +1: bbc $2, 0(%r1), 1f + pushl %r2 +1: + pushal 9f + pushl %fp + pushl %ap + movl 16(%ap), %r3 # struct return address, if needed + movl %r0, %ap + movzwl 4(%fp), %r0 # previous PSW, without the saved registers mask + bisl2 $0x20000000, %r0 # calls frame + movzwl 0(%r1), %r2 + bicw2 $0xf003, %r2 # only keep R11-R2 + ashl $16, %r2, %r2 + bisl2 %r2, %r0 # saved register mask of the called function + pushl %r0 + pushl $0 + movl %sp, %fp + + # Invoke the function + pushal 2(%r1) # skip procedure entry mask + movl %r3, %r1 + bicpsw $0x000f + rsb + +9: + # Copy return value if necessary + tstl 16(%ap) + jeql 9f + movl 16(%ap), %r2 + + bbc $0, 12(%ap), 1f # CIF_FLAGS_CHAR + movb %r0, 0(%r2) + brb 9f +1: + bbc $1, 12(%ap), 1f # CIF_FLAGS_SHORT + movw %r0, 0(%r2) + brb 9f +1: + bbc $2, 12(%ap), 1f # CIF_FLAGS_INT + movl %r0, 0(%r2) + brb 9f +1: + bbc $3, 12(%ap), 1f # CIF_FLAGS_DINT + movq %r0, 0(%r2) + brb 9f +1: + movl %r1, %r0 # might have been a struct + #brb 9f + +9: + ret + +/* + * ffi_closure_elfbsd(void); + * invoked with %r0: ffi_closure *closure + */ + .globl ffi_closure_elfbsd + .type ffi_closure_elfbsd, @function + .align 2 +ffi_closure_elfbsd: + .word 0 + + # Allocate room on stack for return value + subl2 $8, %sp + + # Invoke the closure function + pushal 4(%ap) # calling stack + pushal 4(%sp) # return value + pushl %r0 # closure + calls $3, ffi_closure_elfbsd_inner + + # Copy return value if necessary + bitb $1, %r0 # CIF_FLAGS_CHAR + beql 1f + movb 0(%sp), %r0 + brb 9f +1: + bitb $2, %r0 # CIF_FLAGS_SHORT + beql 1f + movw 0(%sp), %r0 + brb 9f +1: + bitb $4, %r0 # CIF_FLAGS_INT + beql 1f + movl 0(%sp), %r0 + brb 9f +1: + bitb $8, %r0 # CIF_FLAGS_DINT + beql 1f + movq 0(%sp), %r0 + #brb 9f +1: + +9: + ret + +/* + * ffi_closure_struct_elfbsd(void); + * invoked with %r0: ffi_closure *closure + * %r1: struct return address + */ + .globl ffi_closure_struct_elfbsd + .type ffi_closure_struct_elfbsd, @function + .align 2 +ffi_closure_struct_elfbsd: + .word 0 + + # Invoke the closure function + pushal 4(%ap) # calling stack + pushl %r1 # return value + pushl %r0 # closure + calls $3, ffi_closure_elfbsd_inner + + ret diff --git a/libffi/src/vax/ffi.c b/libffi/src/vax/ffi.c new file mode 100644 index 0000000..f4d6bbb --- /dev/null +++ b/libffi/src/vax/ffi.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2013 Miodrag Vallat. <miod@openbsd.org> + * + * 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. + */ + +/* + * vax Foreign Function Interface + * + * This file attempts to provide all the FFI entry points which can reliably + * be implemented in C. + */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> +#include <unistd.h> + +#define CIF_FLAGS_CHAR 1 /* for struct only */ +#define CIF_FLAGS_SHORT 2 /* for struct only */ +#define CIF_FLAGS_INT 4 +#define CIF_FLAGS_DINT 8 + +/* + * Foreign Function Interface API + */ + +void ffi_call_elfbsd (extended_cif *, unsigned, unsigned, void *, + void (*) ()); +void *ffi_prep_args (extended_cif *ecif, void *stack); + +void * +ffi_prep_args (extended_cif *ecif, void *stack) +{ + unsigned int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + void *struct_value_ptr; + + argp = stack; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT + && !ecif->cif->flags) + struct_value_ptr = ecif->rvalue; + else + struct_value_ptr = NULL; + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i != 0; + i--, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + if (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, z); + break; + + default: + FFI_ASSERT (0); + } + z = sizeof (int); + } + else + { + memcpy (argp, *p_argv, z); + + /* Align if necessary. */ + if ((sizeof(int) - 1) & z) + z = ALIGN(z, sizeof(int)); + } + + p_argv++; + argp += z; + } + + return struct_value_ptr; +} + +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + cif->flags = 0; + break; + + case FFI_TYPE_STRUCT: + if (cif->rtype->elements[0]->type == FFI_TYPE_STRUCT && + cif->rtype->elements[1]) + { + cif->flags = 0; + break; + } + + if (cif->rtype->size == sizeof (char)) + cif->flags = CIF_FLAGS_CHAR; + else if (cif->rtype->size == sizeof (short)) + cif->flags = CIF_FLAGS_SHORT; + else if (cif->rtype->size == sizeof (int)) + cif->flags = CIF_FLAGS_INT; + else if (cif->rtype->size == 2 * sizeof (int)) + cif->flags = CIF_FLAGS_DINT; + else + cif->flags = 0; + break; + + default: + if (cif->rtype->size <= sizeof (int)) + cif->flags = CIF_FLAGS_INT; + else + cif->flags = CIF_FLAGS_DINT; + break; + } + + return FFI_OK; +} + +void +ffi_call (ffi_cif *cif, void (*fn) (), 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->flags == 0) + ecif.rvalue = alloca (cif->rtype->size); + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_ELFBSD: + ffi_call_elfbsd (&ecif, cif->bytes, cif->flags, ecif.rvalue, fn); + break; + + default: + FFI_ASSERT (0); + break; + } +} + +/* + * Closure API + */ + +void ffi_closure_elfbsd (void); +void ffi_closure_struct_elfbsd (void); +unsigned int ffi_closure_elfbsd_inner (ffi_closure *, void *, char *); + +static void +ffi_prep_closure_elfbsd (ffi_cif *cif, void **avalue, char *stackp) +{ + unsigned int i; + void **p_argv; + ffi_type **p_arg; + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + *p_argv = stackp; + + /* Align if necessary */ + if ((sizeof (int) - 1) & z) + z = ALIGN(z, sizeof (int)); + + p_argv++; + stackp += z; + } +} + +unsigned int +ffi_closure_elfbsd_inner (ffi_closure *closure, void *resp, char *stack) +{ + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void **) alloca (cif->nargs * sizeof (void *)); + + ffi_prep_closure_elfbsd (cif, arg_area, stack); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + return cif->flags; +} + +ffi_status +ffi_prep_closure_loc (ffi_closure *closure, ffi_cif *cif, + void (*fun)(ffi_cif *, void *, void **, void *), + void *user_data, void *codeloc) +{ + char *tramp = (char *) codeloc; + void *fn; + + FFI_ASSERT (cif->abi == FFI_ELFBSD); + + /* entry mask */ + *(unsigned short *)(tramp + 0) = 0x0000; + /* movl #closure, r0 */ + tramp[2] = 0xd0; + tramp[3] = 0x8f; + *(unsigned int *)(tramp + 4) = (unsigned int) closure; + tramp[8] = 0x50; + + if (cif->rtype->type == FFI_TYPE_STRUCT + && !cif->flags) + fn = &ffi_closure_struct_elfbsd; + else + fn = &ffi_closure_elfbsd; + + /* jmpl #fn */ + tramp[9] = 0x17; + tramp[10] = 0xef; + *(unsigned int *)(tramp + 11) = (unsigned int)fn + 2 - + (unsigned int)tramp - 9 - 6; + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} diff --git a/libffi/src/vax/ffitarget.h b/libffi/src/vax/ffitarget.h new file mode 100644 index 0000000..2fc9488 --- /dev/null +++ b/libffi/src/vax/ffitarget.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013 Miodrag Vallat. <miod@openbsd.org> + * + * 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. + */ + +/* + * vax Foreign Function Interface + */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_ELFBSD, + FFI_DEFAULT_ABI = FFI_ELFBSD, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 15 +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/libffi/src/x86/darwin64_c.c b/libffi/src/x86/darwin64_c.c new file mode 100644 index 0000000..1daa1c0 --- /dev/null +++ b/libffi/src/x86/darwin64_c.c @@ -0,0 +1,643 @@ +/* ----------------------------------------------------------------------- + ffi64.c - Copyright (c) 20011 Anthony Green + Copyright (c) 2008, 2010 Red Hat, Inc. + Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de> + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL 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 <stdarg.h> + +#ifdef __x86_64__ + +#define MAX_GPR_REGS 6 +#define MAX_SSE_REGS 8 + +#ifdef __INTEL_COMPILER +#define UINT128 __m128 +#else +#define UINT128 __int128_t +#endif + +struct register_args +{ + /* Registers for argument passing. */ + UINT64 gpr[MAX_GPR_REGS]; + UINT128 sse[MAX_SSE_REGS]; +}; + +extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, + void *raddr, void (*fnaddr)(void), unsigned ssecount); + +/* All reference to register classes here is identical to the code in + gcc/config/i386/i386.c. Do *not* change one without the other. */ + +/* Register class used for passing given 64bit part of the argument. + These represent classes as documented by the PS ABI, with the + exception of SSESF, SSEDF classes, that are basically SSE class, + just gcc will use SF or DFmode move instead of DImode to avoid + reformatting penalties. + + Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves + whenever possible (upper half does contain padding). */ +enum x86_64_reg_class + { + X86_64_NO_CLASS, + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS, + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS, + X86_64_X87_CLASS, + X86_64_X87UP_CLASS, + X86_64_COMPLEX_X87_CLASS, + X86_64_MEMORY_CLASS + }; + +#define MAX_CLASSES 4 + +#define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS) + +/* x86-64 register passing implementation. See x86-64 ABI for details. Goal + of this code is to classify each 8bytes of incoming argument by the register + class and assign registers accordingly. */ + +/* Return the union class of CLASS1 and CLASS2. + See the x86-64 PS ABI for details. */ + +static enum x86_64_reg_class +merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) +{ + /* Rule #1: If both classes are equal, this is the resulting class. */ + if (class1 == class2) + return class1; + + /* Rule #2: If one of the classes is NO_CLASS, the resulting class is + the other class. */ + if (class1 == X86_64_NO_CLASS) + return class2; + if (class2 == X86_64_NO_CLASS) + return class1; + + /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ + if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ + if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) + || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) + return X86_64_INTEGERSI_CLASS; + if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS + || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) + return X86_64_INTEGER_CLASS; + + /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class, + MEMORY is used. */ + if (class1 == X86_64_X87_CLASS + || class1 == X86_64_X87UP_CLASS + || class1 == X86_64_COMPLEX_X87_CLASS + || class2 == X86_64_X87_CLASS + || class2 == X86_64_X87UP_CLASS + || class2 == X86_64_COMPLEX_X87_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #6: Otherwise class SSE is used. */ + return X86_64_SSE_CLASS; +} + +/* Classify the argument of type TYPE and mode MODE. + CLASSES will be filled by the register class used to pass each word + of the operand. The number of words is returned. In case the parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 is returned. + + See the x86-64 PS ABI for details. +*/ +static int +classify_argument (ffi_type *type, enum x86_64_reg_class classes[], + size_t byte_offset) +{ + switch (type->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + { + int size = byte_offset + type->size; + + if (size <= 4) + { + classes[0] = X86_64_INTEGERSI_CLASS; + return 1; + } + else if (size <= 8) + { + classes[0] = X86_64_INTEGER_CLASS; + return 1; + } + else if (size <= 12) + { + classes[0] = X86_64_INTEGER_CLASS; + classes[1] = X86_64_INTEGERSI_CLASS; + return 2; + } + else if (size <= 16) + { + classes[0] = classes[1] = X86_64_INTEGERSI_CLASS; + return 2; + } + else + FFI_ASSERT (0); + } + case FFI_TYPE_FLOAT: + if (!(byte_offset % 8)) + classes[0] = X86_64_SSESF_CLASS; + else + classes[0] = X86_64_SSE_CLASS; + return 1; + case FFI_TYPE_DOUBLE: + classes[0] = X86_64_SSEDF_CLASS; + return 1; + case FFI_TYPE_LONGDOUBLE: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + return 2; + case FFI_TYPE_STRUCT: + { + const int UNITS_PER_WORD = 8; + int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + ffi_type **ptr; + int i; + enum x86_64_reg_class subclasses[MAX_CLASSES]; + + /* If the struct is larger than 32 bytes, pass it on the stack. */ + if (type->size > 32) + return 0; + + for (i = 0; i < words; i++) + classes[i] = X86_64_NO_CLASS; + + /* Zero sized arrays or structures are NO_CLASS. We return 0 to + signalize memory class, so handle it as special case. */ + if (!words) + { + classes[0] = X86_64_NO_CLASS; + return 1; + } + + /* Merge the fields of structure. */ + for (ptr = type->elements; *ptr != NULL; ptr++) + { + int num; + + byte_offset = ALIGN (byte_offset, (*ptr)->alignment); + + num = classify_argument (*ptr, subclasses, byte_offset % 8); + if (num == 0) + return 0; + for (i = 0; i < num; i++) + { + int pos = byte_offset / 8; + classes[i + pos] = + merge_classes (subclasses[i], classes[i + pos]); + } + + byte_offset += (*ptr)->size; + } + + if (words > 2) + { + /* When size > 16 bytes, if the first one isn't + X86_64_SSE_CLASS or any other ones aren't + X86_64_SSEUP_CLASS, everything should be passed in + memory. */ + if (classes[0] != X86_64_SSE_CLASS) + return 0; + + for (i = 1; i < words; i++) + if (classes[i] != X86_64_SSEUP_CLASS) + return 0; + } + + /* Final merger cleanup. */ + for (i = 0; i < words; i++) + { + /* If one class is MEMORY, everything should be passed in + memory. */ + if (classes[i] == X86_64_MEMORY_CLASS) + return 0; + + /* The X86_64_SSEUP_CLASS should be always preceded by + X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */ + if (classes[i] == X86_64_SSEUP_CLASS + && classes[i - 1] != X86_64_SSE_CLASS + && classes[i - 1] != X86_64_SSEUP_CLASS) + { + /* The first one should never be X86_64_SSEUP_CLASS. */ + FFI_ASSERT (i != 0); + classes[i] = X86_64_SSE_CLASS; + } + + /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS, + everything should be passed in memory. */ + if (classes[i] == X86_64_X87UP_CLASS + && (classes[i - 1] != X86_64_X87_CLASS)) + { + /* The first one should never be X86_64_X87UP_CLASS. */ + FFI_ASSERT (i != 0); + return 0; + } + } + return words; + } + + default: + FFI_ASSERT(0); + } + return 0; /* Never reached. */ +} + +/* Examine the argument and return set number of register required in each + class. Return zero iff parameter should be passed in memory, otherwise + the number of registers. */ + +static int +examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], + _Bool in_return, int *pngpr, int *pnsse) +{ + int i, n, ngpr, nsse; + + n = classify_argument (type, classes, 0); + if (n == 0) + return 0; + + ngpr = nsse = 0; + for (i = 0; i < n; ++i) + switch (classes[i]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + ngpr++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + nsse++; + break; + case X86_64_NO_CLASS: + case X86_64_SSEUP_CLASS: + break; + case X86_64_X87_CLASS: + case X86_64_X87UP_CLASS: + case X86_64_COMPLEX_X87_CLASS: + return in_return != 0; + default: + abort (); + } + + *pngpr = ngpr; + *pnsse = nsse; + + return n; +} + +/* Perform machine dependent cif processing. */ + +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + int gprcount, ssecount, i, avn, n, ngpr, nsse, flags; + enum x86_64_reg_class classes[MAX_CLASSES]; + size_t bytes; + + gprcount = ssecount = 0; + + flags = cif->rtype->type; + if (flags != FFI_TYPE_VOID) + { + n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); + if (n == 0) + { + /* The return value is passed in memory. A pointer to that + memory is the first argument. Allocate a register for it. */ + gprcount++; + /* We don't have to do anything in asm for the return. */ + flags = FFI_TYPE_VOID; + } + else if (flags == FFI_TYPE_STRUCT) + { + /* Mark which registers the result appears in. */ + _Bool sse0 = SSE_CLASS_P (classes[0]); + _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]); + if (sse0 && !sse1) + flags |= 1 << 8; + else if (!sse0 && sse1) + flags |= 1 << 9; + else if (sse0 && sse1) + flags |= 1 << 10; + /* Mark the true size of the structure. */ + flags |= cif->rtype->size << 12; + } + } + + /* Go over all arguments and determine the way they should be passed. + If it's in a register and there is space for it, let that be so. If + not, add it's size to the stack byte count. */ + for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++) + { + if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = cif->arg_types[i]->alignment; + + if (align < 8) + align = 8; + + bytes = ALIGN (bytes, align); + bytes += cif->arg_types[i]->size; + } + else + { + gprcount += ngpr; + ssecount += nsse; + } + } + if (ssecount) + flags |= 1 << 11; + cif->flags = flags; + cif->bytes = ALIGN (bytes, 8); + + return FFI_OK; +} + +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + char *stack, *argp; + ffi_type **arg_types; + int gprcount, ssecount, ngpr, nsse, i, avn; + _Bool ret_in_memory; + struct register_args *reg_args; + + /* Can't call 32-bit mode from 64-bit mode. */ + FFI_ASSERT (cif->abi == FFI_UNIX64); + + /* If the return value is a struct and we don't have a return value + address then we need to make one. Note the setting of flags to + VOID above in ffi_prep_cif_machdep. */ + ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT + && (cif->flags & 0xff) == FFI_TYPE_VOID); + if (rvalue == NULL && ret_in_memory) + rvalue = alloca (cif->rtype->size); + + /* Allocate the space for the arguments, plus 4 words of temp space. */ + stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8); + reg_args = (struct register_args *) stack; + argp = stack + sizeof (struct register_args); + + gprcount = ssecount = 0; + + /* If the return value is passed in memory, add the pointer as the + first integer argument. */ + if (ret_in_memory) + reg_args->gpr[gprcount++] = (unsigned long) rvalue; + + avn = cif->nargs; + arg_types = cif->arg_types; + + for (i = 0; i < avn; ++i) + { + size_t size = arg_types[i]->size; + int n; + + n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); + if (n == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = arg_types[i]->alignment; + + /* Stack arguments are *always* at least 8 byte aligned. */ + if (align < 8) + align = 8; + + /* Pass this argument in memory. */ + argp = (void *) ALIGN (argp, align); + memcpy (argp, avalue[i], size); + argp += size; + } + else + { + /* The argument is passed entirely in registers. */ + char *a = (char *) avalue[i]; + int j; + + for (j = 0; j < n; j++, a += 8, size -= 8) + { + switch (classes[j]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + reg_args->gpr[gprcount] = 0; + memcpy (®_args->gpr[gprcount], a, size < 8 ? size : 8); + gprcount++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSEDF_CLASS: + reg_args->sse[ssecount++] = *(UINT64 *) a; + break; + case X86_64_SSESF_CLASS: + reg_args->sse[ssecount++] = *(UINT32 *) a; + break; + default: + abort(); + } + } + } + } + + ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args), + cif->flags, rvalue, fn, ssecount); +} + + +extern void ffi_closure_unix64(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) +{ + volatile unsigned short *tramp; + + /* Sanity check on the cif ABI. */ + { + int abi = cif->abi; + if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))) + return FFI_BAD_ABI; + } + + tramp = (volatile unsigned short *) &closure->tramp[0]; + + tramp[0] = 0xbb49; /* mov <code>, %r11 */ + *((unsigned long long * volatile) &tramp[1]) + = (unsigned long) ffi_closure_unix64; + tramp[5] = 0xba49; /* mov <data>, %r10 */ + *((unsigned long long * volatile) &tramp[6]) + = (unsigned long) codeloc; + + /* Set the carry bit iff the function uses any sse registers. + This is clc or stc, together with the first byte of the jmp. */ + tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8; + + tramp[11] = 0xe3ff; /* jmp *%r11 */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +int +ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, + struct register_args *reg_args, char *argp) +{ + ffi_cif *cif; + void **avalue; + ffi_type **arg_types; + long i, avn; + int gprcount, ssecount, ngpr, nsse; + int ret; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + gprcount = ssecount = 0; + + ret = cif->rtype->type; + if (ret != FFI_TYPE_VOID) + { + enum x86_64_reg_class classes[MAX_CLASSES]; + int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); + if (n == 0) + { + /* The return value goes in memory. Arrange for the closure + return value to go directly back to the original caller. */ + rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++]; + /* We don't have to do anything in asm for the return. */ + ret = FFI_TYPE_VOID; + } + else if (ret == FFI_TYPE_STRUCT && n == 2) + { + /* Mark which register the second word of the structure goes in. */ + _Bool sse0 = SSE_CLASS_P (classes[0]); + _Bool sse1 = SSE_CLASS_P (classes[1]); + if (!sse0 && sse1) + ret |= 1 << 8; + else if (sse0 && !sse1) + ret |= 1 << 9; + } + } + + avn = cif->nargs; + arg_types = cif->arg_types; + + for (i = 0; i < avn; ++i) + { + enum x86_64_reg_class classes[MAX_CLASSES]; + int n; + + n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); + if (n == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = arg_types[i]->alignment; + + /* Stack arguments are *always* at least 8 byte aligned. */ + if (align < 8) + align = 8; + + /* Pass this argument in memory. */ + argp = (void *) ALIGN (argp, align); + avalue[i] = argp; + argp += arg_types[i]->size; + } + /* If the argument is in a single register, or two consecutive + integer registers, then we can use that address directly. */ + else if (n == 1 + || (n == 2 && !(SSE_CLASS_P (classes[0]) + || SSE_CLASS_P (classes[1])))) + { + /* The argument is in a single register. */ + if (SSE_CLASS_P (classes[0])) + { + avalue[i] = ®_args->sse[ssecount]; + ssecount += n; + } + else + { + avalue[i] = ®_args->gpr[gprcount]; + gprcount += n; + } + } + /* Otherwise, allocate space to make them consecutive. */ + else + { + char *a = alloca (16); + int j; + + avalue[i] = a; + for (j = 0; j < n; j++, a += 8) + { + if (SSE_CLASS_P (classes[j])) + memcpy (a, ®_args->sse[ssecount++], 8); + else + memcpy (a, ®_args->gpr[gprcount++], 8); + } + } + } + + /* Invoke the closure. */ + closure->fun (cif, rvalue, avalue, closure->user_data); + + /* Tell assembly how to perform return type promotions. */ + return ret; +} + +#endif /* __x86_64__ */ diff --git a/libffi/src/x86/darwin_c.c b/libffi/src/x86/darwin_c.c new file mode 100644 index 0000000..6338de2 --- /dev/null +++ b/libffi/src/x86/darwin_c.c @@ -0,0 +1,843 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc. + Copyright (c) 2002 Ranjit Mathew + Copyright (c) 2002 Bo Thorsen + Copyright (c) 2002 Roger Sayle + Copyright (C) 2008, 2010 Free Software Foundation, Inc. + + x86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#if !defined(__x86_64__) || defined(_WIN64) || defined(__CYGWIN__) + +#ifdef _WIN64 +#include <windows.h> +#endif + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void ffi_prep_args(char *stack, extended_cif *ecif) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; +#ifdef X86_WIN32 + size_t p_stack_args[2]; + void *p_stack_data[2]; + char *argp2 = stack; + int stack_args_count = 0; + int cabi = ecif->cif->abi; +#endif + + argp = stack; + + if ((ecif->cif->flags == FFI_TYPE_STRUCT + || ecif->cif->flags == FFI_TYPE_MS_STRUCT) +#ifdef X86_WIN64 + && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2 + && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8) +#endif + ) + { + *(void **) argp = ecif->rvalue; +#ifdef X86_WIN32 + /* For fastcall/thiscall this is first register-passed + argument. */ + if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL) + { + p_stack_args[stack_args_count] = sizeof (void*); + p_stack_data[stack_args_count] = argp; + ++stack_args_count; + } +#endif + argp += sizeof(void*); + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i != 0; + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(void*) - 1) & (size_t) argp) + argp = (char *) ALIGN(argp, sizeof(void*)); + + z = (*p_arg)->size; +#ifdef X86_WIN64 + if (z > sizeof(ffi_arg) + || ((*p_arg)->type == FFI_TYPE_STRUCT + && (z != 1 && z != 2 && z != 4 && z != 8)) +#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE + || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE) +#endif + ) + { + z = sizeof(ffi_arg); + *(void **)argp = *p_argv; + } + else if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + memcpy(argp, *p_argv, z); + } + else +#endif + if (z < sizeof(ffi_arg)) + { + z = sizeof(ffi_arg); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(ffi_arg *) argp = *(ffi_arg *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else + { + memcpy(argp, *p_argv, z); + } + +#ifdef X86_WIN32 + /* For thiscall/fastcall convention register-passed arguments + are the first two none-floating-point arguments with a size + smaller or equal to sizeof (void*). */ + if ((cabi == FFI_THISCALL && stack_args_count < 1) + || (cabi == FFI_FASTCALL && stack_args_count < 2)) + { + if (z <= 4 + && ((*p_arg)->type != FFI_TYPE_FLOAT + && (*p_arg)->type != FFI_TYPE_STRUCT)) + { + p_stack_args[stack_args_count] = z; + p_stack_data[stack_args_count] = argp; + ++stack_args_count; + } + } +#endif + p_argv++; +#ifdef X86_WIN64 + argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); +#else + argp += z; +#endif + } + +#ifdef X86_WIN32 + /* We need to move the register-passed arguments for thiscall/fastcall + on top of stack, so that those can be moved to registers ecx/edx by + call-handler. */ + if (stack_args_count > 0) + { + size_t zz = (p_stack_args[0] + 3) & ~3; + char *h; + + /* Move first argument to top-stack position. */ + if (p_stack_data[0] != argp2) + { + h = alloca (zz + 1); + memcpy (h, p_stack_data[0], zz); + memmove (argp2 + zz, argp2, + (size_t) ((char *) p_stack_data[0] - (char*)argp2)); + memcpy (argp2, h, zz); + } + + argp2 += zz; + --stack_args_count; + if (zz > 4) + stack_args_count = 0; + + /* If we have a second argument, then move it on top + after the first one. */ + if (stack_args_count > 0 && p_stack_data[1] != argp2) + { + zz = p_stack_args[1]; + zz = (zz + 3) & ~3; + h = alloca (zz + 1); + h = alloca (zz + 1); + memcpy (h, p_stack_data[1], zz); + memmove (argp2 + zz, argp2, (size_t) ((char*) p_stack_data[1] - (char*)argp2)); + memcpy (argp2, h, zz); + } + } +#endif + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + unsigned int i; + ffi_type **ptr; + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: +#ifdef X86_WIN64 + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: +#endif + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#ifndef X86_WIN64 +#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif +#endif + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: +#ifdef X86_WIN64 + case FFI_TYPE_POINTER: +#endif + cif->flags = FFI_TYPE_SINT64; + break; + + case FFI_TYPE_STRUCT: +#ifndef X86 + if (cif->rtype->size == 1) + { + cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */ + } + else if (cif->rtype->size == 2) + { + cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */ + } + else if (cif->rtype->size == 4) + { +#ifdef X86_WIN64 + cif->flags = FFI_TYPE_SMALL_STRUCT_4B; +#else + cif->flags = FFI_TYPE_INT; /* same as int type */ +#endif + } + else if (cif->rtype->size == 8) + { + cif->flags = FFI_TYPE_SINT64; /* same as int64 type */ + } + else +#endif + { +#ifdef X86_WIN32 + if (cif->abi == FFI_MS_CDECL) + cif->flags = FFI_TYPE_MS_STRUCT; + else +#endif + cif->flags = FFI_TYPE_STRUCT; + /* allocate space for return value pointer */ + cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG); + } + break; + + default: +#ifdef X86_WIN64 + cif->flags = FFI_TYPE_SINT64; + break; + case FFI_TYPE_INT: + cif->flags = FFI_TYPE_SINT32; +#else + cif->flags = FFI_TYPE_INT; +#endif + break; + } + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + if (((*ptr)->alignment - 1) & cif->bytes) + cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment); + cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG); + } + +#ifdef X86_WIN64 + /* ensure space for storing four registers */ + cif->bytes += 4 * sizeof(ffi_arg); +#endif + +#ifdef X86_DARWIN + cif->bytes = (cif->bytes + 15) & ~0xF; +#endif + + return FFI_OK; +} + +#ifdef X86_WIN64 +extern int +ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *, + unsigned, unsigned, unsigned *, void (*fn)(void)); +#elif defined(X86_WIN32) +extern void +ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *, + unsigned, unsigned, unsigned, unsigned *, void (*fn)(void)); +#else +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, + unsigned, unsigned, unsigned *, void (*fn)(void)); +#endif + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + +#ifdef X86_WIN64 + if (rvalue == NULL + && cif->flags == FFI_TYPE_STRUCT + && cif->rtype->size != 1 && cif->rtype->size != 2 + && cif->rtype->size != 4 && cif->rtype->size != 8) + { + ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF); + } +#else + if (rvalue == NULL + && (cif->flags == FFI_TYPE_STRUCT + || cif->flags == FFI_TYPE_MS_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } +#endif + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { +#ifdef X86_WIN64 + case FFI_WIN64: + ffi_call_win64(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; +#elif defined(X86_WIN32) + case FFI_SYSV: + case FFI_STDCALL: + case FFI_MS_CDECL: + ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags, + ecif.rvalue, fn); + break; + case FFI_THISCALL: + case FFI_FASTCALL: + { + unsigned int abi = cif->abi; + unsigned int i, passed_regs = 0; + + if (cif->flags == FFI_TYPE_STRUCT) + ++passed_regs; + + for (i=0; i < cif->nargs && passed_regs < 2;i++) + { + size_t sz; + + if (cif->arg_types[i]->type == FFI_TYPE_FLOAT + || cif->arg_types[i]->type == FFI_TYPE_STRUCT) + continue; + sz = (cif->arg_types[i]->size + 3) & ~3; + if (sz == 0 || sz > 4) + continue; + ++passed_regs; + } + if (passed_regs < 2 && abi == FFI_FASTCALL) + abi = FFI_THISCALL; + if (passed_regs < 1 && abi == FFI_THISCALL) + abi = FFI_STDCALL; + ffi_call_win32(ffi_prep_args, &ecif, abi, cif->bytes, cif->flags, + ecif.rvalue, fn); + } + break; +#else + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, + fn); + break; +#endif + default: + FFI_ASSERT(0); + break; + } +} + + +/** private members **/ + +/* The following __attribute__((regparm(1))) decorations will have no effect + on MSVC - standard cdecl convention applies. */ +static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, + void** args, ffi_cif* cif); +void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *) + __attribute__ ((regparm(1))); +unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *) + __attribute__ ((regparm(1))); +void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *) + __attribute__ ((regparm(1))); +#ifdef X86_WIN32 +void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *) + __attribute__ ((regparm(1))); +void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *) + __attribute__ ((regparm(1))); +void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *) + __attribute__ ((regparm(1))); +#endif +#ifdef X86_WIN64 +void FFI_HIDDEN ffi_closure_win64 (ffi_closure *); +#endif + +/* This function is jumped to by the trampoline */ + +#ifdef X86_WIN64 +void * FFI_HIDDEN +ffi_closure_win64_inner (ffi_closure *closure, void *args) { + ffi_cif *cif; + void **arg_area; + void *result; + void *resp = &result; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will change RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + /* The result is returned in rax. This does the right thing for + result types except for floats; we have to 'mov xmm0, rax' in the + caller to correct this. + TODO: structure sizes of 3 5 6 7 are returned by reference, too!!! + */ + return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp; +} + +#else +unsigned int FFI_HIDDEN __attribute__ ((regparm(1))) +ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args) +{ + /* our various things... */ + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will change RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); + + (closure->fun) (cif, *respp, arg_area, closure->user_data); + + return cif->flags; +} +#endif /* !X86_WIN64 */ + +static void +ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, + ffi_cif *cif) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + +#ifdef X86_WIN64 + if (cif->rtype->size > sizeof(ffi_arg) + || (cif->flags == FFI_TYPE_STRUCT + && (cif->rtype->size != 1 && cif->rtype->size != 2 + && cif->rtype->size != 4 && cif->rtype->size != 8))) { + *rvalue = *(void **) argp; + argp += sizeof(void *); + } +#else + if ( cif->flags == FFI_TYPE_STRUCT + || cif->flags == FFI_TYPE_MS_STRUCT ) { + *rvalue = *(void **) argp; + argp += sizeof(void *); + } +#endif + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(void*) - 1) & (size_t) argp) { + argp = (char *) ALIGN(argp, sizeof(void*)); + } + +#ifdef X86_WIN64 + if ((*p_arg)->size > sizeof(ffi_arg) + || ((*p_arg)->type == FFI_TYPE_STRUCT + && ((*p_arg)->size != 1 && (*p_arg)->size != 2 + && (*p_arg)->size != 4 && (*p_arg)->size != 8))) + { + z = sizeof(void *); + *p_argv = *(void **)argp; + } + else +#endif + { + z = (*p_arg)->size; + + /* because we're little endian, this is what it turns into. */ + + *p_argv = (void*) argp; + } + + p_argv++; +#ifdef X86_WIN64 + argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); +#else + argp += z; +#endif + } + + return; +} + +#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \ +{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + void* __fun = (void*)(FUN); \ + void* __ctx = (void*)(CTX); \ + *(unsigned char*) &__tramp[0] = 0x41; \ + *(unsigned char*) &__tramp[1] = 0xbb; \ + *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \ + *(unsigned char*) &__tramp[6] = 0x48; \ + *(unsigned char*) &__tramp[7] = 0xb8; \ + *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \ + *(unsigned char *) &__tramp[16] = 0x49; \ + *(unsigned char *) &__tramp[17] = 0xba; \ + *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \ + *(unsigned char *) &__tramp[26] = 0x41; \ + *(unsigned char *) &__tramp[27] = 0xff; \ + *(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \ + } + +/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ + +#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ +{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - (__ctx + 10); \ + *(unsigned char*) &__tramp[0] = 0xb8; \ + *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ + *(unsigned char *) &__tramp[5] = 0xe9; \ + *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ + } + +#define FFI_INIT_TRAMPOLINE_THISCALL(TRAMP,FUN,CTX,SIZE) \ +{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - (__ctx + 49); \ + unsigned short __size = (unsigned short)(SIZE); \ + *(unsigned int *) &__tramp[0] = 0x8324048b; /* mov (%esp), %eax */ \ + *(unsigned int *) &__tramp[4] = 0x4c890cec; /* sub $12, %esp */ \ + *(unsigned int *) &__tramp[8] = 0x04890424; /* mov %ecx, 4(%esp) */ \ + *(unsigned char*) &__tramp[12] = 0x24; /* mov %eax, (%esp) */ \ + *(unsigned char*) &__tramp[13] = 0xb8; \ + *(unsigned int *) &__tramp[14] = __size; /* mov __size, %eax */ \ + *(unsigned int *) &__tramp[18] = 0x08244c8d; /* lea 8(%esp), %ecx */ \ + *(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \ + *(unsigned short*) &__tramp[26] = 0x0b74; /* jz 1f */ \ + *(unsigned int *) &__tramp[28] = 0x8908518b; /* 2b: mov 8(%ecx), %edx */ \ + *(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \ + *(unsigned char*) &__tramp[36] = 0x48; /* dec %eax */ \ + *(unsigned short*) &__tramp[37] = 0xf575; /* jnz 2b ; 1f: */ \ + *(unsigned char*) &__tramp[39] = 0xb8; \ + *(unsigned int*) &__tramp[40] = __ctx; /* movl __ctx, %eax */ \ + *(unsigned char *) &__tramp[44] = 0xe8; \ + *(unsigned int*) &__tramp[45] = __dis; /* call __fun */ \ + *(unsigned char*) &__tramp[49] = 0xc2; /* ret */ \ + *(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \ + } + +#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \ +{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - (__ctx + 10); \ + unsigned short __size = (unsigned short)(SIZE); \ + *(unsigned char*) &__tramp[0] = 0xb8; \ + *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ + *(unsigned char *) &__tramp[5] = 0xe8; \ + *(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \ + *(unsigned char *) &__tramp[10] = 0xc2; \ + *(unsigned short*) &__tramp[11] = __size; /* ret __size */ \ + } + +/* the cif must already be prep'ed */ + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ +#ifdef X86_WIN64 +#define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE) +#define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0) + if (cif->abi == FFI_WIN64) + { + int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3); + FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0], + &ffi_closure_win64, + codeloc, mask); + /* make sure we can execute here */ + } +#else + if (cif->abi == FFI_SYSV) + { + FFI_INIT_TRAMPOLINE (&closure->tramp[0], + &ffi_closure_SYSV, + (void*)codeloc); + } +#ifdef X86_WIN32 + else if (cif->abi == FFI_THISCALL) + { + FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0], + &ffi_closure_THISCALL, + (void*)codeloc, + cif->bytes); + } + else if (cif->abi == FFI_STDCALL) + { + FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0], + &ffi_closure_STDCALL, + (void*)codeloc, cif->bytes); + } + else if (cif->abi == FFI_MS_CDECL) + { + FFI_INIT_TRAMPOLINE (&closure->tramp[0], + &ffi_closure_SYSV, + (void*)codeloc); + } +#endif /* X86_WIN32 */ +#endif /* !X86_WIN64 */ + else + { + return FFI_BAD_ABI; + } + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +/* ------- Native raw API support -------------------------------- */ + +#if !FFI_NO_RAW_API + +ffi_status +ffi_prep_raw_closure_loc (ffi_raw_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data, + void *codeloc) +{ + int i; + + if (cif->abi != FFI_SYSV) { +#ifdef X86_WIN32 + if (cif->abi != FFI_THISCALL) +#endif + return FFI_BAD_ABI; + } + + /* we currently don't support certain kinds of arguments for raw + closures. This should be implemented by a separate assembly + language routine, since it would require argument processing, + something we don't do now for performance. */ + + for (i = cif->nargs-1; i >= 0; i--) + { + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT); + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); + } + +#ifdef X86_WIN32 + if (cif->abi == FFI_SYSV) + { +#endif + FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV, + codeloc); +#ifdef X86_WIN32 + } + else if (cif->abi == FFI_THISCALL) + { + FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0], &ffi_closure_raw_THISCALL, + codeloc, cif->bytes); + } +#endif + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +static void +ffi_prep_args_raw(char *stack, extended_cif *ecif) +{ + memcpy (stack, ecif->avalue, ecif->cif->bytes); +} + +/* we borrow this routine from libffi (it must be changed, though, to + * actually call the function passed in the first argument. as of + * libffi-1.20, this is not the case.) + */ + +void +ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue) +{ + extended_cif ecif; + void **avalue = (void **)fake_avalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if (rvalue == NULL + && (cif->flags == FFI_TYPE_STRUCT + || cif->flags == FFI_TYPE_MS_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { +#ifdef X86_WIN32 + case FFI_SYSV: + case FFI_STDCALL: + case FFI_MS_CDECL: + ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags, + ecif.rvalue, fn); + break; + case FFI_THISCALL: + case FFI_FASTCALL: + { + unsigned int abi = cif->abi; + unsigned int i, passed_regs = 0; + + if (cif->flags == FFI_TYPE_STRUCT) + ++passed_regs; + + for (i=0; i < cif->nargs && passed_regs < 2;i++) + { + size_t sz; + + if (cif->arg_types[i]->type == FFI_TYPE_FLOAT + || cif->arg_types[i]->type == FFI_TYPE_STRUCT) + continue; + sz = (cif->arg_types[i]->size + 3) & ~3; + if (sz == 0 || sz > 4) + continue; + ++passed_regs; + } + if (passed_regs < 2 && abi == FFI_FASTCALL) + cif->abi = abi = FFI_THISCALL; + if (passed_regs < 1 && abi == FFI_THISCALL) + cif->abi = abi = FFI_STDCALL; + ffi_call_win32(ffi_prep_args_raw, &ecif, abi, cif->bytes, cif->flags, + ecif.rvalue, fn); + } + break; +#else + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, + ecif.rvalue, fn); + break; +#endif + default: + FFI_ASSERT(0); + break; + } +} + +#endif + +#endif /* !__x86_64__ || X86_WIN64 */ + diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c index 6338de2..3885e39 100644 --- a/libffi/src/x86/ffi.c +++ b/libffi/src/x86/ffi.c @@ -28,620 +28,473 @@ DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ -#if !defined(__x86_64__) || defined(_WIN64) || defined(__CYGWIN__) - -#ifdef _WIN64 -#include <windows.h> -#endif - +#ifndef __x86_64__ #include <ffi.h> #include <ffi_common.h> - #include <stdlib.h> - -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments */ - -void ffi_prep_args(char *stack, extended_cif *ecif) -{ - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; -#ifdef X86_WIN32 - size_t p_stack_args[2]; - void *p_stack_data[2]; - char *argp2 = stack; - int stack_args_count = 0; - int cabi = ecif->cif->abi; +#include "internal.h" + +/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; + all further uses in this file will refer to the 80-bit type. */ +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +# if FFI_TYPE_LONGDOUBLE != 4 +# error FFI_TYPE_LONGDOUBLE out of date +# endif +#else +# undef FFI_TYPE_LONGDOUBLE +# define FFI_TYPE_LONGDOUBLE 4 #endif - argp = stack; - - if ((ecif->cif->flags == FFI_TYPE_STRUCT - || ecif->cif->flags == FFI_TYPE_MS_STRUCT) -#ifdef X86_WIN64 - && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2 - && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8) +#if defined(__GNUC__) && !defined(__declspec) +# define __declspec(x) __attribute__((x)) #endif - ) - { - *(void **) argp = ecif->rvalue; -#ifdef X86_WIN32 - /* For fastcall/thiscall this is first register-passed - argument. */ - if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL) - { - p_stack_args[stack_args_count] = sizeof (void*); - p_stack_data[stack_args_count] = argp; - ++stack_args_count; - } -#endif - argp += sizeof(void*); - } - - p_argv = ecif->avalue; - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - i != 0; - i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(void*) - 1) & (size_t) argp) - argp = (char *) ALIGN(argp, sizeof(void*)); - - z = (*p_arg)->size; -#ifdef X86_WIN64 - if (z > sizeof(ffi_arg) - || ((*p_arg)->type == FFI_TYPE_STRUCT - && (z != 1 && z != 2 && z != 4 && z != 8)) -#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE - || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE) -#endif - ) - { - z = sizeof(ffi_arg); - *(void **)argp = *p_argv; - } - else if ((*p_arg)->type == FFI_TYPE_FLOAT) - { - memcpy(argp, *p_argv, z); - } - else -#endif - if (z < sizeof(ffi_arg)) - { - z = sizeof(ffi_arg); - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv); - break; - - case FFI_TYPE_SINT32: - *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv); - break; - - case FFI_TYPE_UINT32: - *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv); - break; - - case FFI_TYPE_STRUCT: - *(ffi_arg *) argp = *(ffi_arg *)(* p_argv); - break; - - default: - FFI_ASSERT(0); - } - } - else - { - memcpy(argp, *p_argv, z); - } - -#ifdef X86_WIN32 - /* For thiscall/fastcall convention register-passed arguments - are the first two none-floating-point arguments with a size - smaller or equal to sizeof (void*). */ - if ((cabi == FFI_THISCALL && stack_args_count < 1) - || (cabi == FFI_FASTCALL && stack_args_count < 2)) - { - if (z <= 4 - && ((*p_arg)->type != FFI_TYPE_FLOAT - && (*p_arg)->type != FFI_TYPE_STRUCT)) - { - p_stack_args[stack_args_count] = z; - p_stack_data[stack_args_count] = argp; - ++stack_args_count; - } - } -#endif - p_argv++; -#ifdef X86_WIN64 - argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); -#else - argp += z; -#endif - } +/* Perform machine dependent cif processing. */ +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep(ffi_cif *cif) +{ + size_t bytes = 0; + int i, n, flags, cabi = cif->abi; -#ifdef X86_WIN32 - /* We need to move the register-passed arguments for thiscall/fastcall - on top of stack, so that those can be moved to registers ecx/edx by - call-handler. */ - if (stack_args_count > 0) + switch (cabi) { - size_t zz = (p_stack_args[0] + 3) & ~3; - char *h; - - /* Move first argument to top-stack position. */ - if (p_stack_data[0] != argp2) - { - h = alloca (zz + 1); - memcpy (h, p_stack_data[0], zz); - memmove (argp2 + zz, argp2, - (size_t) ((char *) p_stack_data[0] - (char*)argp2)); - memcpy (argp2, h, zz); - } - - argp2 += zz; - --stack_args_count; - if (zz > 4) - stack_args_count = 0; - - /* If we have a second argument, then move it on top - after the first one. */ - if (stack_args_count > 0 && p_stack_data[1] != argp2) - { - zz = p_stack_args[1]; - zz = (zz + 3) & ~3; - h = alloca (zz + 1); - h = alloca (zz + 1); - memcpy (h, p_stack_data[1], zz); - memmove (argp2 + zz, argp2, (size_t) ((char*) p_stack_data[1] - (char*)argp2)); - memcpy (argp2, h, zz); - } + case FFI_SYSV: + case FFI_STDCALL: + case FFI_THISCALL: + case FFI_FASTCALL: + case FFI_MS_CDECL: + case FFI_PASCAL: + case FFI_REGISTER: + break; + default: + return FFI_BAD_ABI; } -#endif - return; -} - -/* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif) -{ - unsigned int i; - ffi_type **ptr; - /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_VOID: + flags = X86_RET_VOID; + break; + case FFI_TYPE_FLOAT: + flags = X86_RET_FLOAT; + break; + case FFI_TYPE_DOUBLE: + flags = X86_RET_DOUBLE; + break; + case FFI_TYPE_LONGDOUBLE: + flags = X86_RET_LDOUBLE; + break; case FFI_TYPE_UINT8: + flags = X86_RET_UINT8; + break; case FFI_TYPE_UINT16: + flags = X86_RET_UINT16; + break; case FFI_TYPE_SINT8: + flags = X86_RET_SINT8; + break; case FFI_TYPE_SINT16: -#ifdef X86_WIN64 - case FFI_TYPE_UINT32: + flags = X86_RET_SINT16; + break; + case FFI_TYPE_INT: case FFI_TYPE_SINT32: -#endif - case FFI_TYPE_SINT64: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: -#ifndef X86_WIN64 -#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE - case FFI_TYPE_LONGDOUBLE: -#endif -#endif - cif->flags = (unsigned) cif->rtype->type; + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + flags = X86_RET_INT32; break; - + case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: -#ifdef X86_WIN64 - case FFI_TYPE_POINTER: -#endif - cif->flags = FFI_TYPE_SINT64; + flags = X86_RET_INT64; break; - case FFI_TYPE_STRUCT: #ifndef X86 + /* ??? This should be a different ABI rather than an ifdef. */ if (cif->rtype->size == 1) - { - cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */ - } + flags = X86_RET_STRUCT_1B; else if (cif->rtype->size == 2) - { - cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */ - } + flags = X86_RET_STRUCT_2B; else if (cif->rtype->size == 4) - { -#ifdef X86_WIN64 - cif->flags = FFI_TYPE_SMALL_STRUCT_4B; -#else - cif->flags = FFI_TYPE_INT; /* same as int type */ -#endif - } + flags = X86_RET_INT32; else if (cif->rtype->size == 8) - { - cif->flags = FFI_TYPE_SINT64; /* same as int64 type */ - } + flags = X86_RET_INT64; else #endif - { -#ifdef X86_WIN32 - if (cif->abi == FFI_MS_CDECL) - cif->flags = FFI_TYPE_MS_STRUCT; - else -#endif - cif->flags = FFI_TYPE_STRUCT; - /* allocate space for return value pointer */ - cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG); - } - break; - - default: -#ifdef X86_WIN64 - cif->flags = FFI_TYPE_SINT64; + { + 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 += ALIGN (sizeof(void*), FFI_SIZEOF_ARG); + } break; - case FFI_TYPE_INT: - cif->flags = FFI_TYPE_SINT32; -#else - cif->flags = FFI_TYPE_INT; -#endif + case FFI_TYPE_COMPLEX: + switch (cif->rtype->elements[0]->type) + { + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + goto do_struct; + case FFI_TYPE_FLOAT: + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + flags = X86_RET_INT64; + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + flags = X86_RET_INT32; + break; + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + flags = X86_RET_STRUCT_2B; + break; + default: + return FFI_BAD_TYPEDEF; + } break; + default: + return FFI_BAD_TYPEDEF; } + cif->flags = flags; - for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + for (i = 0, n = cif->nargs; i < n; i++) { - if (((*ptr)->alignment - 1) & cif->bytes) - cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment); - cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG); - } + ffi_type *t = cif->arg_types[i]; -#ifdef X86_WIN64 - /* ensure space for storing four registers */ - cif->bytes += 4 * sizeof(ffi_arg); -#endif - -#ifdef X86_DARWIN - cif->bytes = (cif->bytes + 15) & ~0xF; -#endif + bytes = ALIGN (bytes, t->alignment); + bytes += ALIGN (t->size, FFI_SIZEOF_ARG); + } + cif->bytes = ALIGN (bytes, 16); return FFI_OK; } -#ifdef X86_WIN64 -extern int -ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *, - unsigned, unsigned, unsigned *, void (*fn)(void)); -#elif defined(X86_WIN32) -extern void -ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *, - unsigned, unsigned, unsigned, unsigned *, void (*fn)(void)); -#else -extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, - unsigned, unsigned, unsigned *, void (*fn)(void)); -#endif - -void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +static ffi_arg +extend_basic_type(void *arg, int type) { - extended_cif ecif; - - ecif.cif = cif; - ecif.avalue = avalue; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ - -#ifdef X86_WIN64 - if (rvalue == NULL - && cif->flags == FFI_TYPE_STRUCT - && cif->rtype->size != 1 && cif->rtype->size != 2 - && cif->rtype->size != 4 && cif->rtype->size != 8) + switch (type) { - ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF); + case FFI_TYPE_SINT8: + return *(SINT8 *)arg; + case FFI_TYPE_UINT8: + return *(UINT8 *)arg; + case FFI_TYPE_SINT16: + return *(SINT16 *)arg; + case FFI_TYPE_UINT16: + return *(UINT16 *)arg; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + case FFI_TYPE_FLOAT: + return *(UINT32 *)arg; + + default: + abort(); } -#else - if (rvalue == NULL - && (cif->flags == FFI_TYPE_STRUCT - || cif->flags == FFI_TYPE_MS_STRUCT)) +} + +struct call_frame +{ + void *ebp; /* 0 */ + void *retaddr; /* 4 */ + void (*fn)(void); /* 8 */ + int flags; /* 12 */ + void *rvalue; /* 16 */ + unsigned regs[3]; /* 20-28 */ +}; + +struct abi_params +{ + int dir; /* parameter growth direction */ + int static_chain; /* the static chain register used by gcc */ + int nregs; /* number of register parameters */ + int regs[3]; +}; + +static const struct abi_params abi_params[FFI_LAST_ABI] = { + [FFI_SYSV] = { 1, R_ECX, 0 }, + [FFI_THISCALL] = { 1, R_EAX, 1, { R_ECX } }, + [FFI_FASTCALL] = { 1, R_EAX, 2, { R_ECX, R_EDX } }, + [FFI_STDCALL] = { 1, R_ECX, 0 }, + [FFI_PASCAL] = { -1, R_ECX, 0 }, + /* ??? No defined static chain; gcc does not support REGISTER. */ + [FFI_REGISTER] = { -1, R_ECX, 3, { R_EAX, R_EDX, R_ECX } }, + [FFI_MS_CDECL] = { 1, R_ECX, 0 } +}; + +extern void ffi_call_i386(struct call_frame *, char *) +#if HAVE_FASTCALL + __declspec(fastcall) +#endif + FFI_HIDDEN; + +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + size_t rsize, bytes; + struct call_frame *frame; + char *stack, *argp; + ffi_type **arg_types; + int flags, cabi, i, n, dir, narg_reg; + const struct abi_params *pabi; + + flags = cif->flags; + cabi = cif->abi; + pabi = &abi_params[cabi]; + dir = pabi->dir; + + rsize = 0; + if (rvalue == NULL) { - ecif.rvalue = alloca(cif->rtype->size); + switch (flags) + { + case X86_RET_FLOAT: + case X86_RET_DOUBLE: + case X86_RET_LDOUBLE: + case X86_RET_STRUCTPOP: + case X86_RET_STRUCTARG: + /* The float cases need to pop the 387 stack. + The struct cases need to pass a valid pointer to the callee. */ + rsize = cif->rtype->size; + break; + default: + /* We can pretend that the callee returns nothing. */ + flags = X86_RET_VOID; + break; + } } -#endif - else - ecif.rvalue = rvalue; - - - switch (cif->abi) + + bytes = cif->bytes; + stack = alloca(bytes + sizeof(*frame) + rsize); + argp = (dir < 0 ? stack + bytes : stack); + frame = (struct call_frame *)(stack + bytes); + if (rsize) + rvalue = frame + 1; + + frame->fn = fn; + frame->flags = flags; + frame->rvalue = rvalue; + frame->regs[pabi->static_chain] = (unsigned)closure; + + narg_reg = 0; + switch (flags) { -#ifdef X86_WIN64 - case FFI_WIN64: - ffi_call_win64(ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); - break; -#elif defined(X86_WIN32) - case FFI_SYSV: - case FFI_STDCALL: - case FFI_MS_CDECL: - ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags, - ecif.rvalue, fn); - break; - case FFI_THISCALL: - case FFI_FASTCALL: - { - unsigned int abi = cif->abi; - unsigned int i, passed_regs = 0; - - if (cif->flags == FFI_TYPE_STRUCT) - ++passed_regs; - - for (i=0; i < cif->nargs && passed_regs < 2;i++) - { - size_t sz; - - if (cif->arg_types[i]->type == FFI_TYPE_FLOAT - || cif->arg_types[i]->type == FFI_TYPE_STRUCT) - continue; - sz = (cif->arg_types[i]->size + 3) & ~3; - if (sz == 0 || sz > 4) - continue; - ++passed_regs; - } - if (passed_regs < 2 && abi == FFI_FASTCALL) - abi = FFI_THISCALL; - if (passed_regs < 1 && abi == FFI_THISCALL) - abi = FFI_STDCALL; - ffi_call_win32(ffi_prep_args, &ecif, abi, cif->bytes, cif->flags, - ecif.rvalue, fn); - } - break; -#else - case FFI_SYSV: - ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, - fn); - break; -#endif - default: - FFI_ASSERT(0); + case X86_RET_STRUCTARG: + /* The pointer is passed as the first argument. */ + if (pabi->nregs > 0) + { + frame->regs[pabi->regs[0]] = (unsigned)rvalue; + narg_reg = 1; + break; + } + /* fallthru */ + case X86_RET_STRUCTPOP: + *(void **)argp = rvalue; + argp += sizeof(void *); break; } -} - -/** private members **/ + arg_types = cif->arg_types; + for (i = 0, n = cif->nargs; i < n; i++) + { + ffi_type *ty = arg_types[i]; + void *valp = avalue[i]; + size_t z = ty->size; + int t = ty->type; -/* The following __attribute__((regparm(1))) decorations will have no effect - on MSVC - standard cdecl convention applies. */ -static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, - void** args, ffi_cif* cif); -void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *) - __attribute__ ((regparm(1))); -unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *) - __attribute__ ((regparm(1))); -void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *) - __attribute__ ((regparm(1))); -#ifdef X86_WIN32 -void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *) - __attribute__ ((regparm(1))); -void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *) - __attribute__ ((regparm(1))); -void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *) - __attribute__ ((regparm(1))); -#endif -#ifdef X86_WIN64 -void FFI_HIDDEN ffi_closure_win64 (ffi_closure *); -#endif + if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT) + { + ffi_arg val = extend_basic_type (valp, t); + + if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs) + frame->regs[pabi->regs[narg_reg++]] = val; + else if (dir < 0) + { + argp -= 4; + *(ffi_arg *)argp = val; + } + else + { + *(ffi_arg *)argp = val; + argp += 4; + } + } + else + { + size_t za = ALIGN (z, FFI_SIZEOF_ARG); + size_t align = FFI_SIZEOF_ARG; + + /* Alignment rules for arguments are quite complex. Vectors and + structures with 16 byte alignment get it. Note that long double + on Darwin does have 16 byte alignment, and does not get this + alignment if passed directly; a structure with a long double + inside, however, would get 16 byte alignment. Since libffi does + not support vectors, we need non concern ourselves with other + cases. */ + if (t == FFI_TYPE_STRUCT && ty->alignment >= 16) + align = 16; + + if (dir < 0) + { + /* ??? These reverse argument ABIs are probably too old + to have cared about alignment. Someone should check. */ + argp -= za; + memcpy (argp, valp, z); + } + else + { + argp = (char *)ALIGN (argp, align); + memcpy (argp, valp, z); + argp += za; + } + } + } + FFI_ASSERT (dir > 0 || argp == stack); -/* This function is jumped to by the trampoline */ - -#ifdef X86_WIN64 -void * FFI_HIDDEN -ffi_closure_win64_inner (ffi_closure *closure, void *args) { - ffi_cif *cif; - void **arg_area; - void *result; - void *resp = &result; - - cif = closure->cif; - arg_area = (void**) alloca (cif->nargs * sizeof (void*)); - - /* this call will initialize ARG_AREA, such that each - * element in that array points to the corresponding - * value on the stack; and if the function returns - * a structure, it will change RESP to point to the - * structure return address. */ - - ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif); - - (closure->fun) (cif, resp, arg_area, closure->user_data); - - /* The result is returned in rax. This does the right thing for - result types except for floats; we have to 'mov xmm0, rax' in the - caller to correct this. - TODO: structure sizes of 3 5 6 7 are returned by reference, too!!! - */ - return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp; + ffi_call_i386 (frame, stack); } -#else -unsigned int FFI_HIDDEN __attribute__ ((regparm(1))) -ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args) +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { - /* our various things... */ - ffi_cif *cif; - void **arg_area; - - cif = closure->cif; - arg_area = (void**) alloca (cif->nargs * sizeof (void*)); - - /* this call will initialize ARG_AREA, such that each - * element in that array points to the corresponding - * value on the stack; and if the function returns - * a structure, it will change RESP to point to the - * structure return address. */ + ffi_call_int (cif, fn, rvalue, avalue, NULL); +} - ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); +void +ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int (cif, fn, rvalue, avalue, closure); +} - (closure->fun) (cif, *respp, arg_area, closure->user_data); +/** private members **/ - return cif->flags; -} -#endif /* !X86_WIN64 */ +void FFI_HIDDEN ffi_closure_i386(void); +void FFI_HIDDEN ffi_closure_STDCALL(void); +void FFI_HIDDEN ffi_closure_REGISTER(void); -static void -ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, - ffi_cif *cif) +struct closure_frame { - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - - argp = stack; - -#ifdef X86_WIN64 - if (cif->rtype->size > sizeof(ffi_arg) - || (cif->flags == FFI_TYPE_STRUCT - && (cif->rtype->size != 1 && cif->rtype->size != 2 - && cif->rtype->size != 4 && cif->rtype->size != 8))) { - *rvalue = *(void **) argp; - argp += sizeof(void *); - } -#else - if ( cif->flags == FFI_TYPE_STRUCT - || cif->flags == FFI_TYPE_MS_STRUCT ) { - *rvalue = *(void **) argp; - argp += sizeof(void *); - } -#endif + unsigned rettemp[4]; /* 0 */ + unsigned regs[3]; /* 16-24 */ + ffi_cif *cif; /* 28 */ + void (*fun)(ffi_cif*,void*,void**,void*); /* 32 */ + void *user_data; /* 36 */ +}; + +int FFI_HIDDEN +#if HAVE_FASTCALL +__declspec(fastcall) +#endif +ffi_closure_inner (struct closure_frame *frame, char *stack) +{ + ffi_cif *cif = frame->cif; + int cabi, i, n, flags, dir, narg_reg; + const struct abi_params *pabi; + ffi_type **arg_types; + char *argp; + void *rvalue; + void **avalue; + + cabi = cif->abi; + flags = cif->flags; + narg_reg = 0; + rvalue = frame->rettemp; + pabi = &abi_params[cabi]; + dir = pabi->dir; + argp = (dir < 0 ? stack + cif->bytes : stack); + + switch (flags) + { + case X86_RET_STRUCTARG: + if (pabi->nregs > 0) + { + rvalue = (void *)frame->regs[pabi->regs[0]]; + narg_reg = 1; + frame->rettemp[0] = (unsigned)rvalue; + break; + } + /* fallthru */ + case X86_RET_STRUCTPOP: + rvalue = *(void **)argp; + argp += sizeof(void *); + frame->rettemp[0] = (unsigned)rvalue; + break; + } - p_argv = avalue; + n = cif->nargs; + avalue = alloca(sizeof(void *) * n); - for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + arg_types = cif->arg_types; + for (i = 0; i < n; ++i) { - size_t z; - - /* Align if necessary */ - if ((sizeof(void*) - 1) & (size_t) argp) { - argp = (char *) ALIGN(argp, sizeof(void*)); - } + ffi_type *ty = arg_types[i]; + size_t z = ty->size; + int t = ty->type; + void *valp; -#ifdef X86_WIN64 - if ((*p_arg)->size > sizeof(ffi_arg) - || ((*p_arg)->type == FFI_TYPE_STRUCT - && ((*p_arg)->size != 1 && (*p_arg)->size != 2 - && (*p_arg)->size != 4 && (*p_arg)->size != 8))) - { - z = sizeof(void *); - *p_argv = *(void **)argp; - } + if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT) + { + if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs) + valp = &frame->regs[pabi->regs[narg_reg++]]; + else if (dir < 0) + { + argp -= 4; + valp = argp; + } + else + { + valp = argp; + argp += 4; + } + } else -#endif - { - z = (*p_arg)->size; - - /* because we're little endian, this is what it turns into. */ - - *p_argv = (void*) argp; - } - - p_argv++; -#ifdef X86_WIN64 - argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); -#else - argp += z; -#endif + { + size_t za = ALIGN (z, FFI_SIZEOF_ARG); + size_t align = FFI_SIZEOF_ARG; + + /* See the comment in ffi_call_int. */ + if (t == FFI_TYPE_STRUCT && ty->alignment >= 16) + align = 16; + + if (dir < 0) + { + /* ??? These reverse argument ABIs are probably too old + to have cared about alignment. Someone should check. */ + argp -= za; + valp = argp; + } + else + { + argp = (char *)ALIGN (argp, align); + valp = argp; + argp += za; + } + } + + avalue[i] = valp; } - - return; -} -#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \ -{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - void* __fun = (void*)(FUN); \ - void* __ctx = (void*)(CTX); \ - *(unsigned char*) &__tramp[0] = 0x41; \ - *(unsigned char*) &__tramp[1] = 0xbb; \ - *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \ - *(unsigned char*) &__tramp[6] = 0x48; \ - *(unsigned char*) &__tramp[7] = 0xb8; \ - *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \ - *(unsigned char *) &__tramp[16] = 0x49; \ - *(unsigned char *) &__tramp[17] = 0xba; \ - *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \ - *(unsigned char *) &__tramp[26] = 0x41; \ - *(unsigned char *) &__tramp[27] = 0xff; \ - *(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \ - } - -/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ - -#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ -{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - unsigned int __fun = (unsigned int)(FUN); \ - unsigned int __ctx = (unsigned int)(CTX); \ - unsigned int __dis = __fun - (__ctx + 10); \ - *(unsigned char*) &__tramp[0] = 0xb8; \ - *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ - *(unsigned char *) &__tramp[5] = 0xe9; \ - *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ - } - -#define FFI_INIT_TRAMPOLINE_THISCALL(TRAMP,FUN,CTX,SIZE) \ -{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - unsigned int __fun = (unsigned int)(FUN); \ - unsigned int __ctx = (unsigned int)(CTX); \ - unsigned int __dis = __fun - (__ctx + 49); \ - unsigned short __size = (unsigned short)(SIZE); \ - *(unsigned int *) &__tramp[0] = 0x8324048b; /* mov (%esp), %eax */ \ - *(unsigned int *) &__tramp[4] = 0x4c890cec; /* sub $12, %esp */ \ - *(unsigned int *) &__tramp[8] = 0x04890424; /* mov %ecx, 4(%esp) */ \ - *(unsigned char*) &__tramp[12] = 0x24; /* mov %eax, (%esp) */ \ - *(unsigned char*) &__tramp[13] = 0xb8; \ - *(unsigned int *) &__tramp[14] = __size; /* mov __size, %eax */ \ - *(unsigned int *) &__tramp[18] = 0x08244c8d; /* lea 8(%esp), %ecx */ \ - *(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \ - *(unsigned short*) &__tramp[26] = 0x0b74; /* jz 1f */ \ - *(unsigned int *) &__tramp[28] = 0x8908518b; /* 2b: mov 8(%ecx), %edx */ \ - *(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \ - *(unsigned char*) &__tramp[36] = 0x48; /* dec %eax */ \ - *(unsigned short*) &__tramp[37] = 0xf575; /* jnz 2b ; 1f: */ \ - *(unsigned char*) &__tramp[39] = 0xb8; \ - *(unsigned int*) &__tramp[40] = __ctx; /* movl __ctx, %eax */ \ - *(unsigned char *) &__tramp[44] = 0xe8; \ - *(unsigned int*) &__tramp[45] = __dis; /* call __fun */ \ - *(unsigned char*) &__tramp[49] = 0xc2; /* ret */ \ - *(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \ - } - -#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \ -{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - unsigned int __fun = (unsigned int)(FUN); \ - unsigned int __ctx = (unsigned int)(CTX); \ - unsigned int __dis = __fun - (__ctx + 10); \ - unsigned short __size = (unsigned short)(SIZE); \ - *(unsigned char*) &__tramp[0] = 0xb8; \ - *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ - *(unsigned char *) &__tramp[5] = 0xe8; \ - *(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \ - *(unsigned char *) &__tramp[10] = 0xc2; \ - *(unsigned short*) &__tramp[11] = __size; /* ret __size */ \ - } - -/* the cif must already be prep'ed */ + frame->fun (cif, rvalue, avalue, frame->user_data); + + if (cabi == FFI_STDCALL) + return flags + (cif->bytes << X86_RET_POP_SHIFT); + else + return flags; +} ffi_status ffi_prep_closure_loc (ffi_closure* closure, @@ -650,54 +503,76 @@ ffi_prep_closure_loc (ffi_closure* closure, void *user_data, void *codeloc) { -#ifdef X86_WIN64 -#define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE) -#define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0) - if (cif->abi == FFI_WIN64) - { - int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3); - FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0], - &ffi_closure_win64, - codeloc, mask); - /* make sure we can execute here */ - } -#else - if (cif->abi == FFI_SYSV) - { - FFI_INIT_TRAMPOLINE (&closure->tramp[0], - &ffi_closure_SYSV, - (void*)codeloc); - } -#ifdef X86_WIN32 - else if (cif->abi == FFI_THISCALL) - { - FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0], - &ffi_closure_THISCALL, - (void*)codeloc, - cif->bytes); - } - else if (cif->abi == FFI_STDCALL) - { - FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0], - &ffi_closure_STDCALL, - (void*)codeloc, cif->bytes); - } - else if (cif->abi == FFI_MS_CDECL) + char *tramp = closure->tramp; + void (*dest)(void); + int op = 0xb8; /* movl imm, %eax */ + + switch (cif->abi) { - FFI_INIT_TRAMPOLINE (&closure->tramp[0], - &ffi_closure_SYSV, - (void*)codeloc); + case FFI_SYSV: + case FFI_THISCALL: + case FFI_FASTCALL: + case FFI_MS_CDECL: + dest = ffi_closure_i386; + break; + case FFI_STDCALL: + case FFI_PASCAL: + dest = ffi_closure_STDCALL; + break; + case FFI_REGISTER: + dest = ffi_closure_REGISTER; + op = 0x68; /* pushl imm */ + default: + return FFI_BAD_ABI; } -#endif /* X86_WIN32 */ -#endif /* !X86_WIN64 */ - else + + /* movl or pushl immediate. */ + tramp[0] = op; + *(void **)(tramp + 1) = codeloc; + + /* jmp dest */ + tramp[5] = 0xe9; + *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10); + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +void FFI_HIDDEN ffi_go_closure_EAX(void); +void FFI_HIDDEN ffi_go_closure_ECX(void); +void FFI_HIDDEN ffi_go_closure_STDCALL(void); + +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*)) +{ + void (*dest)(void); + + switch (cif->abi) { + case FFI_SYSV: + case FFI_MS_CDECL: + dest = ffi_go_closure_ECX; + break; + case FFI_THISCALL: + case FFI_FASTCALL: + dest = ffi_go_closure_EAX; + break; + case FFI_STDCALL: + case FFI_PASCAL: + dest = ffi_go_closure_STDCALL; + break; + case FFI_REGISTER: + default: return FFI_BAD_ABI; } - - closure->cif = cif; - closure->user_data = user_data; - closure->fun = fun; + + closure->tramp = dest; + closure->cif = cif; + closure->fun = fun; return FFI_OK; } @@ -706,138 +581,145 @@ ffi_prep_closure_loc (ffi_closure* closure, #if !FFI_NO_RAW_API +void FFI_HIDDEN ffi_closure_raw_SYSV(void); +void FFI_HIDDEN ffi_closure_raw_THISCALL(void); + ffi_status -ffi_prep_raw_closure_loc (ffi_raw_closure* closure, - ffi_cif* cif, +ffi_prep_raw_closure_loc (ffi_raw_closure *closure, + ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data, void *codeloc) { + char *tramp = closure->tramp; + void (*dest)(void); int i; - if (cif->abi != FFI_SYSV) { -#ifdef X86_WIN32 - if (cif->abi != FFI_THISCALL) -#endif - return FFI_BAD_ABI; - } - - /* we currently don't support certain kinds of arguments for raw + /* We currently don't support certain kinds of arguments for raw closures. This should be implemented by a separate assembly language routine, since it would require argument processing, something we don't do now for performance. */ - for (i = cif->nargs-1; i >= 0; i--) + switch (cif->arg_types[i]->type) + { + case FFI_TYPE_STRUCT: + case FFI_TYPE_LONGDOUBLE: + return FFI_BAD_TYPEDEF; + } + + switch (cif->abi) { - FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT); - FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); - } - -#ifdef X86_WIN32 - if (cif->abi == FFI_SYSV) - { -#endif - FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV, - codeloc); -#ifdef X86_WIN32 - } - else if (cif->abi == FFI_THISCALL) - { - FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0], &ffi_closure_raw_THISCALL, - codeloc, cif->bytes); + case FFI_THISCALL: + dest = ffi_closure_raw_THISCALL; + break; + case FFI_SYSV: + dest = ffi_closure_raw_SYSV; + break; + default: + return FFI_BAD_ABI; } -#endif - closure->cif = cif; + + /* movl imm, %eax. */ + tramp[0] = 0xb8; + *(void **)(tramp + 1) = codeloc; + + /* jmp dest */ + tramp[5] = 0xe9; + *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10); + + closure->cif = cif; + closure->fun = fun; closure->user_data = user_data; - closure->fun = fun; return FFI_OK; } -static void -ffi_prep_args_raw(char *stack, extended_cif *ecif) -{ - memcpy (stack, ecif->avalue, ecif->cif->bytes); -} - -/* we borrow this routine from libffi (it must be changed, though, to - * actually call the function passed in the first argument. as of - * libffi-1.20, this is not the case.) - */ - void -ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue) +ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue) { - extended_cif ecif; - void **avalue = (void **)fake_avalue; - - ecif.cif = cif; - ecif.avalue = avalue; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ - - if (rvalue == NULL - && (cif->flags == FFI_TYPE_STRUCT - || cif->flags == FFI_TYPE_MS_STRUCT)) + size_t rsize, bytes; + struct call_frame *frame; + char *stack, *argp; + ffi_type **arg_types; + int flags, cabi, i, n, narg_reg; + const struct abi_params *pabi; + + flags = cif->flags; + cabi = cif->abi; + pabi = &abi_params[cabi]; + + rsize = 0; + if (rvalue == NULL) { - ecif.rvalue = alloca(cif->rtype->size); + switch (flags) + { + case X86_RET_FLOAT: + case X86_RET_DOUBLE: + case X86_RET_LDOUBLE: + case X86_RET_STRUCTPOP: + case X86_RET_STRUCTARG: + /* The float cases need to pop the 387 stack. + The struct cases need to pass a valid pointer to the callee. */ + rsize = cif->rtype->size; + break; + default: + /* We can pretend that the callee returns nothing. */ + flags = X86_RET_VOID; + break; + } } - else - ecif.rvalue = rvalue; - - - switch (cif->abi) + + bytes = cif->bytes; + argp = stack = alloca(bytes + sizeof(*frame) + rsize); + frame = (struct call_frame *)(stack + bytes); + if (rsize) + rvalue = frame + 1; + + narg_reg = 0; + switch (flags) { -#ifdef X86_WIN32 - case FFI_SYSV: - case FFI_STDCALL: - case FFI_MS_CDECL: - ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags, - ecif.rvalue, fn); - break; - case FFI_THISCALL: - case FFI_FASTCALL: - { - unsigned int abi = cif->abi; - unsigned int i, passed_regs = 0; - - if (cif->flags == FFI_TYPE_STRUCT) - ++passed_regs; - - for (i=0; i < cif->nargs && passed_regs < 2;i++) - { - size_t sz; - - if (cif->arg_types[i]->type == FFI_TYPE_FLOAT - || cif->arg_types[i]->type == FFI_TYPE_STRUCT) - continue; - sz = (cif->arg_types[i]->size + 3) & ~3; - if (sz == 0 || sz > 4) - continue; - ++passed_regs; - } - if (passed_regs < 2 && abi == FFI_FASTCALL) - cif->abi = abi = FFI_THISCALL; - if (passed_regs < 1 && abi == FFI_THISCALL) - cif->abi = abi = FFI_STDCALL; - ffi_call_win32(ffi_prep_args_raw, &ecif, abi, cif->bytes, cif->flags, - ecif.rvalue, fn); - } - break; -#else - case FFI_SYSV: - ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, - ecif.rvalue, fn); - break; -#endif - default: - FFI_ASSERT(0); + case X86_RET_STRUCTARG: + /* The pointer is passed as the first argument. */ + if (pabi->nregs > 0) + { + frame->regs[pabi->regs[0]] = (unsigned)rvalue; + narg_reg = 1; + break; + } + /* fallthru */ + case X86_RET_STRUCTPOP: + *(void **)argp = rvalue; + argp += sizeof(void *); + bytes -= sizeof(void *); break; } -} -#endif + arg_types = cif->arg_types; + for (i = 0, n = cif->nargs; narg_reg < pabi->nregs && i < n; i++) + { + ffi_type *ty = arg_types[i]; + size_t z = ty->size; + int t = ty->type; -#endif /* !__x86_64__ || X86_WIN64 */ + if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT && t != FFI_TYPE_FLOAT) + { + ffi_arg val = extend_basic_type (avalue, t); + frame->regs[pabi->regs[narg_reg++]] = val; + z = FFI_SIZEOF_ARG; + } + else + { + memcpy (argp, avalue, z); + z = ALIGN (z, FFI_SIZEOF_ARG); + argp += z; + } + avalue += z; + bytes -= z; + } + if (i < n) + memcpy (argp, avalue, bytes); + ffi_call_i386 (frame, stack); +} +#endif /* !FFI_NO_RAW_API */ +#endif /* !__x86_64__ */ diff --git a/libffi/src/x86/ffi64.c b/libffi/src/x86/ffi64.c index 1daa1c0..131b5e3 100644 --- a/libffi/src/x86/ffi64.c +++ b/libffi/src/x86/ffi64.c @@ -1,9 +1,10 @@ /* ----------------------------------------------------------------------- - ffi64.c - Copyright (c) 20011 Anthony Green + ffi64.c - Copyright (c) 2013 The Written Word, Inc. + Copyright (c) 2011 Anthony Green Copyright (c) 2008, 2010 Red Hat, Inc. Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de> - - x86-64 Foreign Function Interface + + x86-64 Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -31,27 +32,44 @@ #include <stdlib.h> #include <stdarg.h> +#include <stdint.h> +#include "internal64.h" #ifdef __x86_64__ #define MAX_GPR_REGS 6 #define MAX_SSE_REGS 8 -#ifdef __INTEL_COMPILER +#if defined(__INTEL_COMPILER) +#include "xmmintrin.h" #define UINT128 __m128 #else +#if defined(__SUNPRO_C) +#include <sunmedia_types.h> +#define UINT128 __m128i +#else #define UINT128 __int128_t #endif +#endif + +union big_int_union +{ + UINT32 i32; + UINT64 i64; + UINT128 i128; +}; struct register_args { /* Registers for argument passing. */ UINT64 gpr[MAX_GPR_REGS]; - UINT128 sse[MAX_SSE_REGS]; + union big_int_union sse[MAX_SSE_REGS]; + UINT64 rax; /* ssecount */ + UINT64 r10; /* static chain */ }; extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, - void *raddr, void (*fnaddr)(void), unsigned ssecount); + void *raddr, void (*fnaddr)(void)) FFI_HIDDEN; /* All reference to register classes here is identical to the code in gcc/config/i386/i386.c. Do *not* change one without the other. */ @@ -138,7 +156,7 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) See the x86-64 PS ABI for details. */ -static int +static size_t classify_argument (ffi_type *type, enum x86_64_reg_class classes[], size_t byte_offset) { @@ -153,8 +171,9 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: case FFI_TYPE_POINTER: + do_integer: { - int size = byte_offset + type->size; + size_t size = byte_offset + type->size; if (size <= 4) { @@ -174,7 +193,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], } else if (size <= 16) { - classes[0] = classes[1] = X86_64_INTEGERSI_CLASS; + classes[0] = classes[1] = X86_64_INTEGER_CLASS; return 2; } else @@ -189,15 +208,17 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], case FFI_TYPE_DOUBLE: classes[0] = X86_64_SSEDF_CLASS; return 1; +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: classes[0] = X86_64_X87_CLASS; classes[1] = X86_64_X87UP_CLASS; return 2; +#endif case FFI_TYPE_STRUCT: { - const int UNITS_PER_WORD = 8; - int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; - ffi_type **ptr; + const size_t UNITS_PER_WORD = 8; + size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + ffi_type **ptr; int i; enum x86_64_reg_class subclasses[MAX_CLASSES]; @@ -212,6 +233,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], signalize memory class, so handle it as special case. */ if (!words) { + case FFI_TYPE_VOID: classes[0] = X86_64_NO_CLASS; return 1; } @@ -219,7 +241,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], /* Merge the fields of structure. */ for (ptr = type->elements; *ptr != NULL; ptr++) { - int num; + size_t num; byte_offset = ALIGN (byte_offset, (*ptr)->alignment); @@ -228,7 +250,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], return 0; for (i = 0; i < num; i++) { - int pos = byte_offset / 8; + size_t pos = byte_offset / 8; classes[i + pos] = merge_classes (subclasses[i], classes[i + pos]); } @@ -281,22 +303,54 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], } return words; } - - default: - FFI_ASSERT(0); + case FFI_TYPE_COMPLEX: + { + ffi_type *inner = type->elements[0]; + switch (inner->type) + { + case FFI_TYPE_INT: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + goto do_integer; + + case FFI_TYPE_FLOAT: + classes[0] = X86_64_SSE_CLASS; + if (byte_offset % 8) + { + classes[1] = X86_64_SSESF_CLASS; + return 2; + } + return 1; + case FFI_TYPE_DOUBLE: + classes[0] = classes[1] = X86_64_SSEDF_CLASS; + return 2; +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + classes[0] = X86_64_COMPLEX_X87_CLASS; + return 1; +#endif + } + } } - return 0; /* Never reached. */ + abort(); } /* Examine the argument and return set number of register required in each class. Return zero iff parameter should be passed in memory, otherwise the number of registers. */ -static int +static size_t examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], _Bool in_return, int *pngpr, int *pnsse) { - int i, n, ngpr, nsse; + size_t n; + int i, ngpr, nsse; n = classify_argument (type, classes, 0); if (n == 0) @@ -337,15 +391,59 @@ examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], ffi_status ffi_prep_cif_machdep (ffi_cif *cif) { - int gprcount, ssecount, i, avn, n, ngpr, nsse, flags; + int gprcount, ssecount, i, avn, ngpr, nsse, flags; enum x86_64_reg_class classes[MAX_CLASSES]; - size_t bytes; + size_t bytes, n, rtype_size; + ffi_type *rtype; + + if (cif->abi != FFI_UNIX64) + return FFI_BAD_ABI; gprcount = ssecount = 0; - flags = cif->rtype->type; - if (flags != FFI_TYPE_VOID) + rtype = cif->rtype; + rtype_size = rtype->size; + switch (rtype->type) { + case FFI_TYPE_VOID: + flags = UNIX64_RET_VOID; + break; + case FFI_TYPE_UINT8: + flags = UNIX64_RET_UINT8; + break; + case FFI_TYPE_SINT8: + flags = UNIX64_RET_SINT8; + break; + case FFI_TYPE_UINT16: + flags = UNIX64_RET_UINT16; + break; + case FFI_TYPE_SINT16: + flags = UNIX64_RET_SINT16; + break; + case FFI_TYPE_UINT32: + flags = UNIX64_RET_UINT32; + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + flags = UNIX64_RET_SINT32; + break; + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + flags = UNIX64_RET_INT64; + break; + case FFI_TYPE_POINTER: + flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64); + break; + case FFI_TYPE_FLOAT: + flags = UNIX64_RET_XMM32; + break; + case FFI_TYPE_DOUBLE: + flags = UNIX64_RET_XMM64; + break; + case FFI_TYPE_LONGDOUBLE: + flags = UNIX64_RET_X87; + break; + case FFI_TYPE_STRUCT: n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); if (n == 0) { @@ -353,22 +451,62 @@ ffi_prep_cif_machdep (ffi_cif *cif) memory is the first argument. Allocate a register for it. */ gprcount++; /* We don't have to do anything in asm for the return. */ - flags = FFI_TYPE_VOID; + flags = UNIX64_RET_VOID | UNIX64_FLAG_RET_IN_MEM; } - else if (flags == FFI_TYPE_STRUCT) + else { - /* Mark which registers the result appears in. */ _Bool sse0 = SSE_CLASS_P (classes[0]); - _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]); - if (sse0 && !sse1) - flags |= 1 << 8; - else if (!sse0 && sse1) - flags |= 1 << 9; - else if (sse0 && sse1) - flags |= 1 << 10; - /* Mark the true size of the structure. */ - flags |= cif->rtype->size << 12; + + if (rtype_size == 4 && sse0) + flags = UNIX64_RET_XMM32; + else if (rtype_size == 8) + flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64; + else + { + _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]); + if (sse0 && sse1) + flags = UNIX64_RET_ST_XMM0_XMM1; + else if (sse0) + flags = UNIX64_RET_ST_XMM0_RAX; + else if (sse1) + flags = UNIX64_RET_ST_RAX_XMM0; + else + flags = UNIX64_RET_ST_RAX_RDX; + flags |= rtype_size << UNIX64_SIZE_SHIFT; + } + } + break; + case FFI_TYPE_COMPLEX: + switch (rtype->elements[0]->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + flags = UNIX64_RET_ST_RAX_RDX | (rtype_size << UNIX64_SIZE_SHIFT); + break; + case FFI_TYPE_FLOAT: + flags = UNIX64_RET_XMM64; + break; + case FFI_TYPE_DOUBLE: + flags = UNIX64_RET_ST_XMM0_XMM1 | (16 << UNIX64_SIZE_SHIFT); + break; +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + flags = UNIX64_RET_X87_2; + break; +#endif + default: + return FFI_BAD_TYPEDEF; } + break; + default: + return FFI_BAD_TYPEDEF; } /* Go over all arguments and determine the way they should be passed. @@ -395,44 +533,50 @@ ffi_prep_cif_machdep (ffi_cif *cif) } } if (ssecount) - flags |= 1 << 11; + flags |= UNIX64_FLAG_XMM_ARGS; + cif->flags = flags; cif->bytes = ALIGN (bytes, 8); return FFI_OK; } -void -ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) { enum x86_64_reg_class classes[MAX_CLASSES]; char *stack, *argp; ffi_type **arg_types; - int gprcount, ssecount, ngpr, nsse, i, avn; - _Bool ret_in_memory; + int gprcount, ssecount, ngpr, nsse, i, avn, flags; struct register_args *reg_args; /* Can't call 32-bit mode from 64-bit mode. */ FFI_ASSERT (cif->abi == FFI_UNIX64); /* If the return value is a struct and we don't have a return value - address then we need to make one. Note the setting of flags to - VOID above in ffi_prep_cif_machdep. */ - ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT - && (cif->flags & 0xff) == FFI_TYPE_VOID); - if (rvalue == NULL && ret_in_memory) - rvalue = alloca (cif->rtype->size); + address then we need to make one. Otherwise we can ignore it. */ + flags = cif->flags; + if (rvalue == NULL) + { + if (flags & UNIX64_FLAG_RET_IN_MEM) + rvalue = alloca (cif->rtype->size); + else + flags = UNIX64_RET_VOID; + } /* Allocate the space for the arguments, plus 4 words of temp space. */ stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8); reg_args = (struct register_args *) stack; argp = stack + sizeof (struct register_args); + reg_args->r10 = (uintptr_t) closure; + gprcount = ssecount = 0; /* If the return value is passed in memory, add the pointer as the first integer argument. */ - if (ret_in_memory) + if (flags & UNIX64_FLAG_RET_IN_MEM) reg_args->gpr[gprcount++] = (unsigned long) rvalue; avn = cif->nargs; @@ -440,8 +584,7 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) for (i = 0; i < avn; ++i) { - size_t size = arg_types[i]->size; - int n; + size_t n, size = arg_types[i]->size; n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); if (n == 0 @@ -469,18 +612,38 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { switch (classes[j]) { + case X86_64_NO_CLASS: + case X86_64_SSEUP_CLASS: + break; case X86_64_INTEGER_CLASS: case X86_64_INTEGERSI_CLASS: - reg_args->gpr[gprcount] = 0; - memcpy (®_args->gpr[gprcount], a, size < 8 ? size : 8); + /* Sign-extend integer arguments passed in general + purpose registers, to cope with the fact that + LLVM incorrectly assumes that this will be done + (the x86-64 PS ABI does not specify this). */ + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a); + break; + case FFI_TYPE_SINT16: + reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a); + break; + case FFI_TYPE_SINT32: + reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a); + break; + default: + reg_args->gpr[gprcount] = 0; + memcpy (®_args->gpr[gprcount], a, size); + } gprcount++; break; case X86_64_SSE_CLASS: case X86_64_SSEDF_CLASS: - reg_args->sse[ssecount++] = *(UINT64 *) a; + reg_args->sse[ssecount++].i64 = *(UINT64 *) a; break; case X86_64_SSESF_CLASS: - reg_args->sse[ssecount++] = *(UINT32 *) a; + reg_args->sse[ssecount++].i32 = *(UINT32 *) a; break; default: abort(); @@ -488,13 +651,27 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) } } } + reg_args->rax = ssecount; ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args), - cif->flags, rvalue, fn, ssecount); + flags, rvalue, fn); } +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + ffi_call_int (cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int (cif, fn, rvalue, avalue, closure); +} -extern void ffi_closure_unix64(void); +extern void ffi_closure_unix64(void) FFI_HIDDEN; +extern void ffi_closure_unix64_sse(void) FFI_HIDDEN; ffi_status ffi_prep_closure_loc (ffi_closure* closure, @@ -503,29 +680,27 @@ ffi_prep_closure_loc (ffi_closure* closure, void *user_data, void *codeloc) { - volatile unsigned short *tramp; - - /* Sanity check on the cif ABI. */ - { - int abi = cif->abi; - if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))) - return FFI_BAD_ABI; - } - - tramp = (volatile unsigned short *) &closure->tramp[0]; + static const unsigned char trampoline[16] = { + /* leaq -0x7(%rip),%r10 # 0x0 */ + 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff, + /* jmpq *0x3(%rip) # 0x10 */ + 0xff, 0x25, 0x03, 0x00, 0x00, 0x00, + /* nopl (%rax) */ + 0x0f, 0x1f, 0x00 + }; + void (*dest)(void); + char *tramp = closure->tramp; - tramp[0] = 0xbb49; /* mov <code>, %r11 */ - *((unsigned long long * volatile) &tramp[1]) - = (unsigned long) ffi_closure_unix64; - tramp[5] = 0xba49; /* mov <data>, %r10 */ - *((unsigned long long * volatile) &tramp[6]) - = (unsigned long) codeloc; + if (cif->abi != FFI_UNIX64) + return FFI_BAD_ABI; - /* Set the carry bit iff the function uses any sse registers. - This is clc or stc, together with the first byte of the jmp. */ - tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8; + if (cif->flags & UNIX64_FLAG_XMM_ARGS) + dest = ffi_closure_unix64_sse; + else + dest = ffi_closure_unix64; - tramp[11] = 0xe3ff; /* jmp *%r11 */ + memcpy (tramp, trampoline, sizeof(trampoline)); + *(UINT64 *)(tramp + 16) = (uintptr_t)dest; closure->cif = cif; closure->fun = fun; @@ -534,53 +709,40 @@ ffi_prep_closure_loc (ffi_closure* closure, return FFI_OK; } -int -ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, - struct register_args *reg_args, char *argp) +int FFI_HIDDEN +ffi_closure_unix64_inner(ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *rvalue, + struct register_args *reg_args, + char *argp) { - ffi_cif *cif; void **avalue; ffi_type **arg_types; long i, avn; int gprcount, ssecount, ngpr, nsse; - int ret; + int flags; - cif = closure->cif; - avalue = alloca(cif->nargs * sizeof(void *)); + avn = cif->nargs; + flags = cif->flags; + avalue = alloca(avn * sizeof(void *)); gprcount = ssecount = 0; - ret = cif->rtype->type; - if (ret != FFI_TYPE_VOID) + if (flags & UNIX64_FLAG_RET_IN_MEM) { - enum x86_64_reg_class classes[MAX_CLASSES]; - int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); - if (n == 0) - { - /* The return value goes in memory. Arrange for the closure - return value to go directly back to the original caller. */ - rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++]; - /* We don't have to do anything in asm for the return. */ - ret = FFI_TYPE_VOID; - } - else if (ret == FFI_TYPE_STRUCT && n == 2) - { - /* Mark which register the second word of the structure goes in. */ - _Bool sse0 = SSE_CLASS_P (classes[0]); - _Bool sse1 = SSE_CLASS_P (classes[1]); - if (!sse0 && sse1) - ret |= 1 << 8; - else if (sse0 && !sse1) - ret |= 1 << 9; - } + /* On return, %rax will contain the address that was passed + by the caller in %rdi. */ + void *r = (void *)(uintptr_t)reg_args->gpr[gprcount++]; + *(void **)rvalue = r; + rvalue = r; + flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64); } - avn = cif->nargs; arg_types = cif->arg_types; - for (i = 0; i < avn; ++i) { enum x86_64_reg_class classes[MAX_CLASSES]; - int n; + size_t n; n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); if (n == 0 @@ -634,10 +796,29 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, } /* Invoke the closure. */ - closure->fun (cif, rvalue, avalue, closure->user_data); + fun (cif, rvalue, avalue, user_data); /* Tell assembly how to perform return type promotions. */ - return ret; + return flags; +} + +extern void ffi_go_closure_unix64(void) FFI_HIDDEN; +extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN; + +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*)) +{ + if (cif->abi != FFI_UNIX64) + return FFI_BAD_ABI; + + closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS + ? ffi_go_closure_unix64_sse + : ffi_go_closure_unix64); + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; } #endif /* __x86_64__ */ diff --git a/libffi/src/x86/ffitarget.h b/libffi/src/x86/ffitarget.h index 46f294c..8c1dcac 100644 --- a/libffi/src/x86/ffitarget.h +++ b/libffi/src/x86/ffitarget.h @@ -1,5 +1,5 @@ /* -----------------------------------------------------------------*-C-*- - ffitarget.h - Copyright (c) 2012 Anthony Green + ffitarget.h - Copyright (c) 2012, 2014 Anthony Green Copyright (c) 1996-2003, 2010 Red Hat, Inc. Copyright (C) 2008 Free Software Foundation, Inc. @@ -49,6 +49,11 @@ #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ #endif +#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION +#ifndef _MSC_VER +#define FFI_TARGET_HAS_COMPLEX_TYPE +#endif + /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM @@ -73,37 +78,40 @@ typedef signed long ffi_sarg; #endif typedef enum ffi_abi { +#if defined(X86_WIN64) FFI_FIRST_ABI = 0, - - /* ---- Intel x86 Win32 ---------- */ -#ifdef X86_WIN32 - FFI_SYSV, - FFI_STDCALL, - FFI_THISCALL, - FFI_FASTCALL, - FFI_MS_CDECL, - FFI_LAST_ABI, -#ifdef _MSC_VER - FFI_DEFAULT_ABI = FFI_MS_CDECL -#else - FFI_DEFAULT_ABI = FFI_SYSV -#endif - -#elif defined(X86_WIN64) FFI_WIN64, FFI_LAST_ABI, FFI_DEFAULT_ABI = FFI_WIN64 +#elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) + FFI_FIRST_ABI = 1, + FFI_UNIX64, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_UNIX64 + +#elif defined(X86_WIN32) + FFI_FIRST_ABI = 0, + FFI_SYSV = 1, + FFI_STDCALL = 2, + FFI_THISCALL = 3, + FFI_FASTCALL = 4, + FFI_MS_CDECL = 5, + FFI_PASCAL = 6, + FFI_REGISTER = 7, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_MS_CDECL #else - /* ---- Intel x86 and AMD x86-64 - */ - FFI_SYSV, - FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */ + FFI_FIRST_ABI = 0, + FFI_SYSV = 1, + FFI_THISCALL = 3, + FFI_FASTCALL = 4, + FFI_STDCALL = 5, + FFI_PASCAL = 6, + FFI_REGISTER = 7, + FFI_MS_CDECL = 8, FFI_LAST_ABI, -#if defined(__i386__) || defined(__i386) FFI_DEFAULT_ABI = FFI_SYSV -#else - FFI_DEFAULT_ABI = FFI_UNIX64 -#endif #endif } ffi_abi; #endif @@ -111,29 +119,20 @@ typedef enum ffi_abi { /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 + #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) -#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) -#define FFI_TRAMPOLINE_SIZE 24 -#define FFI_NATIVE_RAW_API 0 +#if defined (X86_64) || defined(X86_WIN64) \ + || (defined (__x86_64__) && defined (X86_DARWIN)) +# define FFI_TRAMPOLINE_SIZE 24 +# define FFI_NATIVE_RAW_API 0 #else -#ifdef X86_WIN32 -#define FFI_TRAMPOLINE_SIZE 52 -#else -#ifdef X86_WIN64 -#define FFI_TRAMPOLINE_SIZE 29 -#define FFI_NATIVE_RAW_API 0 -#define FFI_NO_RAW_API 1 -#else -#define FFI_TRAMPOLINE_SIZE 10 -#endif -#endif -#ifndef X86_WIN64 -#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ -#endif +# define FFI_TRAMPOLINE_SIZE 12 +# define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif diff --git a/libffi/src/x86/ffiw64.c b/libffi/src/x86/ffiw64.c new file mode 100644 index 0000000..8a33a6c --- /dev/null +++ b/libffi/src/x86/ffiw64.c @@ -0,0 +1,281 @@ +/* ----------------------------------------------------------------------- + ffiw64.c - Copyright (c) 2014 Red Hat, Inc. + + x86 win64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> +#include <stdlib.h> +#include <stdint.h> + +#ifdef X86_WIN64 + +struct win64_call_frame +{ + UINT64 rbp; /* 0 */ + UINT64 retaddr; /* 8 */ + UINT64 fn; /* 16 */ + UINT64 flags; /* 24 */ + UINT64 rvalue; /* 32 */ +}; + +extern void ffi_call_win64 (void *stack, struct win64_call_frame *, + void *closure) FFI_HIDDEN; + +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + int flags, n; + + if (cif->abi != FFI_WIN64) + return FFI_BAD_ABI; + + flags = cif->rtype->type; + switch (flags) + { + default: + break; + case FFI_TYPE_LONGDOUBLE: + flags = FFI_TYPE_STRUCT; + break; + case FFI_TYPE_COMPLEX: + flags = FFI_TYPE_STRUCT; + /* FALLTHRU */ + case FFI_TYPE_STRUCT: + switch (cif->rtype->size) + { + case 8: + flags = FFI_TYPE_UINT64; + break; + case 4: + flags = FFI_TYPE_SMALL_STRUCT_4B; + break; + case 2: + flags = FFI_TYPE_SMALL_STRUCT_2B; + break; + case 1: + flags = FFI_TYPE_SMALL_STRUCT_1B; + break; + } + break; + } + cif->flags = flags; + + /* Each argument either fits in a register, an 8 byte slot, or is + passed by reference with the pointer in the 8 byte slot. */ + n = cif->nargs; + n += (flags == FFI_TYPE_STRUCT); + if (n < 4) + n = 4; + cif->bytes = n * 8; + + return FFI_OK; +} + +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + int i, j, n, flags; + UINT64 *stack; + size_t rsize; + struct win64_call_frame *frame; + + FFI_ASSERT(cif->abi == FFI_WIN64); + + flags = cif->flags; + rsize = 0; + + /* If we have no return value for a structure, we need to create one. + Otherwise we can ignore the return type entirely. */ + if (rvalue == NULL) + { + if (flags == FFI_TYPE_STRUCT) + rsize = cif->rtype->size; + else + flags = FFI_TYPE_VOID; + } + + stack = alloca(cif->bytes + sizeof(struct win64_call_frame) + rsize); + frame = (struct win64_call_frame *)((char *)stack + cif->bytes); + if (rsize) + rvalue = frame + 1; + + frame->fn = (uintptr_t)fn; + frame->flags = flags; + frame->rvalue = (uintptr_t)rvalue; + + j = 0; + if (flags == FFI_TYPE_STRUCT) + { + stack[0] = (uintptr_t)rvalue; + j = 1; + } + + for (i = 0, n = cif->nargs; i < n; ++i, ++j) + { + switch (cif->arg_types[i]->size) + { + case 8: + stack[j] = *(UINT64 *)avalue[i]; + break; + case 4: + stack[j] = *(UINT32 *)avalue[i]; + break; + case 2: + stack[j] = *(UINT16 *)avalue[i]; + break; + case 1: + stack[j] = *(UINT8 *)avalue[i]; + break; + default: + stack[j] = (uintptr_t)avalue[i]; + break; + } + } + + ffi_call_win64 (stack, frame, closure); +} + +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + ffi_call_int (cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int (cif, fn, rvalue, avalue, closure); +} + + +extern void ffi_closure_win64(void) FFI_HIDDEN; +extern void ffi_go_closure_win64(void) FFI_HIDDEN; + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + static const unsigned char trampoline[16] = { + /* leaq -0x7(%rip),%r10 # 0x0 */ + 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff, + /* jmpq *0x3(%rip) # 0x10 */ + 0xff, 0x25, 0x03, 0x00, 0x00, 0x00, + /* nopl (%rax) */ + 0x0f, 0x1f, 0x00 + }; + unsigned char *tramp = closure->tramp; + + if (cif->abi != FFI_WIN64) + return FFI_BAD_ABI; + + memcpy (tramp, trampoline, sizeof(trampoline)); + *(UINT64 *)(tramp + 16) = (uintptr_t)ffi_closure_win64; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*)) +{ + if (cif->abi != FFI_WIN64) + return FFI_BAD_ABI; + + closure->tramp = ffi_go_closure_win64; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + +struct win64_closure_frame +{ + UINT64 rvalue[2]; + UINT64 fargs[4]; + UINT64 retaddr; + UINT64 args[]; +}; + +int FFI_HIDDEN +ffi_closure_win64_inner(ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + struct win64_closure_frame *frame) +{ + void **avalue; + void *rvalue; + int i, n, nreg, flags; + + avalue = alloca(cif->nargs * sizeof(void *)); + rvalue = frame->rvalue; + nreg = 0; + + /* When returning a structure, the address is in the first argument. + We must also be prepared to return the same address in eax, so + install that address in the frame and pretend we return a pointer. */ + flags = cif->flags; + if (flags == FFI_TYPE_STRUCT) + { + rvalue = (void *)(uintptr_t)frame->args[0]; + frame->rvalue[0] = frame->args[0]; + nreg = 1; + } + + for (i = 0, n = cif->nargs; i < n; ++i, ++nreg) + { + size_t size = cif->arg_types[i]->size; + size_t type = cif->arg_types[i]->type; + void *a; + + if (type == FFI_TYPE_DOUBLE || type == FFI_TYPE_FLOAT) + { + if (nreg < 4) + a = &frame->fargs[nreg]; + else + a = &frame->args[nreg]; + } + else if (size == 1 || size == 2 || size == 4 || size == 8) + a = &frame->args[nreg]; + else + a = (void *)(uintptr_t)frame->args[nreg]; + + avalue[i] = a; + } + + /* Invoke the closure. */ + fun (cif, rvalue, avalue, user_data); + return flags; +} + +#endif /* X86_WIN64 */ diff --git a/libffi/src/x86/freebsd.S b/libffi/src/x86/freebsd.S deleted file mode 100644 index afde513..0000000 --- a/libffi/src/x86/freebsd.S +++ /dev/null @@ -1,458 +0,0 @@ -/* ----------------------------------------------------------------------- - freebsd.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc. - Copyright (c) 2008 Björn König - - X86 Foreign Function Interface for FreeBSD - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------ */ - -#ifndef __x86_64__ - -#define LIBFFI_ASM -#include <fficonfig.h> -#include <ffi.h> - -.text - -.globl ffi_prep_args - - .align 4 -.globl ffi_call_SYSV - .type ffi_call_SYSV,@function - -ffi_call_SYSV: -.LFB1: - pushl %ebp -.LCFI0: - movl %esp,%ebp -.LCFI1: - /* Make room for all of the new args. */ - movl 16(%ebp),%ecx - subl %ecx,%esp - - movl %esp,%eax - - /* Place all of the ffi_prep_args in position */ - pushl 12(%ebp) - pushl %eax - call *8(%ebp) - - /* Return stack to previous state and call the function */ - addl $8,%esp - - call *28(%ebp) - - /* Load %ecx with the return type code */ - movl 20(%ebp),%ecx - - /* Protect %esi. We're going to pop it in the epilogue. */ - pushl %esi - - /* If the return value pointer is NULL, assume no return value. */ - cmpl $0,24(%ebp) - jne 0f - - /* Even if there is no space for the return value, we are - obliged to handle floating-point values. */ - cmpl $FFI_TYPE_FLOAT,%ecx - jne noretval - fstp %st(0) - - jmp epilogue - -0: - call 1f - -.Lstore_table: - .long noretval-.Lstore_table /* FFI_TYPE_VOID */ - .long retint-.Lstore_table /* FFI_TYPE_INT */ - .long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */ - .long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */ - .long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */ - .long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */ - .long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */ - .long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */ - .long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */ - .long retint-.Lstore_table /* FFI_TYPE_UINT32 */ - .long retint-.Lstore_table /* FFI_TYPE_SINT32 */ - .long retint64-.Lstore_table /* FFI_TYPE_UINT64 */ - .long retint64-.Lstore_table /* FFI_TYPE_SINT64 */ - .long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */ - .long retint-.Lstore_table /* FFI_TYPE_POINTER */ - .long retstruct1b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_1B */ - .long retstruct2b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_2B */ - -1: - pop %esi - add (%esi, %ecx, 4), %esi - jmp *%esi - - /* Sign/zero extend as appropriate. */ -retsint8: - movsbl %al, %eax - jmp retint - -retsint16: - movswl %ax, %eax - jmp retint - -retuint8: - movzbl %al, %eax - jmp retint - -retuint16: - movzwl %ax, %eax - jmp retint - -retfloat: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - fstps (%ecx) - jmp epilogue - -retdouble: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - fstpl (%ecx) - jmp epilogue - -retlongdouble: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - fstpt (%ecx) - jmp epilogue - -retint64: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movl %eax,0(%ecx) - movl %edx,4(%ecx) - jmp epilogue - -retstruct1b: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movb %al,0(%ecx) - jmp epilogue - -retstruct2b: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movw %ax,0(%ecx) - jmp epilogue - -retint: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movl %eax,0(%ecx) - -retstruct: - /* Nothing to do! */ - -noretval: -epilogue: - popl %esi - movl %ebp,%esp - popl %ebp - ret -.LFE1: -.ffi_call_SYSV_end: - .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV - - .align 4 -FFI_HIDDEN (ffi_closure_SYSV) -.globl ffi_closure_SYSV - .type ffi_closure_SYSV, @function - -ffi_closure_SYSV: -.LFB2: - pushl %ebp -.LCFI2: - movl %esp, %ebp -.LCFI3: - subl $40, %esp - leal -24(%ebp), %edx - movl %edx, -12(%ebp) /* resp */ - leal 8(%ebp), %edx - movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ - leal -12(%ebp), %edx - movl %edx, (%esp) /* &resp */ -#if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__ - call ffi_closure_SYSV_inner -#else - movl %ebx, 8(%esp) -.LCFI7: - call 1f -1: popl %ebx - addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx - call ffi_closure_SYSV_inner@PLT - movl 8(%esp), %ebx -#endif - movl -12(%ebp), %ecx - cmpl $FFI_TYPE_INT, %eax - je .Lcls_retint - - /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, - FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ - cmpl $FFI_TYPE_UINT64, %eax - jge 0f - cmpl $FFI_TYPE_UINT8, %eax - jge .Lcls_retint - -0: cmpl $FFI_TYPE_FLOAT, %eax - je .Lcls_retfloat - cmpl $FFI_TYPE_DOUBLE, %eax - je .Lcls_retdouble - cmpl $FFI_TYPE_LONGDOUBLE, %eax - je .Lcls_retldouble - cmpl $FFI_TYPE_SINT64, %eax - je .Lcls_retllong - cmpl $FFI_TYPE_SMALL_STRUCT_1B, %eax - je .Lcls_retstruct1b - cmpl $FFI_TYPE_SMALL_STRUCT_2B, %eax - je .Lcls_retstruct2b - cmpl $FFI_TYPE_STRUCT, %eax - je .Lcls_retstruct -.Lcls_epilogue: - movl %ebp, %esp - popl %ebp - ret -.Lcls_retint: - movl (%ecx), %eax - jmp .Lcls_epilogue -.Lcls_retfloat: - flds (%ecx) - jmp .Lcls_epilogue -.Lcls_retdouble: - fldl (%ecx) - jmp .Lcls_epilogue -.Lcls_retldouble: - fldt (%ecx) - jmp .Lcls_epilogue -.Lcls_retllong: - movl (%ecx), %eax - movl 4(%ecx), %edx - jmp .Lcls_epilogue -.Lcls_retstruct1b: - movsbl (%ecx), %eax - jmp .Lcls_epilogue -.Lcls_retstruct2b: - movswl (%ecx), %eax - jmp .Lcls_epilogue -.Lcls_retstruct: - movl %ebp, %esp - popl %ebp - ret $4 -.LFE2: - .size ffi_closure_SYSV, .-ffi_closure_SYSV - -#if !FFI_NO_RAW_API - -#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) -#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) -#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) -#define CIF_FLAGS_OFFSET 20 - - .align 4 -FFI_HIDDEN (ffi_closure_raw_SYSV) -.globl ffi_closure_raw_SYSV - .type ffi_closure_raw_SYSV, @function - -ffi_closure_raw_SYSV: -.LFB3: - pushl %ebp -.LCFI4: - movl %esp, %ebp -.LCFI5: - pushl %esi -.LCFI6: - subl $36, %esp - movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ - movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ - movl %edx, 12(%esp) /* user_data */ - leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ - movl %edx, 8(%esp) /* raw_args */ - leal -24(%ebp), %edx - movl %edx, 4(%esp) /* &res */ - movl %esi, (%esp) /* cif */ - call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ - movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ - cmpl $FFI_TYPE_INT, %eax - je .Lrcls_retint - - /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, - FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ - cmpl $FFI_TYPE_UINT64, %eax - jge 0f - cmpl $FFI_TYPE_UINT8, %eax - jge .Lrcls_retint -0: - cmpl $FFI_TYPE_FLOAT, %eax - je .Lrcls_retfloat - cmpl $FFI_TYPE_DOUBLE, %eax - je .Lrcls_retdouble - cmpl $FFI_TYPE_LONGDOUBLE, %eax - je .Lrcls_retldouble - cmpl $FFI_TYPE_SINT64, %eax - je .Lrcls_retllong -.Lrcls_epilogue: - addl $36, %esp - popl %esi - popl %ebp - ret -.Lrcls_retint: - movl -24(%ebp), %eax - jmp .Lrcls_epilogue -.Lrcls_retfloat: - flds -24(%ebp) - jmp .Lrcls_epilogue -.Lrcls_retdouble: - fldl -24(%ebp) - jmp .Lrcls_epilogue -.Lrcls_retldouble: - fldt -24(%ebp) - jmp .Lrcls_epilogue -.Lrcls_retllong: - movl -24(%ebp), %eax - movl -20(%ebp), %edx - jmp .Lrcls_epilogue -.LFE3: - .size ffi_closure_raw_SYSV, .-ffi_closure_raw_SYSV -#endif - - .section .eh_frame,EH_FRAME_FLAGS,@progbits -.Lframe1: - .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */ -.LSCIE1: - .long 0x0 /* CIE Identifier Tag */ - .byte 0x1 /* CIE Version */ -#ifdef __PIC__ - .ascii "zR\0" /* CIE Augmentation */ -#else - .ascii "\0" /* CIE Augmentation */ -#endif - .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */ - .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ - .byte 0x8 /* CIE RA Column */ -#ifdef __PIC__ - .byte 0x1 /* .uleb128 0x1; Augmentation size */ - .byte 0x1b /* FDE Encoding (pcrel sdata4) */ -#endif - .byte 0xc /* DW_CFA_def_cfa */ - .byte 0x4 /* .uleb128 0x4 */ - .byte 0x4 /* .uleb128 0x4 */ - .byte 0x88 /* DW_CFA_offset, column 0x8 */ - .byte 0x1 /* .uleb128 0x1 */ - .align 4 -.LECIE1: -.LSFDE1: - .long .LEFDE1-.LASFDE1 /* FDE Length */ -.LASFDE1: - .long .LASFDE1-.Lframe1 /* FDE CIE offset */ -#ifdef __PIC__ - .long .LFB1-. /* FDE initial location */ -#else - .long .LFB1 /* FDE initial location */ -#endif - .long .LFE1-.LFB1 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ -#endif - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI0-.LFB1 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 */ - .byte 0x2 /* .uleb128 0x2 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI1-.LCFI0 - .byte 0xd /* DW_CFA_def_cfa_register */ - .byte 0x5 /* .uleb128 0x5 */ - .align 4 -.LEFDE1: -.LSFDE2: - .long .LEFDE2-.LASFDE2 /* FDE Length */ -.LASFDE2: - .long .LASFDE2-.Lframe1 /* FDE CIE offset */ -#ifdef __PIC__ - .long .LFB2-. /* FDE initial location */ -#else - .long .LFB2 -#endif - .long .LFE2-.LFB2 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ -#endif - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI2-.LFB2 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 */ - .byte 0x2 /* .uleb128 0x2 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI3-.LCFI2 - .byte 0xd /* DW_CFA_def_cfa_register */ - .byte 0x5 /* .uleb128 0x5 */ -#if !defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE && defined __PIC__ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI7-.LCFI3 - .byte 0x83 /* DW_CFA_offset, column 0x3 */ - .byte 0xa /* .uleb128 0xa */ -#endif - .align 4 -.LEFDE2: - -#if !FFI_NO_RAW_API - -.LSFDE3: - .long .LEFDE3-.LASFDE3 /* FDE Length */ -.LASFDE3: - .long .LASFDE3-.Lframe1 /* FDE CIE offset */ -#ifdef __PIC__ - .long .LFB3-. /* FDE initial location */ -#else - .long .LFB3 -#endif - .long .LFE3-.LFB3 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ -#endif - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI4-.LFB3 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 */ - .byte 0x2 /* .uleb128 0x2 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI5-.LCFI4 - .byte 0xd /* DW_CFA_def_cfa_register */ - .byte 0x5 /* .uleb128 0x5 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI6-.LCFI5 - .byte 0x86 /* DW_CFA_offset, column 0x6 */ - .byte 0x3 /* .uleb128 0x3 */ - .align 4 -.LEFDE3: - -#endif - -#endif /* ifndef __x86_64__ */ diff --git a/libffi/src/x86/internal.h b/libffi/src/x86/internal.h new file mode 100644 index 0000000..09771ba --- /dev/null +++ b/libffi/src/x86/internal.h @@ -0,0 +1,29 @@ +#define X86_RET_FLOAT 0 +#define X86_RET_DOUBLE 1 +#define X86_RET_LDOUBLE 2 +#define X86_RET_SINT8 3 +#define X86_RET_SINT16 4 +#define X86_RET_UINT8 5 +#define X86_RET_UINT16 6 +#define X86_RET_INT64 7 +#define X86_RET_INT32 8 +#define X86_RET_VOID 9 +#define X86_RET_STRUCTPOP 10 +#define X86_RET_STRUCTARG 11 +#define X86_RET_STRUCT_1B 12 +#define X86_RET_STRUCT_2B 13 +#define X86_RET_UNUSED14 14 +#define X86_RET_UNUSED15 15 + +#define X86_RET_TYPE_MASK 15 +#define X86_RET_POP_SHIFT 4 + +#define R_EAX 0 +#define R_EDX 1 +#define R_ECX 2 + +#ifdef __PCC__ +# define HAVE_FASTCALL 0 +#else +# define HAVE_FASTCALL 1 +#endif diff --git a/libffi/src/x86/internal64.h b/libffi/src/x86/internal64.h new file mode 100644 index 0000000..512e955 --- /dev/null +++ b/libffi/src/x86/internal64.h @@ -0,0 +1,22 @@ +#define UNIX64_RET_VOID 0 +#define UNIX64_RET_UINT8 1 +#define UNIX64_RET_UINT16 2 +#define UNIX64_RET_UINT32 3 +#define UNIX64_RET_SINT8 4 +#define UNIX64_RET_SINT16 5 +#define UNIX64_RET_SINT32 6 +#define UNIX64_RET_INT64 7 +#define UNIX64_RET_XMM32 8 +#define UNIX64_RET_XMM64 9 +#define UNIX64_RET_X87 10 +#define UNIX64_RET_X87_2 11 +#define UNIX64_RET_ST_XMM0_RAX 12 +#define UNIX64_RET_ST_RAX_XMM0 13 +#define UNIX64_RET_ST_XMM0_XMM1 14 +#define UNIX64_RET_ST_RAX_RDX 15 + +#define UNIX64_RET_LAST 15 + +#define UNIX64_FLAG_RET_IN_MEM (1 << 10) +#define UNIX64_FLAG_XMM_ARGS (1 << 11) +#define UNIX64_SIZE_SHIFT 12 diff --git a/libffi/src/x86/sysv.S b/libffi/src/x86/sysv.S index f108dd8..ebbea5d 100644 --- a/libffi/src/x86/sysv.S +++ b/libffi/src/x86/sysv.S @@ -1,5 +1,6 @@ /* ----------------------------------------------------------------------- - sysv.S - Copyright (c) 1996, 1998, 2001-2003, 2005, 2008, 2010 Red Hat, Inc. + sysv.S - Copyright (c) 2013 The Written Word, Inc. + - Copyright (c) 1996,1998,2001-2003,2005,2008,2010 Red Hat, Inc. X86 Foreign Function Interface @@ -29,437 +30,1006 @@ #define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> +#include "internal.h" -.text - -.globl ffi_prep_args - - .align 4 -.globl ffi_call_SYSV - .type ffi_call_SYSV,@function - -ffi_call_SYSV: -.LFB1: - pushl %ebp -.LCFI0: - movl %esp,%ebp -.LCFI1: - /* Make room for all of the new args. */ - movl 16(%ebp),%ecx - subl %ecx,%esp - - /* Align the stack pointer to 16-bytes */ - andl $0xfffffff0, %esp - - movl %esp,%eax - - /* Place all of the ffi_prep_args in position */ - pushl 12(%ebp) - pushl %eax - call *8(%ebp) - - /* Return stack to previous state and call the function */ - addl $8,%esp - - call *28(%ebp) - - /* Load %ecx with the return type code */ - movl 20(%ebp),%ecx - - /* Protect %esi. We're going to pop it in the epilogue. */ - pushl %esi - - /* If the return value pointer is NULL, assume no return value. */ - cmpl $0,24(%ebp) - jne 0f - - /* Even if there is no space for the return value, we are - obliged to handle floating-point values. */ - cmpl $FFI_TYPE_FLOAT,%ecx - jne noretval - fstp %st(0) - - jmp epilogue - -0: - call 1f - -.Lstore_table: - .long noretval-.Lstore_table /* FFI_TYPE_VOID */ - .long retint-.Lstore_table /* FFI_TYPE_INT */ - .long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */ - .long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */ - .long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */ - .long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */ - .long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */ - .long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */ - .long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */ - .long retint-.Lstore_table /* FFI_TYPE_UINT32 */ - .long retint-.Lstore_table /* FFI_TYPE_SINT32 */ - .long retint64-.Lstore_table /* FFI_TYPE_UINT64 */ - .long retint64-.Lstore_table /* FFI_TYPE_SINT64 */ - .long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */ - .long retint-.Lstore_table /* FFI_TYPE_POINTER */ - -1: - pop %esi - add (%esi, %ecx, 4), %esi - jmp *%esi - - /* Sign/zero extend as appropriate. */ -retsint8: - movsbl %al, %eax - jmp retint +#define C2(X, Y) X ## Y +#define C1(X, Y) C2(X, Y) +#ifdef __USER_LABEL_PREFIX__ +# define C(X) C1(__USER_LABEL_PREFIX__, X) +#else +# define C(X) X +#endif -retsint16: - movswl %ax, %eax - jmp retint +#ifdef X86_DARWIN +# define L(X) C1(L, X) +#else +# define L(X) C1(.L, X) +#endif -retuint8: - movzbl %al, %eax - jmp retint +#ifdef __ELF__ +# define ENDF(X) .type X,@function; .size X, . - X +#else +# define ENDF(X) +#endif -retuint16: - movzwl %ax, %eax - jmp retint - -retfloat: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - fstps (%ecx) - jmp epilogue - -retdouble: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - fstpl (%ecx) - jmp epilogue - -retlongdouble: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - fstpt (%ecx) - jmp epilogue - -retint64: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movl %eax,0(%ecx) - movl %edx,4(%ecx) - jmp epilogue - -retint: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movl %eax,0(%ecx) - -retstruct: - /* Nothing to do! */ - -noretval: -epilogue: - popl %esi - movl %ebp,%esp - popl %ebp - ret -.LFE1: -.ffi_call_SYSV_end: - .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV - - .align 4 -FFI_HIDDEN (ffi_closure_SYSV) -.globl ffi_closure_SYSV - .type ffi_closure_SYSV, @function - -ffi_closure_SYSV: -.LFB2: - pushl %ebp -.LCFI2: - movl %esp, %ebp -.LCFI3: - subl $40, %esp - leal -24(%ebp), %edx - movl %edx, -12(%ebp) /* resp */ - leal 8(%ebp), %edx - movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ - leal -12(%ebp), %edx - movl %edx, (%esp) /* &resp */ -#if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__ - call ffi_closure_SYSV_inner +/* Handle win32 fastcall name mangling. */ +#ifdef X86_WIN32 +# define ffi_call_i386 @ffi_call_i386@8 +# define ffi_closure_inner @ffi_closure_inner@8 #else - movl %ebx, 8(%esp) -.LCFI7: - call 1f -1: popl %ebx - addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx - call ffi_closure_SYSV_inner@PLT - movl 8(%esp), %ebx +# define ffi_call_i386 C(ffi_call_i386) +# define ffi_closure_inner C(ffi_closure_inner) #endif - movl -12(%ebp), %ecx - cmpl $FFI_TYPE_INT, %eax - je .Lcls_retint - - /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, - FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ - cmpl $FFI_TYPE_UINT64, %eax - jge 0f - cmpl $FFI_TYPE_UINT8, %eax - jge .Lcls_retint - -0: cmpl $FFI_TYPE_FLOAT, %eax - je .Lcls_retfloat - cmpl $FFI_TYPE_DOUBLE, %eax - je .Lcls_retdouble - cmpl $FFI_TYPE_LONGDOUBLE, %eax - je .Lcls_retldouble - cmpl $FFI_TYPE_SINT64, %eax - je .Lcls_retllong - cmpl $FFI_TYPE_STRUCT, %eax - je .Lcls_retstruct -.Lcls_epilogue: - movl %ebp, %esp - popl %ebp - ret -.Lcls_retint: - movl (%ecx), %eax - jmp .Lcls_epilogue -.Lcls_retfloat: - flds (%ecx) - jmp .Lcls_epilogue -.Lcls_retdouble: - fldl (%ecx) - jmp .Lcls_epilogue -.Lcls_retldouble: - fldt (%ecx) - jmp .Lcls_epilogue -.Lcls_retllong: - movl (%ecx), %eax - movl 4(%ecx), %edx - jmp .Lcls_epilogue -.Lcls_retstruct: - movl %ebp, %esp - popl %ebp - ret $4 -.LFE2: - .size ffi_closure_SYSV, .-ffi_closure_SYSV -#if !FFI_NO_RAW_API +/* This macro allows the safe creation of jump tables without an + actual table. The entry points into the table are all 8 bytes. + The use of ORG asserts that we're at the correct location. */ +/* ??? The clang assembler doesn't handle .org with symbolic expressions. */ +#if defined(__clang__) || defined(__APPLE__) +# define E(BASE, X) .balign 8 +#else +# define E(BASE, X) .balign 8; .org BASE + X * 8 +#endif + + .text + .balign 16 + .globl ffi_call_i386 + FFI_HIDDEN(ffi_call_i386) + +/* This is declared as + + void ffi_call_i386(struct call_frame *frame, char *argp) + __attribute__((fastcall)); + + Thus the arguments are present in + + ecx: frame + edx: argp +*/ + +ffi_call_i386: +L(UW0): + # cfi_startproc +#if !HAVE_FASTCALL + movl 4(%esp), %ecx + movl 8(%esp), %edx +#endif + movl (%esp), %eax /* move the return address */ + movl %ebp, (%ecx) /* store %ebp into local frame */ + movl %eax, 4(%ecx) /* store retaddr into local frame */ + + /* New stack frame based off ebp. This is a itty bit of unwind + trickery in that the CFA *has* changed. There is no easy way + to describe it correctly on entry to the function. Fortunately, + it doesn't matter too much since at all points we can correctly + unwind back to ffi_call. Note that the location to which we + moved the return address is (the new) CFA-4, so from the + perspective of the unwind info, it hasn't moved. */ + movl %ecx, %ebp +L(UW1): + # cfi_def_cfa(%ebp, 8) + # cfi_rel_offset(%ebp, 0) -/* Precalculate for e.g. the Solaris 10/x86 assembler. */ -#if FFI_TRAMPOLINE_SIZE == 10 -#define RAW_CLOSURE_CIF_OFFSET 12 -#define RAW_CLOSURE_FUN_OFFSET 16 -#define RAW_CLOSURE_USER_DATA_OFFSET 20 -#elif FFI_TRAMPOLINE_SIZE == 24 -#define RAW_CLOSURE_CIF_OFFSET 24 -#define RAW_CLOSURE_FUN_OFFSET 28 -#define RAW_CLOSURE_USER_DATA_OFFSET 32 + movl %edx, %esp /* set outgoing argument stack */ + movl 20+R_EAX*4(%ebp), %eax /* set register arguments */ + movl 20+R_EDX*4(%ebp), %edx + movl 20+R_ECX*4(%ebp), %ecx + + call *8(%ebp) + + movl 12(%ebp), %ecx /* load return type code */ + movl %ebx, 8(%ebp) /* preserve %ebx */ +L(UW2): + # cfi_rel_offset(%ebx, 8) + + andl $X86_RET_TYPE_MASK, %ecx +#ifdef __PIC__ + call C(__x86.get_pc_thunk.bx) +L(pc1): + leal L(store_table)-L(pc1)(%ebx, %ecx, 8), %ebx #else -#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) -#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) -#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) + leal L(store_table)(,%ecx, 8), %ebx #endif -#define CIF_FLAGS_OFFSET 20 - - .align 4 -FFI_HIDDEN (ffi_closure_raw_SYSV) -.globl ffi_closure_raw_SYSV - .type ffi_closure_raw_SYSV, @function - -ffi_closure_raw_SYSV: -.LFB3: - pushl %ebp -.LCFI4: - movl %esp, %ebp -.LCFI5: - pushl %esi -.LCFI6: - subl $36, %esp - movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ - movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ - movl %edx, 12(%esp) /* user_data */ - leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ - movl %edx, 8(%esp) /* raw_args */ - leal -24(%ebp), %edx - movl %edx, 4(%esp) /* &res */ - movl %esi, (%esp) /* cif */ - call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ - movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ - cmpl $FFI_TYPE_INT, %eax - je .Lrcls_retint - - /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, - FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ - cmpl $FFI_TYPE_UINT64, %eax - jge 0f - cmpl $FFI_TYPE_UINT8, %eax - jge .Lrcls_retint -0: - cmpl $FFI_TYPE_FLOAT, %eax - je .Lrcls_retfloat - cmpl $FFI_TYPE_DOUBLE, %eax - je .Lrcls_retdouble - cmpl $FFI_TYPE_LONGDOUBLE, %eax - je .Lrcls_retldouble - cmpl $FFI_TYPE_SINT64, %eax - je .Lrcls_retllong -.Lrcls_epilogue: - addl $36, %esp - popl %esi + movl 16(%ebp), %ecx /* load result address */ + jmp *%ebx + + .balign 8 +L(store_table): +E(L(store_table), X86_RET_FLOAT) + fstps (%ecx) + jmp L(e1) +E(L(store_table), X86_RET_DOUBLE) + fstpl (%ecx) + jmp L(e1) +E(L(store_table), X86_RET_LDOUBLE) + fstpt (%ecx) + jmp L(e1) +E(L(store_table), X86_RET_SINT8) + movsbl %al, %eax + mov %eax, (%ecx) + jmp L(e1) +E(L(store_table), X86_RET_SINT16) + movswl %ax, %eax + mov %eax, (%ecx) + jmp L(e1) +E(L(store_table), X86_RET_UINT8) + movzbl %al, %eax + mov %eax, (%ecx) + jmp L(e1) +E(L(store_table), X86_RET_UINT16) + movzwl %ax, %eax + mov %eax, (%ecx) + jmp L(e1) +E(L(store_table), X86_RET_INT64) + movl %edx, 4(%ecx) + /* fallthru */ +E(L(store_table), X86_RET_INT32) + movl %eax, (%ecx) + /* fallthru */ +E(L(store_table), X86_RET_VOID) +L(e1): + movl 8(%ebp), %ebx + movl %ebp, %esp popl %ebp +L(UW3): + # cfi_remember_state + # cfi_def_cfa(%esp, 4) + # cfi_restore(%ebx) + # cfi_restore(%ebp) ret -.Lrcls_retint: - movl -24(%ebp), %eax - jmp .Lrcls_epilogue -.Lrcls_retfloat: - flds -24(%ebp) - jmp .Lrcls_epilogue -.Lrcls_retdouble: - fldl -24(%ebp) - jmp .Lrcls_epilogue -.Lrcls_retldouble: - fldt -24(%ebp) - jmp .Lrcls_epilogue -.Lrcls_retllong: - movl -24(%ebp), %eax - movl -20(%ebp), %edx - jmp .Lrcls_epilogue -.LFE3: - .size ffi_closure_raw_SYSV, .-ffi_closure_raw_SYSV +L(UW4): + # cfi_restore_state + +E(L(store_table), X86_RET_STRUCTPOP) + jmp L(e1) +E(L(store_table), X86_RET_STRUCTARG) + jmp L(e1) +E(L(store_table), X86_RET_STRUCT_1B) + movb %al, (%ecx) + jmp L(e1) +E(L(store_table), X86_RET_STRUCT_2B) + movw %ax, (%ecx) + jmp L(e1) + + /* Fill out the table so that bad values are predictable. */ +E(L(store_table), X86_RET_UNUSED14) + ud2 +E(L(store_table), X86_RET_UNUSED15) + ud2 + +L(UW5): + # cfi_endproc +ENDF(ffi_call_i386) + +/* The inner helper is declared as + + void ffi_closure_inner(struct closure_frame *frame, char *argp) + __attribute_((fastcall)) + + Thus the arguments are placed in + + ecx: frame + edx: argp +*/ + +/* Macros to help setting up the closure_data structure. */ + +#if HAVE_FASTCALL +# define closure_FS (40 + 4) +# define closure_CF 0 +#else +# define closure_FS (8 + 40 + 12) +# define closure_CF 8 #endif -#if defined __PIC__ -# if defined __sun__ && defined __svr4__ -/* 32-bit Solaris 2/x86 uses datarel encoding for PIC. GNU ld before 2.22 - doesn't correctly sort .eh_frame_hdr with mixed encodings, so match this. */ -# define FDE_ENCODING 0x30 /* datarel */ -# define FDE_ENCODE(X) X@GOTOFF -# else -# define FDE_ENCODING 0x1b /* pcrel sdata4 */ -# if defined HAVE_AS_X86_PCREL -# define FDE_ENCODE(X) X-. -# else -# define FDE_ENCODE(X) X@rel -# endif -# endif +#define FFI_CLOSURE_SAVE_REGS \ + movl %eax, closure_CF+16+R_EAX*4(%esp); \ + movl %edx, closure_CF+16+R_EDX*4(%esp); \ + movl %ecx, closure_CF+16+R_ECX*4(%esp) + +#define FFI_CLOSURE_COPY_TRAMP_DATA \ + movl FFI_TRAMPOLINE_SIZE(%eax), %edx; /* copy cif */ \ + movl FFI_TRAMPOLINE_SIZE+4(%eax), %ecx; /* copy fun */ \ + movl FFI_TRAMPOLINE_SIZE+8(%eax), %eax; /* copy user_data */ \ + movl %edx, closure_CF+28(%esp); \ + movl %ecx, closure_CF+32(%esp); \ + movl %eax, closure_CF+36(%esp) + +#if HAVE_FASTCALL +# define FFI_CLOSURE_PREP_CALL \ + movl %esp, %ecx; /* load closure_data */ \ + leal closure_FS+4(%esp), %edx; /* load incoming stack */ #else -# define FDE_ENCODING 0 /* absolute */ -# define FDE_ENCODE(X) X +# define FFI_CLOSURE_PREP_CALL \ + leal closure_CF(%esp), %ecx; /* load closure_data */ \ + leal closure_FS+4(%esp), %edx; /* load incoming stack */ \ + movl %ecx, (%esp); \ + movl %edx, 4(%esp) #endif - .section .eh_frame,EH_FRAME_FLAGS,@progbits -.Lframe1: - .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */ -.LSCIE1: - .long 0x0 /* CIE Identifier Tag */ - .byte 0x1 /* CIE Version */ -#ifdef HAVE_AS_ASCII_PSEUDO_OP +#define FFI_CLOSURE_CALL_INNER(UWN) \ + call ffi_closure_inner + +#define FFI_CLOSURE_MASK_AND_JUMP(N, UW) \ + andl $X86_RET_TYPE_MASK, %eax; \ + leal L(C1(load_table,N))(, %eax, 8), %edx; \ + movl closure_CF(%esp), %eax; /* optimiztic load */ \ + jmp *%edx + #ifdef __PIC__ - .ascii "zR\0" /* CIE Augmentation */ +# if defined X86_DARWIN || defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE +# undef FFI_CLOSURE_MASK_AND_JUMP +# define FFI_CLOSURE_MASK_AND_JUMP(N, UW) \ + andl $X86_RET_TYPE_MASK, %eax; \ + call C(__x86.get_pc_thunk.dx); \ +L(C1(pc,N)): \ + leal L(C1(load_table,N))-L(C1(pc,N))(%edx, %eax, 8), %edx; \ + movl closure_CF(%esp), %eax; /* optimiztic load */ \ + jmp *%edx +# else +# define FFI_CLOSURE_CALL_INNER_SAVE_EBX +# undef FFI_CLOSURE_CALL_INNER +# define FFI_CLOSURE_CALL_INNER(UWN) \ + movl %ebx, 40(%esp); /* save ebx */ \ +L(C1(UW,UWN)): \ + # cfi_rel_offset(%ebx, 40); \ + call C(__x86.get_pc_thunk.bx); /* load got register */ \ + addl $C(_GLOBAL_OFFSET_TABLE_), %ebx; \ + call ffi_closure_inner@PLT +# undef FFI_CLOSURE_MASK_AND_JUMP +# define FFI_CLOSURE_MASK_AND_JUMP(N, UWN) \ + andl $X86_RET_TYPE_MASK, %eax; \ + leal L(C1(load_table,N))@GOTOFF(%ebx, %eax, 8), %edx; \ + movl 40(%esp), %ebx; /* restore ebx */ \ +L(C1(UW,UWN)): \ + # cfi_restore(%ebx); \ + movl closure_CF(%esp), %eax; /* optimiztic load */ \ + jmp *%edx +# endif /* DARWIN || HIDDEN */ +#endif /* __PIC__ */ + + .balign 16 + .globl C(ffi_go_closure_EAX) + FFI_HIDDEN(C(ffi_go_closure_EAX)) +C(ffi_go_closure_EAX): +L(UW6): + # cfi_startproc + subl $closure_FS, %esp +L(UW7): + # cfi_def_cfa_offset(closure_FS + 4) + FFI_CLOSURE_SAVE_REGS + movl 4(%eax), %edx /* copy cif */ + movl 8(%eax), %ecx /* copy fun */ + movl %edx, closure_CF+28(%esp) + movl %ecx, closure_CF+32(%esp) + movl %eax, closure_CF+36(%esp) /* closure is user_data */ + jmp L(do_closure_i386) +L(UW8): + # cfi_endproc +ENDF(C(ffi_go_closure_EAX)) + + .balign 16 + .globl C(ffi_go_closure_ECX) + FFI_HIDDEN(C(ffi_go_closure_ECX)) +C(ffi_go_closure_ECX): +L(UW9): + # cfi_startproc + subl $closure_FS, %esp +L(UW10): + # cfi_def_cfa_offset(closure_FS + 4) + FFI_CLOSURE_SAVE_REGS + movl 4(%ecx), %edx /* copy cif */ + movl 8(%ecx), %eax /* copy fun */ + movl %edx, closure_CF+28(%esp) + movl %eax, closure_CF+32(%esp) + movl %ecx, closure_CF+36(%esp) /* closure is user_data */ + jmp L(do_closure_i386) +L(UW11): + # cfi_endproc +ENDF(C(ffi_go_closure_ECX)) + +/* The closure entry points are reached from the ffi_closure trampoline. + On entry, %eax contains the address of the ffi_closure. */ + + .balign 16 + .globl C(ffi_closure_i386) + FFI_HIDDEN(C(ffi_closure_i386)) + +C(ffi_closure_i386): +L(UW12): + # cfi_startproc + subl $closure_FS, %esp +L(UW13): + # cfi_def_cfa_offset(closure_FS + 4) + + FFI_CLOSURE_SAVE_REGS + FFI_CLOSURE_COPY_TRAMP_DATA + + /* Entry point from preceeding Go closures. */ +L(do_closure_i386): + + FFI_CLOSURE_PREP_CALL + FFI_CLOSURE_CALL_INNER(14) + FFI_CLOSURE_MASK_AND_JUMP(2, 15) + + .balign 8 +L(load_table2): +E(L(load_table2), X86_RET_FLOAT) + flds closure_CF(%esp) + jmp L(e2) +E(L(load_table2), X86_RET_DOUBLE) + fldl closure_CF(%esp) + jmp L(e2) +E(L(load_table2), X86_RET_LDOUBLE) + fldt closure_CF(%esp) + jmp L(e2) +E(L(load_table2), X86_RET_SINT8) + movsbl %al, %eax + jmp L(e2) +E(L(load_table2), X86_RET_SINT16) + movswl %ax, %eax + jmp L(e2) +E(L(load_table2), X86_RET_UINT8) + movzbl %al, %eax + jmp L(e2) +E(L(load_table2), X86_RET_UINT16) + movzwl %ax, %eax + jmp L(e2) +E(L(load_table2), X86_RET_INT64) + movl closure_CF+4(%esp), %edx + jmp L(e2) +E(L(load_table2), X86_RET_INT32) + nop + /* fallthru */ +E(L(load_table2), X86_RET_VOID) +L(e2): + addl $closure_FS, %esp +L(UW16): + # cfi_adjust_cfa_offset(-closure_FS) + ret +L(UW17): + # cfi_adjust_cfa_offset(closure_FS) +E(L(load_table2), X86_RET_STRUCTPOP) + addl $closure_FS, %esp +L(UW18): + # cfi_adjust_cfa_offset(-closure_FS) + ret $4 +L(UW19): + # cfi_adjust_cfa_offset(closure_FS) +E(L(load_table2), X86_RET_STRUCTARG) + jmp L(e2) +E(L(load_table2), X86_RET_STRUCT_1B) + movzbl %al, %eax + jmp L(e2) +E(L(load_table2), X86_RET_STRUCT_2B) + movzwl %ax, %eax + jmp L(e2) + + /* Fill out the table so that bad values are predictable. */ +E(L(load_table2), X86_RET_UNUSED14) + ud2 +E(L(load_table2), X86_RET_UNUSED15) + ud2 + +L(UW20): + # cfi_endproc +ENDF(C(ffi_closure_i386)) + + .balign 16 + .globl C(ffi_go_closure_STDCALL) + FFI_HIDDEN(C(ffi_go_closure_STDCALL)) +C(ffi_go_closure_STDCALL): +L(UW21): + # cfi_startproc + subl $closure_FS, %esp +L(UW22): + # cfi_def_cfa_offset(closure_FS + 4) + FFI_CLOSURE_SAVE_REGS + movl 4(%ecx), %edx /* copy cif */ + movl 8(%ecx), %eax /* copy fun */ + movl %edx, closure_CF+28(%esp) + movl %eax, closure_CF+32(%esp) + movl %ecx, closure_CF+36(%esp) /* closure is user_data */ + jmp L(do_closure_STDCALL) +L(UW23): + # cfi_endproc +ENDF(C(ffi_go_closure_STDCALL)) + +/* For REGISTER, we have no available parameter registers, and so we + enter here having pushed the closure onto the stack. */ + + .balign 16 + .globl C(ffi_closure_REGISTER) + FFI_HIDDEN(C(ffi_closure_REGISTER)) +C(ffi_closure_REGISTER): +L(UW24): + # cfi_startproc + # cfi_def_cfa(%esp, 8) + # cfi_offset(%eip, -8) + subl $closure_FS-4, %esp +L(UW25): + # cfi_def_cfa_offset(closure_FS + 4) + FFI_CLOSURE_SAVE_REGS + movl closure_FS-4(%esp), %ecx /* load retaddr */ + movl closure_FS(%esp), %eax /* load closure */ + movl %ecx, closure_FS(%esp) /* move retaddr */ + jmp L(do_closure_REGISTER) +L(UW26): + # cfi_endproc +ENDF(C(ffi_closure_REGISTER)) + +/* For STDCALL (and others), we need to pop N bytes of arguments off + the stack following the closure. The amount needing to be popped + is returned to us from ffi_closure_inner. */ + + .balign 16 + .globl C(ffi_closure_STDCALL) + FFI_HIDDEN(C(ffi_closure_STDCALL)) +C(ffi_closure_STDCALL): +L(UW27): + # cfi_startproc + subl $closure_FS, %esp +L(UW28): + # cfi_def_cfa_offset(closure_FS + 4) + + FFI_CLOSURE_SAVE_REGS + + /* Entry point from ffi_closure_REGISTER. */ +L(do_closure_REGISTER): + + FFI_CLOSURE_COPY_TRAMP_DATA + + /* Entry point from preceeding Go closure. */ +L(do_closure_STDCALL): + + FFI_CLOSURE_PREP_CALL + FFI_CLOSURE_CALL_INNER(29) + + movl %eax, %ecx + shrl $X86_RET_POP_SHIFT, %ecx /* isolate pop count */ + leal closure_FS(%esp, %ecx), %ecx /* compute popped esp */ + movl closure_FS(%esp), %edx /* move return address */ + movl %edx, (%ecx) + + /* From this point on, the value of %esp upon return is %ecx+4, + and we've copied the return address to %ecx to make return easy. + There's no point in representing this in the unwind info, as + there is always a window between the mov and the ret which + will be wrong from one point of view or another. */ + + FFI_CLOSURE_MASK_AND_JUMP(3, 30) + + .balign 8 +L(load_table3): +E(L(load_table3), X86_RET_FLOAT) + flds closure_CF(%esp) + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_DOUBLE) + fldl closure_CF(%esp) + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_LDOUBLE) + fldt closure_CF(%esp) + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_SINT8) + movsbl %al, %eax + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_SINT16) + movswl %ax, %eax + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_UINT8) + movzbl %al, %eax + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_UINT16) + movzwl %ax, %eax + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_INT64) + movl closure_CF+4(%esp), %edx + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_INT32) + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_VOID) + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_STRUCTPOP) + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_STRUCTARG) + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_STRUCT_1B) + movzbl %al, %eax + movl %ecx, %esp + ret +E(L(load_table3), X86_RET_STRUCT_2B) + movzwl %ax, %eax + movl %ecx, %esp + ret + + /* Fill out the table so that bad values are predictable. */ +E(L(load_table3), X86_RET_UNUSED14) + ud2 +E(L(load_table3), X86_RET_UNUSED15) + ud2 + +L(UW31): + # cfi_endproc +ENDF(C(ffi_closure_STDCALL)) + +#if !FFI_NO_RAW_API + +#define raw_closure_S_FS (16+16+12) + + .balign 16 + .globl C(ffi_closure_raw_SYSV) + FFI_HIDDEN(C(ffi_closure_raw_SYSV)) +C(ffi_closure_raw_SYSV): +L(UW32): + # cfi_startproc + subl $raw_closure_S_FS, %esp +L(UW33): + # cfi_def_cfa_offset(raw_closure_S_FS + 4) + movl %ebx, raw_closure_S_FS-4(%esp) +L(UW34): + # cfi_rel_offset(%ebx, raw_closure_S_FS-4) + + movl FFI_TRAMPOLINE_SIZE+8(%eax), %edx /* load cl->user_data */ + movl %edx, 12(%esp) + leal raw_closure_S_FS+4(%esp), %edx /* load raw_args */ + movl %edx, 8(%esp) + leal 16(%esp), %edx /* load &res */ + movl %edx, 4(%esp) + movl FFI_TRAMPOLINE_SIZE(%eax), %ebx /* load cl->cif */ + movl %ebx, (%esp) + call *FFI_TRAMPOLINE_SIZE+4(%eax) /* call cl->fun */ + + movl 20(%ebx), %eax /* load cif->flags */ + andl $X86_RET_TYPE_MASK, %eax +#ifdef __PIC__ + call C(__x86.get_pc_thunk.bx) +L(pc4): + leal L(load_table4)-L(pc4)(%ebx, %eax, 8), %ecx #else - .ascii "\0" /* CIE Augmentation */ + leal L(load_table4)(,%eax, 8), %ecx #endif -#elif defined HAVE_AS_STRING_PSEUDO_OP + movl raw_closure_S_FS-4(%esp), %ebx +L(UW35): + # cfi_restore(%ebx) + movl 16(%esp), %eax /* Optimistic load */ + jmp *%ecx + + .balign 8 +L(load_table4): +E(L(load_table4), X86_RET_FLOAT) + flds 16(%esp) + jmp L(e4) +E(L(load_table4), X86_RET_DOUBLE) + fldl 16(%esp) + jmp L(e4) +E(L(load_table4), X86_RET_LDOUBLE) + fldt 16(%esp) + jmp L(e4) +E(L(load_table4), X86_RET_SINT8) + movsbl %al, %eax + jmp L(e4) +E(L(load_table4), X86_RET_SINT16) + movswl %ax, %eax + jmp L(e4) +E(L(load_table4), X86_RET_UINT8) + movzbl %al, %eax + jmp L(e4) +E(L(load_table4), X86_RET_UINT16) + movzwl %ax, %eax + jmp L(e4) +E(L(load_table4), X86_RET_INT64) + movl 16+4(%esp), %edx + jmp L(e4) +E(L(load_table4), X86_RET_INT32) + nop + /* fallthru */ +E(L(load_table4), X86_RET_VOID) +L(e4): + addl $raw_closure_S_FS, %esp +L(UW36): + # cfi_adjust_cfa_offset(-raw_closure_S_FS) + ret +L(UW37): + # cfi_adjust_cfa_offset(raw_closure_S_FS) +E(L(load_table4), X86_RET_STRUCTPOP) + addl $raw_closure_S_FS, %esp +L(UW38): + # cfi_adjust_cfa_offset(-raw_closure_S_FS) + ret $4 +L(UW39): + # cfi_adjust_cfa_offset(raw_closure_S_FS) +E(L(load_table4), X86_RET_STRUCTARG) + jmp L(e4) +E(L(load_table4), X86_RET_STRUCT_1B) + movzbl %al, %eax + jmp L(e4) +E(L(load_table4), X86_RET_STRUCT_2B) + movzwl %ax, %eax + jmp L(e4) + + /* Fill out the table so that bad values are predictable. */ +E(L(load_table4), X86_RET_UNUSED14) + ud2 +E(L(load_table4), X86_RET_UNUSED15) + ud2 + +L(UW40): + # cfi_endproc +ENDF(C(ffi_closure_raw_SYSV)) + +#define raw_closure_T_FS (16+16+8) + + .balign 16 + .globl C(ffi_closure_raw_THISCALL) + FFI_HIDDEN(C(ffi_closure_raw_THISCALL)) +C(ffi_closure_raw_THISCALL): +L(UW41): + # cfi_startproc + /* Rearrange the stack such that %ecx is the first argument. + This means moving the return address. */ + popl %edx +L(UW42): + # cfi_def_cfa_offset(0) + # cfi_register(%eip, %edx) + pushl %ecx +L(UW43): + # cfi_adjust_cfa_offset(4) + pushl %edx +L(UW44): + # cfi_adjust_cfa_offset(4) + # cfi_rel_offset(%eip, 0) + subl $raw_closure_T_FS, %esp +L(UW45): + # cfi_adjust_cfa_offset(raw_closure_T_FS) + movl %ebx, raw_closure_T_FS-4(%esp) +L(UW46): + # cfi_rel_offset(%ebx, raw_closure_T_FS-4) + + movl FFI_TRAMPOLINE_SIZE+8(%eax), %edx /* load cl->user_data */ + movl %edx, 12(%esp) + leal raw_closure_T_FS+4(%esp), %edx /* load raw_args */ + movl %edx, 8(%esp) + leal 16(%esp), %edx /* load &res */ + movl %edx, 4(%esp) + movl FFI_TRAMPOLINE_SIZE(%eax), %ebx /* load cl->cif */ + movl %ebx, (%esp) + call *FFI_TRAMPOLINE_SIZE+4(%eax) /* call cl->fun */ + + movl 20(%ebx), %eax /* load cif->flags */ + andl $X86_RET_TYPE_MASK, %eax #ifdef __PIC__ - .string "zR" /* CIE Augmentation */ + call C(__x86.get_pc_thunk.bx) +L(pc5): + leal L(load_table5)-L(pc5)(%ebx, %eax, 8), %ecx #else - .string "" /* CIE Augmentation */ + leal L(load_table5)(,%eax, 8), %ecx #endif + movl raw_closure_T_FS-4(%esp), %ebx +L(UW47): + # cfi_restore(%ebx) + movl 16(%esp), %eax /* Optimistic load */ + jmp *%ecx + + .balign 8 +L(load_table5): +E(L(load_table5), X86_RET_FLOAT) + flds 16(%esp) + jmp L(e5) +E(L(load_table5), X86_RET_DOUBLE) + fldl 16(%esp) + jmp L(e5) +E(L(load_table5), X86_RET_LDOUBLE) + fldt 16(%esp) + jmp L(e5) +E(L(load_table5), X86_RET_SINT8) + movsbl %al, %eax + jmp L(e5) +E(L(load_table5), X86_RET_SINT16) + movswl %ax, %eax + jmp L(e5) +E(L(load_table5), X86_RET_UINT8) + movzbl %al, %eax + jmp L(e5) +E(L(load_table5), X86_RET_UINT16) + movzwl %ax, %eax + jmp L(e5) +E(L(load_table5), X86_RET_INT64) + movl 16+4(%esp), %edx + jmp L(e5) +E(L(load_table5), X86_RET_INT32) + nop + /* fallthru */ +E(L(load_table5), X86_RET_VOID) +L(e5): + addl $raw_closure_T_FS, %esp +L(UW48): + # cfi_adjust_cfa_offset(-raw_closure_T_FS) + /* Remove the extra %ecx argument we pushed. */ + ret $4 +L(UW49): + # cfi_adjust_cfa_offset(raw_closure_T_FS) +E(L(load_table5), X86_RET_STRUCTPOP) + addl $raw_closure_T_FS, %esp +L(UW50): + # cfi_adjust_cfa_offset(-raw_closure_T_FS) + ret $8 +L(UW51): + # cfi_adjust_cfa_offset(raw_closure_T_FS) +E(L(load_table5), X86_RET_STRUCTARG) + jmp L(e5) +E(L(load_table5), X86_RET_STRUCT_1B) + movzbl %al, %eax + jmp L(e5) +E(L(load_table5), X86_RET_STRUCT_2B) + movzwl %ax, %eax + jmp L(e5) + + /* Fill out the table so that bad values are predictable. */ +E(L(load_table5), X86_RET_UNUSED14) + ud2 +E(L(load_table5), X86_RET_UNUSED15) + ud2 + +L(UW52): + # cfi_endproc +ENDF(C(ffi_closure_raw_THISCALL)) + +#endif /* !FFI_NO_RAW_API */ + +#ifdef X86_DARWIN +# define COMDAT(X) \ + .section __TEXT,__textcoal_nt,coalesced,pure_instructions; \ + .weak_definition X; \ + .private_extern X +#elif defined __ELF__ +# define COMDAT(X) \ + .section .text.X,"axG",@progbits,X,comdat; \ + .globl X; \ + FFI_HIDDEN(X) #else -#error missing .ascii/.string -#endif - .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */ - .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ - .byte 0x8 /* CIE RA Column */ -#ifdef __PIC__ - .byte 0x1 /* .uleb128 0x1; Augmentation size */ - .byte FDE_ENCODING -#endif - .byte 0xc /* DW_CFA_def_cfa */ - .byte 0x4 /* .uleb128 0x4 */ - .byte 0x4 /* .uleb128 0x4 */ - .byte 0x88 /* DW_CFA_offset, column 0x8 */ - .byte 0x1 /* .uleb128 0x1 */ - .align 4 -.LECIE1: -.LSFDE1: - .long .LEFDE1-.LASFDE1 /* FDE Length */ -.LASFDE1: - .long .LASFDE1-.Lframe1 /* FDE CIE offset */ - .long FDE_ENCODE(.LFB1) /* FDE initial location */ - .long .LFE1-.LFB1 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ +# define COMDAT(X) #endif - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI0-.LFB1 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 */ - .byte 0x2 /* .uleb128 0x2 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI1-.LCFI0 - .byte 0xd /* DW_CFA_def_cfa_register */ - .byte 0x5 /* .uleb128 0x5 */ - .align 4 -.LEFDE1: -.LSFDE2: - .long .LEFDE2-.LASFDE2 /* FDE Length */ -.LASFDE2: - .long .LASFDE2-.Lframe1 /* FDE CIE offset */ - .long FDE_ENCODE(.LFB2) /* FDE initial location */ - .long .LFE2-.LFB2 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ + +#if defined(__PIC__) + COMDAT(C(__x86.get_pc_thunk.bx)) +C(__x86.get_pc_thunk.bx): + movl (%esp), %ebx + ret +ENDF(C(__x86.get_pc_thunk.bx)) +# if defined X86_DARWIN || defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE + COMDAT(C(__x86.get_pc_thunk.dx)) +C(__x86.get_pc_thunk.dx): + movl (%esp), %edx + ret +ENDF(C(__x86.get_pc_thunk.dx)) +#endif /* DARWIN || HIDDEN */ +#endif /* __PIC__ */ + +/* Sadly, OSX cctools-as doesn't understand .cfi directives at all. */ + +#ifdef __APPLE__ +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support +EHFrame0: +#elif defined(HAVE_AS_X86_64_UNWIND_SECTION_TYPE) +.section .eh_frame,"a",@unwind +#else +.section .eh_frame,"a",@progbits #endif - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI2-.LFB2 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 */ - .byte 0x2 /* .uleb128 0x2 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI3-.LCFI2 - .byte 0xd /* DW_CFA_def_cfa_register */ - .byte 0x5 /* .uleb128 0x5 */ -#if !defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE && defined __PIC__ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI7-.LCFI3 - .byte 0x83 /* DW_CFA_offset, column 0x3 */ - .byte 0xa /* .uleb128 0xa */ + +#ifdef HAVE_AS_X86_PCREL +# define PCREL(X) X - . +#else +# define PCREL(X) X@rel #endif - .align 4 -.LEFDE2: -#if !FFI_NO_RAW_API +/* Simplify advancing between labels. Assume DW_CFA_advance_loc1 fits. */ +#define ADV(N, P) .byte 2, L(N)-L(P) -.LSFDE3: - .long .LEFDE3-.LASFDE3 /* FDE Length */ -.LASFDE3: - .long .LASFDE3-.Lframe1 /* FDE CIE offset */ - .long FDE_ENCODE(.LFB3) /* FDE initial location */ - .long .LFE3-.LFB3 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ + .balign 4 +L(CIE): + .set L(set0),L(ECIE)-L(SCIE) + .long L(set0) /* CIE Length */ +L(SCIE): + .long 0 /* CIE Identifier Tag */ + .byte 1 /* CIE Version */ + .ascii "zR\0" /* CIE Augmentation */ + .byte 1 /* CIE Code Alignment Factor */ + .byte 0x7c /* CIE Data Alignment Factor */ + .byte 0x8 /* CIE RA Column */ + .byte 1 /* Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ + .byte 0xc, 4, 4 /* DW_CFA_def_cfa, %esp offset 4 */ + .byte 0x80+8, 1 /* DW_CFA_offset, %eip offset 1*-4 */ + .balign 4 +L(ECIE): + + .set L(set1),L(EFDE1)-L(SFDE1) + .long L(set1) /* FDE Length */ +L(SFDE1): + .long L(SFDE1)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW0)) /* Initial location */ + .long L(UW5)-L(UW0) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW1, UW0) + .byte 0xc, 5, 8 /* DW_CFA_def_cfa, %ebp 8 */ + .byte 0x80+5, 2 /* DW_CFA_offset, %ebp 2*-4 */ + ADV(UW2, UW1) + .byte 0x80+3, 0 /* DW_CFA_offset, %ebx 0*-4 */ + ADV(UW3, UW2) + .byte 0xa /* DW_CFA_remember_state */ + .byte 0xc, 4, 4 /* DW_CFA_def_cfa, %esp 4 */ + .byte 0xc0+3 /* DW_CFA_restore, %ebx */ + .byte 0xc0+5 /* DW_CFA_restore, %ebp */ + ADV(UW4, UW3) + .byte 0xb /* DW_CFA_restore_state */ + .balign 4 +L(EFDE1): + + .set L(set2),L(EFDE2)-L(SFDE2) + .long L(set2) /* FDE Length */ +L(SFDE2): + .long L(SFDE2)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW6)) /* Initial location */ + .long L(UW8)-L(UW6) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW7, UW6) + .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ + .balign 4 +L(EFDE2): + + .set L(set3),L(EFDE3)-L(SFDE3) + .long L(set3) /* FDE Length */ +L(SFDE3): + .long L(SFDE3)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW9)) /* Initial location */ + .long L(UW11)-L(UW9) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW10, UW9) + .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ + .balign 4 +L(EFDE3): + + .set L(set4),L(EFDE4)-L(SFDE4) + .long L(set4) /* FDE Length */ +L(SFDE4): + .long L(SFDE4)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW12)) /* Initial location */ + .long L(UW20)-L(UW12) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW13, UW12) + .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ +#ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX + ADV(UW14, UW13) + .byte 0x80+3, (40-(closure_FS+4))/-4 /* DW_CFA_offset %ebx */ + ADV(UW15, UW14) + .byte 0xc0+3 /* DW_CFA_restore %ebx */ + ADV(UW16, UW15) +#else + ADV(UW16, UW13) #endif - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI4-.LFB3 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 */ - .byte 0x2 /* .uleb128 0x2 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI5-.LCFI4 - .byte 0xd /* DW_CFA_def_cfa_register */ - .byte 0x5 /* .uleb128 0x5 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI6-.LCFI5 - .byte 0x86 /* DW_CFA_offset, column 0x6 */ - .byte 0x3 /* .uleb128 0x3 */ - .align 4 -.LEFDE3: + .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ + ADV(UW17, UW16) + .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ + ADV(UW18, UW17) + .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ + ADV(UW19, UW18) + .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ + .balign 4 +L(EFDE4): + + .set L(set5),L(EFDE5)-L(SFDE5) + .long L(set5) /* FDE Length */ +L(SFDE5): + .long L(SFDE5)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW21)) /* Initial location */ + .long L(UW23)-L(UW21) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW22, UW21) + .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ + .balign 4 +L(EFDE5): + .set L(set6),L(EFDE6)-L(SFDE6) + .long L(set6) /* FDE Length */ +L(SFDE6): + .long L(SFDE6)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW24)) /* Initial location */ + .long L(UW26)-L(UW24) /* Address range */ + .byte 0 /* Augmentation size */ + .byte 0xe, 8 /* DW_CFA_def_cfa_offset */ + .byte 0x80+8, 2 /* DW_CFA_offset %eip, 2*-4 */ + ADV(UW25, UW24) + .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ + .balign 4 +L(EFDE6): + + .set L(set7),L(EFDE7)-L(SFDE7) + .long L(set7) /* FDE Length */ +L(SFDE7): + .long L(SFDE7)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW27)) /* Initial location */ + .long L(UW31)-L(UW27) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW28, UW27) + .byte 0xe, closure_FS+4 /* DW_CFA_def_cfa_offset */ +#ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX + ADV(UW29, UW28) + .byte 0x80+3, (40-(closure_FS+4))/-4 /* DW_CFA_offset %ebx */ + ADV(UW30, UW29) + .byte 0xc0+3 /* DW_CFA_restore %ebx */ #endif + .balign 4 +L(EFDE7): + +#if !FFI_NO_RAW_API + .set L(set8),L(EFDE8)-L(SFDE8) + .long L(set8) /* FDE Length */ +L(SFDE8): + .long L(SFDE8)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW32)) /* Initial location */ + .long L(UW40)-L(UW32) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW33, UW32) + .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */ + ADV(UW34, UW33) + .byte 0x80+3, 2 /* DW_CFA_offset %ebx 2*-4 */ + ADV(UW35, UW34) + .byte 0xc0+3 /* DW_CFA_restore %ebx */ + ADV(UW36, UW35) + .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ + ADV(UW37, UW36) + .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */ + ADV(UW38, UW37) + .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ + ADV(UW39, UW38) + .byte 0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */ + .balign 4 +L(EFDE8): + + .set L(set9),L(EFDE9)-L(SFDE9) + .long L(set9) /* FDE Length */ +L(SFDE9): + .long L(SFDE9)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW41)) /* Initial location */ + .long L(UW52)-L(UW41) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW42, UW41) + .byte 0xe, 0 /* DW_CFA_def_cfa_offset */ + .byte 0x9, 8, 2 /* DW_CFA_register %eip, %edx */ + ADV(UW43, UW42) + .byte 0xe, 4 /* DW_CFA_def_cfa_offset */ + ADV(UW44, UW43) + .byte 0xe, 8 /* DW_CFA_def_cfa_offset */ + .byte 0x80+8, 2 /* DW_CFA_offset %eip 2*-4 */ + ADV(UW45, UW44) + .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */ + ADV(UW46, UW45) + .byte 0x80+3, 3 /* DW_CFA_offset %ebx 3*-4 */ + ADV(UW47, UW46) + .byte 0xc0+3 /* DW_CFA_restore %ebx */ + ADV(UW48, UW47) + .byte 0xe, 8 /* DW_CFA_def_cfa_offset */ + ADV(UW49, UW48) + .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */ + ADV(UW50, UW49) + .byte 0xe, 8 /* DW_CFA_def_cfa_offset */ + ADV(UW51, UW50) + .byte 0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */ + .balign 4 +L(EFDE9): +#endif /* !FFI_NO_RAW_API */ #endif /* ifndef __x86_64__ */ diff --git a/libffi/src/x86/unix64.S b/libffi/src/x86/unix64.S index 7a6619a..f9f9163 100644 --- a/libffi/src/x86/unix64.S +++ b/libffi/src/x86/unix64.S @@ -1,6 +1,7 @@ /* ----------------------------------------------------------------------- - unix64.S - Copyright (c) 2002 Bo Thorsen <bo@suse.de> - Copyright (c) 2008 Red Hat, Inc + unix64.S - Copyright (c) 2013 The Written Word, Inc. + - Copyright (c) 2008 Red Hat, Inc + - Copyright (c) 2002 Bo Thorsen <bo@suse.de> x86-64 Foreign Function Interface @@ -29,8 +30,41 @@ #define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> +#include "internal64.h" -.text + .text + +#define C2(X, Y) X ## Y +#define C1(X, Y) C2(X, Y) +#ifdef __USER_LABEL_PREFIX__ +# define C(X) C1(__USER_LABEL_PREFIX__, X) +#else +# define C(X) X +#endif + +#ifdef __APPLE__ +# define L(X) C1(L, X) +#else +# define L(X) C1(.L, X) +#endif + +#ifdef __ELF__ +# define PLT(X) X@PLT +# define ENDF(X) .type X,@function; .size X, . - X +#else +# define PLT(X) X +# define ENDF(X) +#endif + +/* This macro allows the safe creation of jump tables without an + actual table. The entry points into the table are all 8 bytes. + The use of ORG asserts that we're at the correct location. */ +/* ??? The clang assembler doesn't handle .org with symbolic expressions. */ +#if defined(__clang__) || defined(__APPLE__) +# define E(BASE, X) .balign 8 +#else +# define E(BASE, X) .balign 8; .org BASE + X * 8 +#endif /* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, void *raddr, void (*fnaddr)(void)); @@ -39,12 +73,12 @@ for this function. This has been allocated by ffi_call. We also deallocate some of the stack that has been alloca'd. */ - .align 2 - .globl ffi_call_unix64 - .type ffi_call_unix64,@function + .balign 8 + .globl C(ffi_call_unix64) + FFI_HIDDEN(C(ffi_call_unix64)) -ffi_call_unix64: -.LUW0: +C(ffi_call_unix64): +L(UW0): movq (%rsp), %r10 /* Load return address. */ leaq (%rdi, %rsi), %rax /* Find local stack base. */ movq %rdx, (%rax) /* Save flags. */ @@ -52,24 +86,37 @@ ffi_call_unix64: movq %rbp, 16(%rax) /* Save old frame pointer. */ movq %r10, 24(%rax) /* Relocate return address. */ movq %rax, %rbp /* Finalize local stack frame. */ -.LUW1: + + /* New stack frame based off rbp. This is a itty bit of unwind + trickery in that the CFA *has* changed. There is no easy way + to describe it correctly on entry to the function. Fortunately, + it doesn't matter too much since at all points we can correctly + unwind back to ffi_call. Note that the location to which we + moved the return address is (the new) CFA-8, so from the + perspective of the unwind info, it hasn't moved. */ +L(UW1): + /* cfi_def_cfa(%rbp, 32) */ + /* cfi_rel_offset(%rbp, 16) */ + movq %rdi, %r10 /* Save a copy of the register area. */ movq %r8, %r11 /* Save a copy of the target fn. */ movl %r9d, %eax /* Set number of SSE registers. */ /* Load up all argument registers. */ movq (%r10), %rdi - movq 8(%r10), %rsi - movq 16(%r10), %rdx - movq 24(%r10), %rcx - movq 32(%r10), %r8 - movq 40(%r10), %r9 + movq 0x08(%r10), %rsi + movq 0x10(%r10), %rdx + movq 0x18(%r10), %rcx + movq 0x20(%r10), %r8 + movq 0x28(%r10), %r9 + movl 0xb0(%r10), %eax testl %eax, %eax - jnz .Lload_sse -.Lret_from_load_sse: + jnz L(load_sse) +L(ret_from_load_sse): - /* Deallocate the reg arg area. */ - leaq 176(%r10), %rsp + /* Deallocate the reg arg area, except for r10, then load via pop. */ + leaq 0xb8(%r10), %rsp + popq %r10 /* Call the user function. */ call *%r11 @@ -80,347 +127,420 @@ ffi_call_unix64: movq 0(%rbp), %rcx /* Reload flags. */ movq 8(%rbp), %rdi /* Reload raddr. */ movq 16(%rbp), %rbp /* Reload old frame pointer. */ -.LUW2: +L(UW2): + /* cfi_remember_state */ + /* cfi_def_cfa(%rsp, 8) */ + /* cfi_restore(%rbp) */ /* The first byte of the flags contains the FFI_TYPE. */ + cmpb $UNIX64_RET_LAST, %cl movzbl %cl, %r10d - leaq .Lstore_table(%rip), %r11 - movslq (%r11, %r10, 4), %r10 - addq %r11, %r10 + leaq L(store_table)(%rip), %r11 + ja L(sa) + leaq (%r11, %r10, 8), %r10 + + /* Prep for the structure cases: scratch area in redzone. */ + leaq -20(%rsp), %rsi jmp *%r10 -.Lstore_table: - .long .Lst_void-.Lstore_table /* FFI_TYPE_VOID */ - .long .Lst_sint32-.Lstore_table /* FFI_TYPE_INT */ - .long .Lst_float-.Lstore_table /* FFI_TYPE_FLOAT */ - .long .Lst_double-.Lstore_table /* FFI_TYPE_DOUBLE */ - .long .Lst_ldouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */ - .long .Lst_uint8-.Lstore_table /* FFI_TYPE_UINT8 */ - .long .Lst_sint8-.Lstore_table /* FFI_TYPE_SINT8 */ - .long .Lst_uint16-.Lstore_table /* FFI_TYPE_UINT16 */ - .long .Lst_sint16-.Lstore_table /* FFI_TYPE_SINT16 */ - .long .Lst_uint32-.Lstore_table /* FFI_TYPE_UINT32 */ - .long .Lst_sint32-.Lstore_table /* FFI_TYPE_SINT32 */ - .long .Lst_int64-.Lstore_table /* FFI_TYPE_UINT64 */ - .long .Lst_int64-.Lstore_table /* FFI_TYPE_SINT64 */ - .long .Lst_struct-.Lstore_table /* FFI_TYPE_STRUCT */ - .long .Lst_int64-.Lstore_table /* FFI_TYPE_POINTER */ - - .align 2 -.Lst_void: + .balign 8 +L(store_table): +E(L(store_table), UNIX64_RET_VOID) ret - .align 2 - -.Lst_uint8: - movzbq %al, %rax +E(L(store_table), UNIX64_RET_UINT8) + movzbl %al, %eax movq %rax, (%rdi) ret - .align 2 -.Lst_sint8: - movsbq %al, %rax +E(L(store_table), UNIX64_RET_UINT16) + movzwl %ax, %eax movq %rax, (%rdi) ret - .align 2 -.Lst_uint16: - movzwq %ax, %rax +E(L(store_table), UNIX64_RET_UINT32) + movl %eax, %eax movq %rax, (%rdi) - .align 2 -.Lst_sint16: - movswq %ax, %rax + ret +E(L(store_table), UNIX64_RET_SINT8) + movsbq %al, %rax movq %rax, (%rdi) ret - .align 2 -.Lst_uint32: - movl %eax, %eax +E(L(store_table), UNIX64_RET_SINT16) + movswq %ax, %rax movq %rax, (%rdi) - .align 2 -.Lst_sint32: + ret +E(L(store_table), UNIX64_RET_SINT32) cltq movq %rax, (%rdi) ret - .align 2 -.Lst_int64: +E(L(store_table), UNIX64_RET_INT64) movq %rax, (%rdi) ret - - .align 2 -.Lst_float: - movss %xmm0, (%rdi) +E(L(store_table), UNIX64_RET_XMM32) + movd %xmm0, (%rdi) ret - .align 2 -.Lst_double: - movsd %xmm0, (%rdi) +E(L(store_table), UNIX64_RET_XMM64) + movq %xmm0, (%rdi) ret -.Lst_ldouble: +E(L(store_table), UNIX64_RET_X87) fstpt (%rdi) ret - - .align 2 -.Lst_struct: - leaq -20(%rsp), %rsi /* Scratch area in redzone. */ - - /* We have to locate the values now, and since we don't want to - write too much data into the user's return value, we spill the - value to a 16 byte scratch area first. Bits 8, 9, and 10 - control where the values are located. Only one of the three - bits will be set; see ffi_prep_cif_machdep for the pattern. */ - movd %xmm0, %r10 - movd %xmm1, %r11 - testl $0x100, %ecx - cmovnz %rax, %rdx - cmovnz %r10, %rax - testl $0x200, %ecx - cmovnz %r10, %rdx - testl $0x400, %ecx - cmovnz %r10, %rax - cmovnz %r11, %rdx - movq %rax, (%rsi) +E(L(store_table), UNIX64_RET_X87_2) + fstpt (%rdi) + fstpt 16(%rdi) + ret +E(L(store_table), UNIX64_RET_ST_XMM0_RAX) + movq %rax, 8(%rsi) + jmp L(s3) +E(L(store_table), UNIX64_RET_ST_RAX_XMM0) + movq %xmm0, 8(%rsi) + jmp L(s2) +E(L(store_table), UNIX64_RET_ST_XMM0_XMM1) + movq %xmm1, 8(%rsi) + jmp L(s3) +E(L(store_table), UNIX64_RET_ST_RAX_RDX) movq %rdx, 8(%rsi) - - /* Bits 12-31 contain the true size of the structure. Copy from - the scratch area to the true destination. */ - shrl $12, %ecx +L(s2): + movq %rax, (%rsi) + shrl $UNIX64_SIZE_SHIFT, %ecx rep movsb ret + .balign 8 +L(s3): + movq %xmm0, (%rsi) + shrl $UNIX64_SIZE_SHIFT, %ecx + rep movsb + ret + +L(sa): call PLT(C(abort)) /* Many times we can avoid loading any SSE registers at all. It's not worth an indirect jump to load the exact set of SSE registers needed; zero or all is a good compromise. */ - .align 2 -.LUW3: -.Lload_sse: - movdqa 48(%r10), %xmm0 - movdqa 64(%r10), %xmm1 - movdqa 80(%r10), %xmm2 - movdqa 96(%r10), %xmm3 - movdqa 112(%r10), %xmm4 - movdqa 128(%r10), %xmm5 - movdqa 144(%r10), %xmm6 - movdqa 160(%r10), %xmm7 - jmp .Lret_from_load_sse - -.LUW4: - .size ffi_call_unix64,.-ffi_call_unix64 - - .align 2 - .globl ffi_closure_unix64 - .type ffi_closure_unix64,@function - -ffi_closure_unix64: -.LUW5: - /* The carry flag is set by the trampoline iff SSE registers - are used. Don't clobber it before the branch instruction. */ - leaq -200(%rsp), %rsp -.LUW6: - movq %rdi, (%rsp) - movq %rsi, 8(%rsp) - movq %rdx, 16(%rsp) - movq %rcx, 24(%rsp) - movq %r8, 32(%rsp) - movq %r9, 40(%rsp) - jc .Lsave_sse -.Lret_from_save_sse: - - movq %r10, %rdi - leaq 176(%rsp), %rsi - movq %rsp, %rdx - leaq 208(%rsp), %rcx - call ffi_closure_unix64_inner@PLT + .balign 2 +L(UW3): + /* cfi_restore_state */ +L(load_sse): + movdqa 0x30(%r10), %xmm0 + movdqa 0x40(%r10), %xmm1 + movdqa 0x50(%r10), %xmm2 + movdqa 0x60(%r10), %xmm3 + movdqa 0x70(%r10), %xmm4 + movdqa 0x80(%r10), %xmm5 + movdqa 0x90(%r10), %xmm6 + movdqa 0xa0(%r10), %xmm7 + jmp L(ret_from_load_sse) + +L(UW4): +ENDF(C(ffi_call_unix64)) + +/* 6 general registers, 8 vector registers, + 32 bytes of rvalue, 8 bytes of alignment. */ +#define ffi_closure_OFS_G 0 +#define ffi_closure_OFS_V (6*8) +#define ffi_closure_OFS_RVALUE (ffi_closure_OFS_V + 8*16) +#define ffi_closure_FS (ffi_closure_OFS_RVALUE + 32 + 8) + +/* The location of rvalue within the red zone after deallocating the frame. */ +#define ffi_closure_RED_RVALUE (ffi_closure_OFS_RVALUE - ffi_closure_FS) + + .balign 2 + .globl C(ffi_closure_unix64_sse) + FFI_HIDDEN(C(ffi_closure_unix64_sse)) + +C(ffi_closure_unix64_sse): +L(UW5): + subq $ffi_closure_FS, %rsp +L(UW6): + /* cfi_adjust_cfa_offset(ffi_closure_FS) */ + + movdqa %xmm0, ffi_closure_OFS_V+0x00(%rsp) + movdqa %xmm1, ffi_closure_OFS_V+0x10(%rsp) + movdqa %xmm2, ffi_closure_OFS_V+0x20(%rsp) + movdqa %xmm3, ffi_closure_OFS_V+0x30(%rsp) + movdqa %xmm4, ffi_closure_OFS_V+0x40(%rsp) + movdqa %xmm5, ffi_closure_OFS_V+0x50(%rsp) + movdqa %xmm6, ffi_closure_OFS_V+0x60(%rsp) + movdqa %xmm7, ffi_closure_OFS_V+0x70(%rsp) + jmp L(sse_entry1) + +L(UW7): +ENDF(C(ffi_closure_unix64_sse)) + + .balign 2 + .globl C(ffi_closure_unix64) + FFI_HIDDEN(C(ffi_closure_unix64)) + +C(ffi_closure_unix64): +L(UW8): + subq $ffi_closure_FS, %rsp +L(UW9): + /* cfi_adjust_cfa_offset(ffi_closure_FS) */ +L(sse_entry1): + movq %rdi, ffi_closure_OFS_G+0x00(%rsp) + movq %rsi, ffi_closure_OFS_G+0x08(%rsp) + movq %rdx, ffi_closure_OFS_G+0x10(%rsp) + movq %rcx, ffi_closure_OFS_G+0x18(%rsp) + movq %r8, ffi_closure_OFS_G+0x20(%rsp) + movq %r9, ffi_closure_OFS_G+0x28(%rsp) + +#ifdef __ILP32__ + movl FFI_TRAMPOLINE_SIZE(%r10), %edi /* Load cif */ + movl FFI_TRAMPOLINE_SIZE+4(%r10), %esi /* Load fun */ + movl FFI_TRAMPOLINE_SIZE+8(%r10), %edx /* Load user_data */ +#else + movq FFI_TRAMPOLINE_SIZE(%r10), %rdi /* Load cif */ + movq FFI_TRAMPOLINE_SIZE+8(%r10), %rsi /* Load fun */ + movq FFI_TRAMPOLINE_SIZE+16(%r10), %rdx /* Load user_data */ +#endif +L(do_closure): + leaq ffi_closure_OFS_RVALUE(%rsp), %rcx /* Load rvalue */ + movq %rsp, %r8 /* Load reg_args */ + leaq ffi_closure_FS+8(%rsp), %r9 /* Load argp */ + call C(ffi_closure_unix64_inner) /* Deallocate stack frame early; return value is now in redzone. */ - addq $200, %rsp -.LUW7: + addq $ffi_closure_FS, %rsp +L(UW10): + /* cfi_adjust_cfa_offset(-ffi_closure_FS) */ /* The first byte of the return value contains the FFI_TYPE. */ + cmpb $UNIX64_RET_LAST, %al movzbl %al, %r10d - leaq .Lload_table(%rip), %r11 - movslq (%r11, %r10, 4), %r10 - addq %r11, %r10 + leaq L(load_table)(%rip), %r11 + ja L(la) + leaq (%r11, %r10, 8), %r10 + leaq ffi_closure_RED_RVALUE(%rsp), %rsi jmp *%r10 -.Lload_table: - .long .Lld_void-.Lload_table /* FFI_TYPE_VOID */ - .long .Lld_int32-.Lload_table /* FFI_TYPE_INT */ - .long .Lld_float-.Lload_table /* FFI_TYPE_FLOAT */ - .long .Lld_double-.Lload_table /* FFI_TYPE_DOUBLE */ - .long .Lld_ldouble-.Lload_table /* FFI_TYPE_LONGDOUBLE */ - .long .Lld_int8-.Lload_table /* FFI_TYPE_UINT8 */ - .long .Lld_int8-.Lload_table /* FFI_TYPE_SINT8 */ - .long .Lld_int16-.Lload_table /* FFI_TYPE_UINT16 */ - .long .Lld_int16-.Lload_table /* FFI_TYPE_SINT16 */ - .long .Lld_int32-.Lload_table /* FFI_TYPE_UINT32 */ - .long .Lld_int32-.Lload_table /* FFI_TYPE_SINT32 */ - .long .Lld_int64-.Lload_table /* FFI_TYPE_UINT64 */ - .long .Lld_int64-.Lload_table /* FFI_TYPE_SINT64 */ - .long .Lld_struct-.Lload_table /* FFI_TYPE_STRUCT */ - .long .Lld_int64-.Lload_table /* FFI_TYPE_POINTER */ - - .align 2 -.Lld_void: + .balign 8 +L(load_table): +E(L(load_table), UNIX64_RET_VOID) ret - - .align 2 -.Lld_int8: - movzbl -24(%rsp), %eax +E(L(load_table), UNIX64_RET_UINT8) + movzbl (%rsi), %eax ret - .align 2 -.Lld_int16: - movzwl -24(%rsp), %eax +E(L(load_table), UNIX64_RET_UINT16) + movzwl (%rsi), %eax ret - .align 2 -.Lld_int32: - movl -24(%rsp), %eax +E(L(load_table), UNIX64_RET_UINT32) + movl (%rsi), %eax ret - .align 2 -.Lld_int64: - movq -24(%rsp), %rax +E(L(load_table), UNIX64_RET_SINT8) + movsbl (%rsi), %eax ret - - .align 2 -.Lld_float: - movss -24(%rsp), %xmm0 +E(L(load_table), UNIX64_RET_SINT16) + movswl (%rsi), %eax ret - .align 2 -.Lld_double: - movsd -24(%rsp), %xmm0 +E(L(load_table), UNIX64_RET_SINT32) + movl (%rsi), %eax ret - .align 2 -.Lld_ldouble: - fldt -24(%rsp) +E(L(load_table), UNIX64_RET_INT64) + movq (%rsi), %rax ret - - .align 2 -.Lld_struct: - /* There are four possibilities here, %rax/%rdx, %xmm0/%rax, - %rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading - both rdx and xmm1 with the second word. For the remaining, - bit 8 set means xmm0 gets the second word, and bit 9 means - that rax gets the second word. */ - movq -24(%rsp), %rcx - movq -16(%rsp), %rdx - movq -16(%rsp), %xmm1 - testl $0x100, %eax - cmovnz %rdx, %rcx - movd %rcx, %xmm0 - testl $0x200, %eax - movq -24(%rsp), %rax - cmovnz %rdx, %rax +E(L(load_table), UNIX64_RET_XMM32) + movd (%rsi), %xmm0 + ret +E(L(load_table), UNIX64_RET_XMM64) + movq (%rsi), %xmm0 + ret +E(L(load_table), UNIX64_RET_X87) + fldt (%rsi) + ret +E(L(load_table), UNIX64_RET_X87_2) + fldt 16(%rsi) + fldt (%rsi) + ret +E(L(load_table), UNIX64_RET_ST_XMM0_RAX) + movq 8(%rsi), %rax + jmp L(l3) +E(L(load_table), UNIX64_RET_ST_RAX_XMM0) + movq 8(%rsi), %xmm0 + jmp L(l2) +E(L(load_table), UNIX64_RET_ST_XMM0_XMM1) + movq 8(%rsi), %xmm1 + jmp L(l3) +E(L(load_table), UNIX64_RET_ST_RAX_RDX) + movq 8(%rsi), %rdx +L(l2): + movq (%rsi), %rax + ret + .balign 8 +L(l3): + movq (%rsi), %xmm0 ret - /* See the comment above .Lload_sse; the same logic applies here. */ - .align 2 -.LUW8: -.Lsave_sse: - movdqa %xmm0, 48(%rsp) - movdqa %xmm1, 64(%rsp) - movdqa %xmm2, 80(%rsp) - movdqa %xmm3, 96(%rsp) - movdqa %xmm4, 112(%rsp) - movdqa %xmm5, 128(%rsp) - movdqa %xmm6, 144(%rsp) - movdqa %xmm7, 160(%rsp) - jmp .Lret_from_save_sse - -.LUW9: - .size ffi_closure_unix64,.-ffi_closure_unix64 - -#ifdef HAVE_AS_X86_64_UNWIND_SECTION_TYPE - .section .eh_frame,"a",@unwind -#else - .section .eh_frame,"a",@progbits -#endif -.Lframe1: - .long .LECIE1-.LSCIE1 /* CIE Length */ -.LSCIE1: - .long 0 /* CIE Identifier Tag */ - .byte 1 /* CIE Version */ - .ascii "zR\0" /* CIE Augmentation */ - .uleb128 1 /* CIE Code Alignment Factor */ - .sleb128 -8 /* CIE Data Alignment Factor */ - .byte 0x10 /* CIE RA Column */ - .uleb128 1 /* Augmentation size */ - .byte 0x1b /* FDE Encoding (pcrel sdata4) */ - .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ - .uleb128 7 - .uleb128 8 - .byte 0x80+16 /* DW_CFA_offset, %rip offset 1*-8 */ - .uleb128 1 - .align 8 -.LECIE1: -.LSFDE1: - .long .LEFDE1-.LASFDE1 /* FDE Length */ -.LASFDE1: - .long .LASFDE1-.Lframe1 /* FDE CIE offset */ -#if HAVE_AS_X86_PCREL - .long .LUW0-. /* FDE initial location */ +L(la): call PLT(C(abort)) + +L(UW11): +ENDF(C(ffi_closure_unix64)) + + .balign 2 + .globl C(ffi_go_closure_unix64_sse) + FFI_HIDDEN(C(ffi_go_closure_unix64_sse)) + +C(ffi_go_closure_unix64_sse): +L(UW12): + subq $ffi_closure_FS, %rsp +L(UW13): + /* cfi_adjust_cfa_offset(ffi_closure_FS) */ + + movdqa %xmm0, ffi_closure_OFS_V+0x00(%rsp) + movdqa %xmm1, ffi_closure_OFS_V+0x10(%rsp) + movdqa %xmm2, ffi_closure_OFS_V+0x20(%rsp) + movdqa %xmm3, ffi_closure_OFS_V+0x30(%rsp) + movdqa %xmm4, ffi_closure_OFS_V+0x40(%rsp) + movdqa %xmm5, ffi_closure_OFS_V+0x50(%rsp) + movdqa %xmm6, ffi_closure_OFS_V+0x60(%rsp) + movdqa %xmm7, ffi_closure_OFS_V+0x70(%rsp) + jmp L(sse_entry2) + +L(UW14): +ENDF(C(ffi_go_closure_unix64_sse)) + + .balign 2 + .globl C(ffi_go_closure_unix64) + FFI_HIDDEN(C(ffi_go_closure_unix64)) + +C(ffi_go_closure_unix64): +L(UW15): + subq $ffi_closure_FS, %rsp +L(UW16): + /* cfi_adjust_cfa_offset(ffi_closure_FS) */ +L(sse_entry2): + movq %rdi, ffi_closure_OFS_G+0x00(%rsp) + movq %rsi, ffi_closure_OFS_G+0x08(%rsp) + movq %rdx, ffi_closure_OFS_G+0x10(%rsp) + movq %rcx, ffi_closure_OFS_G+0x18(%rsp) + movq %r8, ffi_closure_OFS_G+0x20(%rsp) + movq %r9, ffi_closure_OFS_G+0x28(%rsp) + +#ifdef __ILP32__ + movl 4(%r10), %edi /* Load cif */ + movl 8(%r10), %esi /* Load fun */ + movl %r10d, %edx /* Load closure (user_data) */ #else - .long .LUW0@rel + movq 8(%r10), %rdi /* Load cif */ + movq 16(%r10), %rsi /* Load fun */ + movq %r10, %rdx /* Load closure (user_data) */ #endif - .long .LUW4-.LUW0 /* FDE address range */ - .uleb128 0x0 /* Augmentation size */ + jmp L(do_closure) - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LUW1-.LUW0 +L(UW17): +ENDF(C(ffi_go_closure_unix64)) - /* New stack frame based off rbp. This is a itty bit of unwind - trickery in that the CFA *has* changed. There is no easy way - to describe it correctly on entry to the function. Fortunately, - it doesn't matter too much since at all points we can correctly - unwind back to ffi_call. Note that the location to which we - moved the return address is (the new) CFA-8, so from the - perspective of the unwind info, it hasn't moved. */ - .byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */ - .uleb128 6 - .uleb128 32 - .byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */ - .uleb128 2 - .byte 0xa /* DW_CFA_remember_state */ +/* Sadly, OSX cctools-as doesn't understand .cfi directives at all. */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LUW2-.LUW1 - .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ - .uleb128 7 - .uleb128 8 - .byte 0xc0+6 /* DW_CFA_restore, %rbp */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LUW3-.LUW2 - .byte 0xb /* DW_CFA_restore_state */ - - .align 8 -.LEFDE1: -.LSFDE3: - .long .LEFDE3-.LASFDE3 /* FDE Length */ -.LASFDE3: - .long .LASFDE3-.Lframe1 /* FDE CIE offset */ -#if HAVE_AS_X86_PCREL - .long .LUW5-. /* FDE initial location */ +#ifdef __APPLE__ +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support +EHFrame0: +#elif defined(HAVE_AS_X86_64_UNWIND_SECTION_TYPE) +.section .eh_frame,"a",@unwind #else - .long .LUW5@rel +.section .eh_frame,"a",@progbits #endif - .long .LUW9-.LUW5 /* FDE address range */ - .uleb128 0x0 /* Augmentation size */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LUW6-.LUW5 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .uleb128 208 - .byte 0xa /* DW_CFA_remember_state */ +#ifdef HAVE_AS_X86_PCREL +# define PCREL(X) X - . +#else +# define PCREL(X) X@rel +#endif - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LUW7-.LUW6 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .uleb128 8 +/* Simplify advancing between labels. Assume DW_CFA_advance_loc1 fits. */ +#define ADV(N, P) .byte 2, L(N)-L(P) - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LUW8-.LUW7 + .balign 8 +L(CIE): + .set L(set0),L(ECIE)-L(SCIE) + .long L(set0) /* CIE Length */ +L(SCIE): + .long 0 /* CIE Identifier Tag */ + .byte 1 /* CIE Version */ + .ascii "zR\0" /* CIE Augmentation */ + .byte 1 /* CIE Code Alignment Factor */ + .byte 0x78 /* CIE Data Alignment Factor */ + .byte 0x10 /* CIE RA Column */ + .byte 1 /* Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ + .byte 0xc, 7, 8 /* DW_CFA_def_cfa, %rsp offset 8 */ + .byte 0x80+16, 1 /* DW_CFA_offset, %rip offset 1*-8 */ + .balign 8 +L(ECIE): + + .set L(set1),L(EFDE1)-L(SFDE1) + .long L(set1) /* FDE Length */ +L(SFDE1): + .long L(SFDE1)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW0)) /* Initial location */ + .long L(UW4)-L(UW0) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW1, UW0) + .byte 0xc, 6, 32 /* DW_CFA_def_cfa, %rbp 32 */ + .byte 0x80+6, 2 /* DW_CFA_offset, %rbp 2*-8 */ + ADV(UW2, UW1) + .byte 0xa /* DW_CFA_remember_state */ + .byte 0xc, 7, 8 /* DW_CFA_def_cfa, %rsp 8 */ + .byte 0xc0+6 /* DW_CFA_restore, %rbp */ + ADV(UW3, UW2) .byte 0xb /* DW_CFA_restore_state */ - - .align 8 -.LEFDE3: + .balign 8 +L(EFDE1): + + .set L(set2),L(EFDE2)-L(SFDE2) + .long L(set2) /* FDE Length */ +L(SFDE2): + .long L(SFDE2)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW5)) /* Initial location */ + .long L(UW7)-L(UW5) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW6, UW5) + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */ + .balign 8 +L(EFDE2): + + .set L(set3),L(EFDE3)-L(SFDE3) + .long L(set3) /* FDE Length */ +L(SFDE3): + .long L(SFDE3)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW8)) /* Initial location */ + .long L(UW11)-L(UW8) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW9, UW8) + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */ + ADV(UW10, UW9) + .byte 0xe, 8 /* DW_CFA_def_cfa_offset 8 */ +L(EFDE3): + + .set L(set4),L(EFDE4)-L(SFDE4) + .long L(set4) /* FDE Length */ +L(SFDE4): + .long L(SFDE4)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW12)) /* Initial location */ + .long L(UW14)-L(UW12) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW13, UW12) + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */ + .balign 8 +L(EFDE4): + + .set L(set5),L(EFDE5)-L(SFDE5) + .long L(set5) /* FDE Length */ +L(SFDE5): + .long L(SFDE5)-L(CIE) /* FDE CIE offset */ + .long PCREL(L(UW15)) /* Initial location */ + .long L(UW17)-L(UW15) /* Address range */ + .byte 0 /* Augmentation size */ + ADV(UW16, UW15) + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte ffi_closure_FS + 8, 1 /* uleb128, assuming 128 <= FS < 255 */ + .balign 8 +L(EFDE5): +#ifdef __APPLE__ + .subsections_via_symbols +#endif #endif /* __x86_64__ */ - #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits #endif diff --git a/libffi/src/x86/win32.S b/libffi/src/x86/win32.S deleted file mode 100644 index 24b7bbd..0000000 --- a/libffi/src/x86/win32.S +++ /dev/null @@ -1,1201 +0,0 @@ -/* ----------------------------------------------------------------------- - win32.S - Copyright (c) 1996, 1998, 2001, 2002, 2009 Red Hat, Inc. - Copyright (c) 2001 John Beniton - Copyright (c) 2002 Ranjit Mathew - Copyright (c) 2009 Daniel Witte - - - X86 Foreign Function Interface - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- - */ - -#define LIBFFI_ASM -#include <fficonfig.h> -#include <ffi.h> - -#ifdef _MSC_VER - -.386 -.MODEL FLAT, C - -EXTRN ffi_closure_SYSV_inner:NEAR - -_TEXT SEGMENT - -ffi_call_win32 PROC NEAR, - ffi_prep_args : NEAR PTR DWORD, - ecif : NEAR PTR DWORD, - cif_abi : DWORD, - cif_bytes : DWORD, - cif_flags : DWORD, - rvalue : NEAR PTR DWORD, - fn : NEAR PTR DWORD - - ;; Make room for all of the new args. - mov ecx, cif_bytes - sub esp, ecx - - mov eax, esp - - ;; Place all of the ffi_prep_args in position - push ecif - push eax - call ffi_prep_args - - ;; Return stack to previous state and call the function - add esp, 8 - - ;; Handle thiscall and fastcall - cmp cif_abi, 3 ;; FFI_THISCALL - jz do_thiscall - cmp cif_abi, 4 ;; FFI_FASTCALL - jnz do_stdcall - mov ecx, DWORD PTR [esp] - mov edx, DWORD PTR [esp+4] - add esp, 8 - jmp do_stdcall -do_thiscall: - mov ecx, DWORD PTR [esp] - add esp, 4 -do_stdcall: - call fn - - ;; cdecl: we restore esp in the epilogue, so there's no need to - ;; remove the space we pushed for the args. - ;; stdcall: the callee has already cleaned the stack. - - ;; Load ecx with the return type code - mov ecx, cif_flags - - ;; If the return value pointer is NULL, assume no return value. - cmp rvalue, 0 - jne ca_jumptable - - ;; Even if there is no space for the return value, we are - ;; obliged to handle floating-point values. - cmp ecx, FFI_TYPE_FLOAT - jne ca_epilogue - fstp st(0) - - jmp ca_epilogue - -ca_jumptable: - jmp [ca_jumpdata + 4 * ecx] -ca_jumpdata: - ;; Do not insert anything here between label and jump table. - dd offset ca_epilogue ;; FFI_TYPE_VOID - dd offset ca_retint ;; FFI_TYPE_INT - dd offset ca_retfloat ;; FFI_TYPE_FLOAT - dd offset ca_retdouble ;; FFI_TYPE_DOUBLE - dd offset ca_retlongdouble ;; FFI_TYPE_LONGDOUBLE - dd offset ca_retuint8 ;; FFI_TYPE_UINT8 - dd offset ca_retsint8 ;; FFI_TYPE_SINT8 - dd offset ca_retuint16 ;; FFI_TYPE_UINT16 - dd offset ca_retsint16 ;; FFI_TYPE_SINT16 - dd offset ca_retint ;; FFI_TYPE_UINT32 - dd offset ca_retint ;; FFI_TYPE_SINT32 - dd offset ca_retint64 ;; FFI_TYPE_UINT64 - dd offset ca_retint64 ;; FFI_TYPE_SINT64 - dd offset ca_epilogue ;; FFI_TYPE_STRUCT - dd offset ca_retint ;; FFI_TYPE_POINTER - dd offset ca_retstruct1b ;; FFI_TYPE_SMALL_STRUCT_1B - dd offset ca_retstruct2b ;; FFI_TYPE_SMALL_STRUCT_2B - dd offset ca_retint ;; FFI_TYPE_SMALL_STRUCT_4B - dd offset ca_epilogue ;; FFI_TYPE_MS_STRUCT - - /* Sign/zero extend as appropriate. */ -ca_retuint8: - movzx eax, al - jmp ca_retint - -ca_retsint8: - movsx eax, al - jmp ca_retint - -ca_retuint16: - movzx eax, ax - jmp ca_retint - -ca_retsint16: - movsx eax, ax - jmp ca_retint - -ca_retint: - ;; Load %ecx with the pointer to storage for the return value - mov ecx, rvalue - mov [ecx + 0], eax - jmp ca_epilogue - -ca_retint64: - ;; Load %ecx with the pointer to storage for the return value - mov ecx, rvalue - mov [ecx + 0], eax - mov [ecx + 4], edx - jmp ca_epilogue - -ca_retfloat: - ;; Load %ecx with the pointer to storage for the return value - mov ecx, rvalue - fstp DWORD PTR [ecx] - jmp ca_epilogue - -ca_retdouble: - ;; Load %ecx with the pointer to storage for the return value - mov ecx, rvalue - fstp QWORD PTR [ecx] - jmp ca_epilogue - -ca_retlongdouble: - ;; Load %ecx with the pointer to storage for the return value - mov ecx, rvalue - fstp TBYTE PTR [ecx] - jmp ca_epilogue - -ca_retstruct1b: - ;; Load %ecx with the pointer to storage for the return value - mov ecx, rvalue - mov [ecx + 0], al - jmp ca_epilogue - -ca_retstruct2b: - ;; Load %ecx with the pointer to storage for the return value - mov ecx, rvalue - mov [ecx + 0], ax - jmp ca_epilogue - -ca_epilogue: - ;; Epilogue code is autogenerated. - ret -ffi_call_win32 ENDP - -ffi_closure_THISCALL PROC NEAR FORCEFRAME - sub esp, 40 - lea edx, [ebp -24] - mov [ebp - 12], edx /* resp */ - lea edx, [ebp + 12] /* account for stub return address on stack */ - jmp stub -ffi_closure_THISCALL ENDP - -ffi_closure_SYSV PROC NEAR FORCEFRAME - ;; the ffi_closure ctx is passed in eax by the trampoline. - - sub esp, 40 - lea edx, [ebp - 24] - mov [ebp - 12], edx ;; resp - lea edx, [ebp + 8] -stub:: - mov [esp + 8], edx ;; args - lea edx, [ebp - 12] - mov [esp + 4], edx ;; &resp - mov [esp], eax ;; closure - call ffi_closure_SYSV_inner - mov ecx, [ebp - 12] - -cs_jumptable: - jmp [cs_jumpdata + 4 * eax] -cs_jumpdata: - ;; Do not insert anything here between the label and jump table. - dd offset cs_epilogue ;; FFI_TYPE_VOID - dd offset cs_retint ;; FFI_TYPE_INT - dd offset cs_retfloat ;; FFI_TYPE_FLOAT - dd offset cs_retdouble ;; FFI_TYPE_DOUBLE - dd offset cs_retlongdouble ;; FFI_TYPE_LONGDOUBLE - dd offset cs_retuint8 ;; FFI_TYPE_UINT8 - dd offset cs_retsint8 ;; FFI_TYPE_SINT8 - dd offset cs_retuint16 ;; FFI_TYPE_UINT16 - dd offset cs_retsint16 ;; FFI_TYPE_SINT16 - dd offset cs_retint ;; FFI_TYPE_UINT32 - dd offset cs_retint ;; FFI_TYPE_SINT32 - dd offset cs_retint64 ;; FFI_TYPE_UINT64 - dd offset cs_retint64 ;; FFI_TYPE_SINT64 - dd offset cs_retstruct ;; FFI_TYPE_STRUCT - dd offset cs_retint ;; FFI_TYPE_POINTER - dd offset cs_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B - dd offset cs_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B - dd offset cs_retint ;; FFI_TYPE_SMALL_STRUCT_4B - dd offset cs_retmsstruct ;; FFI_TYPE_MS_STRUCT - -cs_retuint8: - movzx eax, BYTE PTR [ecx] - jmp cs_epilogue - -cs_retsint8: - movsx eax, BYTE PTR [ecx] - jmp cs_epilogue - -cs_retuint16: - movzx eax, WORD PTR [ecx] - jmp cs_epilogue - -cs_retsint16: - movsx eax, WORD PTR [ecx] - jmp cs_epilogue - -cs_retint: - mov eax, [ecx] - jmp cs_epilogue - -cs_retint64: - mov eax, [ecx + 0] - mov edx, [ecx + 4] - jmp cs_epilogue - -cs_retfloat: - fld DWORD PTR [ecx] - jmp cs_epilogue - -cs_retdouble: - fld QWORD PTR [ecx] - jmp cs_epilogue - -cs_retlongdouble: - fld TBYTE PTR [ecx] - jmp cs_epilogue - -cs_retstruct: - ;; Caller expects us to pop struct return value pointer hidden arg. - ;; Epilogue code is autogenerated. - ret 4 - -cs_retmsstruct: - ;; Caller expects us to return a pointer to the real return value. - mov eax, ecx - ;; Caller doesn't expects us to pop struct return value pointer hidden arg. - jmp cs_epilogue - -cs_epilogue: - ;; Epilogue code is autogenerated. - ret -ffi_closure_SYSV ENDP - -#if !FFI_NO_RAW_API - -#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) AND NOT 3) -#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) -#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) -#define CIF_FLAGS_OFFSET 20 - -ffi_closure_raw_THISCALL PROC NEAR USES esi FORCEFRAME - sub esp, 36 - mov esi, [eax + RAW_CLOSURE_CIF_OFFSET] ;; closure->cif - mov edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET] ;; closure->user_data - mov [esp + 12], edx - lea edx, [ebp + 12] - jmp stubraw -ffi_closure_raw_THISCALL ENDP - -ffi_closure_raw_SYSV PROC NEAR USES esi FORCEFRAME - ;; the ffi_closure ctx is passed in eax by the trampoline. - - sub esp, 40 - mov esi, [eax + RAW_CLOSURE_CIF_OFFSET] ;; closure->cif - mov edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET] ;; closure->user_data - mov [esp + 12], edx ;; user_data - lea edx, [ebp + 8] -stubraw:: - mov [esp + 8], edx ;; raw_args - lea edx, [ebp - 24] - mov [esp + 4], edx ;; &res - mov [esp], esi ;; cif - call DWORD PTR [eax + RAW_CLOSURE_FUN_OFFSET] ;; closure->fun - mov eax, [esi + CIF_FLAGS_OFFSET] ;; cif->flags - lea ecx, [ebp - 24] - -cr_jumptable: - jmp [cr_jumpdata + 4 * eax] -cr_jumpdata: - ;; Do not insert anything here between the label and jump table. - dd offset cr_epilogue ;; FFI_TYPE_VOID - dd offset cr_retint ;; FFI_TYPE_INT - dd offset cr_retfloat ;; FFI_TYPE_FLOAT - dd offset cr_retdouble ;; FFI_TYPE_DOUBLE - dd offset cr_retlongdouble ;; FFI_TYPE_LONGDOUBLE - dd offset cr_retuint8 ;; FFI_TYPE_UINT8 - dd offset cr_retsint8 ;; FFI_TYPE_SINT8 - dd offset cr_retuint16 ;; FFI_TYPE_UINT16 - dd offset cr_retsint16 ;; FFI_TYPE_SINT16 - dd offset cr_retint ;; FFI_TYPE_UINT32 - dd offset cr_retint ;; FFI_TYPE_SINT32 - dd offset cr_retint64 ;; FFI_TYPE_UINT64 - dd offset cr_retint64 ;; FFI_TYPE_SINT64 - dd offset cr_epilogue ;; FFI_TYPE_STRUCT - dd offset cr_retint ;; FFI_TYPE_POINTER - dd offset cr_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B - dd offset cr_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B - dd offset cr_retint ;; FFI_TYPE_SMALL_STRUCT_4B - dd offset cr_epilogue ;; FFI_TYPE_MS_STRUCT - -cr_retuint8: - movzx eax, BYTE PTR [ecx] - jmp cr_epilogue - -cr_retsint8: - movsx eax, BYTE PTR [ecx] - jmp cr_epilogue - -cr_retuint16: - movzx eax, WORD PTR [ecx] - jmp cr_epilogue - -cr_retsint16: - movsx eax, WORD PTR [ecx] - jmp cr_epilogue - -cr_retint: - mov eax, [ecx] - jmp cr_epilogue - -cr_retint64: - mov eax, [ecx + 0] - mov edx, [ecx + 4] - jmp cr_epilogue - -cr_retfloat: - fld DWORD PTR [ecx] - jmp cr_epilogue - -cr_retdouble: - fld QWORD PTR [ecx] - jmp cr_epilogue - -cr_retlongdouble: - fld TBYTE PTR [ecx] - jmp cr_epilogue - -cr_epilogue: - ;; Epilogue code is autogenerated. - ret -ffi_closure_raw_SYSV ENDP - -#endif /* !FFI_NO_RAW_API */ - -ffi_closure_STDCALL PROC NEAR FORCEFRAME - ;; the ffi_closure ctx is passed in eax by the trampoline. - - sub esp, 40 - lea edx, [ebp - 24] - mov [ebp - 12], edx ;; resp - lea edx, [ebp + 12] ;; account for stub return address on stack - mov [esp + 8], edx ;; args - lea edx, [ebp - 12] - mov [esp + 4], edx ;; &resp - mov [esp], eax ;; closure - call ffi_closure_SYSV_inner - mov ecx, [ebp - 12] - -cd_jumptable: - jmp [cd_jumpdata + 4 * eax] -cd_jumpdata: - ;; Do not insert anything here between the label and jump table. - dd offset cd_epilogue ;; FFI_TYPE_VOID - dd offset cd_retint ;; FFI_TYPE_INT - dd offset cd_retfloat ;; FFI_TYPE_FLOAT - dd offset cd_retdouble ;; FFI_TYPE_DOUBLE - dd offset cd_retlongdouble ;; FFI_TYPE_LONGDOUBLE - dd offset cd_retuint8 ;; FFI_TYPE_UINT8 - dd offset cd_retsint8 ;; FFI_TYPE_SINT8 - dd offset cd_retuint16 ;; FFI_TYPE_UINT16 - dd offset cd_retsint16 ;; FFI_TYPE_SINT16 - dd offset cd_retint ;; FFI_TYPE_UINT32 - dd offset cd_retint ;; FFI_TYPE_SINT32 - dd offset cd_retint64 ;; FFI_TYPE_UINT64 - dd offset cd_retint64 ;; FFI_TYPE_SINT64 - dd offset cd_epilogue ;; FFI_TYPE_STRUCT - dd offset cd_retint ;; FFI_TYPE_POINTER - dd offset cd_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B - dd offset cd_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B - dd offset cd_retint ;; FFI_TYPE_SMALL_STRUCT_4B - -cd_retuint8: - movzx eax, BYTE PTR [ecx] - jmp cd_epilogue - -cd_retsint8: - movsx eax, BYTE PTR [ecx] - jmp cd_epilogue - -cd_retuint16: - movzx eax, WORD PTR [ecx] - jmp cd_epilogue - -cd_retsint16: - movsx eax, WORD PTR [ecx] - jmp cd_epilogue - -cd_retint: - mov eax, [ecx] - jmp cd_epilogue - -cd_retint64: - mov eax, [ecx + 0] - mov edx, [ecx + 4] - jmp cd_epilogue - -cd_retfloat: - fld DWORD PTR [ecx] - jmp cd_epilogue - -cd_retdouble: - fld QWORD PTR [ecx] - jmp cd_epilogue - -cd_retlongdouble: - fld TBYTE PTR [ecx] - jmp cd_epilogue - -cd_epilogue: - ;; Epilogue code is autogenerated. - ret -ffi_closure_STDCALL ENDP - -_TEXT ENDS -END - -#else - - .text - - # This assumes we are using gas. - .balign 16 - .globl _ffi_call_win32 -#ifndef __OS2__ - .def _ffi_call_win32; .scl 2; .type 32; .endef -#endif -_ffi_call_win32: -.LFB1: - pushl %ebp -.LCFI0: - movl %esp,%ebp -.LCFI1: - # Make room for all of the new args. - movl 20(%ebp),%ecx - subl %ecx,%esp - - movl %esp,%eax - - # Place all of the ffi_prep_args in position - pushl 12(%ebp) - pushl %eax - call *8(%ebp) - - # Return stack to previous state and call the function - addl $8,%esp - - # Handle fastcall and thiscall - cmpl $3, 16(%ebp) # FFI_THISCALL - jz .do_thiscall - cmpl $4, 16(%ebp) # FFI_FASTCALL - jnz .do_fncall - movl (%esp), %ecx - movl 4(%esp), %edx - addl $8, %esp - jmp .do_fncall -.do_thiscall: - movl (%esp), %ecx - addl $4, %esp - -.do_fncall: - - # FIXME: Align the stack to a 128-bit boundary to avoid - # potential performance hits. - - call *32(%ebp) - - # stdcall functions pop arguments off the stack themselves - - # Load %ecx with the return type code - movl 24(%ebp),%ecx - - # If the return value pointer is NULL, assume no return value. - cmpl $0,28(%ebp) - jne 0f - - # Even if there is no space for the return value, we are - # obliged to handle floating-point values. - cmpl $FFI_TYPE_FLOAT,%ecx - jne .Lnoretval - fstp %st(0) - - jmp .Lepilogue - -0: - call 1f - # Do not insert anything here between the call and the jump table. -.Lstore_table: - .long .Lnoretval /* FFI_TYPE_VOID */ - .long .Lretint /* FFI_TYPE_INT */ - .long .Lretfloat /* FFI_TYPE_FLOAT */ - .long .Lretdouble /* FFI_TYPE_DOUBLE */ - .long .Lretlongdouble /* FFI_TYPE_LONGDOUBLE */ - .long .Lretuint8 /* FFI_TYPE_UINT8 */ - .long .Lretsint8 /* FFI_TYPE_SINT8 */ - .long .Lretuint16 /* FFI_TYPE_UINT16 */ - .long .Lretsint16 /* FFI_TYPE_SINT16 */ - .long .Lretint /* FFI_TYPE_UINT32 */ - .long .Lretint /* FFI_TYPE_SINT32 */ - .long .Lretint64 /* FFI_TYPE_UINT64 */ - .long .Lretint64 /* FFI_TYPE_SINT64 */ - .long .Lretstruct /* FFI_TYPE_STRUCT */ - .long .Lretint /* FFI_TYPE_POINTER */ - .long .Lretstruct1b /* FFI_TYPE_SMALL_STRUCT_1B */ - .long .Lretstruct2b /* FFI_TYPE_SMALL_STRUCT_2B */ - .long .Lretstruct4b /* FFI_TYPE_SMALL_STRUCT_4B */ - .long .Lretstruct /* FFI_TYPE_MS_STRUCT */ -1: - add %ecx, %ecx - add %ecx, %ecx - add (%esp),%ecx - add $4, %esp - jmp *(%ecx) - - /* Sign/zero extend as appropriate. */ -.Lretsint8: - movsbl %al, %eax - jmp .Lretint - -.Lretsint16: - movswl %ax, %eax - jmp .Lretint - -.Lretuint8: - movzbl %al, %eax - jmp .Lretint - -.Lretuint16: - movzwl %ax, %eax - jmp .Lretint - -.Lretint: - # Load %ecx with the pointer to storage for the return value - movl 28(%ebp),%ecx - movl %eax,0(%ecx) - jmp .Lepilogue - -.Lretfloat: - # Load %ecx with the pointer to storage for the return value - movl 28(%ebp),%ecx - fstps (%ecx) - jmp .Lepilogue - -.Lretdouble: - # Load %ecx with the pointer to storage for the return value - movl 28(%ebp),%ecx - fstpl (%ecx) - jmp .Lepilogue - -.Lretlongdouble: - # Load %ecx with the pointer to storage for the return value - movl 28(%ebp),%ecx - fstpt (%ecx) - jmp .Lepilogue - -.Lretint64: - # Load %ecx with the pointer to storage for the return value - movl 28(%ebp),%ecx - movl %eax,0(%ecx) - movl %edx,4(%ecx) - jmp .Lepilogue - -.Lretstruct1b: - # Load %ecx with the pointer to storage for the return value - movl 28(%ebp),%ecx - movb %al,0(%ecx) - jmp .Lepilogue - -.Lretstruct2b: - # Load %ecx with the pointer to storage for the return value - movl 28(%ebp),%ecx - movw %ax,0(%ecx) - jmp .Lepilogue - -.Lretstruct4b: - # Load %ecx with the pointer to storage for the return value - movl 28(%ebp),%ecx - movl %eax,0(%ecx) - jmp .Lepilogue - -.Lretstruct: - # Nothing to do! - -.Lnoretval: -.Lepilogue: - movl %ebp,%esp - popl %ebp - ret -.ffi_call_win32_end: - .balign 16 - .globl _ffi_closure_THISCALL -#ifndef __OS2__ - .def _ffi_closure_THISCALL; .scl 2; .type 32; .endef -#endif -_ffi_closure_THISCALL: - pushl %ebp - movl %esp, %ebp - subl $40, %esp - leal -24(%ebp), %edx - movl %edx, -12(%ebp) /* resp */ - leal 12(%ebp), %edx /* account for stub return address on stack */ - jmp .stub -.LFE1: - - # This assumes we are using gas. - .balign 16 - .globl _ffi_closure_SYSV -#ifndef __OS2__ - .def _ffi_closure_SYSV; .scl 2; .type 32; .endef -#endif -_ffi_closure_SYSV: -.LFB3: - pushl %ebp -.LCFI4: - movl %esp, %ebp -.LCFI5: - subl $40, %esp - leal -24(%ebp), %edx - movl %edx, -12(%ebp) /* resp */ - leal 8(%ebp), %edx -.stub: - movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ - leal -12(%ebp), %edx - movl %edx, (%esp) /* &resp */ - call _ffi_closure_SYSV_inner - movl -12(%ebp), %ecx - -0: - call 1f - # Do not insert anything here between the call and the jump table. -.Lcls_store_table: - .long .Lcls_noretval /* FFI_TYPE_VOID */ - .long .Lcls_retint /* FFI_TYPE_INT */ - .long .Lcls_retfloat /* FFI_TYPE_FLOAT */ - .long .Lcls_retdouble /* FFI_TYPE_DOUBLE */ - .long .Lcls_retldouble /* FFI_TYPE_LONGDOUBLE */ - .long .Lcls_retuint8 /* FFI_TYPE_UINT8 */ - .long .Lcls_retsint8 /* FFI_TYPE_SINT8 */ - .long .Lcls_retuint16 /* FFI_TYPE_UINT16 */ - .long .Lcls_retsint16 /* FFI_TYPE_SINT16 */ - .long .Lcls_retint /* FFI_TYPE_UINT32 */ - .long .Lcls_retint /* FFI_TYPE_SINT32 */ - .long .Lcls_retllong /* FFI_TYPE_UINT64 */ - .long .Lcls_retllong /* FFI_TYPE_SINT64 */ - .long .Lcls_retstruct /* FFI_TYPE_STRUCT */ - .long .Lcls_retint /* FFI_TYPE_POINTER */ - .long .Lcls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */ - .long .Lcls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */ - .long .Lcls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */ - .long .Lcls_retmsstruct /* FFI_TYPE_MS_STRUCT */ - -1: - add %eax, %eax - add %eax, %eax - add (%esp),%eax - add $4, %esp - jmp *(%eax) - - /* Sign/zero extend as appropriate. */ -.Lcls_retsint8: - movsbl (%ecx), %eax - jmp .Lcls_epilogue - -.Lcls_retsint16: - movswl (%ecx), %eax - jmp .Lcls_epilogue - -.Lcls_retuint8: - movzbl (%ecx), %eax - jmp .Lcls_epilogue - -.Lcls_retuint16: - movzwl (%ecx), %eax - jmp .Lcls_epilogue - -.Lcls_retint: - movl (%ecx), %eax - jmp .Lcls_epilogue - -.Lcls_retfloat: - flds (%ecx) - jmp .Lcls_epilogue - -.Lcls_retdouble: - fldl (%ecx) - jmp .Lcls_epilogue - -.Lcls_retldouble: - fldt (%ecx) - jmp .Lcls_epilogue - -.Lcls_retllong: - movl (%ecx), %eax - movl 4(%ecx), %edx - jmp .Lcls_epilogue - -.Lcls_retstruct1: - movsbl (%ecx), %eax - jmp .Lcls_epilogue - -.Lcls_retstruct2: - movswl (%ecx), %eax - jmp .Lcls_epilogue - -.Lcls_retstruct4: - movl (%ecx), %eax - jmp .Lcls_epilogue - -.Lcls_retstruct: - # Caller expects us to pop struct return value pointer hidden arg. - movl %ebp, %esp - popl %ebp - ret $0x4 - -.Lcls_retmsstruct: - # Caller expects us to return a pointer to the real return value. - mov %ecx, %eax - # Caller doesn't expects us to pop struct return value pointer hidden arg. - jmp .Lcls_epilogue - -.Lcls_noretval: -.Lcls_epilogue: - movl %ebp, %esp - popl %ebp - ret -.ffi_closure_SYSV_end: -.LFE3: - -#if !FFI_NO_RAW_API - -#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) -#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) -#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) -#define CIF_FLAGS_OFFSET 20 - .balign 16 - .globl _ffi_closure_raw_THISCALL -#ifndef __OS2__ - .def _ffi_closure_raw_THISCALL; .scl 2; .type 32; .endef -#endif -_ffi_closure_raw_THISCALL: - pushl %ebp - movl %esp, %ebp - pushl %esi - subl $36, %esp - movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ - movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ - movl %edx, 12(%esp) /* user_data */ - leal 12(%ebp), %edx /* __builtin_dwarf_cfa () */ - jmp .stubraw - # This assumes we are using gas. - .balign 16 - .globl _ffi_closure_raw_SYSV -#ifndef __OS2__ - .def _ffi_closure_raw_SYSV; .scl 2; .type 32; .endef -#endif -_ffi_closure_raw_SYSV: -.LFB4: - pushl %ebp -.LCFI6: - movl %esp, %ebp -.LCFI7: - pushl %esi -.LCFI8: - subl $36, %esp - movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ - movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ - movl %edx, 12(%esp) /* user_data */ - leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ -.stubraw: - movl %edx, 8(%esp) /* raw_args */ - leal -24(%ebp), %edx - movl %edx, 4(%esp) /* &res */ - movl %esi, (%esp) /* cif */ - call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ - movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ -0: - call 1f - # Do not insert anything here between the call and the jump table. -.Lrcls_store_table: - .long .Lrcls_noretval /* FFI_TYPE_VOID */ - .long .Lrcls_retint /* FFI_TYPE_INT */ - .long .Lrcls_retfloat /* FFI_TYPE_FLOAT */ - .long .Lrcls_retdouble /* FFI_TYPE_DOUBLE */ - .long .Lrcls_retldouble /* FFI_TYPE_LONGDOUBLE */ - .long .Lrcls_retuint8 /* FFI_TYPE_UINT8 */ - .long .Lrcls_retsint8 /* FFI_TYPE_SINT8 */ - .long .Lrcls_retuint16 /* FFI_TYPE_UINT16 */ - .long .Lrcls_retsint16 /* FFI_TYPE_SINT16 */ - .long .Lrcls_retint /* FFI_TYPE_UINT32 */ - .long .Lrcls_retint /* FFI_TYPE_SINT32 */ - .long .Lrcls_retllong /* FFI_TYPE_UINT64 */ - .long .Lrcls_retllong /* FFI_TYPE_SINT64 */ - .long .Lrcls_retstruct /* FFI_TYPE_STRUCT */ - .long .Lrcls_retint /* FFI_TYPE_POINTER */ - .long .Lrcls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */ - .long .Lrcls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */ - .long .Lrcls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */ - .long .Lrcls_retstruct /* FFI_TYPE_MS_STRUCT */ -1: - add %eax, %eax - add %eax, %eax - add (%esp),%eax - add $4, %esp - jmp *(%eax) - - /* Sign/zero extend as appropriate. */ -.Lrcls_retsint8: - movsbl -24(%ebp), %eax - jmp .Lrcls_epilogue - -.Lrcls_retsint16: - movswl -24(%ebp), %eax - jmp .Lrcls_epilogue - -.Lrcls_retuint8: - movzbl -24(%ebp), %eax - jmp .Lrcls_epilogue - -.Lrcls_retuint16: - movzwl -24(%ebp), %eax - jmp .Lrcls_epilogue - -.Lrcls_retint: - movl -24(%ebp), %eax - jmp .Lrcls_epilogue - -.Lrcls_retfloat: - flds -24(%ebp) - jmp .Lrcls_epilogue - -.Lrcls_retdouble: - fldl -24(%ebp) - jmp .Lrcls_epilogue - -.Lrcls_retldouble: - fldt -24(%ebp) - jmp .Lrcls_epilogue - -.Lrcls_retllong: - movl -24(%ebp), %eax - movl -20(%ebp), %edx - jmp .Lrcls_epilogue - -.Lrcls_retstruct1: - movsbl -24(%ebp), %eax - jmp .Lrcls_epilogue - -.Lrcls_retstruct2: - movswl -24(%ebp), %eax - jmp .Lrcls_epilogue - -.Lrcls_retstruct4: - movl -24(%ebp), %eax - jmp .Lrcls_epilogue - -.Lrcls_retstruct: - # Nothing to do! - -.Lrcls_noretval: -.Lrcls_epilogue: - addl $36, %esp - popl %esi - popl %ebp - ret -.ffi_closure_raw_SYSV_end: -.LFE4: - -#endif /* !FFI_NO_RAW_API */ - - # This assumes we are using gas. - .balign 16 - .globl _ffi_closure_STDCALL -#ifndef __OS2__ - .def _ffi_closure_STDCALL; .scl 2; .type 32; .endef -#endif -_ffi_closure_STDCALL: -.LFB5: - pushl %ebp -.LCFI9: - movl %esp, %ebp -.LCFI10: - subl $40, %esp - leal -24(%ebp), %edx - movl %edx, -12(%ebp) /* resp */ - leal 12(%ebp), %edx /* account for stub return address on stack */ - movl %edx, 4(%esp) /* args */ - leal -12(%ebp), %edx - movl %edx, (%esp) /* &resp */ - call _ffi_closure_SYSV_inner - movl -12(%ebp), %ecx -0: - call 1f - # Do not insert anything here between the call and the jump table. -.Lscls_store_table: - .long .Lscls_noretval /* FFI_TYPE_VOID */ - .long .Lscls_retint /* FFI_TYPE_INT */ - .long .Lscls_retfloat /* FFI_TYPE_FLOAT */ - .long .Lscls_retdouble /* FFI_TYPE_DOUBLE */ - .long .Lscls_retldouble /* FFI_TYPE_LONGDOUBLE */ - .long .Lscls_retuint8 /* FFI_TYPE_UINT8 */ - .long .Lscls_retsint8 /* FFI_TYPE_SINT8 */ - .long .Lscls_retuint16 /* FFI_TYPE_UINT16 */ - .long .Lscls_retsint16 /* FFI_TYPE_SINT16 */ - .long .Lscls_retint /* FFI_TYPE_UINT32 */ - .long .Lscls_retint /* FFI_TYPE_SINT32 */ - .long .Lscls_retllong /* FFI_TYPE_UINT64 */ - .long .Lscls_retllong /* FFI_TYPE_SINT64 */ - .long .Lscls_retstruct /* FFI_TYPE_STRUCT */ - .long .Lscls_retint /* FFI_TYPE_POINTER */ - .long .Lscls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */ - .long .Lscls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */ - .long .Lscls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */ -1: - add %eax, %eax - add %eax, %eax - add (%esp),%eax - add $4, %esp - jmp *(%eax) - - /* Sign/zero extend as appropriate. */ -.Lscls_retsint8: - movsbl (%ecx), %eax - jmp .Lscls_epilogue - -.Lscls_retsint16: - movswl (%ecx), %eax - jmp .Lscls_epilogue - -.Lscls_retuint8: - movzbl (%ecx), %eax - jmp .Lscls_epilogue - -.Lscls_retuint16: - movzwl (%ecx), %eax - jmp .Lscls_epilogue - -.Lscls_retint: - movl (%ecx), %eax - jmp .Lscls_epilogue - -.Lscls_retfloat: - flds (%ecx) - jmp .Lscls_epilogue - -.Lscls_retdouble: - fldl (%ecx) - jmp .Lscls_epilogue - -.Lscls_retldouble: - fldt (%ecx) - jmp .Lscls_epilogue - -.Lscls_retllong: - movl (%ecx), %eax - movl 4(%ecx), %edx - jmp .Lscls_epilogue - -.Lscls_retstruct1: - movsbl (%ecx), %eax - jmp .Lscls_epilogue - -.Lscls_retstruct2: - movswl (%ecx), %eax - jmp .Lscls_epilogue - -.Lscls_retstruct4: - movl (%ecx), %eax - jmp .Lscls_epilogue - -.Lscls_retstruct: - # Nothing to do! - -.Lscls_noretval: -.Lscls_epilogue: - movl %ebp, %esp - popl %ebp - ret -.ffi_closure_STDCALL_end: -.LFE5: - -#ifndef __OS2__ - .section .eh_frame,"w" -#endif -.Lframe1: -.LSCIE1: - .long .LECIE1-.LASCIE1 /* Length of Common Information Entry */ -.LASCIE1: - .long 0x0 /* CIE Identifier Tag */ - .byte 0x1 /* CIE Version */ -#ifdef __PIC__ - .ascii "zR\0" /* CIE Augmentation */ -#else - .ascii "\0" /* CIE Augmentation */ -#endif - .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */ - .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ - .byte 0x8 /* CIE RA Column */ -#ifdef __PIC__ - .byte 0x1 /* .uleb128 0x1; Augmentation size */ - .byte 0x1b /* FDE Encoding (pcrel sdata4) */ -#endif - .byte 0xc /* DW_CFA_def_cfa CFA = r4 + 4 = 4(%esp) */ - .byte 0x4 /* .uleb128 0x4 */ - .byte 0x4 /* .uleb128 0x4 */ - .byte 0x88 /* DW_CFA_offset, column 0x8 %eip at CFA + 1 * -4 */ - .byte 0x1 /* .uleb128 0x1 */ - .align 4 -.LECIE1: - -.LSFDE1: - .long .LEFDE1-.LASFDE1 /* FDE Length */ -.LASFDE1: - .long .LASFDE1-.Lframe1 /* FDE CIE offset */ -#if defined __PIC__ && defined HAVE_AS_X86_PCREL - .long .LFB1-. /* FDE initial location */ -#else - .long .LFB1 -#endif - .long .LFE1-.LFB1 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ -#endif - /* DW_CFA_xxx CFI instructions go here. */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI0-.LFB1 - .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */ - .byte 0x2 /* .uleb128 0x2 */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI1-.LCFI0 - .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */ - .byte 0x5 /* .uleb128 0x5 */ - - /* End of DW_CFA_xxx CFI instructions. */ - .align 4 -.LEFDE1: - - -.LSFDE3: - .long .LEFDE3-.LASFDE3 /* FDE Length */ -.LASFDE3: - .long .LASFDE3-.Lframe1 /* FDE CIE offset */ -#if defined __PIC__ && defined HAVE_AS_X86_PCREL - .long .LFB3-. /* FDE initial location */ -#else - .long .LFB3 -#endif - .long .LFE3-.LFB3 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ -#endif - /* DW_CFA_xxx CFI instructions go here. */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI4-.LFB3 - .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */ - .byte 0x2 /* .uleb128 0x2 */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI5-.LCFI4 - .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */ - .byte 0x5 /* .uleb128 0x5 */ - - /* End of DW_CFA_xxx CFI instructions. */ - .align 4 -.LEFDE3: - -#if !FFI_NO_RAW_API - -.LSFDE4: - .long .LEFDE4-.LASFDE4 /* FDE Length */ -.LASFDE4: - .long .LASFDE4-.Lframe1 /* FDE CIE offset */ -#if defined __PIC__ && defined HAVE_AS_X86_PCREL - .long .LFB4-. /* FDE initial location */ -#else - .long .LFB4 -#endif - .long .LFE4-.LFB4 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ -#endif - /* DW_CFA_xxx CFI instructions go here. */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI6-.LFB4 - .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */ - .byte 0x2 /* .uleb128 0x2 */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI7-.LCFI6 - .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */ - .byte 0x5 /* .uleb128 0x5 */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI8-.LCFI7 - .byte 0x86 /* DW_CFA_offset, column 0x6 %esi at CFA + 3 * -4 */ - .byte 0x3 /* .uleb128 0x3 */ - - /* End of DW_CFA_xxx CFI instructions. */ - .align 4 -.LEFDE4: - -#endif /* !FFI_NO_RAW_API */ - -.LSFDE5: - .long .LEFDE5-.LASFDE5 /* FDE Length */ -.LASFDE5: - .long .LASFDE5-.Lframe1 /* FDE CIE offset */ -#if defined __PIC__ && defined HAVE_AS_X86_PCREL - .long .LFB5-. /* FDE initial location */ -#else - .long .LFB5 -#endif - .long .LFE5-.LFB5 /* FDE address range */ -#ifdef __PIC__ - .byte 0x0 /* .uleb128 0x0; Augmentation size */ -#endif - /* DW_CFA_xxx CFI instructions go here. */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI9-.LFB5 - .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */ - .byte 0x8 /* .uleb128 0x8 */ - .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */ - .byte 0x2 /* .uleb128 0x2 */ - - .byte 0x4 /* DW_CFA_advance_loc4 */ - .long .LCFI10-.LCFI9 - .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */ - .byte 0x5 /* .uleb128 0x5 */ - - /* End of DW_CFA_xxx CFI instructions. */ - .align 4 -.LEFDE5: - -#endif /* !_MSC_VER */ - diff --git a/libffi/src/x86/win64.S b/libffi/src/x86/win64.S index 687f97c..a5a20b6 100644 --- a/libffi/src/x86/win64.S +++ b/libffi/src/x86/win64.S @@ -1,264 +1,16 @@ #define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> +#include <ffi_cfi.h> -/* Constants for ffi_call_win64 */ -#define STACK 0 -#define PREP_ARGS_FN 32 -#define ECIF 40 -#define CIF_BYTES 48 -#define CIF_FLAGS 56 -#define RVALUE 64 -#define FN 72 - -/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *), - extended_cif *ecif, unsigned bytes, unsigned flags, - unsigned *rvalue, void (*fn)()); - */ - -#ifdef _MSC_VER -PUBLIC ffi_call_win64 - -EXTRN __chkstk:NEAR -EXTRN ffi_closure_win64_inner:NEAR - -_TEXT SEGMENT - -;;; ffi_closure_win64 will be called with these registers set: -;;; rax points to 'closure' -;;; r11 contains a bit mask that specifies which of the -;;; first four parameters are float or double -;;; -;;; It must move the parameters passed in registers to their stack location, -;;; call ffi_closure_win64_inner for the actual work, then return the result. -;;; -ffi_closure_win64 PROC FRAME - ;; copy register arguments onto stack - test r11, 1 - jne first_is_float - mov QWORD PTR [rsp+8], rcx - jmp second -first_is_float: - movlpd QWORD PTR [rsp+8], xmm0 - -second: - test r11, 2 - jne second_is_float - mov QWORD PTR [rsp+16], rdx - jmp third -second_is_float: - movlpd QWORD PTR [rsp+16], xmm1 - -third: - test r11, 4 - jne third_is_float - mov QWORD PTR [rsp+24], r8 - jmp fourth -third_is_float: - movlpd QWORD PTR [rsp+24], xmm2 - -fourth: - test r11, 8 - jne fourth_is_float - mov QWORD PTR [rsp+32], r9 - jmp done -fourth_is_float: - movlpd QWORD PTR [rsp+32], xmm3 - -done: - .ALLOCSTACK 40 - sub rsp, 40 - .ENDPROLOG - mov rcx, rax ; context is first parameter - mov rdx, rsp ; stack is second parameter - add rdx, 48 ; point to start of arguments - mov rax, ffi_closure_win64_inner - call rax ; call the real closure function - add rsp, 40 - movd xmm0, rax ; If the closure returned a float, - ; ffi_closure_win64_inner wrote it to rax - ret 0 -ffi_closure_win64 ENDP - -ffi_call_win64 PROC FRAME - ;; copy registers onto stack - mov QWORD PTR [rsp+32], r9 - mov QWORD PTR [rsp+24], r8 - mov QWORD PTR [rsp+16], rdx - mov QWORD PTR [rsp+8], rcx - .PUSHREG rbp - push rbp - .ALLOCSTACK 48 - sub rsp, 48 ; 00000030H - .SETFRAME rbp, 32 - lea rbp, QWORD PTR [rsp+32] - .ENDPROLOG - - mov eax, DWORD PTR CIF_BYTES[rbp] - add rax, 15 - and rax, -16 - call __chkstk - sub rsp, rax - lea rax, QWORD PTR [rsp+32] - mov QWORD PTR STACK[rbp], rax - - mov rdx, QWORD PTR ECIF[rbp] - mov rcx, QWORD PTR STACK[rbp] - call QWORD PTR PREP_ARGS_FN[rbp] - - mov rsp, QWORD PTR STACK[rbp] - - movlpd xmm3, QWORD PTR [rsp+24] - movd r9, xmm3 - - movlpd xmm2, QWORD PTR [rsp+16] - movd r8, xmm2 - - movlpd xmm1, QWORD PTR [rsp+8] - movd rdx, xmm1 - - movlpd xmm0, QWORD PTR [rsp] - movd rcx, xmm0 - - call QWORD PTR FN[rbp] -ret_struct4b$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B - jne ret_struct2b$ - - mov rcx, QWORD PTR RVALUE[rbp] - mov DWORD PTR [rcx], eax - jmp ret_void$ - -ret_struct2b$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B - jne ret_struct1b$ - - mov rcx, QWORD PTR RVALUE[rbp] - mov WORD PTR [rcx], ax - jmp ret_void$ - -ret_struct1b$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B - jne ret_uint8$ - - mov rcx, QWORD PTR RVALUE[rbp] - mov BYTE PTR [rcx], al - jmp ret_void$ - -ret_uint8$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8 - jne ret_sint8$ - - mov rcx, QWORD PTR RVALUE[rbp] - movzx rax, al - mov QWORD PTR [rcx], rax - jmp ret_void$ - -ret_sint8$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8 - jne ret_uint16$ - - mov rcx, QWORD PTR RVALUE[rbp] - movsx rax, al - mov QWORD PTR [rcx], rax - jmp ret_void$ - -ret_uint16$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16 - jne ret_sint16$ - - mov rcx, QWORD PTR RVALUE[rbp] - movzx rax, ax - mov QWORD PTR [rcx], rax - jmp SHORT ret_void$ - -ret_sint16$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16 - jne ret_uint32$ - - mov rcx, QWORD PTR RVALUE[rbp] - movsx rax, ax - mov QWORD PTR [rcx], rax - jmp SHORT ret_void$ - -ret_uint32$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32 - jne ret_sint32$ - - mov rcx, QWORD PTR RVALUE[rbp] - mov eax, eax - mov QWORD PTR [rcx], rax - jmp SHORT ret_void$ - -ret_sint32$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32 - jne ret_float$ - - mov rcx, QWORD PTR RVALUE[rbp] - cdqe - mov QWORD PTR [rcx], rax - jmp SHORT ret_void$ - -ret_float$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT - jne SHORT ret_double$ - - mov rax, QWORD PTR RVALUE[rbp] - movss DWORD PTR [rax], xmm0 - jmp SHORT ret_void$ - -ret_double$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE - jne SHORT ret_uint64$ - - mov rax, QWORD PTR RVALUE[rbp] - movlpd QWORD PTR [rax], xmm0 - jmp SHORT ret_void$ - -ret_uint64$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT64 - jne SHORT ret_sint64$ - - mov rcx, QWORD PTR RVALUE[rbp] - mov QWORD PTR [rcx], rax - jmp SHORT ret_void$ - -ret_sint64$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64 - jne SHORT ret_pointer$ - - mov rcx, QWORD PTR RVALUE[rbp] - mov QWORD PTR [rcx], rax - jmp SHORT ret_void$ - -ret_pointer$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_POINTER - jne SHORT ret_int$ - - mov rcx, QWORD PTR RVALUE[rbp] - mov QWORD PTR [rcx], rax - jmp SHORT ret_void$ - -ret_int$: - cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_INT - jne SHORT ret_void$ - - mov rcx, QWORD PTR RVALUE[rbp] - cdqe - mov QWORD PTR [rcx], rax - jmp SHORT ret_void$ - -ret_void$: - xor rax, rax - - lea rsp, QWORD PTR [rbp+16] - pop rbp - ret 0 -ffi_call_win64 ENDP -_TEXT ENDS -END +#if defined(HAVE_AS_CFI_PSEUDO_OP) + .cfi_sections .debug_frame +#endif -#else +#define arg0 %rcx +#define arg1 %rdx +#define arg2 %r8 +#define arg3 %r9 #ifdef SYMBOL_UNDERSCORE #define SYMBOL_NAME(name) _##name @@ -266,255 +18,202 @@ END #define SYMBOL_NAME(name) name #endif -.text - -.extern SYMBOL_NAME(ffi_closure_win64_inner) - -# ffi_closure_win64 will be called with these registers set: -# rax points to 'closure' -# r11 contains a bit mask that specifies which of the -# first four parameters are float or double -# -# It must move the parameters passed in registers to their stack location, -# call ffi_closure_win64_inner for the actual work, then return the result. -# - .balign 16 - .globl SYMBOL_NAME(ffi_closure_win64) - .seh_proc SYMBOL_NAME(ffi_closure_win64) -SYMBOL_NAME(ffi_closure_win64): - # copy register arguments onto stack - test $1,%r11 - jne .Lfirst_is_float - mov %rcx, 8(%rsp) - jmp .Lsecond -.Lfirst_is_float: - movlpd %xmm0, 8(%rsp) - -.Lsecond: - test $2, %r11 - jne .Lsecond_is_float - mov %rdx, 16(%rsp) - jmp .Lthird -.Lsecond_is_float: - movlpd %xmm1, 16(%rsp) - -.Lthird: - test $4, %r11 - jne .Lthird_is_float - mov %r8,24(%rsp) - jmp .Lfourth -.Lthird_is_float: - movlpd %xmm2, 24(%rsp) - -.Lfourth: - test $8, %r11 - jne .Lfourth_is_float - mov %r9, 32(%rsp) - jmp .Ldone -.Lfourth_is_float: - movlpd %xmm3, 32(%rsp) - -.Ldone: - .seh_stackalloc 40 - sub $40, %rsp +.macro E which + .align 8 + .org 0b + \which * 8 +.endm + + .text + +/* ffi_call_win64 (void *stack, struct win64_call_frame *frame, void *r10) + + Bit o trickiness here -- FRAME is the base of the stack frame + for this function. This has been allocated by ffi_call. We also + deallocate some of the stack that has been alloca'd. */ + + .align 8 + .globl ffi_call_win64 + + .seh_proc ffi_call_win64 +ffi_call_win64: + cfi_startproc + /* Set up the local stack frame and install it in rbp/rsp. */ + movq (%rsp), %rax + movq %rbp, (arg1) + movq %rax, 8(arg1) + movq arg1, %rbp + cfi_def_cfa(%rbp, 16) + cfi_rel_offset(%rbp, 0) + .seh_pushreg %rbp + .seh_setframe %rbp, 0 .seh_endprologue - mov %rax, %rcx # context is first parameter - mov %rsp, %rdx # stack is second parameter - add $48, %rdx # point to start of arguments - leaq SYMBOL_NAME(ffi_closure_win64_inner)(%rip), %rax - callq *%rax # call the real closure function - add $40, %rsp - movq %rax, %xmm0 # If the closure returned a float, - # ffi_closure_win64_inner wrote it to rax - retq + movq arg0, %rsp + + movq arg2, %r10 + + /* Load all slots into both general and xmm registers. */ + movq (%rsp), %rcx + movsd (%rsp), %xmm0 + movq 8(%rsp), %rdx + movsd 8(%rsp), %xmm1 + movq 16(%rsp), %r8 + movsd 16(%rsp), %xmm2 + movq 24(%rsp), %r9 + movsd 24(%rsp), %xmm3 + + call *16(%rbp) + + movl 24(%rbp), %ecx + movq 32(%rbp), %r8 + leaq 0f(%rip), %r10 + cmpl $FFI_TYPE_SMALL_STRUCT_4B, %ecx + leaq (%r10, %rcx, 8), %r10 + ja 99f + jmp *%r10 + +/* Below, we're space constrained most of the time. Thus we eschew the + modern "mov, pop, ret" sequence (5 bytes) for "leave, ret" (2 bytes). */ +.macro epilogue + leaveq + cfi_remember_state + cfi_def_cfa(%rsp, 8) + cfi_restore(%rbp) + ret + cfi_restore_state +.endm + + .align 8 +0: +E FFI_TYPE_VOID + epilogue +E FFI_TYPE_INT + movslq %eax, %rax + movq %rax, (%r8) + epilogue +E FFI_TYPE_FLOAT + movss %xmm0, (%r8) + epilogue +E FFI_TYPE_DOUBLE + movsd %xmm0, (%r8) + epilogue +E FFI_TYPE_LONGDOUBLE + call abort +E FFI_TYPE_UINT8 + movzbl %al, %eax + movq %rax, (%r8) + epilogue +E FFI_TYPE_SINT8 + movsbq %al, %rax + jmp 98f +E FFI_TYPE_UINT16 + movzwl %ax, %eax + movq %rax, (%r8) + epilogue +E FFI_TYPE_SINT16 + movswq %ax, %rax + jmp 98f +E FFI_TYPE_UINT32 + movl %eax, %eax + movq %rax, (%r8) + epilogue +E FFI_TYPE_SINT32 + movslq %eax, %rax + movq %rax, (%r8) + epilogue +E FFI_TYPE_UINT64 +98: movq %rax, (%r8) + epilogue +E FFI_TYPE_SINT64 + movq %rax, (%r8) + epilogue +E FFI_TYPE_STRUCT + epilogue +E FFI_TYPE_POINTER + movq %rax, (%r8) + epilogue +E FFI_TYPE_COMPLEX + call abort +E FFI_TYPE_SMALL_STRUCT_1B + movb %al, (%r8) + epilogue +E FFI_TYPE_SMALL_STRUCT_2B + movw %ax, (%r8) + epilogue +E FFI_TYPE_SMALL_STRUCT_4B + movl %eax, (%r8) + epilogue + + .align 8 +99: call abort + +.purgem epilogue + + cfi_endproc .seh_endproc - .balign 16 - .globl SYMBOL_NAME(ffi_call_win64) - .seh_proc SYMBOL_NAME(ffi_call_win64) -SYMBOL_NAME(ffi_call_win64): - # copy registers onto stack - mov %r9,32(%rsp) - mov %r8,24(%rsp) - mov %rdx,16(%rsp) - mov %rcx,8(%rsp) - .seh_pushreg rbp - push %rbp - .seh_stackalloc 48 - sub $48,%rsp - .seh_setframe rbp, 32 - lea 32(%rsp),%rbp - .seh_endprologue - - mov CIF_BYTES(%rbp),%eax - add $15, %rax - and $-16, %rax - cmpq $0x1000, %rax - jb Lch_done -Lch_probe: - subq $0x1000,%rsp - orl $0x0, (%rsp) - subq $0x1000,%rax - cmpq $0x1000,%rax - ja Lch_probe -Lch_done: - subq %rax, %rsp - orl $0x0, (%rsp) - lea 32(%rsp), %rax - mov %rax, STACK(%rbp) - - mov ECIF(%rbp), %rdx - mov STACK(%rbp), %rcx - callq *PREP_ARGS_FN(%rbp) - - mov STACK(%rbp), %rsp - - movlpd 24(%rsp), %xmm3 - movd %xmm3, %r9 - - movlpd 16(%rsp), %xmm2 - movd %xmm2, %r8 - - movlpd 8(%rsp), %xmm1 - movd %xmm1, %rdx - - movlpd (%rsp), %xmm0 - movd %xmm0, %rcx - - callq *FN(%rbp) -.Lret_struct4b: - cmpl $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp) - jne .Lret_struct2b - - mov RVALUE(%rbp), %rcx - mov %eax, (%rcx) - jmp .Lret_void - -.Lret_struct2b: - cmpl $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp) - jne .Lret_struct1b - - mov RVALUE(%rbp), %rcx - mov %ax, (%rcx) - jmp .Lret_void - -.Lret_struct1b: - cmpl $FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp) - jne .Lret_uint8 - mov RVALUE(%rbp), %rcx - mov %al, (%rcx) - jmp .Lret_void - -.Lret_uint8: - cmpl $FFI_TYPE_UINT8, CIF_FLAGS(%rbp) - jne .Lret_sint8 - - mov RVALUE(%rbp), %rcx - movzbq %al, %rax - movq %rax, (%rcx) - jmp .Lret_void - -.Lret_sint8: - cmpl $FFI_TYPE_SINT8, CIF_FLAGS(%rbp) - jne .Lret_uint16 - - mov RVALUE(%rbp), %rcx - movsbq %al, %rax - movq %rax, (%rcx) - jmp .Lret_void - -.Lret_uint16: - cmpl $FFI_TYPE_UINT16, CIF_FLAGS(%rbp) - jne .Lret_sint16 - - mov RVALUE(%rbp), %rcx - movzwq %ax, %rax - movq %rax, (%rcx) - jmp .Lret_void - -.Lret_sint16: - cmpl $FFI_TYPE_SINT16, CIF_FLAGS(%rbp) - jne .Lret_uint32 - - mov RVALUE(%rbp), %rcx - movswq %ax, %rax - movq %rax, (%rcx) - jmp .Lret_void - -.Lret_uint32: - cmpl $FFI_TYPE_UINT32, CIF_FLAGS(%rbp) - jne .Lret_sint32 - - mov RVALUE(%rbp), %rcx - movl %eax, %eax - movq %rax, (%rcx) - jmp .Lret_void - -.Lret_sint32: - cmpl $FFI_TYPE_SINT32, CIF_FLAGS(%rbp) - jne .Lret_float - - mov RVALUE(%rbp), %rcx - cltq - movq %rax, (%rcx) - jmp .Lret_void - -.Lret_float: - cmpl $FFI_TYPE_FLOAT, CIF_FLAGS(%rbp) - jne .Lret_double - - mov RVALUE(%rbp), %rax - movss %xmm0, (%rax) - jmp .Lret_void - -.Lret_double: - cmpl $FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp) - jne .Lret_uint64 - - mov RVALUE(%rbp), %rax - movlpd %xmm0, (%rax) - jmp .Lret_void - -.Lret_uint64: - cmpl $FFI_TYPE_UINT64, CIF_FLAGS(%rbp) - jne .Lret_sint64 - - mov RVALUE(%rbp), %rcx - mov %rax, (%rcx) - jmp .Lret_void - -.Lret_sint64: - cmpl $FFI_TYPE_SINT64, CIF_FLAGS(%rbp) - jne .Lret_pointer - - mov RVALUE(%rbp), %rcx - mov %rax, (%rcx) - jmp .Lret_void +/* 32 bytes of outgoing register stack space, 8 bytes of alignment, + 16 bytes of result, 32 bytes of xmm registers. */ +#define ffi_clo_FS (32+8+16+32) +#define ffi_clo_OFF_R (32+8) +#define ffi_clo_OFF_X (32+8+16) + + .align 8 + .globl ffi_go_closure_win64 + + .seh_proc ffi_go_closure_win64 +ffi_go_closure_win64: + cfi_startproc + /* Save all integer arguments into the incoming reg stack space. */ + movq arg0, 8(%rsp) + movq arg1, 16(%rsp) + movq arg2, 24(%rsp) + movq arg3, 32(%rsp) + + movq 8(%r10), arg0 /* load cif */ + movq 16(%r10), arg1 /* load fun */ + movq %r10, arg2 /* closure is user_data */ + jmp 0f + cfi_endproc + .seh_endproc -.Lret_pointer: - cmpl $FFI_TYPE_POINTER, CIF_FLAGS(%rbp) - jne .Lret_int + .align 8 + .globl ffi_closure_win64 + + .seh_proc ffi_closure_win64 +ffi_closure_win64: + cfi_startproc + /* Save all integer arguments into the incoming reg stack space. */ + movq arg0, 8(%rsp) + movq arg1, 16(%rsp) + movq arg2, 24(%rsp) + movq arg3, 32(%rsp) + + movq FFI_TRAMPOLINE_SIZE(%r10), arg0 /* load cif */ + movq FFI_TRAMPOLINE_SIZE+8(%r10), arg1 /* load fun */ + movq FFI_TRAMPOLINE_SIZE+16(%r10), arg2 /* load user_data */ +0: + subq $ffi_clo_FS, %rsp + cfi_adjust_cfa_offset(ffi_clo_FS) + .seh_stackalloc ffi_clo_FS + .seh_endprologue - mov RVALUE(%rbp), %rcx - mov %rax, (%rcx) - jmp .Lret_void + /* Save all sse arguments into the stack frame. */ + movsd %xmm0, ffi_clo_OFF_X(%rsp) + movsd %xmm1, ffi_clo_OFF_X+8(%rsp) + movsd %xmm2, ffi_clo_OFF_X+16(%rsp) + movsd %xmm3, ffi_clo_OFF_X+24(%rsp) -.Lret_int: - cmpl $FFI_TYPE_INT, CIF_FLAGS(%rbp) - jne .Lret_void + leaq ffi_clo_OFF_R(%rsp), arg3 + call ffi_closure_win64_inner - mov RVALUE(%rbp), %rcx - cltq - movq %rax, (%rcx) - jmp .Lret_void + /* Load the result into both possible result registers. */ + movq ffi_clo_OFF_R(%rsp), %rax + movsd ffi_clo_OFF_R(%rsp), %xmm0 -.Lret_void: - xor %rax, %rax + addq $ffi_clo_FS, %rsp + cfi_adjust_cfa_offset(-ffi_clo_FS) + ret - lea 16(%rbp), %rsp - pop %rbp - retq + cfi_endproc .seh_endproc -#endif /* !_MSC_VER */ - diff --git a/libffi/src/xtensa/ffi.c b/libffi/src/xtensa/ffi.c new file mode 100644 index 0000000..fd94daf --- /dev/null +++ b/libffi/src/xtensa/ffi.c @@ -0,0 +1,298 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2013 Tensilica, Inc. + + XTENSA 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> + +/* + |----------------------------------------| + | | + on entry to ffi_call ----> |----------------------------------------| + | caller stack frame for registers a0-a3 | + |----------------------------------------| + | | + | additional arguments | + entry of the function ---> |----------------------------------------| + | copy of function arguments a2-a7 | + | - - - - - - - - - - - - - | + | | + + The area below the entry line becomes the new stack frame for the function. + +*/ + + +#define FFI_TYPE_STRUCT_REGS FFI_TYPE_LAST + + +extern void ffi_call_SYSV(void *rvalue, unsigned rsize, unsigned flags, + void(*fn)(void), unsigned nbytes, extended_cif*); +extern void ffi_closure_SYSV(void) FFI_HIDDEN; + +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + switch(cif->rtype->type) { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + cif->flags = cif->rtype->type; + break; + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + cif->flags = FFI_TYPE_UINT32; + break; + case FFI_TYPE_DOUBLE: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + cif->flags = FFI_TYPE_UINT64; // cif->rtype->type; + break; + case FFI_TYPE_STRUCT: + cif->flags = FFI_TYPE_STRUCT; //_REGS; + /* Up to 16 bytes are returned in registers */ + if (cif->rtype->size > 4 * 4) { + /* returned structure is referenced by a register; use 8 bytes + (including 4 bytes for potential additional alignment) */ + cif->flags = FFI_TYPE_STRUCT; + cif->bytes += 8; + } + break; + + default: + cif->flags = FFI_TYPE_UINT32; + 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 = ALIGN(cif->bytes, 16); + + return FFI_OK; +} + +void ffi_prep_args(extended_cif *ecif, unsigned char* stack) +{ + unsigned int i; + unsigned long *addr; + ffi_type **ptr; + + union { + void **v; + char **c; + signed char **sc; + unsigned char **uc; + signed short **ss; + unsigned short **us; + unsigned int **i; + long long **ll; + float **f; + double **d; + } p_argv; + + /* Verify that everything is aligned up properly */ + FFI_ASSERT (((unsigned long) stack & 0x7) == 0); + + p_argv.v = ecif->avalue; + addr = (unsigned long*)stack; + + /* structures with a size greater than 16 bytes are passed in memory */ + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 16) + { + *addr++ = (unsigned long)ecif->rvalue; + } + + for (i = ecif->cif->nargs, ptr = ecif->cif->arg_types; + i > 0; + i--, ptr++, p_argv.v++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_SINT8: + *addr++ = **p_argv.sc; + break; + case FFI_TYPE_UINT8: + *addr++ = **p_argv.uc; + break; + case FFI_TYPE_SINT16: + *addr++ = **p_argv.ss; + break; + case FFI_TYPE_UINT16: + *addr++ = **p_argv.us; + break; + case FFI_TYPE_FLOAT: + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + *addr++ = **p_argv.i; + break; + case FFI_TYPE_DOUBLE: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + if (((unsigned long)addr & 4) != 0) + addr++; + *(unsigned long long*)addr = **p_argv.ll; + addr += sizeof(unsigned long long) / sizeof (addr); + break; + + case FFI_TYPE_STRUCT: + { + unsigned long offs; + unsigned long size; + + if (((unsigned long)addr & 4) != 0 && (*ptr)->alignment > 4) + addr++; + + offs = (unsigned long) addr - (unsigned long) stack; + size = (*ptr)->size; + + /* Entire structure must fit the argument registers or referenced */ + if (offs < FFI_REGISTER_NARGS * 4 + && offs + size > FFI_REGISTER_NARGS * 4) + addr = (unsigned long*) (stack + FFI_REGISTER_NARGS * 4); + + memcpy((char*) addr, *p_argv.c, size); + addr += (size + 3) / 4; + break; + } + + default: + FFI_ASSERT(0); + } + } +} + + +void ffi_call(ffi_cif* cif, void(*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + unsigned long rsize = cif->rtype->size; + int flags = cif->flags; + void *alloc = NULL; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* Note that for structures that are returned in registers (size <= 16 bytes) + we allocate a temporary buffer and use memcpy to copy it to the final + destination. The reason is that the target address might be misaligned or + the length not a multiple of 4 bytes. Handling all those cases would be + very complex. */ + + if (flags == FFI_TYPE_STRUCT && (rsize <= 16 || rvalue == NULL)) + { + alloc = alloca(ALIGN(rsize, 4)); + ecif.rvalue = alloc; + } + else + { + ecif.rvalue = rvalue; + } + + if (cif->abi != FFI_SYSV) + FFI_ASSERT(0); + + ffi_call_SYSV (ecif.rvalue, rsize, cif->flags, fn, cif->bytes, &ecif); + + if (alloc != NULL && rvalue != NULL) + memcpy(rvalue, alloc, rsize); +} + +extern void ffi_trampoline(); +extern void ffi_cacheflush(void* start, void* end); + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + /* 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; + + // Do we have this function? + // __builtin___clear_cache(closer->tramp, closer->tramp + FFI_TRAMPOLINE_SIZE) + ffi_cacheflush(closure->tramp, closure->tramp + FFI_TRAMPOLINE_SIZE); + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + return FFI_OK; +} + + +long FFI_HIDDEN +ffi_closure_SYSV_inner(ffi_closure *closure, void **values, void *rvalue) +{ + ffi_cif *cif; + ffi_type **arg_types; + void **avalue; + int i, areg; + + cif = closure->cif; + if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; + + areg = 0; + + int rtype = cif->rtype->type; + if (rtype == FFI_TYPE_STRUCT && cif->rtype->size > 4 * 4) + { + rvalue = *values; + areg++; + } + + cif = closure->cif; + arg_types = cif->arg_types; + avalue = alloca(cif->nargs * sizeof(void *)); + + for (i = 0; i < cif->nargs; i++) + { + if (arg_types[i]->alignment == 8 && (areg & 1) != 0) + areg++; + + // skip the entry 16,a1 framework, add 16 bytes (4 registers) + if (areg == FFI_REGISTER_NARGS) + areg += 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; + } + + avalue[i] = &values[areg]; + areg += (arg_types[i]->size + 3) / 4; + } + + (closure->fun)(cif, rvalue, avalue, closure->user_data); + + return rtype; +} diff --git a/libffi/src/xtensa/ffitarget.h b/libffi/src/xtensa/ffitarget.h new file mode 100644 index 0000000..0ba728b --- /dev/null +++ b/libffi/src/xtensa/ffitarget.h @@ -0,0 +1,53 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2013 Tensilica, Inc. + Target configuration macros for XTENSA. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_H +#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; +#endif + +#define FFI_REGISTER_NARGS 6 + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 +#define FFI_TRAMPOLINE_SIZE 24 + +#endif diff --git a/libffi/src/xtensa/sysv.S b/libffi/src/xtensa/sysv.S new file mode 100644 index 0000000..64e6a09 --- /dev/null +++ b/libffi/src/xtensa/sysv.S @@ -0,0 +1,253 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2013 Tensilica, Inc. + + XTENSA Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +#define ENTRY(name) .text; .globl name; .type name,@function; .align 4; name: +#define END(name) .size name , . - name + +/* Assert that the table below is in sync with ffi.h. */ + +#if FFI_TYPE_UINT8 != 5 \ + || FFI_TYPE_SINT8 != 6 \ + || FFI_TYPE_UINT16 != 7 \ + || FFI_TYPE_SINT16 != 8 \ + || FFI_TYPE_UINT32 != 9 \ + || FFI_TYPE_SINT32 != 10 \ + || FFI_TYPE_UINT64 != 11 +#error "xtensa/sysv.S out of sync with ffi.h" +#endif + + +/* ffi_call_SYSV (rvalue, rbytes, flags, (*fnaddr)(), bytes, ecif) + void *rvalue; a2 + unsigned long rbytes; a3 + unsigned flags; a4 + void (*fnaddr)(); a5 + unsigned long bytes; a6 + extended_cif* ecif) a7 +*/ + +ENTRY(ffi_call_SYSV) + + entry a1, 32 # 32 byte frame for using call8 below + + mov a10, a7 # a10(->arg0): ecif + sub a11, a1, a6 # a11(->arg1): stack pointer + mov a7, a1 # fp + movsp a1, a11 # set new sp = old_sp - bytes + + 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 + + + # 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 + + # move stack pointer + + movsp a1, a6 + + callx8 a5 # (*fn)(args...) + + # Handle return value(s) + + beqz a2, .Lexit + + movi a5, FFI_TYPE_STRUCT + bne a4, a5, .Lstore + movi a5, 16 + blt a5, a3, .Lexit + + s32i a10, a2, 0 + blti a3, 5, .Lexit + addi a3, a3, -1 + s32i a11, a2, 4 + blti a3, 8, .Lexit + s32i a12, a2, 8 + blti a3, 12, .Lexit + s32i a13, a2, 12 + +.Lexit: retw + +.Lstore: + addi a4, a4, -FFI_TYPE_UINT8 + bgei a4, 7, .Lexit # should never happen + movi a6, store_calls + add a4, a4, a4 + addx4 a6, a4, a6 # store_table + idx * 8 + jx a6 + + .align 8 +store_calls: + # UINT8 + s8i a10, a2, 0 + retw + + # SINT8 + .align 8 + s8i a10, a2, 0 + retw + + # UINT16 + .align 8 + s16i a10, a2, 0 + retw + + # SINT16 + .align 8 + s16i a10, a2, 0 + retw + + # UINT32 + .align 8 + s32i a10, a2, 0 + retw + + # SINT32 + .align 8 + s32i a10, a2, 0 + retw + + # UINT64 + .align 8 + s32i a10, a2, 0 + s32i a11, a2, 4 + retw + +END(ffi_call_SYSV) + + +/* + * void ffi_cacheflush (unsigned long start, unsigned long end) + */ + +#define EXTRA_ARGS_SIZE 24 + +ENTRY(ffi_cacheflush) + + entry a1, 16 + +1: dhwbi a2, 0 + ihi a2, 0 + addi a2, a2, 4 + blt a2, a3, 1b + + retw + +END(ffi_cacheflush) + +/* ffi_trampoline is copied to the stack */ + +ENTRY(ffi_trampoline) + + entry a1, 16 + (FFI_REGISTER_NARGS * 4) + (4 * 4) # [ 0] + j 2f # [ 3] + .align 4 # [ 6] +1: .long 0 # [ 8] +2: l32r a15, 1b # [12] + _mov a14, a0 # [15] + callx0 a15 # [18] + # [21] +END(ffi_trampoline) + +/* + * ffi_closure() + * + * a0: closure + 21 + * a14: return address (a0) + */ + +ENTRY(ffi_closure_SYSV) + + /* intentionally omitting entry here */ + + # restore return address (a0) and move pointer to closure to a10 + addi a10, a0, -21 + mov a0, a14 + + # allow up to 4 arguments as return values + addi a11, a1, 4 * 4 + + # save up to 6 arguments to stack (allocated by entry below) + s32i a2, a11, 0 + s32i a3, a11, 4 + s32i a4, a11, 8 + s32i a5, a11, 12 + s32i a6, a11, 16 + s32i a7, a11, 20 + + movi a8, ffi_closure_SYSV_inner + mov a12, a1 + callx8 a8 # .._inner(*closure, **avalue, *rvalue) + + # load up to four return arguments + l32i a2, a1, 0 + l32i a3, a1, 4 + l32i a4, a1, 8 + l32i a5, a1, 12 + + # (sign-)extend return value + movi a11, FFI_TYPE_UINT8 + bne a10, a11, 1f + extui a2, a2, 0, 8 + retw + +1: movi a11, FFI_TYPE_SINT8 + bne a10, a11, 1f + sext a2, a2, 7 + retw + +1: movi a11, FFI_TYPE_UINT16 + bne a10, a11, 1f + extui a2, a2, 0, 16 + retw + +1: movi a11, FFI_TYPE_SINT16 + bne a10, a11, 1f + sext a2, a2, 15 + +1: retw + +END(ffi_closure_SYSV) diff --git a/libffi/testsuite/Makefile.am b/libffi/testsuite/Makefile.am index 146fdf9..209e897 100644 --- a/libffi/testsuite/Makefile.am +++ b/libffi/testsuite/Makefile.am @@ -4,8 +4,8 @@ AUTOMAKE_OPTIONS = foreign dejagnu # Setup the testing framework, if you have one EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then \ - echo $(top_builddir)/../expect/expect ; \ - else echo expect ; fi` + echo $(top_builddir)/../expect/expect ; \ + else echo expect ; fi` RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then \ echo $(top_srcdir)/../dejagnu/runtest ; \ @@ -15,71 +15,80 @@ AM_RUNTESTFLAGS = CLEANFILES = *.exe core* *.log *.sum -EXTRA_DIST = config/default.exp libffi.call/cls_19byte.c \ -libffi.call/cls_align_longdouble_split.c libffi.call/closure_loc_fn0.c \ -libffi.call/cls_schar.c libffi.call/closure_fn1.c \ -libffi.call/many2_win32.c libffi.call/return_ul.c \ -libffi.call/cls_align_double.c libffi.call/return_fl2.c \ -libffi.call/cls_1_1byte.c libffi.call/cls_64byte.c \ -libffi.call/nested_struct7.c libffi.call/cls_align_sint32.c \ -libffi.call/nested_struct2.c libffi.call/ffitest.h \ -libffi.call/nested_struct4.c libffi.call/cls_multi_ushort.c \ -libffi.call/struct3.c libffi.call/cls_3byte1.c \ -libffi.call/cls_16byte.c libffi.call/struct8.c \ -libffi.call/nested_struct8.c libffi.call/cls_multi_sshort.c \ -libffi.call/cls_3byte2.c libffi.call/fastthis2_win32.c \ -libffi.call/cls_pointer.c libffi.call/err_bad_typedef.c \ -libffi.call/cls_4_1byte.c libffi.call/cls_9byte2.c \ -libffi.call/cls_multi_schar.c libffi.call/stret_medium2.c \ -libffi.call/cls_5_1_byte.c libffi.call/call.exp \ -libffi.call/cls_double.c libffi.call/cls_align_sint16.c \ -libffi.call/cls_uint.c libffi.call/return_ll1.c \ -libffi.call/nested_struct3.c libffi.call/cls_20byte1.c \ -libffi.call/closure_fn4.c libffi.call/cls_uchar.c \ -libffi.call/struct2.c libffi.call/cls_7byte.c libffi.call/strlen.c \ -libffi.call/many.c libffi.call/testclosure.c libffi.call/return_fl.c \ -libffi.call/struct5.c libffi.call/cls_12byte.c \ -libffi.call/cls_multi_sshortchar.c \ -libffi.call/cls_align_longdouble_split2.c libffi.call/return_dbl2.c \ -libffi.call/return_fl3.c libffi.call/stret_medium.c \ -libffi.call/nested_struct6.c libffi.call/a.out \ -libffi.call/closure_fn3.c libffi.call/float3.c libffi.call/many2.c \ -libffi.call/closure_stdcall.c libffi.call/cls_align_uint16.c \ -libffi.call/cls_9byte1.c libffi.call/closure_fn6.c \ -libffi.call/cls_double_va.c libffi.call/cls_align_pointer.c \ -libffi.call/cls_align_longdouble.c libffi.call/closure_fn2.c \ -libffi.call/cls_sshort.c libffi.call/many_win32.c \ -libffi.call/nested_struct.c libffi.call/cls_20byte.c \ -libffi.call/cls_longdouble.c libffi.call/cls_multi_uchar.c \ -libffi.call/return_uc.c libffi.call/closure_thiscall.c \ -libffi.call/cls_18byte.c libffi.call/cls_8byte.c \ -libffi.call/promotion.c libffi.call/struct1_win32.c \ -libffi.call/return_dbl.c libffi.call/cls_24byte.c \ -libffi.call/struct4.c libffi.call/cls_6byte.c \ -libffi.call/cls_align_uint32.c libffi.call/float.c \ -libffi.call/float1.c libffi.call/float_va.c libffi.call/negint.c \ -libffi.call/return_dbl1.c libffi.call/cls_3_1byte.c \ -libffi.call/cls_align_float.c libffi.call/return_fl1.c \ -libffi.call/nested_struct10.c libffi.call/nested_struct5.c \ -libffi.call/fastthis1_win32.c libffi.call/cls_align_sint64.c \ -libffi.call/stret_large2.c libffi.call/return_sl.c \ -libffi.call/closure_fn0.c libffi.call/cls_5byte.c \ -libffi.call/cls_2byte.c libffi.call/float2.c \ -libffi.call/cls_dbls_struct.c libffi.call/cls_sint.c \ -libffi.call/stret_large.c libffi.call/cls_ulonglong.c \ -libffi.call/cls_ushort.c libffi.call/nested_struct1.c \ -libffi.call/err_bad_abi.c libffi.call/cls_longdouble_va.c \ -libffi.call/cls_float.c libffi.call/cls_pointer_stack.c \ -libffi.call/pyobjc-tc.c libffi.call/cls_multi_ushortchar.c \ -libffi.call/struct1.c libffi.call/nested_struct9.c \ -libffi.call/huge_struct.c libffi.call/problem1.c libffi.call/float4.c \ -libffi.call/fastthis3_win32.c libffi.call/return_ldl.c \ -libffi.call/strlen2_win32.c libffi.call/closure_fn5.c \ -libffi.call/struct2_win32.c libffi.call/struct6.c \ -libffi.call/return_ll.c libffi.call/struct9.c libffi.call/return_sc.c \ -libffi.call/struct7.c libffi.call/cls_align_uint64.c \ -libffi.call/cls_4byte.c libffi.call/strlen_win32.c \ -libffi.call/cls_6_1_byte.c libffi.call/cls_7_1_byte.c \ -libffi.special/unwindtest.cc libffi.special/special.exp \ -libffi.special/unwindtest_ffi_call.cc libffi.special/ffitestcxx.h \ -lib/wrapper.exp lib/target-libpath.exp lib/libffi.exp +EXTRA_DIST = config/default.exp libffi.call/cls_19byte.c \ +libffi.call/cls_align_longdouble_split.c \ +libffi.call/closure_loc_fn0.c libffi.call/cls_schar.c \ +libffi.call/closure_fn1.c \ +libffi.call/return_ul.c libffi.call/cls_align_double.c \ +libffi.call/return_fl2.c libffi.call/cls_1_1byte.c \ +libffi.call/cls_64byte.c libffi.call/nested_struct7.c \ +libffi.call/cls_align_sint32.c libffi.call/nested_struct2.c \ +libffi.call/ffitest.h libffi.call/nested_struct4.c \ +libffi.call/cls_multi_ushort.c libffi.call/struct3.c \ +libffi.call/cls_3byte1.c libffi.call/cls_16byte.c \ +libffi.call/struct8.c libffi.call/nested_struct8.c \ +libffi.call/cls_multi_sshort.c libffi.call/cls_3byte2.c \ +libffi.call/cls_pointer.c \ +libffi.call/err_bad_typedef.c libffi.call/cls_4_1byte.c \ +libffi.call/cls_9byte2.c libffi.call/cls_multi_schar.c \ +libffi.call/stret_medium2.c libffi.call/cls_5_1_byte.c \ +libffi.call/call.exp libffi.call/cls_double.c \ +libffi.call/cls_align_sint16.c libffi.call/cls_uint.c \ +libffi.call/return_ll1.c libffi.call/nested_struct3.c \ +libffi.call/cls_20byte1.c libffi.call/closure_fn4.c \ +libffi.call/cls_uchar.c libffi.call/struct2.c libffi.call/cls_7byte.c \ +libffi.call/strlen.c libffi.call/many.c libffi.call/testclosure.c \ +libffi.call/return_fl.c libffi.call/struct5.c \ +libffi.call/cls_12byte.c libffi.call/cls_multi_sshortchar.c \ +libffi.call/cls_align_longdouble_split2.c libffi.call/return_dbl2.c \ +libffi.call/return_fl3.c libffi.call/stret_medium.c \ +libffi.call/nested_struct6.c libffi.call/closure_fn3.c \ +libffi.call/float3.c libffi.call/many2.c \ +libffi.call/closure_simple.c libffi.call/cls_align_uint16.c \ +libffi.call/cls_9byte1.c libffi.call/closure_fn6.c \ +libffi.call/cls_double_va.c libffi.call/cls_align_pointer.c \ +libffi.call/cls_align_longdouble.c libffi.call/closure_fn2.c \ +libffi.call/cls_sshort.c \ +libffi.call/nested_struct.c libffi.call/cls_20byte.c \ +libffi.call/cls_longdouble.c libffi.call/cls_multi_uchar.c \ +libffi.call/return_uc.c \ +libffi.call/cls_18byte.c libffi.call/cls_8byte.c \ +libffi.call/promotion.c \ +libffi.call/return_dbl.c libffi.call/cls_24byte.c \ +libffi.call/struct4.c libffi.call/cls_6byte.c \ +libffi.call/cls_align_uint32.c libffi.call/float.c \ +libffi.call/float1.c libffi.call/float_va.c libffi.call/negint.c \ +libffi.call/return_dbl1.c libffi.call/cls_3_1byte.c \ +libffi.call/cls_align_float.c libffi.call/return_fl1.c \ +libffi.call/nested_struct10.c libffi.call/nested_struct5.c \ +libffi.call/cls_align_sint64.c \ +libffi.call/stret_large2.c libffi.call/return_sl.c \ +libffi.call/closure_fn0.c libffi.call/cls_5byte.c \ +libffi.call/cls_2byte.c libffi.call/float2.c \ +libffi.call/cls_dbls_struct.c libffi.call/cls_sint.c \ +libffi.call/stret_large.c libffi.call/cls_ulonglong.c \ +libffi.call/cls_ushort.c libffi.call/nested_struct1.c \ +libffi.call/err_bad_abi.c libffi.call/cls_longdouble_va.c \ +libffi.call/cls_float.c libffi.call/cls_pointer_stack.c \ +libffi.call/pyobjc-tc.c libffi.call/cls_multi_ushortchar.c \ +libffi.call/struct1.c libffi.call/nested_struct9.c \ +libffi.call/huge_struct.c libffi.call/problem1.c \ +libffi.call/float4.c \ +libffi.call/return_ldl.c \ +libffi.call/closure_fn5.c \ +libffi.call/struct6.c libffi.call/return_ll.c libffi.call/struct9.c \ +libffi.call/return_sc.c libffi.call/struct7.c \ +libffi.call/cls_align_uint64.c libffi.call/cls_4byte.c \ +libffi.call/cls_6_1_byte.c \ +libffi.call/cls_7_1_byte.c libffi.call/unwindtest.cc \ +libffi.call/unwindtest_ffi_call.cc \ +lib/wrapper.exp lib/target-libpath.exp \ +lib/libffi.exp libffi.call/cls_struct_va1.c \ +libffi.call/cls_uchar_va.c libffi.call/cls_uint_va.c \ +libffi.call/cls_ulong_va.c libffi.call/cls_ushort_va.c \ +libffi.call/nested_struct11.c libffi.call/uninitialized.c \ +libffi.call/va_1.c libffi.call/va_struct1.c libffi.call/va_struct2.c \ +libffi.call/va_struct3.c \ +libffi.call/strlen2.c \ +libffi.call/strlen3.c \ +libffi.call/strlen4.c diff --git a/libffi/testsuite/Makefile.in b/libffi/testsuite/Makefile.in index 808d4cb..cbfe35b 100644 --- a/libffi/testsuite/Makefile.in +++ b/libffi/testsuite/Makefile.in @@ -74,6 +74,10 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ @@ -126,12 +130,14 @@ SHELL = @SHELL@ STRIP = @STRIP@ TARGET = @TARGET@ TARGETDIR = @TARGETDIR@ +TARGET_OBJ = @TARGET_OBJ@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ @@ -189,82 +195,91 @@ AUTOMAKE_OPTIONS = foreign dejagnu # Setup the testing framework, if you have one EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then \ - echo $(top_builddir)/../expect/expect ; \ - else echo expect ; fi` + echo $(top_builddir)/../expect/expect ; \ + else echo expect ; fi` RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then \ echo $(top_srcdir)/../dejagnu/runtest ; \ else echo runtest; fi` CLEANFILES = *.exe core* *.log *.sum -EXTRA_DIST = config/default.exp libffi.call/cls_19byte.c \ -libffi.call/cls_align_longdouble_split.c libffi.call/closure_loc_fn0.c \ -libffi.call/cls_schar.c libffi.call/closure_fn1.c \ -libffi.call/many2_win32.c libffi.call/return_ul.c \ -libffi.call/cls_align_double.c libffi.call/return_fl2.c \ -libffi.call/cls_1_1byte.c libffi.call/cls_64byte.c \ -libffi.call/nested_struct7.c libffi.call/cls_align_sint32.c \ -libffi.call/nested_struct2.c libffi.call/ffitest.h \ -libffi.call/nested_struct4.c libffi.call/cls_multi_ushort.c \ -libffi.call/struct3.c libffi.call/cls_3byte1.c \ -libffi.call/cls_16byte.c libffi.call/struct8.c \ -libffi.call/nested_struct8.c libffi.call/cls_multi_sshort.c \ -libffi.call/cls_3byte2.c libffi.call/fastthis2_win32.c \ -libffi.call/cls_pointer.c libffi.call/err_bad_typedef.c \ -libffi.call/cls_4_1byte.c libffi.call/cls_9byte2.c \ -libffi.call/cls_multi_schar.c libffi.call/stret_medium2.c \ -libffi.call/cls_5_1_byte.c libffi.call/call.exp \ -libffi.call/cls_double.c libffi.call/cls_align_sint16.c \ -libffi.call/cls_uint.c libffi.call/return_ll1.c \ -libffi.call/nested_struct3.c libffi.call/cls_20byte1.c \ -libffi.call/closure_fn4.c libffi.call/cls_uchar.c \ -libffi.call/struct2.c libffi.call/cls_7byte.c libffi.call/strlen.c \ -libffi.call/many.c libffi.call/testclosure.c libffi.call/return_fl.c \ -libffi.call/struct5.c libffi.call/cls_12byte.c \ -libffi.call/cls_multi_sshortchar.c \ -libffi.call/cls_align_longdouble_split2.c libffi.call/return_dbl2.c \ -libffi.call/return_fl3.c libffi.call/stret_medium.c \ -libffi.call/nested_struct6.c libffi.call/a.out \ -libffi.call/closure_fn3.c libffi.call/float3.c libffi.call/many2.c \ -libffi.call/closure_stdcall.c libffi.call/cls_align_uint16.c \ -libffi.call/cls_9byte1.c libffi.call/closure_fn6.c \ -libffi.call/cls_double_va.c libffi.call/cls_align_pointer.c \ -libffi.call/cls_align_longdouble.c libffi.call/closure_fn2.c \ -libffi.call/cls_sshort.c libffi.call/many_win32.c \ -libffi.call/nested_struct.c libffi.call/cls_20byte.c \ -libffi.call/cls_longdouble.c libffi.call/cls_multi_uchar.c \ -libffi.call/return_uc.c libffi.call/closure_thiscall.c \ -libffi.call/cls_18byte.c libffi.call/cls_8byte.c \ -libffi.call/promotion.c libffi.call/struct1_win32.c \ -libffi.call/return_dbl.c libffi.call/cls_24byte.c \ -libffi.call/struct4.c libffi.call/cls_6byte.c \ -libffi.call/cls_align_uint32.c libffi.call/float.c \ -libffi.call/float1.c libffi.call/float_va.c libffi.call/negint.c \ -libffi.call/return_dbl1.c libffi.call/cls_3_1byte.c \ -libffi.call/cls_align_float.c libffi.call/return_fl1.c \ -libffi.call/nested_struct10.c libffi.call/nested_struct5.c \ -libffi.call/fastthis1_win32.c libffi.call/cls_align_sint64.c \ -libffi.call/stret_large2.c libffi.call/return_sl.c \ -libffi.call/closure_fn0.c libffi.call/cls_5byte.c \ -libffi.call/cls_2byte.c libffi.call/float2.c \ -libffi.call/cls_dbls_struct.c libffi.call/cls_sint.c \ -libffi.call/stret_large.c libffi.call/cls_ulonglong.c \ -libffi.call/cls_ushort.c libffi.call/nested_struct1.c \ -libffi.call/err_bad_abi.c libffi.call/cls_longdouble_va.c \ -libffi.call/cls_float.c libffi.call/cls_pointer_stack.c \ -libffi.call/pyobjc-tc.c libffi.call/cls_multi_ushortchar.c \ -libffi.call/struct1.c libffi.call/nested_struct9.c \ -libffi.call/huge_struct.c libffi.call/problem1.c libffi.call/float4.c \ -libffi.call/fastthis3_win32.c libffi.call/return_ldl.c \ -libffi.call/strlen2_win32.c libffi.call/closure_fn5.c \ -libffi.call/struct2_win32.c libffi.call/struct6.c \ -libffi.call/return_ll.c libffi.call/struct9.c libffi.call/return_sc.c \ -libffi.call/struct7.c libffi.call/cls_align_uint64.c \ -libffi.call/cls_4byte.c libffi.call/strlen_win32.c \ -libffi.call/cls_6_1_byte.c libffi.call/cls_7_1_byte.c \ -libffi.special/unwindtest.cc libffi.special/special.exp \ -libffi.special/unwindtest_ffi_call.cc libffi.special/ffitestcxx.h \ -lib/wrapper.exp lib/target-libpath.exp lib/libffi.exp +EXTRA_DIST = config/default.exp libffi.call/cls_19byte.c \ +libffi.call/cls_align_longdouble_split.c \ +libffi.call/closure_loc_fn0.c libffi.call/cls_schar.c \ +libffi.call/closure_fn1.c \ +libffi.call/return_ul.c libffi.call/cls_align_double.c \ +libffi.call/return_fl2.c libffi.call/cls_1_1byte.c \ +libffi.call/cls_64byte.c libffi.call/nested_struct7.c \ +libffi.call/cls_align_sint32.c libffi.call/nested_struct2.c \ +libffi.call/ffitest.h libffi.call/nested_struct4.c \ +libffi.call/cls_multi_ushort.c libffi.call/struct3.c \ +libffi.call/cls_3byte1.c libffi.call/cls_16byte.c \ +libffi.call/struct8.c libffi.call/nested_struct8.c \ +libffi.call/cls_multi_sshort.c libffi.call/cls_3byte2.c \ +libffi.call/cls_pointer.c \ +libffi.call/err_bad_typedef.c libffi.call/cls_4_1byte.c \ +libffi.call/cls_9byte2.c libffi.call/cls_multi_schar.c \ +libffi.call/stret_medium2.c libffi.call/cls_5_1_byte.c \ +libffi.call/call.exp libffi.call/cls_double.c \ +libffi.call/cls_align_sint16.c libffi.call/cls_uint.c \ +libffi.call/return_ll1.c libffi.call/nested_struct3.c \ +libffi.call/cls_20byte1.c libffi.call/closure_fn4.c \ +libffi.call/cls_uchar.c libffi.call/struct2.c libffi.call/cls_7byte.c \ +libffi.call/strlen.c libffi.call/many.c libffi.call/testclosure.c \ +libffi.call/return_fl.c libffi.call/struct5.c \ +libffi.call/cls_12byte.c libffi.call/cls_multi_sshortchar.c \ +libffi.call/cls_align_longdouble_split2.c libffi.call/return_dbl2.c \ +libffi.call/return_fl3.c libffi.call/stret_medium.c \ +libffi.call/nested_struct6.c libffi.call/closure_fn3.c \ +libffi.call/float3.c libffi.call/many2.c \ +libffi.call/closure_simple.c libffi.call/cls_align_uint16.c \ +libffi.call/cls_9byte1.c libffi.call/closure_fn6.c \ +libffi.call/cls_double_va.c libffi.call/cls_align_pointer.c \ +libffi.call/cls_align_longdouble.c libffi.call/closure_fn2.c \ +libffi.call/cls_sshort.c \ +libffi.call/nested_struct.c libffi.call/cls_20byte.c \ +libffi.call/cls_longdouble.c libffi.call/cls_multi_uchar.c \ +libffi.call/return_uc.c \ +libffi.call/cls_18byte.c libffi.call/cls_8byte.c \ +libffi.call/promotion.c \ +libffi.call/return_dbl.c libffi.call/cls_24byte.c \ +libffi.call/struct4.c libffi.call/cls_6byte.c \ +libffi.call/cls_align_uint32.c libffi.call/float.c \ +libffi.call/float1.c libffi.call/float_va.c libffi.call/negint.c \ +libffi.call/return_dbl1.c libffi.call/cls_3_1byte.c \ +libffi.call/cls_align_float.c libffi.call/return_fl1.c \ +libffi.call/nested_struct10.c libffi.call/nested_struct5.c \ +libffi.call/cls_align_sint64.c \ +libffi.call/stret_large2.c libffi.call/return_sl.c \ +libffi.call/closure_fn0.c libffi.call/cls_5byte.c \ +libffi.call/cls_2byte.c libffi.call/float2.c \ +libffi.call/cls_dbls_struct.c libffi.call/cls_sint.c \ +libffi.call/stret_large.c libffi.call/cls_ulonglong.c \ +libffi.call/cls_ushort.c libffi.call/nested_struct1.c \ +libffi.call/err_bad_abi.c libffi.call/cls_longdouble_va.c \ +libffi.call/cls_float.c libffi.call/cls_pointer_stack.c \ +libffi.call/pyobjc-tc.c libffi.call/cls_multi_ushortchar.c \ +libffi.call/struct1.c libffi.call/nested_struct9.c \ +libffi.call/huge_struct.c libffi.call/problem1.c \ +libffi.call/float4.c \ +libffi.call/return_ldl.c \ +libffi.call/closure_fn5.c \ +libffi.call/struct6.c libffi.call/return_ll.c libffi.call/struct9.c \ +libffi.call/return_sc.c libffi.call/struct7.c \ +libffi.call/cls_align_uint64.c libffi.call/cls_4byte.c \ +libffi.call/cls_6_1_byte.c \ +libffi.call/cls_7_1_byte.c libffi.call/unwindtest.cc \ +libffi.call/unwindtest_ffi_call.cc \ +lib/wrapper.exp lib/target-libpath.exp \ +lib/libffi.exp libffi.call/cls_struct_va1.c \ +libffi.call/cls_uchar_va.c libffi.call/cls_uint_va.c \ +libffi.call/cls_ulong_va.c libffi.call/cls_ushort_va.c \ +libffi.call/nested_struct11.c libffi.call/uninitialized.c \ +libffi.call/va_1.c libffi.call/va_struct1.c libffi.call/va_struct2.c \ +libffi.call/va_struct3.c \ +libffi.call/strlen2.c \ +libffi.call/strlen3.c \ +libffi.call/strlen4.c all: all-am diff --git a/libffi/testsuite/lib/libffi.exp b/libffi/testsuite/lib/libffi.exp index ab0e0e0..b9ef4f1 100644 --- a/libffi/testsuite/lib/libffi.exp +++ b/libffi/testsuite/lib/libffi.exp @@ -1,4 +1,4 @@ -# Copyright (C) 2003, 2005, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +# Copyright (C) 2003, 2005, 2008, 2009, 2010, 2011, 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 @@ -103,12 +103,15 @@ proc libffi-init { args } { global libffi_link_flags global tool_root_dir 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" + set compiler_vendor "gnu" + set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a] if {$gccdir != ""} { set gccdir [file dirname $gccdir] @@ -132,6 +135,7 @@ proc libffi-init { args } { } } } + # add the library path for libffi. append ld_library_path ":${blddirffi}/.libs" # add the library path for libstdc++ as well. @@ -148,7 +152,6 @@ proc libffi-init { args } { if { $libffi_dir != "" } { set libffi_dir [file dirname ${libffi_dir}] set libffi_link_flags "-L${libffi_dir}/.libs" - lappend libffi_link_flags "-L${blddircxx}/src/.libs" } set_ld_library_path_env_vars @@ -215,10 +218,32 @@ proc libffi_target_compile { source dest type options } { lappend options "libs= -lpthread" } + if { [string match "*.cc" $source] } { + lappend options "c++" + } + verbose "options: $options" return [target_compile $source $dest $type $options] } +# TEST should be a preprocessor condition. Returns true if it holds. +proc libffi_feature_test { test } { + set src "ffitest.c" + + set f [open $src "w"] + puts $f "#include <ffi.h>" + puts $f $test + puts $f "xyzzy" + puts $f "#endif" + close $f + + set lines [libffi_target_compile $src "" "preprocess" ""] + file delete $src + + set last [lindex $lines end] + return [regexp -- "xyzzy" $last] +} + # Utility routines. # @@ -238,7 +263,7 @@ proc search_for { file pattern } { # Modified dg-runtest that can cycle through a list of optimization options # as c-torture does. -proc libffi-dg-runtest { testcases flags default-extra-flags } { +proc libffi-dg-runtest { testcases default-extra-flags } { global runtests foreach test $testcases { @@ -259,13 +284,60 @@ proc libffi-dg-runtest { testcases flags default-extra-flags } { set nshort [file tail [file dirname $test]]/[file tail $test] - foreach flags_t $option_list { - verbose "Testing $nshort, $flags $flags_t" 1 - dg-test $test "$flags $flags_t" ${default-extra-flags} + foreach flags $option_list { + verbose "Testing $nshort, $flags" 1 + dg-test $test $flags ${default-extra-flags} } } } +proc run-many-tests { testcases extra_flags } { + global compiler_vendor + switch $compiler_vendor { + "clang" { + set common "-W -Wall" + set optimizations { "-O0" "-O1" "-O2" "-O3" "-Os" } + } + "gnu" { + set common "-W -Wall -Wno-psabi" + set optimizations { "-O0" "-O2" "-O3" "-Os" "-O2 -fomit-frame-pointer" } + } + default { + # Assume we are using the vendor compiler. + set common "" + set optimizations { "" } + } + } + + set targetabis { "" } + if [string match $compiler_vendor "gnu"] { + if [istarget "i?86-*-*"] { + set targetabis { + "" + "-DABI_NUM=FFI_STDCALL -DABI_ATTR=__STDCALL__" + "-DABI_NUM=FFI_THISCALL -DABI_ATTR=__THISCALL__" + "-DABI_NUM=FFI_FASTCALL -DABI_ATTR=__FASTCALL__" + } + } + } + + set common [ concat $common $extra_flags ] + foreach test $testcases { + set testname [file tail $test] + if [search_for $test "ABI_NUM"] { + set abis $targetabis + } else { + set abis { "" } + } + foreach opt $optimizations { + foreach abi $abis { + set options [concat $common $opt $abi] + verbose "Testing $testname, $options" 1 + dg-test $test $options "" + } + } + } +} # Like check_conditional_xfail, but callable from a dg test. diff --git a/libffi/testsuite/lib/target-libpath.exp b/libffi/testsuite/lib/target-libpath.exp new file mode 100644 index 0000000..6b7beba --- /dev/null +++ b/libffi/testsuite/lib/target-libpath.exp @@ -0,0 +1,283 @@ +# Copyright (C) 2004, 2005, 2007 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 GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# This file was contributed by John David Anglin (dave.anglin@nrc-cnrc.gc.ca) + +set orig_environment_saved 0 +set orig_ld_library_path_saved 0 +set orig_ld_run_path_saved 0 +set orig_shlib_path_saved 0 +set orig_ld_libraryn32_path_saved 0 +set orig_ld_library64_path_saved 0 +set orig_ld_library_path_32_saved 0 +set orig_ld_library_path_64_saved 0 +set orig_dyld_library_path_saved 0 +set orig_path_saved 0 + +####################################### +# proc set_ld_library_path_env_vars { } +####################################### + +proc set_ld_library_path_env_vars { } { + global ld_library_path + global orig_environment_saved + global orig_ld_library_path_saved + global orig_ld_run_path_saved + global orig_shlib_path_saved + global orig_ld_libraryn32_path_saved + global orig_ld_library64_path_saved + global orig_ld_library_path_32_saved + global orig_ld_library_path_64_saved + global orig_dyld_library_path_saved + global orig_path_saved + global orig_ld_library_path + global orig_ld_run_path + global orig_shlib_path + global orig_ld_libraryn32_path + global orig_ld_library64_path + global orig_ld_library_path_32 + global orig_ld_library_path_64 + global orig_dyld_library_path + global orig_path + global GCC_EXEC_PREFIX + + # Set the relocated compiler prefix, but only if the user hasn't specified one. + if { [info exists GCC_EXEC_PREFIX] && ![info exists env(GCC_EXEC_PREFIX)] } { + setenv GCC_EXEC_PREFIX "$GCC_EXEC_PREFIX" + } + + # Setting the ld library path causes trouble when testing cross-compilers. + if { [is_remote target] } { + return + } + + if { $orig_environment_saved == 0 } { + global env + + set orig_environment_saved 1 + + # Save the original environment. + if [info exists env(LD_LIBRARY_PATH)] { + set orig_ld_library_path "$env(LD_LIBRARY_PATH)" + set orig_ld_library_path_saved 1 + } + if [info exists env(LD_RUN_PATH)] { + set orig_ld_run_path "$env(LD_RUN_PATH)" + set orig_ld_run_path_saved 1 + } + if [info exists env(SHLIB_PATH)] { + set orig_shlib_path "$env(SHLIB_PATH)" + set orig_shlib_path_saved 1 + } + if [info exists env(LD_LIBRARYN32_PATH)] { + set orig_ld_libraryn32_path "$env(LD_LIBRARYN32_PATH)" + set orig_ld_libraryn32_path_saved 1 + } + if [info exists env(LD_LIBRARY64_PATH)] { + set orig_ld_library64_path "$env(LD_LIBRARY64_PATH)" + set orig_ld_library64_path_saved 1 + } + if [info exists env(LD_LIBRARY_PATH_32)] { + set orig_ld_library_path_32 "$env(LD_LIBRARY_PATH_32)" + set orig_ld_library_path_32_saved 1 + } + if [info exists env(LD_LIBRARY_PATH_64)] { + set orig_ld_library_path_64 "$env(LD_LIBRARY_PATH_64)" + set orig_ld_library_path_64_saved 1 + } + if [info exists env(DYLD_LIBRARY_PATH)] { + set orig_dyld_library_path "$env(DYLD_LIBRARY_PATH)" + set orig_dyld_library_path_saved 1 + } + if [info exists env(PATH)] { + set orig_path "$env(PATH)" + set orig_path_saved 1 + } + } + + # We need to set ld library path in the environment. Currently, + # unix.exp doesn't set the environment correctly for all systems. + # It only sets SHLIB_PATH and LD_LIBRARY_PATH when it executes a + # program. We also need the environment set for compilations, etc. + # + # On IRIX 6, we have to set variables akin to LD_LIBRARY_PATH, but + # called LD_LIBRARYN32_PATH (for the N32 ABI) and LD_LIBRARY64_PATH + # (for the 64-bit ABI). The same applies to Darwin (DYLD_LIBRARY_PATH), + # Solaris 32 bit (LD_LIBRARY_PATH_32), Solaris 64 bit (LD_LIBRARY_PATH_64), + # and HP-UX (SHLIB_PATH). In some cases, the variables are independent + # of LD_LIBRARY_PATH, and in other cases LD_LIBRARY_PATH is used if the + # variable is not defined. + # + # Doing this is somewhat of a hack as ld_library_path gets repeated in + # SHLIB_PATH and LD_LIBRARY_PATH when unix_load sets these variables. + if { $orig_ld_library_path_saved } { + setenv LD_LIBRARY_PATH "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARY_PATH "$ld_library_path" + } + if { $orig_ld_run_path_saved } { + setenv LD_RUN_PATH "$ld_library_path:$orig_ld_run_path" + } else { + setenv LD_RUN_PATH "$ld_library_path" + } + # The default shared library dynamic path search for 64-bit + # HP-UX executables searches LD_LIBRARY_PATH before SHLIB_PATH. + # LD_LIBRARY_PATH isn't used for 32-bit executables. Thus, we + # set LD_LIBRARY_PATH and SHLIB_PATH as if they were independent. + if { $orig_shlib_path_saved } { + setenv SHLIB_PATH "$ld_library_path:$orig_shlib_path" + } else { + setenv SHLIB_PATH "$ld_library_path" + } + if { $orig_ld_libraryn32_path_saved } { + setenv LD_LIBRARYN32_PATH "$ld_library_path:$orig_ld_libraryn32_path" + } elseif { $orig_ld_library_path_saved } { + setenv LD_LIBRARYN32_PATH "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARYN32_PATH "$ld_library_path" + } + if { $orig_ld_library64_path_saved } { + setenv LD_LIBRARY64_PATH "$ld_library_path:$orig_ld_library64_path" + } elseif { $orig_ld_library_path_saved } { + setenv LD_LIBRARY64_PATH "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARY64_PATH "$ld_library_path" + } + if { $orig_ld_library_path_32_saved } { + setenv LD_LIBRARY_PATH_32 "$ld_library_path:$orig_ld_library_path_32" + } elseif { $orig_ld_library_path_saved } { + setenv LD_LIBRARY_PATH_32 "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARY_PATH_32 "$ld_library_path" + } + if { $orig_ld_library_path_64_saved } { + setenv LD_LIBRARY_PATH_64 "$ld_library_path:$orig_ld_library_path_64" + } elseif { $orig_ld_library_path_saved } { + setenv LD_LIBRARY_PATH_64 "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARY_PATH_64 "$ld_library_path" + } + if { $orig_dyld_library_path_saved } { + setenv DYLD_LIBRARY_PATH "$ld_library_path:$orig_dyld_library_path" + } else { + setenv DYLD_LIBRARY_PATH "$ld_library_path" + } + if { [istarget *-*-cygwin*] || [istarget *-*-mingw*] } { + if { $orig_path_saved } { + setenv PATH "$ld_library_path:$orig_path" + } else { + setenv PATH "$ld_library_path" + } + } + + verbose -log "set_ld_library_path_env_vars: ld_library_path=$ld_library_path" +} + +####################################### +# proc restore_ld_library_path_env_vars { } +####################################### + +proc restore_ld_library_path_env_vars { } { + global orig_environment_saved + global orig_ld_library_path_saved + global orig_ld_run_path_saved + global orig_shlib_path_saved + global orig_ld_libraryn32_path_saved + global orig_ld_library64_path_saved + global orig_ld_library_path_32_saved + global orig_ld_library_path_64_saved + global orig_dyld_library_path_saved + global orig_path_saved + global orig_ld_library_path + global orig_ld_run_path + global orig_shlib_path + global orig_ld_libraryn32_path + global orig_ld_library64_path + global orig_ld_library_path_32 + global orig_ld_library_path_64 + global orig_dyld_library_path + global orig_path + + if { $orig_environment_saved == 0 } { + return + } + + if { $orig_ld_library_path_saved } { + setenv LD_LIBRARY_PATH "$orig_ld_library_path" + } elseif [info exists env(LD_LIBRARY_PATH)] { + unsetenv LD_LIBRARY_PATH + } + if { $orig_ld_run_path_saved } { + setenv LD_RUN_PATH "$orig_ld_run_path" + } elseif [info exists env(LD_RUN_PATH)] { + unsetenv LD_RUN_PATH + } + if { $orig_shlib_path_saved } { + setenv SHLIB_PATH "$orig_shlib_path" + } elseif [info exists env(SHLIB_PATH)] { + unsetenv SHLIB_PATH + } + if { $orig_ld_libraryn32_path_saved } { + setenv LD_LIBRARYN32_PATH "$orig_ld_libraryn32_path" + } elseif [info exists env(LD_LIBRARYN32_PATH)] { + unsetenv LD_LIBRARYN32_PATH + } + if { $orig_ld_library64_path_saved } { + setenv LD_LIBRARY64_PATH "$orig_ld_library64_path" + } elseif [info exists env(LD_LIBRARY64_PATH)] { + unsetenv LD_LIBRARY64_PATH + } + if { $orig_ld_library_path_32_saved } { + setenv LD_LIBRARY_PATH_32 "$orig_ld_library_path_32" + } elseif [info exists env(LD_LIBRARY_PATH_32)] { + unsetenv LD_LIBRARY_PATH_32 + } + if { $orig_ld_library_path_64_saved } { + setenv LD_LIBRARY_PATH_64 "$orig_ld_library_path_64" + } elseif [info exists env(LD_LIBRARY_PATH_64)] { + unsetenv LD_LIBRARY_PATH_64 + } + if { $orig_dyld_library_path_saved } { + setenv DYLD_LIBRARY_PATH "$orig_dyld_library_path" + } elseif [info exists env(DYLD_LIBRARY_PATH)] { + unsetenv DYLD_LIBRARY_PATH + } + if { $orig_path_saved } { + setenv PATH "$orig_path" + } elseif [info exists env(PATH)] { + unsetenv PATH + } +} + +####################################### +# proc get_shlib_extension { } +####################################### + +proc get_shlib_extension { } { + global shlib_ext + + if { [ istarget *-*-darwin* ] } { + set shlib_ext "dylib" + } elseif { [ istarget *-*-cygwin* ] || [ istarget *-*-mingw* ] } { + set shlib_ext "dll" + } elseif { [ istarget hppa*-*-hpux* ] } { + set shlib_ext "sl" + } else { + set shlib_ext "so" + } + return $shlib_ext +} + diff --git a/libffi/testsuite/lib/wrapper.exp b/libffi/testsuite/lib/wrapper.exp new file mode 100644 index 0000000..4e5ae43 --- /dev/null +++ b/libffi/testsuite/lib/wrapper.exp @@ -0,0 +1,45 @@ +# Copyright (C) 2004, 2007 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 GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# This file contains GCC-specifics for status wrappers for test programs. + +# ${tool}_maybe_build_wrapper -- Build wrapper object if the target +# needs it. FILENAME is the path to the wrapper file. If there are +# additional arguments, they are command-line options to provide to +# the compiler when compiling FILENAME. + +proc ${tool}_maybe_build_wrapper { filename args } { + global gluefile wrap_flags + + if { [target_info needs_status_wrapper] != "" \ + && [target_info needs_status_wrapper] != "0" \ + && ![info exists gluefile] } { + set saved_wrap_compile_flags [target_info wrap_compile_flags] + set flags [join $args " "] + # The wrapper code may contain code that gcc objects on. This + # became true for dejagnu-1.4.4. The set of warnings and code + # that gcc objects on may change, so just make sure -w is always + # passed to turn off all warnings. + set_currtarget_info wrap_compile_flags \ + "$saved_wrap_compile_flags -w $flags" + set result [build_wrapper $filename] + set_currtarget_info wrap_compile_flags "$saved_wrap_compile_flags" + if { $result != "" } { + set gluefile [lindex $result 0] + set wrap_flags [lindex $result 1] + } + } +} diff --git a/libffi/testsuite/libffi.call/call.exp b/libffi/testsuite/libffi.call/call.exp index 26acd81..46fb1eb 100644 --- a/libffi/testsuite/libffi.call/call.exp +++ b/libffi/testsuite/libffi.call/call.exp @@ -1,4 +1,4 @@ -# Copyright (C) 2003, 2006, 2009, 2010 Free Software Foundation, Inc. +# 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 @@ -19,11 +19,9 @@ libffi-init global srcdir subdir -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-O0 -W -Wall" "" -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-O2" "" -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-O3" "" -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-Os" "" -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-O2 -fomit-frame-pointer" "" +set tlist [lsearch -inline -all -not -glob [lsort [glob -nocomplain -- $srcdir/$subdir/*.{c,cc}]] *complex*] + +run-many-tests $tlist "" dg-finish diff --git a/libffi/testsuite/libffi.call/closure_stdcall.c b/libffi/testsuite/libffi.call/closure_simple.c index 1407f02..5a4e728 100644 --- a/libffi/testsuite/libffi.call/closure_stdcall.c +++ b/libffi/testsuite/libffi.call/closure_simple.c @@ -1,15 +1,14 @@ -/* Area: closure_call (stdcall convention) - Purpose: Check handling when caller expects stdcall callee +/* Area: closure_call + Purpose: Check simple closure handling with all ABIs Limitations: none. PR: none. Originator: <twalljava@dev.java.net> */ -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ +/* { dg-do run } */ #include "ffitest.h" static void -closure_test_stdcall(ffi_cif* cif __UNUSED__, void* resp, void** args, - void* userdata) +closure_test(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata) { *(ffi_arg*)resp = (int)*(int *)args[0] + (int)(*(int *)args[1]) @@ -23,7 +22,7 @@ closure_test_stdcall(ffi_cif* cif __UNUSED__, void* resp, void** args, } -typedef int (__stdcall *closure_test_type0)(int, int, int, int); +typedef int (ABI_ATTR *closure_test_type0)(int, int, int, int); int main (void) { @@ -32,9 +31,6 @@ int main (void) ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); ffi_type * cl_arg_types[17]; int res; - void* sp_pre; - void* sp_post; - char buf[1024]; cl_arg_types[0] = &ffi_type_uint; cl_arg_types[1] = &ffi_type_uint; @@ -43,30 +39,17 @@ int main (void) cl_arg_types[4] = NULL; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 4, + CHECK(ffi_prep_cif(&cif, ABI_NUM, 4, &ffi_type_sint, cl_arg_types) == FFI_OK); - CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_stdcall, + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test, (void *) 3 /* userdata */, code) == FFI_OK); -#ifdef _MSC_VER - __asm { mov sp_pre, esp } -#else - asm volatile (" movl %%esp,%0" : "=g" (sp_pre)); -#endif res = (*(closure_test_type0)code)(0, 1, 2, 3); -#ifdef _MSC_VER - __asm { mov sp_post, esp } -#else - asm volatile (" movl %%esp,%0" : "=g" (sp_post)); -#endif /* { dg-output "0 1 2 3: 9" } */ printf("res: %d\n",res); /* { dg-output "\nres: 9" } */ - sprintf(buf, "mismatch: pre=%p vs post=%p", sp_pre, sp_post); - printf("stack pointer %s\n", (sp_pre == sp_post ? "match" : buf)); - /* { dg-output "\nstack pointer match" } */ exit(0); } diff --git a/libffi/testsuite/libffi.call/closure_thiscall.c b/libffi/testsuite/libffi.call/closure_thiscall.c deleted file mode 100644 index 0f93649..0000000 --- a/libffi/testsuite/libffi.call/closure_thiscall.c +++ /dev/null @@ -1,72 +0,0 @@ -/* Area: closure_call (thiscall convention) - Purpose: Check handling when caller expects thiscall callee - Limitations: none. - PR: none. - Originator: <ktietz@redhat.com> */ - -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ -#include "ffitest.h" - -static void -closure_test_thiscall(ffi_cif* cif __UNUSED__, void* resp, void** args, - void* userdata) -{ - *(ffi_arg*)resp = - (int)*(int *)args[0] + (int)(*(int *)args[1]) - + (int)(*(int *)args[2]) + (int)(*(int *)args[3]) - + (int)(intptr_t)userdata; - - printf("%d %d %d %d: %d\n", - (int)*(int *)args[0], (int)(*(int *)args[1]), - (int)(*(int *)args[2]), (int)(*(int *)args[3]), - (int)*(ffi_arg *)resp); - -} - -typedef int (__thiscall *closure_test_type0)(int, int, int, int); - -int main (void) -{ - ffi_cif cif; - void *code; - ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); - ffi_type * cl_arg_types[17]; - int res; - void* sp_pre; - void* sp_post; - char buf[1024]; - - cl_arg_types[0] = &ffi_type_uint; - cl_arg_types[1] = &ffi_type_uint; - cl_arg_types[2] = &ffi_type_uint; - cl_arg_types[3] = &ffi_type_uint; - cl_arg_types[4] = NULL; - - /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_THISCALL, 4, - &ffi_type_sint, cl_arg_types) == FFI_OK); - - CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_thiscall, - (void *) 3 /* userdata */, code) == FFI_OK); - -#ifdef _MSC_VER - __asm { mov sp_pre, esp } -#else - asm volatile (" movl %%esp,%0" : "=g" (sp_pre)); -#endif - res = (*(closure_test_type0)code)(0, 1, 2, 3); -#ifdef _MSC_VER - __asm { mov sp_post, esp } -#else - asm volatile (" movl %%esp,%0" : "=g" (sp_post)); -#endif - /* { dg-output "0 1 2 3: 9" } */ - - printf("res: %d\n",res); - /* { dg-output "\nres: 9" } */ - - sprintf(buf, "mismatch: pre=%p vs post=%p", sp_pre, sp_post); - printf("stack pointer %s\n", (sp_pre == sp_post ? "match" : buf)); - /* { dg-output "\nstack pointer match" } */ - exit(0); -} diff --git a/libffi/testsuite/libffi.call/cls_align_longdouble_split.c b/libffi/testsuite/libffi.call/cls_align_longdouble_split.c index 15f9365..cc1c43b 100644 --- a/libffi/testsuite/libffi.call/cls_align_longdouble_split.c +++ b/libffi/testsuite/libffi.call/cls_align_longdouble_split.c @@ -4,10 +4,8 @@ PR: none. Originator: <hos@tamanegi.org> 20031203 */ -/* { dg-excess-errors "no long double format" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ /* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */ -/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ #include "ffitest.h" diff --git a/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c b/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c index ca1c356..5d3bec0 100644 --- a/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c +++ b/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c @@ -5,10 +5,8 @@ Originator: Blake Chaffin 6/18/2007 */ -/* { dg-excess-errors "no long double format" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ /* { dg-do run { xfail strongarm*-*-* } } */ /* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */ -/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ #include "ffitest.h" diff --git a/libffi/testsuite/libffi.call/cls_longdouble.c b/libffi/testsuite/libffi.call/cls_longdouble.c index e6bac1f..d24e72e 100644 --- a/libffi/testsuite/libffi.call/cls_longdouble.c +++ b/libffi/testsuite/libffi.call/cls_longdouble.c @@ -4,10 +4,10 @@ PR: none. Originator: Blake Chaffin */ -/* { dg-excess-errors "no long double format" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ -/* { dg-do run { xfail arm*-*-* strongarm*-*-* xscale*-*-* } } */ +/* 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-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ #include "ffitest.h" diff --git a/libffi/testsuite/libffi.call/cls_many_mixed_args.c b/libffi/testsuite/libffi.call/cls_many_mixed_args.c new file mode 100644 index 0000000..7fd6c82 --- /dev/null +++ b/libffi/testsuite/libffi.call/cls_many_mixed_args.c @@ -0,0 +1,70 @@ +/* Area: closure_call + Purpose: Check closures called with many args of mixed types + Limitations: none. + PR: none. + Originator: <david.schneider@picle.org> */ + +/* { dg-do run } */ +#include "ffitest.h" +#include <float.h> +#include <math.h> + +#define NARGS 16 + +static void cls_ret_double_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + int i; + double r = 0; + double t; + for(i = 0; i < NARGS; i++) + { + if(i == 4 || i == 9 || i == 11 || i == 13 || i == 15) + { + t = *(long int *)args[i]; + CHECK(t == i+1); + } + else + { + t = *(double *)args[i]; + CHECK(fabs(t - ((i+1) * 0.1)) < FLT_EPSILON); + } + r += t; + } + *(double *)resp = r; +} +typedef double (*cls_ret_double)(double, double, double, double, long int, +double, double, double, double, long int, double, long int, double, long int, +double, long int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[NARGS]; + double res; + int i; + double expected = 64.9; + + for(i = 0; i < NARGS; i++) + { + if(i == 4 || i == 9 || i == 11 || i == 13 || i == 15) + cl_arg_types[i] = &ffi_type_slong; + else + cl_arg_types[i] = &ffi_type_double; + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NARGS, + &ffi_type_double, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_double_fn, NULL, code) == FFI_OK); + + res = (((cls_ret_double)code))(0.1, 0.2, 0.3, 0.4, 5, 0.6, 0.7, 0.8, 0.9, 10, + 1.1, 12, 1.3, 14, 1.5, 16); + if (fabs(res - expected) < FLT_EPSILON) + exit(0); + else + abort(); +} diff --git a/libffi/testsuite/libffi.call/cls_many_mixed_float_double.c b/libffi/testsuite/libffi.call/cls_many_mixed_float_double.c new file mode 100644 index 0000000..62b0697a --- /dev/null +++ b/libffi/testsuite/libffi.call/cls_many_mixed_float_double.c @@ -0,0 +1,55 @@ +/* Area: closure_call + Purpose: Check register allocation for closure calls with many float and double arguments + Limitations: none. + PR: none. + Originator: <david.schneider@picle.org> */ + +/* { dg-do run } */ +#include "ffitest.h" +#include <float.h> +#include <math.h> + +#define NARGS 16 + +static void cls_mixed_float_double_fn(ffi_cif* cif , void* ret, void** args, + void* userdata __UNUSED__) +{ + double r = 0; + unsigned int i; + double t; + for(i=0; i < cif->nargs; i++) + { + if(cif->arg_types[i] == &ffi_type_double) { + t = *(((double**)(args))[i]); + } else { + t = *(((float**)(args))[i]); + } + r += t; + } + *((double*)ret) = r; +} +typedef double (*cls_mixed)(double, float, double, double, double, double, double, float, float, double, float, float); + +int main (void) +{ + ffi_cif cif; + ffi_closure *closure; + void* code; + ffi_type *argtypes[12] = {&ffi_type_double, &ffi_type_float, &ffi_type_double, + &ffi_type_double, &ffi_type_double, &ffi_type_double, + &ffi_type_double, &ffi_type_float, &ffi_type_float, + &ffi_type_double, &ffi_type_float, &ffi_type_float}; + + + closure = ffi_closure_alloc(sizeof(ffi_closure), (void**)&code); + if(closure ==NULL) + abort(); + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 12, &ffi_type_double, argtypes) == FFI_OK); + CHECK(ffi_prep_closure_loc(closure, &cif, cls_mixed_float_double_fn, NULL, code) == FFI_OK); + double ret = ((cls_mixed)code)(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2); + ffi_closure_free(closure); + if(fabs(ret - 7.8) < FLT_EPSILON) + exit(0); + else + abort(); +} diff --git a/libffi/testsuite/libffi.call/cls_pointer.c b/libffi/testsuite/libffi.call/cls_pointer.c index cf03993..d82a87a 100644 --- a/libffi/testsuite/libffi.call/cls_pointer.c +++ b/libffi/testsuite/libffi.call/cls_pointer.c @@ -35,7 +35,7 @@ int main (void) void *code; ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); void* args[3]; -// ffi_type cls_pointer_type; + /* ffi_type cls_pointer_type; */ ffi_type* arg_types[3]; /* cls_pointer_type.size = sizeof(void*); diff --git a/libffi/testsuite/libffi.call/cls_pointer_stack.c b/libffi/testsuite/libffi.call/cls_pointer_stack.c index e31139e..1f1d915 100644 --- a/libffi/testsuite/libffi.call/cls_pointer_stack.c +++ b/libffi/testsuite/libffi.call/cls_pointer_stack.c @@ -98,7 +98,7 @@ int main (void) void *code; ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); void* args[3]; -// ffi_type cls_pointer_type; + /* ffi_type cls_pointer_type; */ ffi_type* arg_types[3]; /* cls_pointer_type.size = sizeof(void*); @@ -125,18 +125,18 @@ int main (void) ffi_call(&cif, FFI_FN(cls_pointer_fn1), &res, args); printf("res: 0x%08x\n", (unsigned int) res); - // { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } - // { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } - // { dg-output "\nres: 0x8bf258bd" } + /* { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } */ + /* { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } */ + /* { dg-output "\nres: 0x8bf258bd" } */ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_pointer_gn, NULL, code) == FFI_OK); res = (ffi_arg)(uintptr_t)((void*(*)(void*, void*))(code))(arg1, arg2); printf("res: 0x%08x\n", (unsigned int) res); - // { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } - // { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } - // { dg-output "\nres: 0x8bf258bd" } + /* { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } */ + /* { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } */ + /* { dg-output "\nres: 0x8bf258bd" } */ exit(0); } diff --git a/libffi/testsuite/libffi.call/cls_struct_va1.c b/libffi/testsuite/libffi.call/cls_struct_va1.c index 7262d63..6d1fdae 100644 --- a/libffi/testsuite/libffi.call/cls_struct_va1.c +++ b/libffi/testsuite/libffi.call/cls_struct_va1.c @@ -106,9 +106,9 @@ main (void) CHECK(ffi_prep_closure_loc(pcl, &cif, test_fn, NULL, code) == FFI_OK); res = ((int (*)(int, ...))(code))(si, s1, l1, s2); - // { dg-output "4 5 6 10 11 12 13 14 20 21" } + /* { dg-output "4 5 6 10 11 12 13 14 20 21" } */ printf("res: %d\n", (int) res); - // { dg-output "\nres: 42" } + /* { dg-output "\nres: 42" } */ exit(0); } diff --git a/libffi/testsuite/libffi.call/cls_ulonglong.c b/libffi/testsuite/libffi.call/cls_ulonglong.c index 235ab44..62f2cae 100644 --- a/libffi/testsuite/libffi.call/cls_ulonglong.c +++ b/libffi/testsuite/libffi.call/cls_ulonglong.c @@ -11,7 +11,7 @@ static void cls_ret_ulonglong_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__) { - *(unsigned long long *)resp= *(unsigned long long *)args[0]; + *(unsigned long long *)resp= 0xfffffffffffffffLL ^ *(unsigned long long *)args[0]; printf("%" PRIuLL ": %" PRIuLL "\n",*(unsigned long long *)args[0], *(unsigned long long *)(resp)); @@ -34,14 +34,14 @@ int main (void) &ffi_type_uint64, cl_arg_types) == FFI_OK); CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_ulonglong_fn, NULL, code) == FFI_OK); res = (*((cls_ret_ulonglong)code))(214LL); - /* { dg-output "214: 214" } */ + /* { dg-output "214: 1152921504606846761" } */ printf("res: %" PRIdLL "\n", res); - /* { dg-output "\nres: 214" } */ + /* { dg-output "\nres: 1152921504606846761" } */ res = (*((cls_ret_ulonglong)code))(9223372035854775808LL); - /* { dg-output "\n9223372035854775808: 9223372035854775808" } */ + /* { dg-output "\n9223372035854775808: 8070450533247928831" } */ printf("res: %" PRIdLL "\n", res); - /* { dg-output "\nres: 9223372035854775808" } */ + /* { dg-output "\nres: 8070450533247928831" } */ exit(0); } diff --git a/libffi/testsuite/libffi.call/ffitest.h b/libffi/testsuite/libffi.call/ffitest.h index d81d4da..15d5e44 100644 --- a/libffi/testsuite/libffi.call/ffitest.h +++ b/libffi/testsuite/libffi.call/ffitest.h @@ -15,22 +15,25 @@ #define MAX_ARGS 256 -#define CHECK(x) !(x) ? abort() : 0 +#define CHECK(x) (void)(!(x) ? (abort(), 1) : 0) -/* Define __UNUSED__ that also other compilers than gcc can run the tests. */ +/* 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)) #else #define __UNUSED__ +#define __STDCALL__ __stdcall +#define __THISCALL__ __thiscall +#define __FASTCALL__ __fastcall #endif -/* Define __FASTCALL__ so that other compilers than gcc can run the tests. */ -#undef __FASTCALL__ -#if defined _MSC_VER -#define __FASTCALL__ __fastcall -#else -#define __FASTCALL__ __attribute__((fastcall)) +#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 @@ -127,44 +130,6 @@ #define PRId64 "I64d" #endif -#ifdef USING_MMAP -static inline void * -allocate_mmap (size_t size) -{ - void *page; -#if defined (HAVE_MMAP_DEV_ZERO) - static int dev_zero_fd = -1; -#endif - -#ifdef HAVE_MMAP_DEV_ZERO - if (dev_zero_fd == -1) - { - dev_zero_fd = open ("/dev/zero", O_RDONLY); - if (dev_zero_fd == -1) - { - perror ("open /dev/zero: %m"); - exit (1); - } - } -#endif - - -#ifdef HAVE_MMAP_ANON - page = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -#endif -#ifdef HAVE_MMAP_DEV_ZERO - page = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE, dev_zero_fd, 0); -#endif - - if (page == (void *) MAP_FAILED) - { - perror ("virtual memory exhausted"); - exit (1); - } - - return page; -} - +#ifndef PRIuPTR +#define PRIuPTR "u" #endif diff --git a/libffi/testsuite/libffi.call/float1.c b/libffi/testsuite/libffi.call/float1.c index 991d059..c48493c 100644 --- a/libffi/testsuite/libffi.call/float1.c +++ b/libffi/testsuite/libffi.call/float1.c @@ -8,6 +8,8 @@ #include "ffitest.h" #include "float.h" +#include <math.h> + typedef union { double d; @@ -47,7 +49,7 @@ int main (void) /* These are not always the same!! Check for a reasonable delta */ - CHECK(result[0].d - dblit(f) < DBL_EPSILON); + CHECK(fabs(result[0].d - dblit(f)) < DBL_EPSILON); /* Check the canary. */ for (i = 0; i < sizeof (double); ++i) diff --git a/libffi/testsuite/libffi.call/float2.c b/libffi/testsuite/libffi.call/float2.c index a0b296c..20a8c40 100644 --- a/libffi/testsuite/libffi.call/float2.c +++ b/libffi/testsuite/libffi.call/float2.c @@ -3,13 +3,13 @@ Limitations: none. PR: none. Originator: From the original ffitest.c */ - -/* { dg-excess-errors "fails" { target x86_64-*-mingw* x86_64-*-cygwin* } } */ -/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ +/* { dg-do run } */ #include "ffitest.h" #include "float.h" +#include <math.h> + static long double ldblit(float f) { return (long double) (((long double) f)/ (long double) 3.0); @@ -49,7 +49,7 @@ int main (void) #endif /* These are not always the same!! Check for a reasonable delta */ - if (ld - ldblit(f) < LDBL_EPSILON) + if (fabsl(ld - ldblit(f)) < LDBL_EPSILON) puts("long double return value tests ok!"); else CHECK(0); diff --git a/libffi/testsuite/libffi.call/float3.c b/libffi/testsuite/libffi.call/float3.c index 76bd5f2..bab3206 100644 --- a/libffi/testsuite/libffi.call/float3.c +++ b/libffi/testsuite/libffi.call/float3.c @@ -9,6 +9,8 @@ #include "ffitest.h" #include "float.h" +#include <math.h> + static double floating_1(float a, double b, long double c) { return (double) a + b + (double) c; @@ -49,7 +51,7 @@ int main (void) ffi_call(&cif, FFI_FN(floating_1), &rd, values); - CHECK(rd - floating_1(f, d, ld) < DBL_EPSILON); + CHECK(fabs(rd - floating_1(f, d, ld)) < DBL_EPSILON); args[0] = &ffi_type_longdouble; values[0] = &ld; @@ -66,7 +68,7 @@ int main (void) ffi_call(&cif, FFI_FN(floating_2), &rd, values); - CHECK(rd - floating_2(ld, d, f) < DBL_EPSILON); + CHECK(fabs(rd - floating_2(ld, d, f)) < DBL_EPSILON); exit (0); } diff --git a/libffi/testsuite/libffi.call/float_va.c b/libffi/testsuite/libffi.call/float_va.c index aae158e..5acff91 100644 --- a/libffi/testsuite/libffi.call/float_va.c +++ b/libffi/testsuite/libffi.call/float_va.c @@ -56,9 +56,9 @@ int main (void) * different. */ /* Call it statically and then via ffi */ resfp=float_va_fn(0,2.0); - // { dg-output "0: 2.0 : total: 2.0" } + /* { dg-output "0: 2.0 : total: 2.0" } */ printf("compiled: %.1f\n", resfp); - // { dg-output "\ncompiled: 2.0" } + /* { dg-output "\ncompiled: 2.0" } */ arg_types[0] = &ffi_type_uint; arg_types[1] = &ffi_type_double; @@ -71,16 +71,16 @@ int main (void) values[0] = &firstarg; values[1] = &doubles[0]; ffi_call(&cif, FFI_FN(float_va_fn), &resfp, values); - // { dg-output "\n0: 2.0 : total: 2.0" } + /* { dg-output "\n0: 2.0 : total: 2.0" } */ printf("ffi: %.1f\n", resfp); - // { dg-output "\nffi: 2.0" } + /* { dg-output "\nffi: 2.0" } */ /* Second test, float_va_fn(2,2.0,3.0,4.0), now with variadic params */ /* Call it statically and then via ffi */ resfp=float_va_fn(2,2.0,3.0,4.0); - // { dg-output "\n2: 2.0 : 0:3.0 1:4.0 total: 11.0" } + /* { dg-output "\n2: 2.0 : 0:3.0 1:4.0 total: 11.0" } */ printf("compiled: %.1f\n", resfp); - // { dg-output "\ncompiled: 11.0" } + /* { dg-output "\ncompiled: 11.0" } */ arg_types[0] = &ffi_type_uint; arg_types[1] = &ffi_type_double; @@ -99,9 +99,9 @@ int main (void) values[2] = &doubles[1]; values[3] = &doubles[2]; ffi_call(&cif, FFI_FN(float_va_fn), &resfp, values); - // { dg-output "\n2: 2.0 : 0:3.0 1:4.0 total: 11.0" } + /* { dg-output "\n2: 2.0 : 0:3.0 1:4.0 total: 11.0" } */ printf("ffi: %.1f\n", resfp); - // { dg-output "\nffi: 11.0" } + /* { dg-output "\nffi: 11.0" } */ exit(0); } diff --git a/libffi/testsuite/libffi.call/huge_struct.c b/libffi/testsuite/libffi.call/huge_struct.c index 380fedf..187c42c 100644 --- a/libffi/testsuite/libffi.call/huge_struct.c +++ b/libffi/testsuite/libffi.call/huge_struct.c @@ -5,10 +5,9 @@ Originator: Blake Chaffin 6/18/2007 */ -/* { dg-excess-errors "" { target x86_64-*-mingw* x86_64-*-cygwin* } } */ /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ /* { dg-options -mlong-double-128 { target powerpc64*-*-linux* } } */ -/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ +/* { dg-options -Wformat=0 { target moxie*-*-elf } } */ #include "ffitest.h" @@ -295,7 +294,7 @@ main(int argc __UNUSED__, const char** argv __UNUSED__) CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 50, &ret_struct_type, argTypes) == FFI_OK); ffi_call(&cif, FFI_FN(test_large_fn), &retVal, argValues); - // { dg-output "1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } + /* { dg-output "1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } */ printf("res: %" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " @@ -308,7 +307,7 @@ main(int argc __UNUSED__, const char** argv __UNUSED__) retVal.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (unsigned long)retVal.jj, retVal.kk, retVal.ll, retVal.mm, retVal.nn, retVal.oo, retVal.pp, retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (unsigned long)retVal.vv, retVal.ww, retVal.xx); - // { dg-output "\nres: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } + /* { 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); @@ -323,7 +322,7 @@ main(int argc __UNUSED__, const char** argv __UNUSED__) ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p, ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p, ui8, si8); - // { dg-output "\n1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } + /* { dg-output "\n1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } */ printf("res: %" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " "%" PRIu8 " %" PRId8 " %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " @@ -336,7 +335,7 @@ main(int argc __UNUSED__, const char** argv __UNUSED__) retVal.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (unsigned long)retVal.jj, retVal.kk, retVal.ll, retVal.mm, retVal.nn, retVal.oo, retVal.pp, retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (unsigned long)retVal.vv, retVal.ww, retVal.xx); - // { dg-output "\nres: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } + /* { dg-output "\nres: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } */ return 0; } diff --git a/libffi/testsuite/libffi.call/many.c b/libffi/testsuite/libffi.call/many.c index 4869ba9..336968c 100644 --- a/libffi/testsuite/libffi.call/many.c +++ b/libffi/testsuite/libffi.call/many.c @@ -7,21 +7,11 @@ /* { dg-do run } */ #include "ffitest.h" +#include <stdlib.h> #include <float.h> +#include <math.h> -static float many(float f1, - float f2, - float f3, - float f4, - float f5, - float f6, - float f7, - float f8, - float f9, - float f10, - float f11, - float f12, - float f13) +static float ABI_ATTR many(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9, float f10, float f11, float f12, float f13) { #if 0 printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n", @@ -30,7 +20,7 @@ static float many(float f1, (double) f11, (double) f12, (double) f13); #endif - return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); + return f1+f2+f3+f4+f5+f6+f7+f8+f9+f10+f11+f12+f13; } int main (void) @@ -50,7 +40,7 @@ int main (void) } /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, + CHECK(ffi_prep_cif(&cif, ABI_NUM, 13, &ffi_type_float, args) == FFI_OK); ffi_call(&cif, FFI_FN(many), &f, values); @@ -62,7 +52,7 @@ int main (void) fa[8], fa[9], fa[10],fa[11],fa[12]); - if (f - ff < FLT_EPSILON) + if (fabs(f - ff) < FLT_EPSILON) exit(0); else abort(); diff --git a/libffi/testsuite/libffi.call/many2.c b/libffi/testsuite/libffi.call/many2.c index 1077159..1c85746 100644 --- a/libffi/testsuite/libffi.call/many2.c +++ b/libffi/testsuite/libffi.call/many2.c @@ -12,14 +12,17 @@ typedef unsigned char u8; -__attribute__((noinline)) uint8_t +#ifdef __GNUC__ +__attribute__((noinline)) +#endif +uint8_t foo (uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g) { return a + b + c + d + e + f + g; } -uint8_t +uint8_t ABI_ATTR bar (uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g) { @@ -39,7 +42,7 @@ main (void) for (i = 0; i < NARGS; ++i) ffitypes[i] = &ffi_type_uint8; - CHECK (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, NARGS, + CHECK (ffi_prep_cif (&cif, ABI_NUM, NARGS, &ffi_type_uint8, ffitypes) == FFI_OK); for (i = 0; i < NARGS; ++i) diff --git a/libffi/testsuite/libffi.call/many2_win32.c b/libffi/testsuite/libffi.call/many2_win32.c deleted file mode 100644 index 4adbe4d..0000000 --- a/libffi/testsuite/libffi.call/many2_win32.c +++ /dev/null @@ -1,63 +0,0 @@ -/* Area: ffi_call - Purpose: Check stdcall many call on X86_WIN32 systems. - Limitations: none. - PR: none. - Originator: From the original ffitest.c */ - -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ - -#include "ffitest.h" -#include <float.h> - -static float __attribute__((fastcall)) fastcall_many(float f1, - float f2, - float f3, - float f4, - float f5, - float f6, - float f7, - float f8, - float f9, - float f10, - float f11, - float f12, - float f13) -{ - return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); -} - -int main (void) -{ - ffi_cif cif; - ffi_type *args[13]; - void *values[13]; - float fa[13]; - float f, ff; - unsigned long ul; - - for (ul = 0; ul < 13; ul++) - { - args[ul] = &ffi_type_float; - values[ul] = &fa[ul]; - fa[ul] = (float) ul; - } - - /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_FASTCALL, 13, - &ffi_type_float, args) == FFI_OK); - - ff = fastcall_many(fa[0], fa[1], - fa[2], fa[3], - fa[4], fa[5], - fa[6], fa[7], - fa[8], fa[9], - fa[10], fa[11], fa[12]); - - ffi_call(&cif, FFI_FN(fastcall_many), &f, values); - - if (f - ff < FLT_EPSILON) - printf("fastcall many arg tests ok!\n"); - else - CHECK(0); - exit(0); -} diff --git a/libffi/testsuite/libffi.call/many_double.c b/libffi/testsuite/libffi.call/many_double.c new file mode 100644 index 0000000..4ef8c8a --- /dev/null +++ b/libffi/testsuite/libffi.call/many_double.c @@ -0,0 +1,70 @@ +/* Area: ffi_call + Purpose: Check return value double, with many arguments + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +#include <stdlib.h> +#include <float.h> +#include <math.h> + +static double many(double f1, + double f2, + double f3, + double f4, + double f5, + double f6, + double f7, + double f8, + double f9, + double f10, + double f11, + double f12, + double f13) +{ +#if 0 + printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n", + (double) f1, (double) f2, (double) f3, (double) f4, (double) f5, + (double) f6, (double) f7, (double) f8, (double) f9, (double) f10, + (double) f11, (double) f12, (double) f13); +#endif + + return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[13]; + void *values[13]; + double fa[13]; + double f, ff; + int i; + + for (i = 0; i < 13; i++) + { + args[i] = &ffi_type_double; + values[i] = &fa[i]; + fa[i] = (double) i; + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, + &ffi_type_double, args) == FFI_OK); + + ffi_call(&cif, FFI_FN(many), &f, values); + + ff = many(fa[0], fa[1], + fa[2], fa[3], + fa[4], fa[5], + fa[6], fa[7], + fa[8], fa[9], + fa[10],fa[11],fa[12]); + if (fabs(f - ff) < FLT_EPSILON) + exit(0); + else + abort(); +} diff --git a/libffi/testsuite/libffi.call/many_mixed.c b/libffi/testsuite/libffi.call/many_mixed.c new file mode 100644 index 0000000..85ec36e --- /dev/null +++ b/libffi/testsuite/libffi.call/many_mixed.c @@ -0,0 +1,78 @@ +/* Area: ffi_call + Purpose: Check return value double, with many arguments + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +#include <stdlib.h> +#include <float.h> +#include <math.h> + +static double many(double f1, + double f2, + long int i1, + double f3, + double f4, + long int i2, + double f5, + double f6, + long int i3, + double f7, + double f8, + long int i4, + double f9, + double f10, + long int i5, + double f11, + double f12, + long int i6, + double f13) +{ + return ((double) (i1 + i2 + i3 + i4 + i5 + i6) + (f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[19]; + void *values[19]; + double fa[19]; + long int la[19]; + double f, ff; + int i; + + for (i = 0; i < 19; i++) + { + if( (i - 2) % 3 == 0) { + args[i] = &ffi_type_slong; + la[i] = (long int) i; + values[i] = &la[i]; + } + else { + args[i] = &ffi_type_double; + fa[i] = (double) i; + values[i] = &fa[i]; + } + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 19, + &ffi_type_double, args) == FFI_OK); + + ffi_call(&cif, FFI_FN(many), &f, values); + + ff = many(fa[0], fa[1], la[2], + fa[3], fa[4], la[5], + fa[6], fa[7], la[8], + fa[9], fa[10], la[11], + fa[12], fa[13], la[14], + fa[15], fa[16], la[17], + fa[18]); + if (fabs(f - ff) < FLT_EPSILON) + exit(0); + else + abort(); +} diff --git a/libffi/testsuite/libffi.call/many_win32.c b/libffi/testsuite/libffi.call/many_win32.c deleted file mode 100644 index 1b26332..0000000 --- a/libffi/testsuite/libffi.call/many_win32.c +++ /dev/null @@ -1,63 +0,0 @@ -/* Area: ffi_call - Purpose: Check stdcall many call on X86_WIN32 systems. - Limitations: none. - PR: none. - Originator: From the original ffitest.c */ - -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ - -#include "ffitest.h" -#include <float.h> - -static float __attribute__((stdcall)) stdcall_many(float f1, - float f2, - float f3, - float f4, - float f5, - float f6, - float f7, - float f8, - float f9, - float f10, - float f11, - float f12, - float f13) -{ - return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); -} - -int main (void) -{ - ffi_cif cif; - ffi_type *args[13]; - void *values[13]; - float fa[13]; - float f, ff; - unsigned long ul; - - for (ul = 0; ul < 13; ul++) - { - args[ul] = &ffi_type_float; - values[ul] = &fa[ul]; - fa[ul] = (float) ul; - } - - /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 13, - &ffi_type_float, args) == FFI_OK); - - ff = stdcall_many(fa[0], fa[1], - fa[2], fa[3], - fa[4], fa[5], - fa[6], fa[7], - fa[8], fa[9], - fa[10], fa[11], fa[12]); - - ffi_call(&cif, FFI_FN(stdcall_many), &f, values); - - if (f - ff < FLT_EPSILON) - printf("stdcall many arg tests ok!\n"); - else - CHECK(0); - exit(0); -} diff --git a/libffi/testsuite/libffi.call/negint.c b/libffi/testsuite/libffi.call/negint.c index 3168113..6e2f26f 100644 --- a/libffi/testsuite/libffi.call/negint.c +++ b/libffi/testsuite/libffi.call/negint.c @@ -5,7 +5,6 @@ Originator: From the original ffitest.c */ /* { dg-do run } */ -/* { dg-options -O2 } */ #include "ffitest.h" diff --git a/libffi/testsuite/libffi.call/nested_struct1.c b/libffi/testsuite/libffi.call/nested_struct1.c index 1087f7b..477a6b9 100644 --- a/libffi/testsuite/libffi.call/nested_struct1.c +++ b/libffi/testsuite/libffi.call/nested_struct1.c @@ -156,6 +156,6 @@ int main (void) CHECK( res_dbl.e.ii == (e_dbl.c + f_dbl.ii + g_dbl.e.ii)); CHECK( res_dbl.e.dd == (e_dbl.a + f_dbl.dd + g_dbl.e.dd)); CHECK( res_dbl.e.ff == (e_dbl.b + f_dbl.ff + g_dbl.e.ff)); - // CHECK( 1 == 0); + /* CHECK( 1 == 0); */ exit(0); } diff --git a/libffi/testsuite/libffi.call/nested_struct11.c b/libffi/testsuite/libffi.call/nested_struct11.c index fce6948..3510493 100644 --- a/libffi/testsuite/libffi.call/nested_struct11.c +++ b/libffi/testsuite/libffi.call/nested_struct11.c @@ -1,7 +1,7 @@ /* Area: ffi_call, closure_call Purpose: Check parameter passing with nested structs of a single type. This tests the special cases - for homogenous floating-point aggregates in the + for homogeneous floating-point aggregates in the AArch64 PCS. Limitations: none. PR: none. diff --git a/libffi/testsuite/libffi.call/return_dbl.c b/libffi/testsuite/libffi.call/return_dbl.c index 1aab403..fd07e50 100644 --- a/libffi/testsuite/libffi.call/return_dbl.c +++ b/libffi/testsuite/libffi.call/return_dbl.c @@ -9,6 +9,7 @@ static double return_dbl(double dbl) { + printf ("%f\n", dbl); return 2 * dbl; } int main (void) diff --git a/libffi/testsuite/libffi.call/return_ldl.c b/libffi/testsuite/libffi.call/return_ldl.c index 5c2fe65..52a92fe 100644 --- a/libffi/testsuite/libffi.call/return_ldl.c +++ b/libffi/testsuite/libffi.call/return_ldl.c @@ -3,8 +3,8 @@ Limitations: none. PR: none. Originator: <andreast@gcc.gnu.org> 20071113 */ +/* { dg-do run } */ -/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ #include "ffitest.h" static long double return_ldl(long double ldl) diff --git a/libffi/testsuite/libffi.call/return_uc.c b/libffi/testsuite/libffi.call/return_uc.c index 07c45de..6fe5546 100644 --- a/libffi/testsuite/libffi.call/return_uc.c +++ b/libffi/testsuite/libffi.call/return_uc.c @@ -32,7 +32,7 @@ int main (void) uc < (unsigned char) '\xff'; uc++) { ffi_call(&cif, FFI_FN(return_uc), &rint, values); - CHECK(rint == (signed int) uc); + CHECK((unsigned char)rint == uc); } exit(0); } diff --git a/libffi/testsuite/libffi.call/stret_large.c b/libffi/testsuite/libffi.call/stret_large.c index f32938c..71c2469 100644 --- a/libffi/testsuite/libffi.call/stret_large.c +++ b/libffi/testsuite/libffi.call/stret_large.c @@ -9,8 +9,8 @@ /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ #include "ffitest.h" -// 13 FPRs: 104 bytes -// 14 FPRs: 112 bytes +/* 13 FPRs: 104 bytes */ +/* 14 FPRs: 112 bytes */ typedef struct struct_108byte { double a; diff --git a/libffi/testsuite/libffi.call/stret_large2.c b/libffi/testsuite/libffi.call/stret_large2.c index 3b0ef9a..d9c750e 100644 --- a/libffi/testsuite/libffi.call/stret_large2.c +++ b/libffi/testsuite/libffi.call/stret_large2.c @@ -9,8 +9,8 @@ /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ #include "ffitest.h" -// 13 FPRs: 104 bytes -// 14 FPRs: 112 bytes +/* 13 FPRs: 104 bytes */ +/* 14 FPRs: 112 bytes */ typedef struct struct_116byte { double a; diff --git a/libffi/testsuite/libffi.call/strlen.c b/libffi/testsuite/libffi.call/strlen.c index 3de45de..35b70ea 100644 --- a/libffi/testsuite/libffi.call/strlen.c +++ b/libffi/testsuite/libffi.call/strlen.c @@ -7,7 +7,7 @@ /* { dg-do run } */ #include "ffitest.h" -static size_t my_strlen(char *s) +static size_t ABI_ATTR my_strlen(char *s) { return (strlen(s)); } @@ -24,7 +24,7 @@ int main (void) values[0] = (void*) &s; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ffi_type_sint, args) == FFI_OK); s = "a"; diff --git a/libffi/testsuite/libffi.call/fastthis1_win32.c b/libffi/testsuite/libffi.call/strlen2.c index cbc4724..96282bc 100644 --- a/libffi/testsuite/libffi.call/fastthis1_win32.c +++ b/libffi/testsuite/libffi.call/strlen2.c @@ -1,14 +1,14 @@ /* Area: ffi_call - Purpose: Check fastcall fct call on X86_WIN32 systems. + Purpose: Check strlen function call with additional arguments. Limitations: none. PR: none. Originator: From the original ffitest.c */ -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ +/* { dg-do run } */ #include "ffitest.h" -static size_t __FASTCALL__ my_fastcall_f(char *s, float a) +static size_t ABI_ATTR my_f(char *s, float a) { return (size_t) ((int) strlen(s) + (int) a); } @@ -27,24 +27,23 @@ int main (void) values[1] = (void*) &v2; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_FASTCALL, 2, + CHECK(ffi_prep_cif(&cif, ABI_NUM, 2, &ffi_type_sint, args) == FFI_OK); s = "a"; v2 = 0.0; - ffi_call(&cif, FFI_FN(my_fastcall_f), &rint, values); + ffi_call(&cif, FFI_FN(my_f), &rint, values); CHECK(rint == 1); s = "1234567"; v2 = -1.0; - ffi_call(&cif, FFI_FN(my_fastcall_f), &rint, values); + ffi_call(&cif, FFI_FN(my_f), &rint, values); CHECK(rint == 6); s = "1234567890123456789012345"; v2 = 1.0; - ffi_call(&cif, FFI_FN(my_fastcall_f), &rint, values); + ffi_call(&cif, FFI_FN(my_f), &rint, values); CHECK(rint == 26); - printf("fastcall fct1 tests passed\n"); exit(0); } diff --git a/libffi/testsuite/libffi.call/strlen2_win32.c b/libffi/testsuite/libffi.call/strlen2_win32.c deleted file mode 100644 index 0d81061..0000000 --- a/libffi/testsuite/libffi.call/strlen2_win32.c +++ /dev/null @@ -1,44 +0,0 @@ -/* Area: ffi_call - Purpose: Check fastcall strlen call on X86_WIN32 systems. - Limitations: none. - PR: none. - Originator: From the original ffitest.c */ - -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ - -#include "ffitest.h" - -static size_t __FASTCALL__ my_fastcall_strlen(char *s) -{ - return (strlen(s)); -} - -int main (void) -{ - ffi_cif cif; - ffi_type *args[MAX_ARGS]; - void *values[MAX_ARGS]; - ffi_arg rint; - char *s; - args[0] = &ffi_type_pointer; - values[0] = (void*) &s; - - /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_FASTCALL, 1, - &ffi_type_sint, args) == FFI_OK); - - s = "a"; - ffi_call(&cif, FFI_FN(my_fastcall_strlen), &rint, values); - CHECK(rint == 1); - - s = "1234567"; - ffi_call(&cif, FFI_FN(my_fastcall_strlen), &rint, values); - CHECK(rint == 7); - - s = "1234567890123456789012345"; - ffi_call(&cif, FFI_FN(my_fastcall_strlen), &rint, values); - CHECK(rint == 25); - - printf("fastcall strlen tests passed\n"); - exit(0); -} diff --git a/libffi/testsuite/libffi.call/fastthis2_win32.c b/libffi/testsuite/libffi.call/strlen3.c index 7bdd0e1..beba86e 100644 --- a/libffi/testsuite/libffi.call/fastthis2_win32.c +++ b/libffi/testsuite/libffi.call/strlen3.c @@ -1,14 +1,14 @@ /* Area: ffi_call - Purpose: Check fastcall fct call on X86_WIN32 systems. + Purpose: Check strlen function call with additional arguments. Limitations: none. PR: none. Originator: From the original ffitest.c */ -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ +/* { dg-do run } */ #include "ffitest.h" -static size_t __FASTCALL__ my_fastcall_f(float a, char *s) +static size_t ABI_ATTR my_f(float a, char *s) { return (size_t) ((int) strlen(s) + (int) a); } @@ -27,24 +27,23 @@ int main (void) values[0] = (void*) &v2; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_FASTCALL, 2, + CHECK(ffi_prep_cif(&cif, ABI_NUM, 2, &ffi_type_sint, args) == FFI_OK); s = "a"; v2 = 0.0; - ffi_call(&cif, FFI_FN(my_fastcall_f), &rint, values); + ffi_call(&cif, FFI_FN(my_f), &rint, values); CHECK(rint == 1); s = "1234567"; v2 = -1.0; - ffi_call(&cif, FFI_FN(my_fastcall_f), &rint, values); + ffi_call(&cif, FFI_FN(my_f), &rint, values); CHECK(rint == 6); s = "1234567890123456789012345"; v2 = 1.0; - ffi_call(&cif, FFI_FN(my_fastcall_f), &rint, values); + ffi_call(&cif, FFI_FN(my_f), &rint, values); CHECK(rint == 26); - printf("fastcall fct2 tests passed\n"); exit(0); } diff --git a/libffi/testsuite/libffi.call/fastthis3_win32.c b/libffi/testsuite/libffi.call/strlen4.c index b5d606d..d5d42b4 100644 --- a/libffi/testsuite/libffi.call/fastthis3_win32.c +++ b/libffi/testsuite/libffi.call/strlen4.c @@ -1,14 +1,14 @@ /* Area: ffi_call - Purpose: Check fastcall f call on X86_WIN32 systems. + Purpose: Check strlen function call with additional arguments. Limitations: none. PR: none. Originator: From the original ffitest.c */ -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ +/* { dg-do run } */ #include "ffitest.h" -static size_t __FASTCALL__ my_fastcall_f(float a, char *s, int i) +static size_t ABI_ATTR my_f(float a, char *s, int i) { return (size_t) ((int) strlen(s) + (int) a + i); } @@ -30,27 +30,26 @@ int main (void) values[0] = (void*) &v2; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_FASTCALL, 3, + CHECK(ffi_prep_cif(&cif, ABI_NUM, 3, &ffi_type_sint, args) == FFI_OK); s = "a"; v1 = 1; v2 = 0.0; - ffi_call(&cif, FFI_FN(my_fastcall_f), &rint, values); + ffi_call(&cif, FFI_FN(my_f), &rint, values); CHECK(rint == 2); s = "1234567"; v2 = -1.0; v1 = -2; - ffi_call(&cif, FFI_FN(my_fastcall_f), &rint, values); + ffi_call(&cif, FFI_FN(my_f), &rint, values); CHECK(rint == 4); s = "1234567890123456789012345"; v2 = 1.0; v1 = 2; - ffi_call(&cif, FFI_FN(my_fastcall_f), &rint, values); + ffi_call(&cif, FFI_FN(my_f), &rint, values); CHECK(rint == 28); - printf("fastcall fct3 tests passed\n"); exit(0); } diff --git a/libffi/testsuite/libffi.call/strlen_win32.c b/libffi/testsuite/libffi.call/strlen_win32.c deleted file mode 100644 index 6fbcc87..0000000 --- a/libffi/testsuite/libffi.call/strlen_win32.c +++ /dev/null @@ -1,44 +0,0 @@ -/* Area: ffi_call - Purpose: Check stdcall strlen call on X86_WIN32 systems. - Limitations: none. - PR: none. - Originator: From the original ffitest.c */ - -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ - -#include "ffitest.h" - -static size_t __attribute__((stdcall)) my_stdcall_strlen(char *s) -{ - return (strlen(s)); -} - -int main (void) -{ - ffi_cif cif; - ffi_type *args[MAX_ARGS]; - void *values[MAX_ARGS]; - ffi_arg rint; - char *s; - args[0] = &ffi_type_pointer; - values[0] = (void*) &s; - - /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 1, - &ffi_type_sint, args) == FFI_OK); - - s = "a"; - ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values); - CHECK(rint == 1); - - s = "1234567"; - ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values); - CHECK(rint == 7); - - s = "1234567890123456789012345"; - ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values); - CHECK(rint == 25); - - printf("stdcall strlen tests passed\n"); - exit(0); -} diff --git a/libffi/testsuite/libffi.call/struct1.c b/libffi/testsuite/libffi.call/struct1.c index bfc23f64..c13e23f 100644 --- a/libffi/testsuite/libffi.call/struct1.c +++ b/libffi/testsuite/libffi.call/struct1.c @@ -14,7 +14,7 @@ typedef struct unsigned int ui; } test_structure_1; -static test_structure_1 struct1(test_structure_1 ts) +static test_structure_1 ABI_ATTR struct1(test_structure_1 ts) { ts.uc++; ts.d--; @@ -50,7 +50,7 @@ int main (void) values[0] = &ts1_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts1_type, args) == FFI_OK); ts1_arg.uc = '\x01'; diff --git a/libffi/testsuite/libffi.call/struct1_win32.c b/libffi/testsuite/libffi.call/struct1_win32.c deleted file mode 100644 index b756f5a..0000000 --- a/libffi/testsuite/libffi.call/struct1_win32.c +++ /dev/null @@ -1,67 +0,0 @@ -/* Area: ffi_call - Purpose: Check structures with fastcall/thiscall convention. - Limitations: none. - PR: none. - Originator: From the original ffitest.c */ - -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ -#include "ffitest.h" - -typedef struct -{ - unsigned char uc; - double d; - unsigned int ui; -} test_structure_1; - -static test_structure_1 __FASTCALL__ struct1(test_structure_1 ts) -{ - ts.uc++; - ts.d--; - ts.ui++; - - 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_uchar; - ts1_type_elements[1] = &ffi_type_double; - 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, FFI_FASTCALL, 1, - &ts1_type, args) == FFI_OK); - - ts1_arg.uc = '\x01'; - ts1_arg.d = 3.14159; - ts1_arg.ui = 555; - - ffi_call(&cif, FFI_FN(struct1), ts1_result, values); - - CHECK(ts1_result->ui == 556); - CHECK(ts1_result->d == 3.14159 - 1); - - free (ts1_result); - exit(0); -} diff --git a/libffi/testsuite/libffi.call/struct2.c b/libffi/testsuite/libffi.call/struct2.c index d85385e..5077a5e 100644 --- a/libffi/testsuite/libffi.call/struct2.c +++ b/libffi/testsuite/libffi.call/struct2.c @@ -13,7 +13,7 @@ typedef struct double d2; } test_structure_2; -static test_structure_2 struct2(test_structure_2 ts) +static test_structure_2 ABI_ATTR struct2(test_structure_2 ts) { ts.d1--; ts.d2--; @@ -46,7 +46,7 @@ int main (void) values[0] = &ts2_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts2_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts2_type, args) == FFI_OK); ts2_arg.d1 = 5.55; ts2_arg.d2 = 6.66; diff --git a/libffi/testsuite/libffi.call/struct2_win32.c b/libffi/testsuite/libffi.call/struct2_win32.c deleted file mode 100644 index 5d02285..0000000 --- a/libffi/testsuite/libffi.call/struct2_win32.c +++ /dev/null @@ -1,67 +0,0 @@ -/* Area: ffi_call - Purpose: Check structures in fastcall/stdcall function - Limitations: none. - PR: none. - Originator: From the original ffitest.c */ - -/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ -#include "ffitest.h" - -typedef struct -{ - double d1; - double d2; -} test_structure_2; - -static test_structure_2 __FASTCALL__ struct2(test_structure_2 ts) -{ - ts.d1--; - ts.d2--; - - return ts; -} - -int main (void) -{ - ffi_cif cif; - ffi_type *args[MAX_ARGS]; - void *values[MAX_ARGS]; - test_structure_2 ts2_arg; - ffi_type ts2_type; - ffi_type *ts2_type_elements[3]; - - /* This is a hack to get a properly aligned result buffer */ - test_structure_2 *ts2_result = - (test_structure_2 *) malloc (sizeof(test_structure_2)); - - ts2_type.size = 0; - ts2_type.alignment = 0; - ts2_type.type = FFI_TYPE_STRUCT; - ts2_type.elements = ts2_type_elements; - ts2_type_elements[0] = &ffi_type_double; - ts2_type_elements[1] = &ffi_type_double; - ts2_type_elements[2] = NULL; - - args[0] = &ts2_type; - values[0] = &ts2_arg; - - /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_FASTCALL, 1, &ts2_type, args) == FFI_OK); - - ts2_arg.d1 = 5.55; - ts2_arg.d2 = 6.66; - - printf ("%g\n", ts2_arg.d1); - printf ("%g\n", ts2_arg.d2); - - ffi_call(&cif, FFI_FN(struct2), ts2_result, values); - - printf ("%g\n", ts2_result->d1); - printf ("%g\n", ts2_result->d2); - - CHECK(ts2_result->d1 == 5.55 - 1); - CHECK(ts2_result->d2 == 6.66 - 1); - - free (ts2_result); - exit(0); -} diff --git a/libffi/testsuite/libffi.call/struct3.c b/libffi/testsuite/libffi.call/struct3.c index de883c2..7eba0ea 100644 --- a/libffi/testsuite/libffi.call/struct3.c +++ b/libffi/testsuite/libffi.call/struct3.c @@ -12,7 +12,7 @@ typedef struct int si; } test_structure_3; -static test_structure_3 struct3(test_structure_3 ts) +static test_structure_3 ABI_ATTR struct3(test_structure_3 ts) { ts.si = -(ts.si*2); @@ -43,7 +43,7 @@ int main (void) values[0] = &ts3_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts3_type, args) == FFI_OK); ts3_arg.si = -123; diff --git a/libffi/testsuite/libffi.call/struct4.c b/libffi/testsuite/libffi.call/struct4.c index 48e0349..66a9551 100644 --- a/libffi/testsuite/libffi.call/struct4.c +++ b/libffi/testsuite/libffi.call/struct4.c @@ -14,7 +14,7 @@ typedef struct unsigned ui3; } test_structure_4; -static test_structure_4 struct4(test_structure_4 ts) +static test_structure_4 ABI_ATTR struct4(test_structure_4 ts) { ts.ui3 = ts.ui1 * ts.ui2 * ts.ui3; @@ -48,7 +48,7 @@ int main (void) values[0] = &ts4_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts4_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts4_type, args) == FFI_OK); ts4_arg.ui1 = 2; ts4_arg.ui2 = 3; diff --git a/libffi/testsuite/libffi.call/struct5.c b/libffi/testsuite/libffi.call/struct5.c index 28b1f0c..23e2a3f 100644 --- a/libffi/testsuite/libffi.call/struct5.c +++ b/libffi/testsuite/libffi.call/struct5.c @@ -12,7 +12,7 @@ typedef struct char c2; } test_structure_5; -static test_structure_5 struct5(test_structure_5 ts1, test_structure_5 ts2) +static test_structure_5 ABI_ATTR struct5(test_structure_5 ts1, test_structure_5 ts2) { ts1.c1 += ts2.c1; ts1.c2 -= ts2.c2; @@ -48,7 +48,7 @@ int main (void) values[1] = &ts5_arg2; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ts5_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, ABI_NUM, 2, &ts5_type, args) == FFI_OK); ts5_arg1.c1 = 2; ts5_arg1.c2 = 6; diff --git a/libffi/testsuite/libffi.call/struct6.c b/libffi/testsuite/libffi.call/struct6.c index 0e26746..173c66e 100644 --- a/libffi/testsuite/libffi.call/struct6.c +++ b/libffi/testsuite/libffi.call/struct6.c @@ -12,7 +12,7 @@ typedef struct double d; } test_structure_6; -static test_structure_6 struct6 (test_structure_6 ts) +static test_structure_6 ABI_ATTR struct6 (test_structure_6 ts) { ts.f += 1; ts.d += 1; @@ -46,7 +46,7 @@ int main (void) values[0] = &ts6_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts6_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts6_type, args) == FFI_OK); ts6_arg.f = 5.55f; ts6_arg.d = 6.66; diff --git a/libffi/testsuite/libffi.call/struct7.c b/libffi/testsuite/libffi.call/struct7.c index 8f2bbfd..badc7e0 100644 --- a/libffi/testsuite/libffi.call/struct7.c +++ b/libffi/testsuite/libffi.call/struct7.c @@ -13,7 +13,7 @@ typedef struct double d; } test_structure_7; -static test_structure_7 struct7 (test_structure_7 ts) +static test_structure_7 ABI_ATTR struct7 (test_structure_7 ts) { ts.f1 += 1; ts.f2 += 1; @@ -49,7 +49,7 @@ int main (void) values[0] = &ts7_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts7_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts7_type, args) == FFI_OK); ts7_arg.f1 = 5.55f; ts7_arg.f2 = 55.5f; diff --git a/libffi/testsuite/libffi.call/struct8.c b/libffi/testsuite/libffi.call/struct8.c index 266e1f0..ef204ec 100644 --- a/libffi/testsuite/libffi.call/struct8.c +++ b/libffi/testsuite/libffi.call/struct8.c @@ -14,7 +14,7 @@ typedef struct float f4; } test_structure_8; -static test_structure_8 struct8 (test_structure_8 ts) +static test_structure_8 ABI_ATTR struct8 (test_structure_8 ts) { ts.f1 += 1; ts.f2 += 1; @@ -52,7 +52,7 @@ int main (void) values[0] = &ts8_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts8_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts8_type, args) == FFI_OK); ts8_arg.f1 = 5.55f; ts8_arg.f2 = 55.5f; diff --git a/libffi/testsuite/libffi.call/struct9.c b/libffi/testsuite/libffi.call/struct9.c index efeb716..4a13b81 100644 --- a/libffi/testsuite/libffi.call/struct9.c +++ b/libffi/testsuite/libffi.call/struct9.c @@ -13,7 +13,7 @@ typedef struct int i; } test_structure_9; -static test_structure_9 struct9 (test_structure_9 ts) +static test_structure_9 ABI_ATTR struct9 (test_structure_9 ts) { ts.f += 1; ts.i += 1; @@ -47,7 +47,7 @@ int main (void) values[0] = &ts9_arg; /* Initialize the cif */ - CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts9_type, args) == FFI_OK); + CHECK(ffi_prep_cif(&cif, ABI_NUM, 1, &ts9_type, args) == FFI_OK); ts9_arg.f = 5.55f; ts9_arg.i = 5; diff --git a/libffi/testsuite/libffi.complex/cls_align_complex.inc b/libffi/testsuite/libffi.complex/cls_align_complex.inc new file mode 100644 index 0000000..4a812ed --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_align_complex.inc @@ -0,0 +1,91 @@ +/* -*-c-*- */ +#include "ffitest.h" +#include <complex.h> + +typedef struct cls_struct_align { + unsigned char a; + _Complex T_C_TYPE b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn( + struct cls_struct_align a1, struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %f,%fi %d %d %f,%fi %d: %d %f,%fi %d\n", + a1.a, T_CONV creal (a1.b), T_CONV cimag (a1.b), a1.c, + a2.a, T_CONV creal (a2.b), T_CONV cimag (a2.b), a2.c, + result.a, T_CONV creal (result.b), T_CONV cimag (result.b), result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_c[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* c_arg_types[5]; + + struct cls_struct_align g_c = { 12, 4951 + 7 * I, 127 }; + struct cls_struct_align f_c = { 1, 9320 + 1 * I, 13 }; + struct cls_struct_align res_c; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &T_FFI_TYPE; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + c_arg_types[0] = &cls_struct_type; + c_arg_types[1] = &cls_struct_type; + c_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + c_arg_types) == FFI_OK); + + args_c[0] = &g_c; + args_c[1] = &f_c; + args_c[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_c, args_c); + /* { dg-output "12 4951,7i 127 1 9320,1i 13: 13 14271,8i 140" } */ + printf("res: %d %f,%fi %d\n", + res_c.a, T_CONV creal (res_c.b), T_CONV cimag (res_c.b), res_c.c); + /* { dg-output "\nres: 13 14271,8i 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_c = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_c, f_c); + /* { dg-output "\n12 4951,7i 127 1 9320,1i 13: 13 14271,8i 140" } */ + printf("res: %d %f,%fi %d\n", + res_c.a, T_CONV creal (res_c.b), T_CONV cimag (res_c.b), res_c.c); + /* { dg-output "\nres: 13 14271,8i 140" } */ + + exit(0); +} diff --git a/libffi/testsuite/libffi.complex/cls_align_complex_double.c b/libffi/testsuite/libffi.complex/cls_align_complex_double.c new file mode 100644 index 0000000..0dff23a --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_align_complex_double.c @@ -0,0 +1,10 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_double.inc" +#include "cls_align_complex.inc" diff --git a/libffi/testsuite/libffi.complex/cls_align_complex_float.c b/libffi/testsuite/libffi.complex/cls_align_complex_float.c new file mode 100644 index 0000000..0affbd0 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_align_complex_float.c @@ -0,0 +1,10 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_float.inc" +#include "cls_align_complex.inc" diff --git a/libffi/testsuite/libffi.complex/cls_align_complex_longdouble.c b/libffi/testsuite/libffi.complex/cls_align_complex_longdouble.c new file mode 100644 index 0000000..7889ba8 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_align_complex_longdouble.c @@ -0,0 +1,10 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_longdouble.inc" +#include "cls_align_complex.inc" diff --git a/libffi/testsuite/libffi.complex/cls_complex.inc b/libffi/testsuite/libffi.complex/cls_complex.inc new file mode 100644 index 0000000..f937404 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex.inc @@ -0,0 +1,42 @@ +/* -*-c-*- */ +#include "ffitest.h" +#include <complex.h> + +static void cls_ret_complex_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) + { + _Complex T_C_TYPE *pa; + _Complex T_C_TYPE *pr; + pa = (_Complex T_C_TYPE *)args[0]; + pr = (_Complex T_C_TYPE *)resp; + *pr = *pa; + + printf("%.6f,%.6fi: %.6f,%.6fi\n", + T_CONV creal (*pa), T_CONV cimag (*pa), + T_CONV creal (*pr), T_CONV cimag (*pr)); + } +typedef _Complex T_C_TYPE (*cls_ret_complex)(_Complex T_C_TYPE); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + _Complex T_C_TYPE res; + + cl_arg_types[0] = &T_FFI_TYPE; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &T_FFI_TYPE, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_complex_fn, NULL, code) == FFI_OK); + + res = (*((cls_ret_complex)code))(0.125 + 128.0 * I); + printf("res: %.6f,%.6fi\n", T_CONV creal (res), T_CONV cimag (res)); + CHECK (res == (0.125 + 128.0 * I)); + + exit(0); +} diff --git a/libffi/testsuite/libffi.complex/cls_complex_double.c b/libffi/testsuite/libffi.complex/cls_complex_double.c new file mode 100644 index 0000000..05e3534 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_double.c @@ -0,0 +1,10 @@ +/* Area: closure_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_double.inc" +#include "cls_complex.inc" diff --git a/libffi/testsuite/libffi.complex/cls_complex_float.c b/libffi/testsuite/libffi.complex/cls_complex_float.c new file mode 100644 index 0000000..5df7849 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_float.c @@ -0,0 +1,10 @@ +/* Area: closure_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_float.inc" +#include "cls_complex.inc" diff --git a/libffi/testsuite/libffi.complex/cls_complex_longdouble.c b/libffi/testsuite/libffi.complex/cls_complex_longdouble.c new file mode 100644 index 0000000..2b1c320 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_longdouble.c @@ -0,0 +1,10 @@ +/* Area: closure_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_longdouble.inc" +#include "cls_complex.inc" diff --git a/libffi/testsuite/libffi.complex/cls_complex_struct.inc b/libffi/testsuite/libffi.complex/cls_complex_struct.inc new file mode 100644 index 0000000..df8708d --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_struct.inc @@ -0,0 +1,71 @@ +/* -*-c-*- */ +#include "ffitest.h" +#include <complex.h> + +typedef struct Cs { + _Complex T_C_TYPE x; + _Complex T_C_TYPE y; +} Cs; + +Cs gc; + +void +closure_test_fn(Cs p) +{ + printf("%.1f,%.1fi %.1f,%.1fi\n", + T_CONV creal (p.x), T_CONV cimag (p.x), + T_CONV creal (p.y), T_CONV cimag (p.y)); + gc = p; +} + +void +closure_test_gn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__, + void** args, void* userdata __UNUSED__) +{ + closure_test_fn(*(Cs*)args[0]); +} + +int main(int argc __UNUSED__, char** argv __UNUSED__) +{ + ffi_cif cif; + + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type *cl_arg_types[1]; + + ffi_type ts1_type; + ffi_type* ts1_type_elements[4]; + + Cs arg = { 1.0 + 11.0 * I, 2.0 + 22.0 * I}; + + ts1_type.size = 0; + ts1_type.alignment = 0; + ts1_type.type = FFI_TYPE_STRUCT; + ts1_type.elements = ts1_type_elements; + + ts1_type_elements[0] = &T_FFI_TYPE; + ts1_type_elements[1] = &T_FFI_TYPE; + ts1_type_elements[2] = NULL; + + cl_arg_types[0] = &ts1_type; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_void, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_gn, NULL, code) == FFI_OK); + + gc.x = 0.0 + 0.0 * I; + gc.y = 0.0 + 0.0 * I; + ((void*(*)(Cs))(code))(arg); + /* { dg-output "1.0,11.0i 2.0,22.0i\n" } */ + CHECK (gc.x == arg.x && gc.y == arg.y); + + gc.x = 0.0 + 0.0 * I; + gc.y = 0.0 + 0.0 * I; + closure_test_fn(arg); + /* { dg-output "1.0,11.0i 2.0,22.0i\n" } */ + CHECK (gc.x == arg.x && gc.y == arg.y); + + return 0; +} diff --git a/libffi/testsuite/libffi.complex/cls_complex_struct_double.c b/libffi/testsuite/libffi.complex/cls_complex_struct_double.c new file mode 100644 index 0000000..ec71346 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_struct_double.c @@ -0,0 +1,10 @@ +/* Area: ffi_call, closure_call + Purpose: Check complex arguments in structs. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_double.inc" +#include "cls_complex_struct.inc" diff --git a/libffi/testsuite/libffi.complex/cls_complex_struct_float.c b/libffi/testsuite/libffi.complex/cls_complex_struct_float.c new file mode 100644 index 0000000..96fdf750 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_struct_float.c @@ -0,0 +1,10 @@ +/* Area: ffi_call, closure_call + Purpose: Check complex arguments in structs. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_float.inc" +#include "cls_complex_struct.inc" diff --git a/libffi/testsuite/libffi.complex/cls_complex_struct_longdouble.c b/libffi/testsuite/libffi.complex/cls_complex_struct_longdouble.c new file mode 100644 index 0000000..005b467 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_struct_longdouble.c @@ -0,0 +1,10 @@ +/* Area: ffi_call, closure_call + Purpose: Check complex arguments in structs. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_longdouble.inc" +#include "cls_complex_struct.inc" diff --git a/libffi/testsuite/libffi.complex/cls_complex_va.inc b/libffi/testsuite/libffi.complex/cls_complex_va.inc new file mode 100644 index 0000000..8a3e15f --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_va.inc @@ -0,0 +1,80 @@ +/* -*-c-*- */ +#include "ffitest.h" +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <complex.h> + +static _Complex T_C_TYPE gComplexValue1 = 1 + 2 * I; +static _Complex T_C_TYPE gComplexValue2 = 3 + 4 * I; + +static int cls_variadic(const char *format, ...) +{ + va_list ap; + _Complex T_C_TYPE p1, p2; + + va_start (ap, format); + p1 = va_arg (ap, _Complex T_C_TYPE); + p2 = va_arg (ap, _Complex T_C_TYPE); + va_end (ap); + + return printf(format, T_CONV creal (p1), T_CONV cimag (p1), + T_CONV creal (p2), T_CONV cimag (p2)); +} + +static void +cls_complex_va_fn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + char* format = *(char**)args[0]; + gComplexValue1 = *(_Complex T_C_TYPE*)args[1]; + gComplexValue2 = *(_Complex T_C_TYPE*)args[2]; + + *(ffi_arg*)resp = + printf(format, + T_CONV creal (gComplexValue1), T_CONV cimag (gComplexValue1), + T_CONV creal (gComplexValue2), T_CONV cimag (gComplexValue2)); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args[4]; + ffi_type* arg_types[4]; + char *format = "%.1f,%.1fi %.1f,%.1fi\n"; + + _Complex T_C_TYPE complexArg1 = 1.0 + 22.0 *I; + _Complex T_C_TYPE complexArg2 = 333.0 + 4444.0 *I; + ffi_arg res = 0; + + arg_types[0] = &ffi_type_pointer; + arg_types[1] = &T_FFI_TYPE; + arg_types[2] = &T_FFI_TYPE; + arg_types[3] = NULL; + + /* This printf call is variadic */ + CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 3, &ffi_type_sint, + arg_types) == FFI_OK); + + args[0] = &format; + args[1] = &complexArg1; + args[2] = &complexArg2; + args[3] = NULL; + + ffi_call(&cif, FFI_FN(cls_variadic), &res, args); + printf("res: %d\n", (int) res); + CHECK (res == 24); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_complex_va_fn, NULL, code) + == FFI_OK); + + res = ((int(*)(char *, ...))(code))(format, complexArg1, complexArg2); + CHECK (gComplexValue1 == complexArg1); + CHECK (gComplexValue2 == complexArg2); + printf("res: %d\n", (int) res); + CHECK (res == 24); + + exit(0); +} diff --git a/libffi/testsuite/libffi.complex/cls_complex_va_double.c b/libffi/testsuite/libffi.complex/cls_complex_va_double.c new file mode 100644 index 0000000..879ccf3 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_va_double.c @@ -0,0 +1,10 @@ +/* Area: ffi_call, closure_call + Purpose: Test complex' passed in variable argument lists. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_double.inc" +#include "cls_complex_va.inc" diff --git a/libffi/testsuite/libffi.complex/cls_complex_va_float.c b/libffi/testsuite/libffi.complex/cls_complex_va_float.c new file mode 100644 index 0000000..2b17826 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_va_float.c @@ -0,0 +1,16 @@ +/* Area: ffi_call, closure_call + Purpose: Test complex' passed in variable argument lists. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +/* Alpha splits _Complex into two arguments. It's illegal to pass + float through varargs, so _Complex float goes badly. In sort of + gets passed as _Complex double, but the compiler doesn't agree + with itself on this issue. */ +/* { dg-do run { xfail alpha*-*-* } } */ + +#include "complex_defs_float.inc" +#include "cls_complex_va.inc" diff --git a/libffi/testsuite/libffi.complex/cls_complex_va_longdouble.c b/libffi/testsuite/libffi.complex/cls_complex_va_longdouble.c new file mode 100644 index 0000000..6eca965 --- /dev/null +++ b/libffi/testsuite/libffi.complex/cls_complex_va_longdouble.c @@ -0,0 +1,10 @@ +/* Area: ffi_call, closure_call + Purpose: Test complex' passed in variable argument lists. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_longdouble.inc" +#include "cls_complex_va.inc" diff --git a/libffi/testsuite/libffi.complex/complex.exp b/libffi/testsuite/libffi.complex/complex.exp new file mode 100644 index 0000000..4631db2 --- /dev/null +++ b/libffi/testsuite/libffi.complex/complex.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2003, 2006, 2009, 2010, 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +dg-init +libffi-init + +global srcdir subdir + +set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.{c,cc}]] + +if { [libffi_feature_test "#ifdef FFI_TARGET_HAS_COMPLEX_TYPE"] } { + run-many-tests $tlist "" +} else { + foreach test $tlist { + unsupported "$test" + } +} + +dg-finish + +# Local Variables: +# tcl-indent-level:4 +# End: diff --git a/libffi/testsuite/libffi.complex/complex.inc b/libffi/testsuite/libffi.complex/complex.inc new file mode 100644 index 0000000..515ae3e --- /dev/null +++ b/libffi/testsuite/libffi.complex/complex.inc @@ -0,0 +1,51 @@ +/* -*-c-*-*/ +#include "ffitest.h" +#include <complex.h> + +static _Complex T_C_TYPE f_complex(_Complex T_C_TYPE c, int x, int *py) +{ + c = -(2 * creal (c)) + (cimag (c) + 1)* I; + *py += x; + + return c; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + + _Complex T_C_TYPE tc_arg; + _Complex T_C_TYPE tc_result; + int tc_int_arg_x; + int tc_y; + int *tc_ptr_arg_y = &tc_y; + + args[0] = &T_FFI_TYPE; + args[1] = &ffi_type_sint; + args[2] = &ffi_type_pointer; + values[0] = &tc_arg; + values[1] = &tc_int_arg_x; + values[2] = &tc_ptr_arg_y; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, + &T_FFI_TYPE, args) == FFI_OK); + + tc_arg = 1 + 7 * I; + tc_int_arg_x = 1234; + tc_y = 9876; + ffi_call(&cif, FFI_FN(f_complex), &tc_result, values); + + printf ("%f,%fi %f,%fi, x %d 1234, y %d 11110\n", + T_CONV creal (tc_result), T_CONV cimag (tc_result), + T_CONV creal (2.0), T_CONV creal (8.0), tc_int_arg_x, tc_y); + + CHECK (creal (tc_result) == -2); + CHECK (cimag (tc_result) == 8); + CHECK (tc_int_arg_x == 1234); + CHECK (*tc_ptr_arg_y == 11110); + + exit(0); +} diff --git a/libffi/testsuite/libffi.complex/complex_defs_double.inc b/libffi/testsuite/libffi.complex/complex_defs_double.inc new file mode 100644 index 0000000..3583e16 --- /dev/null +++ b/libffi/testsuite/libffi.complex/complex_defs_double.inc @@ -0,0 +1,7 @@ +/* -*-c-*- */ +/* Complex base type. */ +#define T_FFI_TYPE ffi_type_complex_double +/* C type corresponding to the base type. */ +#define T_C_TYPE double +/* C cast for a value of type T_C_TYPE that is passed to printf. */ +#define T_CONV diff --git a/libffi/testsuite/libffi.complex/complex_defs_float.inc b/libffi/testsuite/libffi.complex/complex_defs_float.inc new file mode 100644 index 0000000..bbd9375 --- /dev/null +++ b/libffi/testsuite/libffi.complex/complex_defs_float.inc @@ -0,0 +1,7 @@ +/* -*-c-*- */ +/* Complex base type. */ +#define T_FFI_TYPE ffi_type_complex_float +/* C type corresponding to the base type. */ +#define T_C_TYPE float +/* C cast for a value of type T_C_TYPE that is passed to printf. */ +#define T_CONV (double) diff --git a/libffi/testsuite/libffi.complex/complex_defs_longdouble.inc b/libffi/testsuite/libffi.complex/complex_defs_longdouble.inc new file mode 100644 index 0000000..14b9f24 --- /dev/null +++ b/libffi/testsuite/libffi.complex/complex_defs_longdouble.inc @@ -0,0 +1,7 @@ +/* -*-c-*- */ +/* Complex base type. */ +#define T_FFI_TYPE ffi_type_complex_longdouble +/* C type corresponding to the base type. */ +#define T_C_TYPE long double +/* C cast for a value of type T_C_TYPE that is passed to printf. */ +#define T_CONV diff --git a/libffi/testsuite/libffi.complex/complex_double.c b/libffi/testsuite/libffi.complex/complex_double.c new file mode 100644 index 0000000..8a3297b --- /dev/null +++ b/libffi/testsuite/libffi.complex/complex_double.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check complex types. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_double.inc" +#include "complex.inc" diff --git a/libffi/testsuite/libffi.complex/complex_float.c b/libffi/testsuite/libffi.complex/complex_float.c new file mode 100644 index 0000000..5044ebb --- /dev/null +++ b/libffi/testsuite/libffi.complex/complex_float.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check complex types. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_float.inc" +#include "complex.inc" diff --git a/libffi/testsuite/libffi.complex/complex_int.c b/libffi/testsuite/libffi.complex/complex_int.c new file mode 100644 index 0000000..bac3190 --- /dev/null +++ b/libffi/testsuite/libffi.complex/complex_int.c @@ -0,0 +1,86 @@ +/* Area: ffi_call + Purpose: Check non-standard complex types. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "ffitest.h" +#include "ffi.h" +#include <complex.h> + +_Complex int f_complex(_Complex int c, int x, int *py) +{ + __real__ c = -2 * __real__ c; + __imag__ c = __imag__ c + 1; + *py += x; + return c; +} + +/* + * This macro can be used to define new complex type descriptors + * in a platform independent way. + * + * name: Name of the new descriptor is ffi_type_complex_<name>. + * type: The C base type of the complex type. + */ +#define FFI_COMPLEX_TYPEDEF(name, type, ffitype) \ + static ffi_type *ffi_elements_complex_##name [2] = { \ + (ffi_type *)(&ffitype), NULL \ + }; \ + struct struct_align_complex_##name { \ + char c; \ + _Complex type x; \ + }; \ + ffi_type ffi_type_complex_##name = { \ + sizeof(_Complex type), \ + offsetof(struct struct_align_complex_##name, x), \ + FFI_TYPE_COMPLEX, \ + (ffi_type **)ffi_elements_complex_##name \ + } + +/* Define new complex type descriptors using the macro: */ +/* ffi_type_complex_sint */ +FFI_COMPLEX_TYPEDEF(sint, int, ffi_type_sint); +/* ffi_type_complex_uchar */ +FFI_COMPLEX_TYPEDEF(uchar, unsigned char, ffi_type_uint8); + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + + _Complex int tc_arg; + _Complex int tc_result; + int tc_int_arg_x; + int tc_y; + int *tc_ptr_arg_y = &tc_y; + + args[0] = &ffi_type_complex_sint; + args[1] = &ffi_type_sint; + args[2] = &ffi_type_pointer; + values[0] = &tc_arg; + values[1] = &tc_int_arg_x; + values[2] = &tc_ptr_arg_y; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &ffi_type_complex_sint, args) + == FFI_OK); + + tc_arg = 1 + 7 * I; + tc_int_arg_x = 1234; + tc_y = 9876; + ffi_call(&cif, FFI_FN(f_complex), &tc_result, values); + + printf ("%d,%di %d,%di, x %d 1234, y %d 11110\n", + (int)tc_result, (int)(tc_result * -I), 2, 8, tc_int_arg_x, tc_y); + /* dg-output "-2,8i 2,8i, x 1234 1234, y 11110 11110" */ + CHECK (creal (tc_result) == -2); + CHECK (cimag (tc_result) == 8); + CHECK (tc_int_arg_x == 1234); + CHECK (*tc_ptr_arg_y == 11110); + + exit(0); +} diff --git a/libffi/testsuite/libffi.complex/complex_longdouble.c b/libffi/testsuite/libffi.complex/complex_longdouble.c new file mode 100644 index 0000000..7e78366 --- /dev/null +++ b/libffi/testsuite/libffi.complex/complex_longdouble.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check complex types. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_longdouble.inc" +#include "complex.inc" diff --git a/libffi/testsuite/libffi.complex/ffitest.h b/libffi/testsuite/libffi.complex/ffitest.h new file mode 100644 index 0000000..d27d362 --- /dev/null +++ b/libffi/testsuite/libffi.complex/ffitest.h @@ -0,0 +1 @@ +#include "../libffi.call/ffitest.h" diff --git a/libffi/testsuite/libffi.complex/many_complex.inc b/libffi/testsuite/libffi.complex/many_complex.inc new file mode 100644 index 0000000..e37a774 --- /dev/null +++ b/libffi/testsuite/libffi.complex/many_complex.inc @@ -0,0 +1,78 @@ +/* -*-c-*- */ +#include "ffitest.h" + +#include <stdlib.h> +#include <complex.h> + +static _Complex T_C_TYPE many(_Complex T_C_TYPE c1, + _Complex T_C_TYPE c2, + _Complex T_C_TYPE c3, + _Complex T_C_TYPE c4, + _Complex T_C_TYPE c5, + _Complex T_C_TYPE c6, + _Complex T_C_TYPE c7, + _Complex T_C_TYPE c8, + _Complex T_C_TYPE c9, + _Complex T_C_TYPE c10, + _Complex T_C_TYPE c11, + _Complex T_C_TYPE c12, + _Complex T_C_TYPE c13) +{ + printf("0 :%f,%fi\n" + "1 :%f,%fi\n" + "2 :%f,%fi\n" + "3 :%f,%fi\n" + "4 :%f,%fi\n" + "5 :%f,%fi\n" + "6 :%f,%fi\n" + "7 :%f,%fi\n" + "8 :%f,%fi\n" + "9 :%f,%fi\n" + "10:%f,%fi\n" + "11:%f,%fi\n" + "12:%f,%fi\n", + T_CONV creal (c1), T_CONV cimag (c1), + T_CONV creal (c2), T_CONV cimag (c2), + T_CONV creal (c3), T_CONV cimag (c3), + T_CONV creal (c4), T_CONV cimag (c4), + T_CONV creal (c5), T_CONV cimag (c5), + T_CONV creal (c6), T_CONV cimag (c6), + T_CONV creal (c7), T_CONV cimag (c7), + T_CONV creal (c8), T_CONV cimag (c8), + T_CONV creal (c9), T_CONV cimag (c9), + T_CONV creal (c10), T_CONV cimag (c10), + T_CONV creal (c11), T_CONV cimag (c11), + T_CONV creal (c12), T_CONV cimag (c12), + T_CONV creal (c13), T_CONV cimag (c13)); + + return (c1+c2-c3-c4+c5+c6+c7-c8-c9-c10-c11+c12+c13); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[13]; + void *values[13]; + _Complex T_C_TYPE ca[13]; + _Complex T_C_TYPE c, cc; + int i; + + for (i = 0; i < 13; i++) + { + args[i] = &T_FFI_TYPE; + values[i] = &ca[i]; + ca[i] = i + (-20 - i) * I; + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, &T_FFI_TYPE, args) == FFI_OK); + + ffi_call(&cif, FFI_FN(many), &c, values); + + cc = many(ca[0], ca[1], ca[2], ca[3], ca[4], ca[5], ca[6], ca[7], ca[8], + ca[9], ca[10], ca[11], ca[12]); + CHECK(creal (cc) == creal (c)); + CHECK(cimag (cc) == cimag (c)); + + exit(0); +} diff --git a/libffi/testsuite/libffi.complex/many_complex_double.c b/libffi/testsuite/libffi.complex/many_complex_double.c new file mode 100644 index 0000000..3fd53c3 --- /dev/null +++ b/libffi/testsuite/libffi.complex/many_complex_double.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex, with many arguments + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_double.inc" +#include "many_complex.inc" diff --git a/libffi/testsuite/libffi.complex/many_complex_float.c b/libffi/testsuite/libffi.complex/many_complex_float.c new file mode 100644 index 0000000..c43d21c --- /dev/null +++ b/libffi/testsuite/libffi.complex/many_complex_float.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex, with many arguments + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_float.inc" +#include "many_complex.inc" diff --git a/libffi/testsuite/libffi.complex/many_complex_longdouble.c b/libffi/testsuite/libffi.complex/many_complex_longdouble.c new file mode 100644 index 0000000..dbab723 --- /dev/null +++ b/libffi/testsuite/libffi.complex/many_complex_longdouble.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex, with many arguments + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_longdouble.inc" +#include "many_complex.inc" diff --git a/libffi/testsuite/libffi.complex/return_complex.inc b/libffi/testsuite/libffi.complex/return_complex.inc new file mode 100644 index 0000000..8bf0c1f --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex.inc @@ -0,0 +1,37 @@ +/* -*-c-*- */ +#include "ffitest.h" +#include <complex.h> + +static _Complex T_C_TYPE return_c(_Complex T_C_TYPE c) +{ + printf ("%f,%fi\n", T_CONV creal (c), T_CONV cimag (c)); + return 2 * c; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + _Complex T_C_TYPE c, rc, rc2; + T_C_TYPE cr, ci; + + args[0] = &T_FFI_TYPE; + values[0] = &c; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &T_FFI_TYPE, args) == FFI_OK); + + for (cr = -127.0; cr < 127; cr++) + { + ci = 1000.0 - cr; + c = cr + ci * I; + ffi_call(&cif, FFI_FN(return_c), &rc, values); + rc2 = return_c(c); + printf ("%f,%fi vs %f,%fi\n", + T_CONV creal (rc), T_CONV cimag (rc), + T_CONV creal (rc2), T_CONV cimag (rc2)); + CHECK(rc == 2 * c); + } + exit(0); +} diff --git a/libffi/testsuite/libffi.complex/return_complex1.inc b/libffi/testsuite/libffi.complex/return_complex1.inc new file mode 100644 index 0000000..7cecc0f --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex1.inc @@ -0,0 +1,41 @@ +/* -*-c-*- */ +#include "ffitest.h" +#include <complex.h> + +static _Complex T_C_TYPE return_c(_Complex T_C_TYPE c1, float fl2, unsigned int in3, _Complex T_C_TYPE c4) +{ + return c1 + fl2 + in3 + c4; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + _Complex T_C_TYPE c1, c4, rc, rc2; + float fl2; + unsigned int in3; + args[0] = &T_FFI_TYPE; + args[1] = &ffi_type_float; + args[2] = &ffi_type_uint; + args[3] = &T_FFI_TYPE; + values[0] = &c1; + values[1] = &fl2; + values[2] = &in3; + values[3] = &c4; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &T_FFI_TYPE, args) == FFI_OK); + c1 = 127.0 + 255.0 * I; + fl2 = 128.0; + in3 = 255; + c4 = 512.7 + 1024.1 * I; + + ffi_call(&cif, FFI_FN(return_c), &rc, values); + rc2 = return_c(c1, fl2, in3, c4); + printf ("%f,%fi vs %f,%fi\n", + T_CONV creal (rc), T_CONV cimag (rc), + T_CONV creal (rc2), T_CONV cimag (rc2)); + CHECK(rc == rc2); + exit(0); +} diff --git a/libffi/testsuite/libffi.complex/return_complex1_double.c b/libffi/testsuite/libffi.complex/return_complex1_double.c new file mode 100644 index 0000000..727410d --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex1_double.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_double.inc" +#include "return_complex1.inc" diff --git a/libffi/testsuite/libffi.complex/return_complex1_float.c b/libffi/testsuite/libffi.complex/return_complex1_float.c new file mode 100644 index 0000000..a2aeada --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex1_float.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_float.inc" +#include "return_complex1.inc" diff --git a/libffi/testsuite/libffi.complex/return_complex1_longdouble.c b/libffi/testsuite/libffi.complex/return_complex1_longdouble.c new file mode 100644 index 0000000..103504b --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex1_longdouble.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_longdouble.inc" +#include "return_complex1.inc" diff --git a/libffi/testsuite/libffi.complex/return_complex2.inc b/libffi/testsuite/libffi.complex/return_complex2.inc new file mode 100644 index 0000000..265170b --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex2.inc @@ -0,0 +1,44 @@ +/* -*-c-*- */ +#include "ffitest.h" +#include <complex.h> + +_Complex T_C_TYPE +return_c(_Complex T_C_TYPE c1, _Complex T_C_TYPE c2, + unsigned int in3, _Complex T_C_TYPE c4) +{ + volatile _Complex T_C_TYPE r = c1 + c2 + in3 + c4; + return r; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + _Complex T_C_TYPE c1, c2, c4, rc, rc2; + unsigned int in3; + args[0] = &T_FFI_TYPE; + args[1] = &T_FFI_TYPE; + args[2] = &ffi_type_uint; + args[3] = &T_FFI_TYPE; + values[0] = &c1; + values[1] = &c2; + values[2] = &in3; + values[3] = &c4; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &T_FFI_TYPE, args) == FFI_OK); + c1 = 127.0 + 255.0 * I; + c2 = 128.0 + 256.0; + in3 = 255; + c4 = 512.7 + 1024.1 * I; + + ffi_call(&cif, FFI_FN(return_c), &rc, values); + rc2 = return_c(c1, c2, in3, c4); + printf ("%f,%fi vs %f,%fi\n", + T_CONV creal (rc), T_CONV cimag (rc), + T_CONV creal (rc2), T_CONV cimag (rc2)); + CHECK(rc == rc2); + exit(0); +} diff --git a/libffi/testsuite/libffi.complex/return_complex2_double.c b/libffi/testsuite/libffi.complex/return_complex2_double.c new file mode 100644 index 0000000..ab9efac --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex2_double.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_double.inc" +#include "return_complex2.inc" diff --git a/libffi/testsuite/libffi.complex/return_complex2_float.c b/libffi/testsuite/libffi.complex/return_complex2_float.c new file mode 100644 index 0000000..d7f22c2 --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex2_float.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_float.inc" +#include "return_complex2.inc" diff --git a/libffi/testsuite/libffi.complex/return_complex2_longdouble.c b/libffi/testsuite/libffi.complex/return_complex2_longdouble.c new file mode 100644 index 0000000..3edea62 --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex2_longdouble.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_longdouble.inc" +#include "return_complex2.inc" diff --git a/libffi/testsuite/libffi.complex/return_complex_double.c b/libffi/testsuite/libffi.complex/return_complex_double.c new file mode 100644 index 0000000..e2497cc --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex_double.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_double.inc" +#include "return_complex.inc" diff --git a/libffi/testsuite/libffi.complex/return_complex_float.c b/libffi/testsuite/libffi.complex/return_complex_float.c new file mode 100644 index 0000000..a35528f --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex_float.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_float.inc" +#include "return_complex.inc" diff --git a/libffi/testsuite/libffi.complex/return_complex_longdouble.c b/libffi/testsuite/libffi.complex/return_complex_longdouble.c new file mode 100644 index 0000000..142d7be --- /dev/null +++ b/libffi/testsuite/libffi.complex/return_complex_longdouble.c @@ -0,0 +1,10 @@ +/* Area: ffi_call + Purpose: Check return value complex. + Limitations: none. + PR: none. + Originator: <vogt@linux.vnet.ibm.com>. */ + +/* { dg-do run } */ + +#include "complex_defs_longdouble.inc" +#include "return_complex.inc" diff --git a/libffi/testsuite/libffi.go/aa-direct.c b/libffi/testsuite/libffi.go/aa-direct.c new file mode 100644 index 0000000..b00c404 --- /dev/null +++ b/libffi/testsuite/libffi.go/aa-direct.c @@ -0,0 +1,34 @@ +/* { dg-do run } */ + +#include "static-chain.h" + +#if defined(__GNUC__) && !defined(__clang__) && defined(STATIC_CHAIN_REG) + +#include "ffitest.h" + +/* Blatent assumption here that the prologue doesn't clobber the + static chain for trivial functions. If this is not true, don't + define STATIC_CHAIN_REG, and we'll test what we can via other tests. */ +void *doit(void) +{ + register void *chain __asm__(STATIC_CHAIN_REG); + return chain; +} + +int main() +{ + ffi_cif cif; + void *result; + + CHECK(ffi_prep_cif(&cif, ABI_NUM, 0, &ffi_type_pointer, NULL) == FFI_OK); + + ffi_call_go(&cif, FFI_FN(doit), &result, NULL, &result); + + CHECK(result == &result); + + return 0; +} + +#else /* UNSUPPORTED */ +int main() { return 0; } +#endif diff --git a/libffi/testsuite/libffi.go/closure1.c b/libffi/testsuite/libffi.go/closure1.c new file mode 100644 index 0000000..7b34afc --- /dev/null +++ b/libffi/testsuite/libffi.go/closure1.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ + +#include "ffitest.h" + +void doit(ffi_cif *cif, void *rvalue, void **avalue, void *closure) +{ + (void)cif; + (void)avalue; + *(void **)rvalue = closure; +} + +typedef void * (*FN)(void); + +int main() +{ + ffi_cif cif; + ffi_go_closure cl; + void *result; + + CHECK(ffi_prep_cif(&cif, ABI_NUM, 0, &ffi_type_pointer, NULL) == FFI_OK); + CHECK(ffi_prep_go_closure(&cl, &cif, doit) == FFI_OK); + + ffi_call_go(&cif, FFI_FN(*(FN *)&cl), &result, NULL, &cl); + + CHECK(result == &cl); + + exit(0); +} diff --git a/libffi/testsuite/libffi.go/ffitest.h b/libffi/testsuite/libffi.go/ffitest.h new file mode 100644 index 0000000..d27d362 --- /dev/null +++ b/libffi/testsuite/libffi.go/ffitest.h @@ -0,0 +1 @@ +#include "../libffi.call/ffitest.h" diff --git a/libffi/testsuite/libffi.go/go.exp b/libffi/testsuite/libffi.go/go.exp new file mode 100644 index 0000000..100c5e7 --- /dev/null +++ b/libffi/testsuite/libffi.go/go.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2003, 2006, 2009, 2010, 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +dg-init +libffi-init + +global srcdir subdir + +set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.{c,cc}]] + +if { [libffi_feature_test "#ifdef FFI_GO_CLOSURES"] } { + run-many-tests $tlist "" +} else { + foreach test $tlist { + unsupported "$test" + } +} + +dg-finish + +# Local Variables: +# tcl-indent-level:4 +# End: diff --git a/libffi/testsuite/libffi.go/static-chain.h b/libffi/testsuite/libffi.go/static-chain.h new file mode 100644 index 0000000..3675b40 --- /dev/null +++ b/libffi/testsuite/libffi.go/static-chain.h @@ -0,0 +1,19 @@ +#ifdef __aarch64__ +# define STATIC_CHAIN_REG "x18" +#elif defined(__alpha__) +# define STATIC_CHAIN_REG "$1" +#elif defined(__arm__) +# define STATIC_CHAIN_REG "ip" +#elif defined(__sparc__) +# if defined(__arch64__) || defined(__sparcv9) +# define STATIC_CHAIN_REG "g5" +# else +# define STATIC_CHAIN_REG "g2" +# endif +#elif defined(__x86_64__) +# define STATIC_CHAIN_REG "r10" +#elif defined(__i386__) +# ifndef ABI_NUM +# define STATIC_CHAIN_REG "ecx" /* FFI_DEFAULT_ABI only */ +# endif +#endif |