From 22bcf65c52d9edcd15b2baa55cb18d7eafe1894a Mon Sep 17 00:00:00 2001
From: Gerhard Tonn <GerhardTonn@swol.de>
Date: Mon, 29 Apr 2002 04:14:44 +0000
Subject: [PATCH] Makefile.am: Add Linux for S/390 support.

2002-04-29  Gerhard Tonn  <GerhardTonn@swol.de>

	* Makefile.am: Add Linux for S/390 support.
	* Makefile.in: Regenerate.
	* configure.in: Add Linux for S/390 support.
	* configure: Regenerate.
	* include/ffi.h.in: Add Linux for S/390 support.
	* src/s390/ffi.c: New file from libffi CVS tree.
	* src/s390/sysv.S: New file from libffi CVS tree.

From-SVN: r52873
---
 libffi/ChangeLog           |  10 +
 libffi/Makefile.am         |   8 +-
 libffi/Makefile.in         |  16 +-
 libffi/configure           | 144 ++++-----
 libffi/configure.in        |   2 +
 libffi/include/Makefile.in |   2 +-
 libffi/include/ffi.h.in    |   6 +
 libffi/src/s390/ffi.c      | 589 +++++++++++++++++++++++++++++++++++++
 libffi/src/s390/sysv.S     | 161 ++++++++++
 9 files changed, 867 insertions(+), 71 deletions(-)
 create mode 100644 libffi/src/s390/ffi.c
 create mode 100644 libffi/src/s390/sysv.S

diff --git a/libffi/ChangeLog b/libffi/ChangeLog
index cd5a456e2bca..dc7ceddd058f 100644
--- a/libffi/ChangeLog
+++ b/libffi/ChangeLog
@@ -1,3 +1,13 @@
+2002-04-29  Gerhard Tonn  <GerhardTonn@swol.de>
+
+	* Makefile.am: Add Linux for S/390 support.
+	* Makefile.in: Regenerate.
+	* configure.in: Add Linux for S/390 support.
+	* configure: Regenerate.
+	* include/ffi.h.in: Add Linux for S/390 support.
+	* src/s390/ffi.c: New file from libffi CVS tree.
+	* src/s390/sysv.S: New file from libffi CVS tree.
+
 2002-04-28  Jakub Jelinek  <jakub@redhat.com>
 
 	* configure.in (HAVE_AS_SPARC_UA_PCREL): Check for working
diff --git a/libffi/Makefile.am b/libffi/Makefile.am
index 4d1120d100e1..5281c58b7c27 100644
--- a/libffi/Makefile.am
+++ b/libffi/Makefile.am
@@ -15,7 +15,8 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
 		src/powerpc/ffi_darwin.c \
 		src/powerpc/darwin.S src/powerpc/aix.S \
 		src/powerpc/darwin_closure.S src/powerpc/aix_closures.S \
-		src/arm/ffi.c src/arm/sysv.S
+		src/arm/ffi.c src/arm/sysv.S \
+		src/s390/ffi.c src/s390/sysv.S
 
 VPATH = @srcdir@:@srcdir@/src:@srcdir@/src/@TARGETDIR@
 
@@ -103,6 +104,7 @@ TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closur
 TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closures.S
 TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
 TARGET_SRC_ARM =  src/arm/sysv.S src/arm/ffi.c
+TARGET_SRC_S390 =  src/s390/sysv.S src/s390/ffi.c
 
 ##libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c $(TARGET_SRC_@TARGET@)
 ## Work around automake deficiency
@@ -156,6 +158,10 @@ if ARM
 libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_ARM)
 libffi_convenience_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_ARM)
 endif
+if S390
+libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
+libffi_convenience_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
+endif
 
 AM_CFLAGS = -fexceptions
 
diff --git a/libffi/Makefile.in b/libffi/Makefile.in
index 24f2930d85ed..0e61ec2e2773 100644
--- a/libffi/Makefile.in
+++ b/libffi/Makefile.in
@@ -96,7 +96,8 @@ EXTRA_DIST = LICENSE ChangeLog.v1 src/mips/ffi.c src/mips/n32.S \
 		src/powerpc/ffi_darwin.c \
 		src/powerpc/darwin.S src/powerpc/aix.S \
 		src/powerpc/darwin_closure.S src/powerpc/aix_closures.S \
-		src/arm/ffi.c src/arm/sysv.S
+		src/arm/ffi.c src/arm/sysv.S \
+		src/s390/ffi.c src/s390/sysv.S
 
 
 VPATH = @srcdir@:@srcdir@/src:@srcdir@/src/@TARGETDIR@
@@ -174,6 +175,7 @@ TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closur
 TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closures.S
 TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
 TARGET_SRC_ARM = src/arm/sysv.S src/arm/ffi.c
+TARGET_SRC_S390 = src/s390/sysv.S src/s390/ffi.c
 
 libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \
 		src/raw_api.c src/java_raw_api.c
@@ -190,6 +192,7 @@ libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \
 @POWERPC_AIX_TRUE@libffi_la_SOURCES = @POWERPC_AIX_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC_AIX)
 @POWERPC_DARWIN_TRUE@libffi_la_SOURCES = @POWERPC_DARWIN_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC_DARWIN)
 @ARM_TRUE@libffi_la_SOURCES = @ARM_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ARM)
+@S390_TRUE@libffi_la_SOURCES = @S390_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
 @MIPS_GCC_TRUE@libffi_convenience_la_SOURCES = @MIPS_GCC_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_GCC)
 @MIPS_SGI_TRUE@libffi_convenience_la_SOURCES = @MIPS_SGI_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_SGI)
 @X86_TRUE@libffi_convenience_la_SOURCES = @X86_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_X86)
@@ -202,6 +205,7 @@ libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \
 @POWERPC_AIX_TRUE@libffi_convenience_la_SOURCES = @POWERPC_AIX_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC_AIX)
 @POWERPC_DARWIN_TRUE@libffi_convenience_la_SOURCES = @POWERPC_DARWIN_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC_DARWIN)
 @ARM_TRUE@libffi_convenience_la_SOURCES = @ARM_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ARM)
+@S390_TRUE@libffi_convenience_la_SOURCES = @S390_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
 
 AM_CFLAGS = -fexceptions
 
