| 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 |
| |