diff options
Diffstat (limited to 'package')
| -rw-r--r-- | package/libffi/libffi-0002-Add-aarch64-support-from-upstream.patch | 2326 | 
1 files changed, 2326 insertions, 0 deletions
| diff --git a/package/libffi/libffi-0002-Add-aarch64-support-from-upstream.patch b/package/libffi/libffi-0002-Add-aarch64-support-from-upstream.patch new file mode 100644 index 000000000..a4071302a --- /dev/null +++ b/package/libffi/libffi-0002-Add-aarch64-support-from-upstream.patch @@ -0,0 +1,2326 @@ +From c77c9625dd63138512ce0f67e07dd254771e566f Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 16 Nov 2012 01:15:28 +0100 +Subject: [PATCH 2/2] Add aarch64 support from upstream + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +--- + ChangeLog                |   27 ++ + Makefile.am              |    4 + + Makefile.in              |   44 +- + README                   |    3 + + configure                |  185 +++++--- + configure.ac             |    5 + + src/aarch64/ffi.c        | 1076 ++++++++++++++++++++++++++++++++++++++++++++++ + src/aarch64/ffitarget.h  |   59 +++ + src/aarch64/sysv.S       |  307 +++++++++++++ + testsuite/lib/libffi.exp |    4 + + 10 files changed, 1647 insertions(+), 67 deletions(-) + create mode 100644 src/aarch64/ffi.c + create mode 100644 src/aarch64/ffitarget.h + create mode 100644 src/aarch64/sysv.S + +diff --git a/ChangeLog b/ChangeLog +index 376edf7..4e8ea91 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,30 @@ ++2012-10-30  James Greenhalgh  <james.greenhalgh at arm.com> ++            Marcus Shawcroft  <marcus.shawcroft at arm.com> ++ ++        * README: Add details of aarch64 port. ++        * src/aarch64/ffi.c: New. ++        * src/aarch64/ffitarget.h: Likewise. ++        * src/aarch64/sysv.S: Likewise. ++	* Makefile.am: Support aarch64. ++	* configure.ac: Support aarch64. ++	* Makefile.in, configure: Rebuilt. ++ ++2012-10-30  James Greenhalgh  <james.greenhalgh at arm.com> ++            Marcus Shawcroft  <marcus.shawcroft at arm.com> ++ ++        * testsuite/lib/libffi.exp: Add support for aarch64. ++        * testsuite/libffi.call/cls_struct_va1.c: New. ++        * testsuite/libffi.call/cls_uchar_va.c: Likewise. ++        * testsuite/libffi.call/cls_uint_va.c: Likewise. ++        * testsuite/libffi.call/cls_ulong_va.c: Liekwise. ++        * testsuite/libffi.call/cls_ushort_va.c: Likewise. ++        * testsuite/libffi.call/nested_struct11.c: Likewise. ++        * testsuite/libffi.call/uninitialized.c: Likewise. ++        * testsuite/libffi.call/va_1.c: Likewise. ++        * testsuite/libffi.call/va_struct1.c: Likewise. ++        * testsuite/libffi.call/va_struct2.c: Likewise. ++        * testsuite/libffi.call/va_struct3.c: Likewise. ++ + 2012-04-23  Alexandre Keunecke I. de Mendonca <alexandre.keunecke@gmail.com> +  + 	* configure.ac: Add Blackfin/sysv support +diff --git a/Makefile.am b/Makefile.am +index 16f32a6..bd4d5c4 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -5,6 +5,7 @@ AUTOMAKE_OPTIONS = foreign subdir-objects + 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 \ +@@ -151,6 +152,9 @@ endif + if POWERPC_FREEBSD + nodist_libffi_la_SOURCES += src/powerpc/ffi.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 +diff --git a/Makefile.in b/Makefile.in +index f5c10af..c4f4470 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -65,9 +65,10 @@ target_triplet = @target@ + @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 ++@AARCH64_TRUE@am__append_30 = src/aarch64/sysv.S src/aarch64/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_30 = -DFFI_DEBUG ++@FFI_DEBUG_TRUE@am__append_31 = -DFFI_DEBUG + subdir = . + DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + 	$(srcdir)/Makefile.in $(srcdir)/doc/stamp-vti \ +@@ -156,6 +157,7 @@ am_libffi_la_OBJECTS = src/prep_cif.lo src/types.lo src/raw_api.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 ++@AARCH64_TRUE@am__objects_29 = src/aarch64/sysv.lo src/aarch64/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) \ +@@ -165,17 +167,18 @@ nodist_libffi_la_OBJECTS = $(am__objects_1) $(am__objects_2) \ + 	$(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_27) $(am__objects_28) $(am__objects_29) \ ++	$(am__objects_30) + libffi_la_OBJECTS = $(am_libffi_la_OBJECTS) \ + 	$(nodist_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_30 = src/prep_cif.lo src/types.lo src/raw_api.lo \ ++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_30) +-am__objects_31 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ ++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) \ +@@ -185,7 +188,7 @@ am__objects_31 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ + 	$(am__objects_22) $(am__objects_23) $(am__objects_24) \ + 	$(am__objects_25) $(am__objects_26) $(am__objects_27) \ + 	$(am__objects_28) $(am__objects_29) +-nodist_libffi_convenience_la_OBJECTS = $(am__objects_31) ++nodist_libffi_convenience_la_OBJECTS = $(am__objects_32) + libffi_convenience_la_OBJECTS = $(am_libffi_convenience_la_OBJECTS) \ + 	$(nodist_libffi_convenience_la_OBJECTS) + DEFAULT_INCLUDES = -I.@am__isrc@ +@@ -410,6 +413,7 @@ top_srcdir = @top_srcdir@ + AUTOMAKE_OPTIONS = foreign subdir-objects + 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 \ +@@ -501,10 +505,11 @@ nodist_libffi_la_SOURCES = $(am__append_1) $(am__append_2) \ + 	$(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_27) $(am__append_28) $(am__append_29) \ ++	$(am__append_30) + libffi_convenience_la_SOURCES = $(libffi_la_SOURCES) + nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES) +-AM_CFLAGS = -g $(am__append_30) ++AM_CFLAGS = -g $(am__append_31) + libffi_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LTLDFLAGS) $(AM_LTLDFLAGS) + AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src -DFFI_BUILDING + AM_CCASFLAGS = $(AM_CPPFLAGS) -g +@@ -640,6 +645,16 @@ 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/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/x86/$(am__dirstamp): + 	@$(MKDIR_P) src/x86 + 	@: > src/x86/$(am__dirstamp) +@@ -859,6 +874,10 @@ mostlyclean-compile: + 	-rm -f src/bfin/ffi.lo + 	-rm -f src/bfin/sysv.$(OBJEXT) + 	-rm -f src/bfin/sysv.lo ++	-rm -f src/aarch64/ffi.$(OBJEXT) ++	-rm -f src/aarch64/ffi.lo ++	-rm -f src/aarch64/sysv.$(OBJEXT) ++	-rm -f src/aarch64/sysv.lo + 	-rm -f src/closures.$(OBJEXT) + 	-rm -f src/closures.lo + 	-rm -f src/cris/ffi.$(OBJEXT) +@@ -973,6 +992,8 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/prep_cif.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/raw_api.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/types.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@src/aarch64/$(DEPDIR)/ffi.Plo@am__quote@ ++@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/arm/$(DEPDIR)/ffi.Plo@am__quote@ +@@ -1083,6 +1104,7 @@ mostlyclean-libtool: + clean-libtool: + 	-rm -rf .libs _libs + 	-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/arm/.libs src/arm/_libs + 	-rm -rf src/avr32/.libs src/avr32/_libs +@@ -1635,6 +1657,8 @@ distclean-generic: + 	-rm -f doc/$(am__dirstamp) + 	-rm -f src/$(DEPDIR)/$(am__dirstamp) + 	-rm -f src/$(am__dirstamp) ++	-rm -f src/aarch64/$(DEPDIR)/$(am__dirstamp) ++	-rm -f src/aarch64/$(am__dirstamp) + 	-rm -f src/alpha/$(DEPDIR)/$(am__dirstamp) + 	-rm -f src/alpha/$(am__dirstamp) + 	-rm -f src/arm/$(DEPDIR)/$(am__dirstamp) +@@ -1682,7 +1706,7 @@ clean-am: clean-aminfo clean-generic clean-libLTLIBRARIES \ +  + distclean: distclean-recursive + 	-rm -f $(am__CONFIG_DISTCLEAN_FILES) +-	-rm -rf src/$(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/moxie/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/x86/$(DEPDIR) ++	-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/moxie/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/x86/$(DEPDIR) + 	-rm -f Makefile + distclean-am: clean-am distclean-compile distclean-generic \ + 	distclean-hdr distclean-libtool distclean-tags +@@ -1802,7 +1826,7 @@ installcheck-am: + maintainer-clean: maintainer-clean-recursive + 	-rm -f $(am__CONFIG_DISTCLEAN_FILES) + 	-rm -rf $(top_srcdir)/autom4te.cache +-	-rm -rf src/$(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/moxie/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/x86/$(DEPDIR) ++	-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/moxie/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/x86/$(DEPDIR) + 	-rm -f Makefile + maintainer-clean-am: distclean-am maintainer-clean-aminfo \ + 	maintainer-clean-generic maintainer-clean-vti +diff --git a/README b/README +index ec240a4..9aa99f4 100644 +--- a/README ++++ b/README +@@ -51,6 +51,7 @@ tested: + |--------------+------------------| + | Architecture | Operating System | + |--------------+------------------| ++| AArch64         | Linux            | + | Alpha        | Linux            | + | Alpha        | Tru64            | + | ARM          | Linux            | +@@ -151,6 +152,7 @@ See the ChangeLog files for details. +  + 3.0.12 XXX-XX-XX +         Add Blackfin support. ++	Add AArch64 support. +  + 3.0.11 Apr-11-12 +         Add support for variadic functions (ffi_prep_cif_var). +@@ -320,6 +322,7 @@ Thorup. + Major processor architecture ports were contributed by the following + developers: +  ++aarch64		Marcus Shawcroft, James Greenhalgh + alpha		Richard Henderson + arm		Raffaele Sena + cris		Simon Posnjak, Hans-Peter Nilsson +diff --git a/configure b/configure +index 4ccba55..419275b 100755 +--- a/configure ++++ b/configure +@@ -649,6 +649,8 @@ AVR32_FALSE + AVR32_TRUE + ARM_FALSE + ARM_TRUE ++AARCH64_FALSE ++AARCH64_TRUE + POWERPC_FREEBSD_FALSE + POWERPC_FREEBSD_TRUE + POWERPC_DARWIN_FALSE +@@ -1478,7 +1480,7 @@ Optional Features: + Optional Packages: +   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes] +   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no) +-  --with-pic              try to use only PIC/non-PIC objects [default=use ++  --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use +                           both] +   --with-gnu-ld           assume the C compiler uses GNU ld [default=no] +   --with-sysroot=DIR Search for dependent libraries within DIR +@@ -5276,6 +5278,11 @@ else +     lt_cv_sys_max_cmd_len=196608 +     ;; +  ++  os2*) ++    # The test takes a long time on OS/2. ++    lt_cv_sys_max_cmd_len=8192 ++    ;; ++ +   osf*) +     # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure +     # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not +@@ -5315,7 +5322,7 @@ else +       # If test is not a shell built-in, we'll probably end up computing a +       # maximum length that is only half of the actual maximum length, but +       # we can't tell. +-      while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \ ++      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + 	         = "X$teststring$teststring"; } >/dev/null 2>&1 && + 	      test $i != 17 # 1/2 MB should be enough +       do +@@ -5744,7 +5751,7 @@ irix5* | irix6* | nonstopux*) +   lt_cv_deplibs_check_method=pass_all +   ;; +  +-# This must be Linux ELF. ++# This must be glibc/ELF. + linux* | k*bsd*-gnu | kopensolaris*-gnu) +   lt_cv_deplibs_check_method=pass_all +   ;; +@@ -6538,6 +6545,7 @@ for ac_symprfx in "" "_"; do +     # which start with @ or ?. +     lt_cv_sys_global_symbol_pipe="$AWK '"\ + "     {last_section=section; section=\$ 3};"\ ++"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ + "     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ + "     \$ 0!~/External *\|/{next};"\ + "     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +@@ -6926,7 +6934,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; } +     CFLAGS="$SAVE_CFLAGS" +   fi +   ;; +-sparc*-*solaris*) ++*-*solaris*) +   # Find out which ABI we are using. +   echo 'int i;' > conftest.$ac_ext +   if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 +@@ -6937,7 +6945,20 @@ sparc*-*solaris*) +     case `/usr/bin/file conftest.o` in +     *64-bit*) +       case $lt_cv_prog_gnu_ld in +-      yes*) LD="${LD-ld} -m elf64_sparc" ;; ++      yes*) ++        case $host in ++        i?86-*-solaris*) ++          LD="${LD-ld} -m elf_x86_64" ++          ;; ++        sparc*-*-solaris*) ++          LD="${LD-ld} -m elf64_sparc" ++          ;; ++        esac ++        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available. ++        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then ++          LD="${LD-ld}_sol2" ++        fi ++        ;; +       *) + 	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + 	  LD="${LD-ld} -64" +@@ -7577,7 +7598,13 @@ else + 	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + 	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err +         _lt_result=$? +-	if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then ++	# If there is a non-empty error log, and "single_module" ++	# appears in it, assume the flag caused a linker warning ++        if test -s conftest.err && $GREP single_module conftest.err; then ++	  cat conftest.err >&5 ++	# Otherwise, if the output was created with a 0 exit code from ++	# the compiler, it worked. ++	elif test -f libconftest.dylib && test $_lt_result -eq 0; then + 	  lt_cv_apple_cc_single_mod=yes + 	else + 	  cat conftest.err >&5 +@@ -7588,6 +7615,7 @@ else + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 + $as_echo "$lt_cv_apple_cc_single_mod" >&6; } ++ +     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 + $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } + if ${lt_cv_ld_exported_symbols_list+:} false; then : +@@ -7620,6 +7648,7 @@ rm -f core conftest.err conftest.$ac_objext \ + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 + $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } ++ +     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 + $as_echo_n "checking for -force_load linker flag... " >&6; } + if ${lt_cv_ld_force_load+:} false; then : +@@ -7641,7 +7670,9 @@ _LT_EOF +       echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 +       $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err +       _lt_result=$? +-      if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then ++      if test -s conftest.err && $GREP force_load conftest.err; then ++	cat conftest.err >&5 ++      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + 	lt_cv_ld_force_load=yes +       else + 	cat conftest.err >&5 +@@ -8046,7 +8077,22 @@ fi +  + # Check whether --with-pic was given. + if test "${with_pic+set}" = set; then : +-  withval=$with_pic; pic_mode="$withval" ++  withval=$with_pic; lt_p=${PACKAGE-default} ++    case $withval in ++    yes|no) pic_mode=$withval ;; ++    *) ++      pic_mode=default ++      # Look at the argument we got.  We use all the common list separators. ++      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," ++      for lt_pkg in $withval; do ++	IFS="$lt_save_ifs" ++	if test "X$lt_pkg" = "X$lt_p"; then ++	  pic_mode=yes ++	fi ++      done ++      IFS="$lt_save_ifs" ++      ;; ++    esac + else +   pic_mode=default + fi +@@ -8124,6 +8170,10 @@ LIBTOOL='$(SHELL) $(top_builddir)/libtool' +  +  +  ++ ++ ++ ++ + test -z "$LN_S" && LN_S="ln -s" +  +  +@@ -8579,7 +8629,9 @@ lt_prog_compiler_static= +     case $cc_basename in +     nvcc*) # Cuda Compiler Driver 2.2 +       lt_prog_compiler_wl='-Xlinker ' +-      lt_prog_compiler_pic='-Xcompiler -fPIC' ++      if test -n "$lt_prog_compiler_pic"; then ++        lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" ++      fi +       ;; +     esac +   else +@@ -8670,18 +8722,33 @@ lt_prog_compiler_static= + 	;; +       *) + 	case `$CC -V 2>&1 | sed 5q` in +-	*Sun\ F* | *Sun*Fortran*) ++	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + 	  # Sun Fortran 8.3 passes all unrecognized flags to the linker + 	  lt_prog_compiler_pic='-KPIC' + 	  lt_prog_compiler_static='-Bstatic' + 	  lt_prog_compiler_wl='' + 	  ;; ++	*Sun\ F* | *Sun*Fortran*) ++	  lt_prog_compiler_pic='-KPIC' ++	  lt_prog_compiler_static='-Bstatic' ++	  lt_prog_compiler_wl='-Qoption ld ' ++	  ;; + 	*Sun\ C*) + 	  # Sun C 5.9 + 	  lt_prog_compiler_pic='-KPIC' + 	  lt_prog_compiler_static='-Bstatic' + 	  lt_prog_compiler_wl='-Wl,' + 	  ;; ++        *Intel*\ [CF]*Compiler*) ++	  lt_prog_compiler_wl='-Wl,' ++	  lt_prog_compiler_pic='-fPIC' ++	  lt_prog_compiler_static='-static' ++	  ;; ++	*Portland\ Group*) ++	  lt_prog_compiler_wl='-Wl,' ++	  lt_prog_compiler_pic='-fpic' ++	  lt_prog_compiler_static='-Bstatic' ++	  ;; + 	esac + 	;; +       esac +@@ -9043,7 +9110,6 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie +   hardcode_direct=no +   hardcode_direct_absolute=no +   hardcode_libdir_flag_spec= +-  hardcode_libdir_flag_spec_ld= +   hardcode_libdir_separator= +   hardcode_minus_L=no +   hardcode_shlibpath_var=unsupported +@@ -9293,8 +9359,7 @@ _LT_EOF + 	xlf* | bgf* | bgxlf* | mpixlf*) + 	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + 	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' +-	  hardcode_libdir_flag_spec= +-	  hardcode_libdir_flag_spec_ld='-rpath $libdir' ++	  hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + 	  archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + 	  if test "x$supports_anon_versioning" = xyes; then + 	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ +@@ -9673,6 +9738,7 @@ fi + 	# The linker will not automatically build a static lib if we build a DLL. + 	# _LT_TAGVAR(old_archive_from_new_cmds, )='true' + 	enable_shared_with_static_runtimes=yes ++	exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + 	export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + 	# Don't use ranlib + 	old_postinstall_cmds='chmod 644 $oldlib' +@@ -9718,6 +9784,7 @@ fi +   hardcode_shlibpath_var=unsupported +   if test "$lt_cv_ld_force_load" = "yes"; then +     whole_archive_flag_spec='`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='' +   fi +@@ -9746,10 +9813,6 @@ fi +       hardcode_shlibpath_var=no +       ;; +  +-    freebsd1*) +-      ld_shlibs=no +-      ;; +- +     # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor +     # support.  Future versions do this automatically, but an explicit c++rt0.o +     # does not break anything, and helps significantly (at the cost of a little +@@ -9762,7 +9825,7 @@ fi +       ;; +  +     # Unfortunately, older versions of FreeBSD 2 do not have this feature. +-    freebsd2*) ++    freebsd2.*) +       archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' +       hardcode_direct=yes +       hardcode_minus_L=yes +@@ -9801,7 +9864,6 @@ fi +       fi +       if test "$with_gnu_ld" = no; then + 	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' +-	hardcode_libdir_flag_spec_ld='+b $libdir' + 	hardcode_libdir_separator=: + 	hardcode_direct=yes + 	hardcode_direct_absolute=yes +@@ -10425,11 +10487,6 @@ esac +  +  +  +- +- +- +- +- +   { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 + $as_echo_n "checking dynamic linker characteristics... " >&6; } +  +@@ -10519,7 +10576,7 @@ need_version=unknown +  + case $host_os in + aix3*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' +   shlibpath_var=LIBPATH +  +@@ -10528,7 +10585,7 @@ aix3*) +   ;; +  + aix[4-9]*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   need_lib_prefix=no +   need_version=no +   hardcode_into_libs=yes +@@ -10593,7 +10650,7 @@ beos*) +   ;; +  + bsdi[45]*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   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' +@@ -10732,7 +10789,7 @@ darwin* | rhapsody*) +   ;; +  + dgux*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   need_lib_prefix=no +   need_version=no +   library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' +@@ -10740,10 +10797,6 @@ dgux*) +   shlibpath_var=LD_LIBRARY_PATH +   ;; +  +-freebsd1*) +-  dynamic_linker=no +-  ;; +- + freebsd* | dragonfly*) +   # DragonFly does not have aout.  When/if they implement a new +   # versioning mechanism, adjust this. +@@ -10751,7 +10804,7 @@ freebsd* | dragonfly*) +     objformat=`/usr/bin/objformat` +   else +     case $host_os in +-    freebsd[123]*) objformat=aout ;; ++    freebsd[23].*) objformat=aout ;; +     *) objformat=elf ;; +     esac +   fi +@@ -10769,7 +10822,7 @@ freebsd* | dragonfly*) +   esac +   shlibpath_var=LD_LIBRARY_PATH +   case $host_os in +-  freebsd2*) ++  freebsd2.*) +     shlibpath_overrides_runpath=yes +     ;; +   freebsd3.[01]* | freebsdelf3.[01]*) +@@ -10789,17 +10842,18 @@ freebsd* | dragonfly*) +   ;; +  + gnu*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   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 +   ;; +  + haiku*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   need_lib_prefix=no +   need_version=no +   dynamic_linker="$host_os runtime_loader" +@@ -10860,7 +10914,7 @@ hpux9* | hpux10* | hpux11*) +   ;; +  + interix[3-9]*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   need_lib_prefix=no +   need_version=no +   library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' +@@ -10876,7 +10930,7 @@ irix5* | irix6* | nonstopux*) +     nonstopux*) version_type=nonstopux ;; +     *) + 	if test "$lt_cv_prog_gnu_ld" = yes; then +-		version_type=linux ++		version_type=linux # correct to gnu/linux during the next big refactor + 	else + 		version_type=irix + 	fi ;; +@@ -10913,9 +10967,9 @@ linux*oldld* | linux*aout* | linux*coff*) +   dynamic_linker=no +   ;; +  +-# This must be Linux ELF. ++# This must be glibc/ELF. + linux* | k*bsd*-gnu | kopensolaris*-gnu) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   need_lib_prefix=no +   need_version=no +   library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' +@@ -11001,7 +11055,7 @@ netbsd*) +   ;; +  + newsos6) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   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 +@@ -11070,7 +11124,7 @@ rdos*) +   ;; +  + solaris*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   need_lib_prefix=no +   need_version=no +   library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' +@@ -11095,7 +11149,7 @@ sunos4*) +   ;; +  + sysv4 | sysv4.3*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   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 +@@ -11119,7 +11173,7 @@ sysv4 | sysv4.3*) +  + sysv4*MP*) +   if test -d /usr/nec ;then +-    version_type=linux ++    version_type=linux # correct to gnu/linux during the next big refactor +     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 +@@ -11150,7 +11204,7 @@ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) +  + tpf*) +   # TPF is a cross-target only.  Preferred cross-host = GNU/Linux. +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   need_lib_prefix=no +   need_version=no +   library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' +@@ -11160,7 +11214,7 @@ tpf*) +   ;; +  + uts4*) +-  version_type=linux ++  version_type=linux # correct to gnu/linux during the next big refactor +   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 +@@ -11942,6 +11996,8 @@ CC="$lt_save_CC" +  +  +  ++ ++ +         ac_config_commands="$ac_config_commands libtool" +  +  +@@ -13132,6 +13188,10 @@ fi +  + TARGETDIR="unknown" + case "$host" in ++  aarch64*-*-*) ++	TARGET=AARCH64; TARGETDIR=aarch64 ++	;; ++ +   alpha*-*-*) + 	TARGET=ALPHA; TARGETDIR=alpha; + 	# Support 128-bit long double, changeable via command-line switch. +@@ -13431,6 +13491,14 @@ else +   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='#' +@@ -14786,6 +14854,10 @@ 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 +@@ -15463,6 +15535,7 @@ pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' + enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' + SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' + ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' ++PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' + host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' + host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' + host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +@@ -15545,7 +15618,6 @@ with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' + allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' + no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' + hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +-hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' + hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' + hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' + hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +@@ -15601,6 +15673,7 @@ _LTECHO_EOF' + # Quote evaled strings. + for var in SHELL \ + ECHO \ ++PATH_SEPARATOR \ + SED \ + GREP \ + EGREP \ +@@ -15651,7 +15724,6 @@ with_gnu_ld \ + allow_undefined_flag \ + no_undefined_flag \ + hardcode_libdir_flag_spec \ +-hardcode_libdir_flag_spec_ld \ + hardcode_libdir_separator \ + exclude_expsyms \ + include_expsyms \ +@@ -16633,8 +16705,8 @@ $as_echo X"$file" | + # NOTE: Changes made to this file will be lost: look at ltmain.sh. + # + #   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +-#                 2006, 2007, 2008, 2009, 2010 Free Software Foundation, +-#                 Inc. ++#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software ++#                 Foundation, Inc. + #   Written by Gordon Matzigkeit, 1996 + # + #   This file is part of GNU Libtool. +@@ -16688,6 +16760,9 @@ SHELL=$lt_SHELL + # An echo program that protects backslashes. + ECHO=$lt_ECHO +  ++# The PATH separator for the build system. ++PATH_SEPARATOR=$lt_PATH_SEPARATOR ++ + # The host system. + host_alias=$host_alias + host=$host +@@ -16989,10 +17064,6 @@ no_undefined_flag=$lt_no_undefined_flag + # This must work even if \$libdir does not exist + hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec +  +-# 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 +- + # Whether we need a single "-rpath" flag with a separated argument. + hardcode_libdir_separator=$lt_hardcode_libdir_separator +  +diff --git a/configure.ac b/configure.ac +index 9b946a2..8c3f40c 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -53,6 +53,10 @@ AM_CONDITIONAL(TESTSUBDIR, test -d $srcdir/testsuite) +  + TARGETDIR="unknown" + case "$host" in ++  aarch64*-*-*) ++	TARGET=AARCH64; TARGETDIR=aarch64 ++	;; ++ +   alpha*-*-*) + 	TARGET=ALPHA; TARGETDIR=alpha; + 	# Support 128-bit long double, changeable via command-line switch. +@@ -233,6 +237,7 @@ 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) +diff --git a/src/aarch64/ffi.c b/src/aarch64/ffi.c +new file mode 100644 +index 0000000..1405665 +--- /dev/null ++++ b/src/aarch64/ffi.c +@@ -0,0 +1,1076 @@ ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++``Software''), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */ ++ ++#include <stdio.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) ++ ++union _d ++{ ++  UINT64 d; ++  UINT32 s[2]; ++}; ++ ++struct call_context ++{ ++  UINT64 x [AARCH64_N_XREG]; ++  struct ++  { ++    union _d d[2]; ++  } v [AARCH64_N_VREG]; ++}; ++ ++static void * ++get_x_addr (struct call_context *context, unsigned n) ++{ ++  return &context->x[n]; ++} ++ ++static void * ++get_s_addr (struct call_context *context, unsigned n) ++{ ++#if defined __AARCH64EB__ ++  return &context->v[n].d[1].s[1]; ++#else ++  return &context->v[n].d[0].s[0]; ++#endif ++} ++ ++static void * ++get_d_addr (struct call_context *context, unsigned n) ++{ ++#if defined __AARCH64EB__ ++  return &context->v[n].d[1]; ++#else ++  return &context->v[n].d[0]; ++#endif ++} ++ ++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.  */ ++ ++static size_t ++get_basic_type_size (unsigned short type) ++{ ++  switch (type) ++    { ++    case FFI_TYPE_FLOAT: ++      return sizeof (UINT32); ++    case FFI_TYPE_DOUBLE: ++      return sizeof (UINT64); ++    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)); ++ ++extern void ++ffi_closure_SYSV (ffi_closure *); ++ ++/* Test for an FFI floating point representation.  */ ++ ++static unsigned ++is_floating_type (unsigned short type) ++{ ++  return (type == FFI_TYPE_FLOAT || type == FFI_TYPE_DOUBLE ++	  || type == FFI_TYPE_LONGDOUBLE); ++} ++ ++/* Test for a homogeneous structure.  */ ++ ++static unsigned short ++get_homogeneous_type (ffi_type *ty) ++{ ++  if (ty->type == FFI_TYPE_STRUCT && ty->elements) ++    { ++      unsigned i; ++      unsigned short candidate_type ++	= get_homogeneous_type (ty->elements[0]); ++      for (i =1; ty->elements[i]; i++) ++	{ ++	  unsigned short iteration_type = 0; ++	  /* If we have a nested struct, we must find its homogeneous type. ++	     If that fits with our candidate type, we are still ++	     homogeneous.  */ ++	  if (ty->elements[i]->type == FFI_TYPE_STRUCT ++	      && ty->elements[i]->elements) ++	    { ++	      iteration_type = get_homogeneous_type (ty->elements[i]); ++	    } ++	  else ++	    { ++	      iteration_type = ty->elements[i]->type; ++	    } ++ ++	  /* If we are not homogeneous, return FFI_TYPE_STRUCT.  */ ++	  if (candidate_type != iteration_type) ++	    return FFI_TYPE_STRUCT; ++	} ++      return candidate_type; ++    } ++ ++  /* Base case, we have no more levels of nesting, so we ++     are a basic type, and so, trivially homogeneous in that type.  */ ++  return ty->type; ++} ++ ++/* Determine the number of elements within a STRUCT. ++ ++   Note, we must handle nested structs. ++ ++   If ty is not a STRUCT this function will return 0.  */ ++ ++static unsigned ++element_count (ffi_type *ty) ++{ ++  if (ty->type == FFI_TYPE_STRUCT && ty->elements) ++    { ++      unsigned n; ++      unsigned elems = 0; ++      for (n = 0; ty->elements[n]; n++) ++	{ ++	  if (ty->elements[n]->type == FFI_TYPE_STRUCT ++	      && ty->elements[n]->elements) ++	    elems += element_count (ty->elements[n]); ++	  else ++	    elems++; ++	} ++      return elems; ++    } ++  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.  */ ++ ++static int ++is_hfa (ffi_type *ty) ++{ ++  if (ty->type == FFI_TYPE_STRUCT ++      && ty->elements[0] ++      && is_floating_type (get_homogeneous_type (ty))) ++    { ++      unsigned n = element_count (ty); ++      return n >= 1 && n <= 4; ++    } ++  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) ++    { ++    case FFI_TYPE_VOID: ++    case FFI_TYPE_FLOAT: ++    case FFI_TYPE_DOUBLE: ++    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; ++        } ++      break; ++ ++    default: ++      FFI_ASSERT (0); ++      break; ++    } ++ ++  return 0; ++} ++ ++/* Test if an ffi_type argument or result is a candidate for a vector ++   register.  */ ++ ++static int ++is_v_register_candidate (ffi_type *ty) ++{ ++  return is_floating_type (ty->type) ++	   || (ty->type == FFI_TYPE_STRUCT && is_hfa (ty)); ++} ++ ++/* Representation of the procedure call argument marshalling ++   state. ++ ++   The terse state variable names match the names used in the AARCH64 ++   PCS. */ ++ ++struct arg_state ++{ ++  unsigned ngrn;                /* Next general-purpose register number. */ ++  unsigned nsrn;                /* Next vector register number. */ ++  unsigned nsaa;                /* Next stack offset. */ ++}; ++ ++/* Initialize a procedure call argument marshalling state.  */ ++static void ++arg_init (struct arg_state *state, unsigned call_frame_size) ++{ ++  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)++); ++} ++ ++/* 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) ++{ ++  void *allocation; ++ ++  /* 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; ++ ++  state->nsaa += size; ++  return allocation; ++} ++ ++static void ++copy_basic_type (void *dest, void *source, unsigned short 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; ++    case FFI_TYPE_SINT8: ++      *(ffi_sarg *) dest = *(SINT8 *) source; ++      break; ++    case FFI_TYPE_UINT16: ++      *(ffi_arg *) dest = *(UINT16 *) source; ++      break; ++    case FFI_TYPE_SINT16: ++      *(ffi_sarg *) dest = *(SINT16 *) source; ++      break; ++    case FFI_TYPE_UINT32: ++      *(ffi_arg *) dest = *(UINT32 *) source; ++      break; ++    case FFI_TYPE_INT: ++    case FFI_TYPE_SINT32: ++      *(ffi_sarg *) dest = *(SINT32 *) source; ++      break; ++    case FFI_TYPE_POINTER: ++    case FFI_TYPE_UINT64: ++      *(ffi_arg *) dest = *(UINT64 *) source; ++      break; ++    case FFI_TYPE_SINT64: ++      *(ffi_sarg *) dest = *(SINT64 *) source; ++      break; ++ ++    default: ++      FFI_ASSERT (0); ++    } ++} ++ ++static void ++copy_hfa_to_reg_or_stack (void *memory, ++			  ffi_type *ty, ++			  struct call_context *context, ++			  unsigned char *stack, ++			  struct arg_state *state) ++{ ++  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 ++    { ++      int i; ++      unsigned short type = get_homogeneous_type (ty); ++      unsigned elems = element_count (ty); ++      for (i = 0; i < elems; i++) ++	{ ++	  void *reg = allocate_to_v (context, state); ++	  copy_basic_type (reg, memory, type); ++	  memory += get_basic_type_size (type); ++	} ++    } ++} ++ ++/* Either allocate an appropriate register for the argument type, or if ++   none are available, allocate a stack slot and return a pointer ++   to the allocated space.  */ ++ ++static void * ++allocate_to_register_or_stack (struct call_context *context, ++			       unsigned char *stack, ++			       struct arg_state *state, ++			       unsigned short type) ++{ ++  size_t alignment = get_basic_type_alignment (type); ++  size_t size = alignment; ++  switch (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; ++      break; ++    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: ++      if (state->ngrn < N_X_ARG_REG) ++	return allocate_to_x (context, state); ++      state->ngrn = N_X_ARG_REG; ++      break; ++    default: ++      FFI_ASSERT (0); ++    } ++ ++    return allocate_to_stack (state, stack, alignment, size); ++} ++ ++/* Copy a value to an appropriate register, or if none are ++   available, to the stack.  */ ++ ++static void ++copy_to_register_or_stack (struct call_context *context, ++			   unsigned char *stack, ++			   struct arg_state *state, ++			   void *value, ++			   unsigned short type) ++{ ++  copy_basic_type ( ++	  allocate_to_register_or_stack (context, stack, state, type), ++	  value, ++	  type); ++} ++ ++/* Marshall the arguments from FFI representation to procedure call ++   context and stack.  */ ++ ++static unsigned ++aarch64_prep_args (struct call_context *context, unsigned char *stack, ++		   extended_cif *ecif) ++{ ++  int i; ++  struct arg_state state; ++ ++  arg_init (&state, ALIGN(ecif->cif->bytes, 16)); ++ ++  for (i = 0; i < ecif->cif->nargs; i++) ++    { ++      ffi_type *ty = ecif->cif->arg_types[i]; ++      switch (ty->type) ++	{ ++	case FFI_TYPE_VOID: ++	  FFI_ASSERT (0); ++	  break; ++ ++	/* 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_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); ++	  break; ++ ++	case FFI_TYPE_STRUCT: ++	  if (is_hfa (ty)) ++	    { ++	      copy_hfa_to_reg_or_stack (ecif->avalue[i], ty, context, ++					stack, &state); ++	    } ++	  else if (ty->size > 16) ++	    { ++	      /* If the argument is a composite type that is larger than 16 ++		 bytes, then the argument has been copied to memory, and ++		 the argument is replaced by a pointer to the copy.  */ ++ ++	      copy_to_register_or_stack (context, stack, &state, ++					 &(ecif->avalue[i]), FFI_TYPE_POINTER); ++	    } ++	  else if (available_x (&state) >= (ty->size + 7) / 8) ++	    { ++	      /* If the argument is a composite type and the size in ++		 double-words is not more than the number of available ++		 X registers, then the argument is copied into consecutive ++		 X registers.  */ ++	      int j; ++	      for (j = 0; j < (ty->size + 7) / 8; j++) ++		{ ++		  memcpy (allocate_to_x (context, &state), ++			  &(((UINT64 *) ecif->avalue[i])[j]), ++			  sizeof (UINT64)); ++		} ++	    } ++	  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); ++	    } ++	  break; ++ ++	default: ++	  FFI_ASSERT (0); ++	  break; ++	} ++    } ++ ++  return ecif->cif->aarch64_flags; ++} ++ ++ffi_status ++ffi_prep_cif_machdep (ffi_cif *cif) ++{ ++  /* Round the stack up to a multiple of the stack alignment requirement. */ ++  cif->bytes = ++    (cif->bytes + (AARCH64_STACK_ALIGN - 1)) & ~ (AARCH64_STACK_ALIGN - 1); ++ ++  /* Initialize our flags. We are interested if this CIF will touch a ++     vector register, if so we will enable context save and load to ++     those registers, otherwise not. This is intended to be friendly ++     to lazy float context switching in the kernel.  */ ++  cif->aarch64_flags = 0; ++ ++  if (is_v_register_candidate (cif->rtype)) ++    { ++      cif->aarch64_flags |= AARCH64_FFI_WITH_V; ++    } ++  else ++    { ++      int i; ++      for (i = 0; i < cif->nargs; i++) ++        if (is_v_register_candidate (cif->arg_types[i])) ++          { ++            cif->aarch64_flags |= AARCH64_FFI_WITH_V; ++            break; ++          } ++    } ++ ++  return FFI_OK; ++} ++ ++/* Call a function with the provided arguments and capture the return ++   value.  */ ++void ++ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) ++{ ++  extended_cif ecif; ++ ++  ecif.cif = cif; ++  ecif.avalue = avalue; ++  ecif.rvalue = rvalue; ++ ++  switch (cif->abi) ++    { ++    case FFI_SYSV: ++      { ++        struct call_context context; ++	unsigned stack_bytes; ++ ++	/* Figure out the total amount of stack space we need, the ++	   above call frame space needs to be 16 bytes aligned to ++	   ensure correct alignment of the first object inserted in ++	   that space hence the ALIGN applied to cif->bytes.*/ ++	stack_bytes = ALIGN(cif->bytes, 16); ++ ++	memset (&context, 0, sizeof (context)); ++        if (is_register_candidate (cif->rtype)) ++          { ++            ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn); ++            switch (cif->rtype->type) ++              { ++              case FFI_TYPE_VOID: ++              case FFI_TYPE_FLOAT: ++              case FFI_TYPE_DOUBLE: ++              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; ++		} ++ ++              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; ++      } ++ ++    default: ++      FFI_ASSERT (0); ++      break; ++    } ++} ++ ++static unsigned char trampoline [] = ++{ 0x70, 0x00, 0x00, 0x58,	/* ldr	x16, 1f	*/ ++  0x91, 0x00, 0x00, 0x10,	/* adr	x17, 2f	*/ ++  0x00, 0x02, 0x1f, 0xd6	/* br	x16	*/ ++}; ++ ++/* Build a trampoline.  */ ++ ++#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,FLAGS)			\ ++  ({unsigned char *__tramp = (unsigned char*)(TRAMP);			\ ++    UINT64  __fun = (UINT64)(FUN);					\ ++    UINT64  __ctx = (UINT64)(CTX);					\ ++    UINT64  __flags = (UINT64)(FLAGS);					\ ++    memcpy (__tramp, trampoline, sizeof (trampoline));			\ ++    memcpy (__tramp + 12, &__fun, sizeof (__fun));			\ ++    memcpy (__tramp + 20, &__ctx, sizeof (__ctx));			\ ++    memcpy (__tramp + 28, &__flags, sizeof (__flags));			\ ++    __clear_cache(__tramp, __tramp + FFI_TRAMPOLINE_SIZE);		\ ++  }) ++ ++ffi_status ++ffi_prep_closure_loc (ffi_closure* closure, ++                      ffi_cif* cif, ++                      void (*fun)(ffi_cif*,void*,void**,void*), ++                      void *user_data, ++                      void *codeloc) ++{ ++  if (cif->abi != FFI_SYSV) ++    return FFI_BAD_ABI; ++ ++  FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV, codeloc, ++		       cif->aarch64_flags); ++ ++  closure->cif  = cif; ++  closure->user_data = user_data; ++  closure->fun  = fun; ++ ++  return FFI_OK; ++} ++ ++/* Primary handler to setup and invoke a function within a closure. ++ ++   A closure when invoked enters via the assembler wrapper ++   ffi_closure_SYSV(). The wrapper allocates a call context on the ++   stack, saves the interesting registers (from the perspective of ++   the calling convention) into the context then passes control to ++   ffi_closure_SYSV_inner() passing the saved context and a pointer to ++   the stack at the point ffi_closure_SYSV() was invoked. ++ ++   On the return path the assembler wrapper will reload call context ++   regsiters. ++ ++   ffi_closure_SYSV_inner() marshalls the call context into ffi value ++   desriptors, 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) ++{ ++  ffi_cif *cif = closure->cif; ++  void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); ++  void *rvalue = NULL; ++  int i; ++  struct arg_state state; ++ ++  arg_init (&state, ALIGN(cif->bytes, 16)); ++ ++  for (i = 0; i < cif->nargs; i++) ++    { ++      ffi_type *ty = cif->arg_types[i]; ++ ++      switch (ty->type) ++	{ ++	case FFI_TYPE_VOID: ++	  FFI_ASSERT (0); ++	  break; ++ ++	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); ++	  break; ++ ++	case FFI_TYPE_STRUCT: ++	  if (is_hfa (ty)) ++	    { ++	      unsigned n = element_count (ty); ++	      if (available_v (&state) < n) ++		{ ++		  state.nsrn = N_V_ARG_REG; ++		  avalue[i] = allocate_to_stack (&state, stack, ty->alignment, ++						 ty->size); ++		} ++	      else ++		{ ++		  switch (get_homogeneous_type (ty)) ++		    { ++		    case FFI_TYPE_FLOAT: ++		      { ++			/* Eeek! We need a pointer to the structure, ++			   however the homogeneous float elements are ++			   being passed in individual S registers, ++			   therefore the structure is not represented as ++			   a contiguous sequence of bytes in our saved ++			   register context. We need to fake up a copy ++			   of the structure 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; ++		    } ++		} ++	    } ++	  else if (ty->size > 16) ++	    { ++	      /* Replace Composite type of size greater than 16 with a ++		 pointer.  */ ++	      memcpy (&avalue[i], ++		      allocate_to_register_or_stack (context, stack, ++						     &state, FFI_TYPE_POINTER), ++		      sizeof (avalue[i])); ++	    } ++	  else if (available_x (&state) >= (ty->size + 7) / 8) ++	    { ++	      avalue[i] = get_x_addr (context, state.ngrn); ++	      state.ngrn += (ty->size + 7) / 8; ++	    } ++	  else ++	    { ++	      state.ngrn = N_X_ARG_REG; ++ ++	      avalue[i] = allocate_to_stack (&state, stack, ty->alignment, ++					     ty->size); ++	    } ++	  break; ++ ++	default: ++	  FFI_ASSERT (0); ++	  break; ++	} ++    } ++ ++  /* Figure out where the return value will be passed, either in ++     registers or in a memory block allocated by the caller and passed ++     in x8.  */ ++ ++  if (is_register_candidate (cif->rtype)) ++    { ++      /* Register candidates are *always* returned in registers. */ ++ ++      /* Allocate a scratchpad for the return value, we will let the ++         callee scrible the result into the scratch pad then move the ++         contents into the appropriate return value location for the ++         call convention.  */ ++      rvalue = alloca (cif->rtype->size); ++      (closure->fun) (cif, rvalue, avalue, closure->user_data); ++ ++      /* Copy the return value into the call context so that it is returned ++         as expected to our caller.  */ ++      switch (cif->rtype->type) ++        { ++        case FFI_TYPE_VOID: ++          break; ++ ++        case FFI_TYPE_UINT8: ++        case FFI_TYPE_UINT16: ++        case FFI_TYPE_UINT32: ++        case FFI_TYPE_POINTER: ++        case FFI_TYPE_UINT64: ++        case FFI_TYPE_SINT8: ++        case FFI_TYPE_SINT16: ++        case FFI_TYPE_INT: ++        case FFI_TYPE_SINT32: ++        case FFI_TYPE_SINT64: ++        case FFI_TYPE_FLOAT: ++        case FFI_TYPE_DOUBLE: ++        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); ++    } ++} ++ +diff --git a/src/aarch64/ffitarget.h b/src/aarch64/ffitarget.h +new file mode 100644 +index 0000000..6f1a348 +--- /dev/null ++++ b/src/aarch64/ffitarget.h +@@ -0,0 +1,59 @@ ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++``Software''), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */ ++ ++#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_TRAMPOLINE_SIZE 36 ++#define FFI_NATIVE_RAW_API 0 ++ ++/* ---- Internal ---- */ ++ ++ ++#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) ++ ++#endif +diff --git a/src/aarch64/sysv.S b/src/aarch64/sysv.S +new file mode 100644 +index 0000000..b8cd421 +--- /dev/null ++++ b/src/aarch64/sysv.S +@@ -0,0 +1,307 @@ ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++``Software''), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */ ++ ++#define LIBFFI_ASM ++#include <fficonfig.h> ++#include <ffi.h> ++ ++#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)); ++ ++   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] ++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) ++ ++        ldp     x29, x30, [sp], #16 ++	cfi_adjust_cfa_offset (-16) ++        cfi_restore (x29) ++        cfi_restore (x30) ++ ++        ret ++ ++        .cfi_endproc ++        .size ffi_call_SYSV, .-ffi_call_SYSV ++ ++#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE) ++ ++/* ffi_closure_SYSV ++ ++   Closure invocation glue. This is the low level code invoked directly by ++   the closure trampoline to setup and call a closure. ++ ++   On entry x17 points to a struct trampoline_data, x16 has been clobbered ++   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. ++ ++   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 ++ ++        sub     sp, sp, #ffi_closure_SYSV_FS ++	cfi_adjust_cfa_offset (ffi_closure_SYSV_FS) ++ ++        stp     x21, x22, [x29, #-16] ++        cfi_rel_offset (x21, 0) ++        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_adjust_cfa_offset (-ffi_closure_SYSV_FS) ++ ++        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/testsuite/lib/libffi.exp b/testsuite/lib/libffi.exp +index 4a65ed1..8ee3f15 100644 +--- a/testsuite/lib/libffi.exp ++++ b/testsuite/lib/libffi.exp +@@ -203,6 +203,10 @@ proc libffi_target_compile { source dest type options } { +  +     lappend options "libs= -lffi" +  ++    if { [string match "aarch64*-*-linux*" $target_triplet] } { ++	lappend options "libs= -lpthread" ++    } ++ +     verbose "options: $options" +     return [target_compile $source $dest $type $options] + } +--  +1.7.9.5 + | 