@@ -244,6 +248,9 @@ libffi_convenience_la_LIBADD =
 @MIPS_SGI_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \
 @MIPS_SGI_TRUE@src/java_raw_api.lo src/mips/ffi.lo src/mips/o32.lo \
 @MIPS_SGI_TRUE@src/mips/n32.lo
+@S390_TRUE@libffi_convenience_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
+@S390_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
+@S390_TRUE@src/s390/sysv.lo src/s390/ffi.lo
 @X86_TRUE@libffi_convenience_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @X86_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @X86_TRUE@src/x86/ffi.lo src/x86/sysv.lo
@@ -285,6 +292,9 @@ libffi_la_LIBADD =
 @MIPS_SGI_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @MIPS_SGI_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @MIPS_SGI_TRUE@src/mips/ffi.lo src/mips/o32.lo src/mips/n32.lo
+@S390_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
+@S390_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
+@S390_TRUE@src/s390/sysv.lo src/s390/ffi.lo
 @X86_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo src/types.lo \
 @X86_TRUE@src/raw_api.lo src/java_raw_api.lo src/x86/ffi.lo \
 @X86_TRUE@src/x86/sysv.lo
@@ -579,8 +589,8 @@ distdir: $(DISTFILES)
 	-chmod 777 $(distdir)
 	$(mkinstalldirs) $(distdir)/src/alpha $(distdir)/src/arm \
 	   $(distdir)/src/m68k $(distdir)/src/mips \
-	   $(distdir)/src/powerpc $(distdir)/src/sparc \
-	   $(distdir)/src/x86
+	   $(distdir)/src/powerpc $(distdir)/src/s390 \
+	   $(distdir)/src/sparc $(distdir)/src/x86
 	@for file in $(DISTFILES); do \
 	  if test -f $$file; then d=.; else d=$(srcdir); fi; \
 	  if test -d $$d/$$file; then \
diff --git a/libffi/configure b/libffi/configure
index 9649abaf3a45..7e3d5edea4bf 100755
--- a/libffi/configure
+++ b/libffi/configure
@@ -2386,6 +2386,7 @@ powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;;
 powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
 rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
 arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;;
+s390-*-linux-*) TARGET=S390; TARGETDIR=s390;;
 esac
 
 if test $TARGETDIR = unknown; then
@@ -2501,8 +2502,17 @@ else
   ARM_FALSE=
 fi
 
+
+if test x$TARGET = xS390; then
+  S390_TRUE=
+  S390_FALSE='#'
+else
+  S390_TRUE='#'
+  S390_FALSE=
+fi
+
 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:2506: checking how to run the C preprocessor" >&5
+echo "configure:2516: checking how to run the C preprocessor" >&5
 # On Suns, sometimes $CPP names a directory.
 if test -n "$CPP" && test -d "$CPP"; then
   CPP=
@@ -2517,13 +2527,13 @@ else
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp.
   cat > conftest.$ac_ext <<EOF
-#line 2521 "configure"
+#line 2531 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2527: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2537: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -2534,13 +2544,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -E -traditional-cpp"
   cat > conftest.$ac_ext <<EOF
-#line 2538 "configure"
+#line 2548 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2544: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2554: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -2551,13 +2561,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -nologo -E"
   cat > conftest.$ac_ext <<EOF
-#line 2555 "configure"
+#line 2565 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2561: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2571: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -2582,12 +2592,12 @@ fi
 echo "$ac_t""$CPP" 1>&6
 
 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:2586: checking for ANSI C header files" >&5
+echo "configure:2596: checking for ANSI C header files" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2591 "configure"
+#line 2601 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -2595,7 +2605,7 @@ else
 #include <float.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2599: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2609: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -2612,7 +2622,7 @@ rm -f conftest*
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 2616 "configure"
+#line 2626 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -2630,7 +2640,7 @@ fi
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 2634 "configure"
+#line 2644 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -2651,7 +2661,7 @@ if test "$cross_compiling" = yes; then
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 2655 "configure"
+#line 2665 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -2662,7 +2672,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
 exit (0); }
 
 EOF
-if { (eval echo configure:2666: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2676: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   :
 else
@@ -2688,12 +2698,12 @@ fi
 for ac_func in memcpy
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2692: checking for $ac_func" >&5
+echo "configure:2702: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2697 "configure"
+#line 2707 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2716,7 +2726,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:2720: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2730: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -2743,19 +2753,19 @@ done
 # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
 # for constant arguments.  Useless!
 echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
-echo "configure:2747: checking for working alloca.h" >&5
+echo "configure:2757: checking for working alloca.h" >&5
 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2752 "configure"
+#line 2762 "configure"
 #include "confdefs.h"
 #include <alloca.h>
 int main() {
 char *p = alloca(2 * sizeof(int));
 ; return 0; }
 EOF
-if { (eval echo configure:2759: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2769: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_header_alloca_h=yes
 else
@@ -2776,12 +2786,12 @@ EOF
 fi
 
 echo $ac_n "checking for alloca""... $ac_c" 1>&6
-echo "configure:2780: checking for alloca" >&5
+echo "configure:2790: checking for alloca" >&5
 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2785 "configure"
+#line 2795 "configure"
 #include "confdefs.h"
 
 #ifdef __GNUC__
@@ -2809,7 +2819,7 @@ int main() {
 char *p = (char *) alloca(1);
 ; return 0; }
 EOF
-if { (eval echo configure:2813: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2823: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_func_alloca_works=yes
 else
@@ -2841,12 +2851,12 @@ EOF
 
 
 echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
-echo "configure:2845: checking whether alloca needs Cray hooks" >&5
+echo "configure:2855: checking whether alloca needs Cray hooks" >&5
 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2850 "configure"
+#line 2860 "configure"
 #include "confdefs.h"
 #if defined(CRAY) && ! defined(CRAY2)
 webecray
@@ -2871,12 +2881,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6
 if test $ac_cv_os_cray = yes; then
 for ac_func in _getb67 GETB67 getb67; do
   echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2875: checking for $ac_func" >&5
+echo "configure:2885: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2880 "configure"
+#line 2890 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2899,7 +2909,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:2903: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -2926,7 +2936,7 @@ done
 fi
 
 echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
-echo "configure:2930: checking stack direction for C alloca" >&5
+echo "configure:2940: checking stack direction for C alloca" >&5
 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2934,7 +2944,7 @@ else
   ac_cv_c_stack_direction=0
 else
   cat > conftest.$ac_ext <<EOF
-#line 2938 "configure"
+#line 2948 "configure"
 #include "confdefs.h"
 find_stack_direction ()
 {
@@ -2953,7 +2963,7 @@ main ()
   exit (find_stack_direction() < 0);
 }
 EOF
-if { (eval echo configure:2957: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2967: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_stack_direction=1
 else
@@ -2976,13 +2986,13 @@ fi
 
 
 echo $ac_n "checking size of short""... $ac_c" 1>&6
-echo "configure:2980: checking size of short" >&5
+echo "configure:2990: checking size of short" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   for ac_size in 4 8 1 2 16 12  ; do # List sizes in rough order of prevalence.
   cat > conftest.$ac_ext <<EOF
-#line 2986 "configure"
+#line 2996 "configure"
 #include "confdefs.h"
 #include "confdefs.h"
 #include <sys/types.h>
@@ -2992,7 +3002,7 @@ int main() {
 switch (0) case 0: case (sizeof (short) == $ac_size):;
 ; return 0; }
 EOF
-if { (eval echo configure:2996: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3006: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_sizeof_short=$ac_size
 else
@@ -3015,13 +3025,13 @@ EOF
 
 
 echo $ac_n "checking size of int""... $ac_c" 1>&6
-echo "configure:3019: checking size of int" >&5
+echo "configure:3029: checking size of int" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   for ac_size in 4 8 1 2 16 12  ; do # List sizes in rough order of prevalence.
   cat > conftest.$ac_ext <<EOF
-#line 3025 "configure"
+#line 3035 "configure"
 #include "confdefs.h"
 #include "confdefs.h"
 #include <sys/types.h>
@@ -3031,7 +3041,7 @@ int main() {
 switch (0) case 0: case (sizeof (int) == $ac_size):;
 ; return 0; }
 EOF
-if { (eval echo configure:3035: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3045: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_sizeof_int=$ac_size
 else
@@ -3054,13 +3064,13 @@ EOF
 
 
 echo $ac_n "checking size of long""... $ac_c" 1>&6
-echo "configure:3058: checking size of long" >&5
+echo "configure:3068: checking size of long" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   for ac_size in 4 8 1 2 16 12  ; do # List sizes in rough order of prevalence.
   cat > conftest.$ac_ext <<EOF
-#line 3064 "configure"
+#line 3074 "configure"
 #include "confdefs.h"
 #include "confdefs.h"
 #include <sys/types.h>
@@ -3070,7 +3080,7 @@ int main() {
 switch (0) case 0: case (sizeof (long) == $ac_size):;
 ; return 0; }
 EOF
-if { (eval echo configure:3074: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3084: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_sizeof_long=$ac_size
 else
@@ -3093,13 +3103,13 @@ EOF
 
 
 echo $ac_n "checking size of long long""... $ac_c" 1>&6
-echo "configure:3097: checking size of long long" >&5
+echo "configure:3107: checking size of long long" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_long_long'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   for ac_size in 4 8 1 2 16 12  ; do # List sizes in rough order of prevalence.
   cat > conftest.$ac_ext <<EOF
-#line 3103 "configure"
+#line 3113 "configure"
 #include "confdefs.h"
 #include "confdefs.h"
 #include <sys/types.h>
@@ -3109,7 +3119,7 @@ int main() {
 switch (0) case 0: case (sizeof (long long) == $ac_size):;
 ; return 0; }
 EOF
-if { (eval echo configure:3113: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3123: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_sizeof_long_long=$ac_size
 else
@@ -3132,13 +3142,13 @@ EOF
 
 
 echo $ac_n "checking size of float""... $ac_c" 1>&6
-echo "configure:3136: checking size of float" >&5
+echo "configure:3146: checking size of float" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_float'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   for ac_size in 4 8 1 2 16 12  ; do # List sizes in rough order of prevalence.
   cat > conftest.$ac_ext <<EOF
-#line 3142 "configure"
+#line 3152 "configure"
 #include "confdefs.h"
 #include "confdefs.h"
 #include <sys/types.h>
@@ -3148,7 +3158,7 @@ int main() {
 switch (0) case 0: case (sizeof (float) == $ac_size):;
 ; return 0; }
 EOF
-if { (eval echo configure:3152: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3162: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_sizeof_float=$ac_size
 else
@@ -3171,13 +3181,13 @@ EOF
 
 
 echo $ac_n "checking size of double""... $ac_c" 1>&6
-echo "configure:3175: checking size of double" >&5
+echo "configure:3185: checking size of double" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_double'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   for ac_size in 4 8 1 2 16 12  ; do # List sizes in rough order of prevalence.
   cat > conftest.$ac_ext <<EOF
-#line 3181 "configure"
+#line 3191 "configure"
 #include "confdefs.h"
 #include "confdefs.h"
 #include <sys/types.h>
@@ -3187,7 +3197,7 @@ int main() {
 switch (0) case 0: case (sizeof (double) == $ac_size):;
 ; return 0; }
 EOF
-if { (eval echo configure:3191: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3201: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_sizeof_double=$ac_size
 else
@@ -3210,13 +3220,13 @@ EOF
 
 
 echo $ac_n "checking size of long double""... $ac_c" 1>&6
-echo "configure:3214: checking size of long double" >&5
+echo "configure:3224: checking size of long double" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_long_double'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   for ac_size in 4 8 1 2 16 12  ; do # List sizes in rough order of prevalence.
   cat > conftest.$ac_ext <<EOF
-#line 3220 "configure"
+#line 3230 "configure"
 #include "confdefs.h"
 #include "confdefs.h"
 #include <sys/types.h>
@@ -3226,7 +3236,7 @@ int main() {
 switch (0) case 0: case (sizeof (long double) == $ac_size):;
 ; return 0; }
 EOF
-if { (eval echo configure:3230: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3240: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_sizeof_long_double=$ac_size
 else
@@ -3250,13 +3260,13 @@ EOF
 
 
 echo $ac_n "checking size of void *""... $ac_c" 1>&6
-echo "configure:3254: checking size of void *" >&5
+echo "configure:3264: checking size of void *" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_void_p'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   for ac_size in 4 8 1 2 16 12  ; do # List sizes in rough order of prevalence.
   cat > conftest.$ac_ext <<EOF
-#line 3260 "configure"
+#line 3270 "configure"
 #include "confdefs.h"
 #include "confdefs.h"
 #include <sys/types.h>
@@ -3266,7 +3276,7 @@ int main() {
 switch (0) case 0: case (sizeof (void *) == $ac_size):;
 ; return 0; }
 EOF
-if { (eval echo configure:3270: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3280: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_sizeof_void_p=$ac_size
 else
@@ -3289,14 +3299,14 @@ EOF
 
 
 echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
-echo "configure:3293: checking whether byte ordering is bigendian" >&5
+echo "configure:3303: checking whether byte ordering is bigendian" >&5
 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_cv_c_bigendian=unknown
 # See if sys/param.h defines the BYTE_ORDER macro.
 cat > conftest.$ac_ext <<EOF
-#line 3300 "configure"
+#line 3310 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -3307,11 +3317,11 @@ int main() {
 #endif
 ; return 0; }
 EOF
-if { (eval echo configure:3311: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3321: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   # It does; now see whether it defined to BIG_ENDIAN or not.
 cat > conftest.$ac_ext <<EOF
-#line 3315 "configure"
+#line 3325 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -3322,7 +3332,7 @@ int main() {
 #endif
 ; return 0; }
 EOF
-if { (eval echo configure:3326: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3336: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_bigendian=yes
 else
@@ -3342,7 +3352,7 @@ if test "$cross_compiling" = yes; then
    echo $ac_n "cross-compiling... " 2>&6 
 else
   cat > conftest.$ac_ext <<EOF
-#line 3346 "configure"
+#line 3356 "configure"
 #include "confdefs.h"
 main () {
   /* Are we little or big endian?  From Harbison&Steele.  */
@@ -3355,7 +3365,7 @@ main () {
   exit (u.c[sizeof (long) - 1] == 1);
 }
 EOF
-if { (eval echo configure:3359: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3369: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_bigendian=no
 else
@@ -3373,7 +3383,7 @@ fi
 echo "$ac_t""$ac_cv_c_bigendian" 1>&6
 if test $ac_cv_c_bigendian = unknown; then
 echo $ac_n "checking to probe for byte ordering""... $ac_c" 1>&6
-echo "configure:3377: checking to probe for byte ordering" >&5
+echo "configure:3387: checking to probe for byte ordering" >&5
 
 cat >conftest.c <<EOF
 short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
@@ -3423,7 +3433,7 @@ fi
 
 if test x$TARGET == xSPARC; then
     echo $ac_n "checking assembler and linker support unaligned pc related relocs""... $ac_c" 1>&6
-echo "configure:3426: checking assembler and linker support unaligned pc related relocs" >&5
+echo "configure:3437: checking assembler and linker support unaligned pc related relocs" >&5
 if eval "test \"`echo '$''{'libffi_cv_as_sparc_ua_pcrel'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3433,14 +3443,14 @@ else
 	CFLAGS="$CFLAGS -fpic"
 	LDFLAGS="$LDFLAGS -shared"
 	cat > conftest.$ac_ext <<EOF
-#line 3436 "configure"
+#line 3447 "configure"
 #include "confdefs.h"
 asm (".text; foo: nop; .data; .align 4; .byte 0; .uaword %r_disp32(foo); .text");
 int main() {
 
 ; return 0; }
 EOF
-if { (eval echo configure:3442: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:3454: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   libffi_cv_as_sparc_ua_pcrel=yes
 else
@@ -3721,6 +3731,8 @@ s%@POWERPC_DARWIN_TRUE@%$POWERPC_DARWIN_TRUE%g
 s%@POWERPC_DARWIN_FALSE@%$POWERPC_DARWIN_FALSE%g
 s%@ARM_TRUE@%$ARM_TRUE%g
 s%@ARM_FALSE@%$ARM_FALSE%g
+s%@S390_TRUE@%$S390_TRUE%g
+s%@S390_FALSE@%$S390_FALSE%g
 s%@CPP@%$CPP%g
 s%@ALLOCA@%$ALLOCA%g
 s%@TARGET@%$TARGET%g
diff --git a/libffi/configure.in b/libffi/configure.in
index 9e9ab1c14251..b2cb516b84ac 100644
--- a/libffi/configure.in
+++ b/libffi/configure.in
@@ -61,6 +61,7 @@ powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;;
 powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
 rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;;
 arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;;
+s390-*-linux-*) TARGET=S390; TARGETDIR=s390;;
 esac
 
 if test $TARGETDIR = unknown; then
@@ -79,6 +80,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(ARM, test x$TARGET = xARM)
+AM_CONDITIONAL(S390, test x$TARGET = xS390)
 
 AC_HEADER_STDC
 AC_CHECK_FUNCS(memcpy)
diff --git a/libffi/include/Makefile.in b/libffi/include/Makefile.in
index 4f75451d5f72..13aa274f4055 100644
--- a/libffi/include/Makefile.in
+++ b/libffi/include/Makefile.in
@@ -99,7 +99,7 @@ DIST_COMMON =  Makefile.am Makefile.in ffi.h.in
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = gnutar
+TAR = gtar
 GZIP_ENV = --best
 all: all-redirect
 .SUFFIXES:
diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in
index 8097917fe105..90dfa5189b94 100644
--- a/libffi/include/ffi.h.in
+++ b/libffi/include/ffi.h.in
@@ -251,6 +251,12 @@ typedef enum ffi_abi {
   FFI_DEFAULT_ABI = FFI_SYSV,
 #endif
 
+  /* ---- S390 --------------------- */
+#ifdef S390
+  FFI_SYSV,
+  FFI_DEFAULT_ABI = FFI_SYSV,
+#endif
+
   /* Leave this for debugging purposes */
   FFI_LAST_ABI
 
diff --git a/libffi/src/s390/ffi.c b/libffi/src/s390/ffi.c
new file mode 100644
index 000000000000..8b514e36c266
--- /dev/null
+++ b/libffi/src/s390/ffi.c
@@ -0,0 +1,589 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 2000 Software AG
+ 
+   S390 Foreign Function Interface
+ 
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+ 
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+ 
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+/*====================================================================*/
+/*                          Includes                                  */
+/*                          --------                                  */
+/*====================================================================*/
+ 
+#include <ffi.h>
+#include <ffi_common.h>
+ 
+#include <stdlib.h>
+#include <stdio.h>
+ 
+/*====================== End of Includes =============================*/
+ 
+/*====================================================================*/
+/*                           Defines                                  */
+/*                           -------                                  */
+/*====================================================================*/
+ 
+#define MAX_GPRARGS 5        /* Max. no. of GPR available             */
+#define MAX_FPRARGS 2        /* Max. no. of FPR available             */
+ 
+#define STR_GPR     1        /* Structure will fit in 1 or 2 GPR      */
+#define STR_FPR     2        /* Structure will fit in a FPR           */
+#define STR_STACK   3        /* Structure needs to go on stack        */
+ 
+/*===================== End of Defines ===============================*/
+ 
+/*====================================================================*/
+/*                            Types                                   */
+/*                            -----                                   */
+/*====================================================================*/
+ 
+typedef struct stackLayout
+{
+  int   *backChain;
+  int   *endOfStack;
+  int   glue[2];
+  int   scratch[2];
+  int   gprArgs[MAX_GPRARGS];
+  int   notUsed;
+  union
+  {
+    float  f;
+    double d;
+  } fprArgs[MAX_FPRARGS];
+  int   unUsed[8];
+  int   outArgs[100];
+} stackLayout;
+ 
+/*======================== End of Types ==============================*/
+ 
+/*====================================================================*/
+/*                          Prototypes                                */
+/*                          ----------                                */
+/*====================================================================*/
+ 
+void ffi_prep_args(stackLayout *, extended_cif *);
+static int  ffi_check_struct(ffi_type *, unsigned int *);
+static void ffi_insert_int(int, stackLayout *, int *, int *);
+static void ffi_insert_int64(long long, stackLayout *, int *, int *);
+static void ffi_insert_double(double, stackLayout *, int *, int *);
+ 
+/*====================== End of Prototypes ===========================*/
+ 
+/*====================================================================*/
+/*                          Externals                                 */
+/*                          ---------                                 */
+/*====================================================================*/
+ 
+extern void ffi_call_SYSV(void (*)(stackLayout *, extended_cif *),
+			  extended_cif *,
+			  unsigned, unsigned,
+			  unsigned *,
+			  void (*fn)());
+ 
+/*====================== End of Externals ============================*/
+ 
+/*====================================================================*/
+/*                                                                    */
+/* Name     - ffi_check_struct.                                       */
+/*                                                                    */
+/* Function - Determine if a structure can be passed within a         */
+/*            general or floating point register.                     */
+/*                                                                    */
+/*====================================================================*/
+ 
+int
+ffi_check_struct(ffi_type *arg, unsigned int *strFlags)
+{
+ ffi_type *element;
+ int      i_Element;
+ 
+ for (i_Element = 0; arg->elements[i_Element]; i_Element++) {
+   element = arg->elements[i_Element];
+   switch (element->type) {
+   case FFI_TYPE_DOUBLE :
+     *strFlags |= STR_FPR;
+     break;
+     
+   case FFI_TYPE_STRUCT :
+     *strFlags |= ffi_check_struct(element, strFlags);
+     break;
+     
+   default :
+     *strFlags |= STR_GPR;
+   }
+ }
+ return (*strFlags);
+}
+ 
+/*======================== End of Routine ============================*/
+ 
+/*====================================================================*/
+/*                                                                    */
+/* Name     - ffi_insert_int.                                         */
+/*                                                                    */
+/* Function - Insert an integer parameter in a register if there are  */
+/*            spares else on the stack.                               */
+/*                                                                    */
+/*====================================================================*/
+ 
+void
+ffi_insert_int(int gprValue, stackLayout *stack,
+               int *intArgC, int *outArgC)
+{
+  if (*intArgC < MAX_GPRARGS) {
+    stack->gprArgs[*intArgC] = gprValue;
+    *intArgC += 1;
+  }
+  else {
+    stack->outArgs[*outArgC++] = gprValue;
+    *outArgC += 1;
+  }
+}
+ 
+/*======================== End of Routine ============================*/
+ 
+/*====================================================================*/
+/*                                                                    */
+/* Name     - ffi_insert_int64.                                       */
+/*                                                                    */
+/* Function - Insert a long long parameter in registers if there are  */
+/*            spares else on the stack.                               */
+/*                                                                    */
+/*====================================================================*/
+ 
+void
+ffi_insert_int64(long long llngValue, stackLayout *stack,
+                 int *intArgC, int *outArgC)
+{
+ 
+  if (*intArgC < (MAX_GPRARGS-1)) {
+    memcpy(&stack->gprArgs[*intArgC],
+	   &llngValue, sizeof(long long));	
+    *intArgC += 2;
+  }
+  else {
+    memcpy(&stack->outArgs[*outArgC],
+	   &llngValue, sizeof(long long));
+    *outArgC += 2;
+  }
+ 
+}
+ 
+/*======================== End of Routine ============================*/
+ 
+/*====================================================================*/
+/*                                                                    */
+/* Name     - ffi_insert_double.                                      */
+/*                                                                    */
+/* Function - Insert a double parameter in a FP register if there is  */
+/*            a spare else on the stack.                              */
+/*                                                                    */
+/*====================================================================*/
+ 
+void
+ffi_insert_double(double dblValue, stackLayout *stack,
+                  int *fprArgC, int *outArgC)
+{
+ 
+  if (*fprArgC < MAX_FPRARGS) {
+    stack->fprArgs[*fprArgC].d = dblValue;
+    *fprArgC += 1;
+  }
+  else {
+    memcpy(&stack->outArgs[*outArgC],
+	   &dblValue,sizeof(double));
+    *outArgC += 2;
+  }
+ 
+}
+ 
+/*======================== End of Routine ============================*/
+ 
+/*====================================================================*/
+/*                                                                    */
+/* Name     - ffi_prep_args.                                          */
+/*                                                                    */
+/* Function - Prepare parameters for call to function.                */
+/*                                                                    */
+/* ffi_prep_args is called by the assembly routine once stack space   */
+/* has been allocated for the function's arguments.                   */
+/*                                                                    */
+/* The stack layout we want looks like this:                          */
+/* *------------------------------------------------------------*     */
+/* |  0     | Back chain (a 0 here signifies end of back chain) |     */
+/* +--------+---------------------------------------------------+     */
+/* |  4     | EOS (end of stack, not used on Linux for S390)    |     */
+/* +--------+---------------------------------------------------+     */
+/* |  8     | Glue used in other linkage formats                |     */
+/* +--------+---------------------------------------------------+     */
+/* | 12     | Glue used in other linkage formats                |     */
+/* +--------+---------------------------------------------------+     */
+/* | 16     | Scratch area                                      |     */
+/* +--------+---------------------------------------------------+     */
+/* | 20     | Scratch area                                      |     */
+/* +--------+---------------------------------------------------+     */
+/* | 24     | GPR parameter register 1                          |     */
+/* +--------+---------------------------------------------------+     */
+/* | 28     | GPR parameter register 2                          |     */
+/* +--------+---------------------------------------------------+     */
+/* | 32     | GPR parameter register 3                          |     */
+/* +--------+---------------------------------------------------+     */
+/* | 36     | GPR parameter register 4                          |     */
+/* +--------+---------------------------------------------------+     */
+/* | 40     | GPR parameter register 5                          |     */
+/* +--------+---------------------------------------------------+     */
+/* | 44     | Unused                                            |     */
+/* +--------+---------------------------------------------------+     */
+/* | 48     | FPR parameter register 1                          |     */
+/* +--------+---------------------------------------------------+     */
+/* | 56     | FPR parameter register 2                          |     */
+/* +--------+---------------------------------------------------+     */
+/* | 64     | Unused                                            |     */
+/* +--------+---------------------------------------------------+     */
+/* | 96     | Outgoing args (length x)                          |     */
+/* +--------+---------------------------------------------------+     */
+/* | 96+x   | Copy area for structures (length y)               |     */
+/* +--------+---------------------------------------------------+     */
+/* | 96+x+y | Possible stack alignment                          |     */
+/* *------------------------------------------------------------*     */
+/*                                                                    */
+/*====================================================================*/
+ 
+void
+ffi_prep_args(stackLayout *stack, extended_cif *ecif)
+{
+  const unsigned bytes = ecif->cif->bytes;
+  const unsigned flags = ecif->cif->flags;
+ 
+  /*----------------------------------------------------------*/
+  /* Pointer to the copy area on stack for structures         */
+  /*----------------------------------------------------------*/
+  char *copySpace = (char *) stack + bytes + sizeof(stackLayout);
+ 
+  /*----------------------------------------------------------*/
+  /* Count of general and floating point register usage       */
+  /*----------------------------------------------------------*/
+  int intArgC = 0,
+    fprArgC = 0,
+    outArgC = 0;
+ 
+  int      i;
+  ffi_type **ptr;
+  void     **p_argv;
+  size_t   structCopySize;
+  unsigned gprValue, strFlags = 0;
+  unsigned long long llngValue;
+  double   dblValue;
+ 
+  /* Now for the arguments.  */
+  p_argv  = ecif->avalue;
+ 
+  /*----------------------------------------------------------------------*/
+  /* If we returning a structure then we set the first parameter register */
+  /* to the address of where we are returning this structure              */
+  /*----------------------------------------------------------------------*/
+  if (flags == FFI_TYPE_STRUCT)
+    stack->gprArgs[intArgC++] = (int) ecif->rvalue;
+ 
+  for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
+       i > 0;
+       i--, ptr++, p_argv++)
+    {
+      switch ((*ptr)->type) {
+ 
+      case FFI_TYPE_FLOAT:
+	if (fprArgC < MAX_FPRARGS)
+	  stack->fprArgs[fprArgC++].f = *(float *) *p_argv;
+	else
+	  stack->outArgs[outArgC++] = *(int *) *p_argv;
+	break;
+ 
+      case FFI_TYPE_DOUBLE:
+	dblValue = *(double *) *p_argv;
+	ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
+	break;
+	
+      case FFI_TYPE_UINT64:
+      case FFI_TYPE_SINT64:
+	llngValue = *(unsigned long long *) *p_argv;
+	ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
+	break;
+ 
+      case FFI_TYPE_UINT8:
+	gprValue = *(unsigned char *)*p_argv;
+	ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+	break;
+ 
+      case FFI_TYPE_SINT8:
+	gprValue = *(signed char *)*p_argv;
+	ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+	break;
+ 
+      case FFI_TYPE_UINT16:
+	gprValue = *(unsigned short *)*p_argv;
+	ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+	break;
+ 
+      case FFI_TYPE_SINT16:
+	gprValue = *(signed short *)*p_argv;
+	ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+	break;
+ 
+      case FFI_TYPE_STRUCT:
+	/*--------------------------------------------------*/
+	/* If structure > 8 bytes then it goes on the stack */
+	/*--------------------------------------------------*/
+	if (((*ptr)->size > 8) ||
+	    ((*ptr)->size > 4  &&
+	     (*ptr)->size < 8))
+	  strFlags = STR_STACK;
+	else
+	  strFlags = ffi_check_struct((ffi_type *) *ptr, &strFlags);
+ 
+	switch (strFlags) {
+	/*-------------------------------------------*/
+	/* Structure that will fit in one or two GPR */
+	/*-------------------------------------------*/
+	case STR_GPR :
+	  if ((*ptr)->size <= 4) {
+	    gprValue = *(unsigned int *) *p_argv;
+	    gprValue = gprValue >> ((4 - (*ptr)->size) * 8);
+	    ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+	  }
+	  else {
+	    llngValue = *(unsigned long long *) *p_argv;
+	    ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
+	  }
+	  break;
+ 
+	/*-------------------------------------------*/
+	/* Structure that will fit in one FPR        */
+	/*-------------------------------------------*/
+	case STR_FPR :
+	  dblValue = *(double *) *p_argv;
+	  ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
+	  break;
+ 
+	/*-------------------------------------------*/
+	/* Structure that must be copied to stack    */
+	/*-------------------------------------------*/
+	default :
+	  structCopySize = (((*ptr)->size + 15) & ~0xF);
+	  copySpace -= structCopySize;
+	  memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
+	  gprValue = (unsigned) copySpace;
+	  if (intArgC < MAX_GPRARGS)
+	    stack->gprArgs[intArgC++] = gprValue;
+	  else
+	    stack->outArgs[outArgC++] = gprValue;
+	}
+	break;
+ 
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+      case FFI_TYPE_LONGDOUBLE:
+	structCopySize = (((*ptr)->size + 15) & ~0xF);
+	copySpace -= structCopySize;
+	memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
+	gprValue = (unsigned) copySpace;
+	if (intArgC < MAX_GPRARGS)
+	  stack->gprArgs[intArgC++] = gprValue;
+	else
+	  stack->outArgs[outArgC++] = gprValue;
+	break;
+#endif
+ 
+      case FFI_TYPE_INT:
+      case FFI_TYPE_UINT32:
+      case FFI_TYPE_SINT32:
+      case FFI_TYPE_POINTER:
+	gprValue = *(unsigned *)*p_argv;
+	if (intArgC < MAX_GPRARGS)
+	  stack->gprArgs[intArgC++] = gprValue;
+	else
+	  stack->outArgs[outArgC++] = gprValue;
+	break;
+ 
+      }
+    }
+}
+
+/*======================== End of Routine ============================*/
+ 
+/*====================================================================*/
+/*                                                                    */
+/* Name     - ffi_prep_cif_machdep.                                   */
+/*                                                                    */
+/* Function - Perform machine dependent CIF processing.               */
+/*                                                                    */
+/*====================================================================*/
+ 
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+  int i;
+  ffi_type **ptr;
+  unsigned bytes;
+  int fpArgC  = 0,
+    intArgC = 0;
+  unsigned flags = 0;
+  unsigned structCopySize = 0;
+ 
+  /*-----------------------------------------------------------------*/
+  /* Extra space required in stack for overflow parameters.          */
+  /*-----------------------------------------------------------------*/
+  bytes = 0;
+ 
+  /*--------------------------------------------------------*/
+  /* Return value handling.  The rules are as follows:	    */
+  /* - 32-bit (or less) integer values are returned in gpr2 */
+  /* - Structures are returned as pointers in gpr2	    */
+  /* - 64-bit integer values are returned in gpr2 and 3	    */
+  /* - Single/double FP values are returned in fpr0	    */
+  /*--------------------------------------------------------*/
+  flags = cif->rtype->type;
+ 
+  /*------------------------------------------------------------------------*/
+  /* The first MAX_GPRARGS words of integer arguments, and the      	    */
+  /* first MAX_FPRARGS floating point arguments, go in registers; the rest  */
+  /* goes on the stack.  Structures and long doubles (if not equivalent     */
+  /* to double) are passed as a pointer to a copy of the structure.	    */
+  /* Stuff on the stack needs to keep proper alignment.  		    */
+  /*------------------------------------------------------------------------*/
+  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+    {
+      switch ((*ptr)->type)
+	{
+	case FFI_TYPE_FLOAT:
+	case FFI_TYPE_DOUBLE:
+	  fpArgC++;
+	  if (fpArgC > MAX_FPRARGS && intArgC%2 != 0)
+	    intArgC++;
+	  break;
+ 
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_SINT64:
+	  /*----------------------------------------------------*/
+	  /* 'long long' arguments are passed as two words, but */
+	  /* either both words must fit in registers or both go */
+	  /* on the stack.  If they go on the stack, they must  */
+	  /* be 8-byte-aligned. 			 	      */
+	  /*----------------------------------------------------*/
+	  if ((intArgC == MAX_GPRARGS-1) ||
+	      (intArgC >= MAX_GPRARGS)   &&
+	      (intArgC%2 != 0))
+	    intArgC++;
+	  intArgC += 2;
+	  break;
+ 
+	case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+	case FFI_TYPE_LONGDOUBLE:
+#endif
+	  /*----------------------------------------------------*/
+	  /* We must allocate space for a copy of these to      */
+	  /* enforce pass-by-value. Pad the space up to a       */
+	  /* multiple of 16 bytes (the maximum alignment 	      */
+	  /* required for anything under the SYSV ABI). 	      */
+	  /*----------------------------------------------------*/
+	  structCopySize += ((*ptr)->size + 15) & ~0xF;
+	  /*----------------------------------------------------*/
+	  /* Fall through (allocate space for the pointer).     */
+	  /*----------------------------------------------------*/
+ 
+	default:
+	  /*----------------------------------------------------*/
+	  /* Everything else is passed as a 4-byte word in a    */
+	  /* GPR either the object itself or a pointer to it.   */
+	  /*----------------------------------------------------*/
+	  intArgC++;
+	  break;
+	}
+    }
+ 
+  /*-----------------------------------------------------------------*/
+  /* Stack space.                                                    */
+  /*-----------------------------------------------------------------*/
+  if (intArgC > MAX_GPRARGS)
+    bytes += (intArgC - MAX_GPRARGS) * sizeof(int);
+  if (fpArgC > MAX_FPRARGS)
+    bytes += (fpArgC - MAX_FPRARGS) * sizeof(double);
+ 
+  /*-----------------------------------------------------------------*/
+  /* The stack space allocated needs to be a multiple of 16 bytes.   */
+  /*-----------------------------------------------------------------*/
+  bytes = (bytes + 15) & ~0xF;
+ 
+  /*-----------------------------------------------------------------*/
+  /* Add in the space for the copied structures.                     */
+  /*-----------------------------------------------------------------*/
+  bytes += structCopySize;
+ 
+  cif->flags = flags;
+  cif->bytes = bytes;
+ 
+  return FFI_OK;
+}
+ 
+/*======================== End of Routine ============================*/
+ 
+/*====================================================================*/
+/*                                                                    */
+/* Name     - ffi_call.                                               */
+/*                                                                    */
+/* Function - Call the FFI routine.                                   */
+/*                                                                    */
+/*====================================================================*/
+ 
+void
+ffi_call(ffi_cif *cif,
+	 void (*fn)(),
+	 void *rvalue,
+	 void **avalue)
+{
+  extended_cif ecif;
+ 
+  ecif.cif    = cif;
+  ecif.avalue = avalue;
+ 
+  /*-----------------------------------------------------------------*/
+  /* If the return value is a struct and we don't have a return      */
+  /* value address then we need to make one                          */
+  /*-----------------------------------------------------------------*/
+  if ((rvalue == NULL) &&
+      (cif->rtype->type == FFI_TYPE_STRUCT))
+    ecif.rvalue = alloca(cif->rtype->size);
+  else
+    ecif.rvalue = rvalue;
+ 
+  switch (cif->abi)
+    {
+    case FFI_SYSV:
+      ffi_call_SYSV(ffi_prep_args,
+		    &ecif, cif->bytes,
+		    cif->flags, ecif.rvalue, fn);
+      break;
+ 
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+}
+ 
+/*======================== End of Routine ============================*/
diff --git a/libffi/src/s390/sysv.S b/libffi/src/s390/sysv.S
new file mode 100644
index 000000000000..afaf1ea1ca30
--- /dev/null
+++ b/libffi/src/s390/sysv.S
@@ -0,0 +1,161 @@
+/* -----------------------------------------------------------------------
+   sysv.S - Copyright (c) 2000 Software AG
+ 
+   S390 Foreign Function Interface
+ 
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   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 CYGNUS SOLUTIONS 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 <ffi.h>
+#ifdef HAVE_MACHINE_ASM_H
+#include <machine/asm.h>
+#endif
+	
+.text
+ 
+	# r2:	ffi_prep_args
+	# r3:	&ecif
+	# r4:	cif->bytes
+	# r5:	fig->flags
+	# r6:	ecif.rvalue
+	# sp+0: fn
+ 
+	# This assumes we are using gas.
+	.globl	ffi_call_SYSV
+	.type	ffi_call_SYSV,%function
+ffi_call_SYSV:
+	# Save registers
+	stm	%r7,%r15,28(%r15)
+	l	%r7,96(%r15)	       # Get A(fn)
+	lr	%r0,%r15
+	ahi	%r15,-128	       # Make room for my args
+	st	%r0,0(%r15)	       # Set backchain
+	lr	%r11,%r15	       # Establish my stack register
+	sr	%r15,%r4	       # Make room for fn args
+	ahi	%r15,-96	       # Make room for new frame
+	lr	%r10,%r15	       # Establish stack build area
+	ahi	%r15,-96	       # Stack for next call
+	lr	%r1,%r7
+	stm	%r2,%r7,96(%r11)       # Save args on my stack
+ 
+#------------------------------------------------------------------
+#	move first 3 parameters in registers
+#------------------------------------------------------------------
+	lr	%r9,%r2		       # r9:	 &ffi_prep_args
+	lr	%r2,%r10	       # Parm 1: &stack Parm 2: &ecif
+	basr	%r14,%r9	       # call ffi_prep_args
+ 
+#------------------------------------------------------------------
+#	load  first 5 parameter registers
+#------------------------------------------------------------------
+	lm	%r2,%r6,24(%r10)
+ 
+#------------------------------------------------------------------
+#	load  fp parameter registers
+#------------------------------------------------------------------
+	ld	%f0,48(%r10)
+	ld	%f2,56(%r10)
+ 
+#------------------------------------------------------------------
+#	call  function
+#------------------------------------------------------------------
+	lr	%r15,%r10	       # Set new stack
+	l	%r9,116(%r11)	       # Get &fn
+	basr	%r14,%r9	       # Call function
+ 
+#------------------------------------------------------------------
+#	On return:
+#	   r2: Return value (r3: Return value + 4 for long long)
+#------------------------------------------------------------------
+ 
+#------------------------------------------------------------------
+#	If the return value pointer is NULL, assume no return value.
+#------------------------------------------------------------------
+	icm	%r6,15,112(%r11)
+	jz	.Lepilogue
+ 
+	l	%r5,108(%r11)	       # Get return type
+#------------------------------------------------------------------
+#	return INT
+#------------------------------------------------------------------
+	chi	%r5,FFI_TYPE_INT
+	jne	.Lchk64
+ 
+	st	%r2,0(%r6)
+	j	.Lepilogue
+ 
+.Lchk64:
+#------------------------------------------------------------------
+#	return LONG LONG (signed/unsigned)
+#------------------------------------------------------------------
+	chi	%r5,FFI_TYPE_UINT64
+	je	.LdoLongLong
+ 
+	chi	%r5,FFI_TYPE_SINT64
+	jne	.LchkFloat
+ 
+.LdoLongLong:
+	stm	%r2,%r3,0(%r6)
+	j	.Lepilogue
+ 
+.LchkFloat:
+#------------------------------------------------------------------
+#	return FLOAT
+#------------------------------------------------------------------
+	chi	%r5,FFI_TYPE_FLOAT
+	jne	.LchkDouble
+ 
+	std	%f0,0(%r6)
+	j	.Lepilogue
+ 
+.LchkDouble:
+#------------------------------------------------------------------
+#	return DOUBLE or LONGDOUBLE
+#------------------------------------------------------------------
+	chi	%r5,FFI_TYPE_DOUBLE
+	jne	.LchkStruct
+ 
+	std	%f0,0(%r6)
+	std	%f2,8(%r6)
+	j	.Lepilogue
+ 
+.LchkStruct:
+#------------------------------------------------------------------
+# Structure - rvalue already set as sent as 1st parm to routine
+#------------------------------------------------------------------
+	chi	%r5,FFI_TYPE_STRUCT
+	je	.Lepilogue
+ 
+.Ldefault:
+#------------------------------------------------------------------
+#	return a pointer
+#------------------------------------------------------------------
+	st	%r2,0(%r6)
+	j	.Lepilogue
+ 
+.Lepilogue:
+	l	%r15,0(%r11)
+	l	%r4,56(%r15)
+	lm	%r7,%r15,28(%r15)
+	br	%r4
+ 
+.ffi_call_SYSV_end:
+	.size	 ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
-- 
GitLab