#! /bin/sh -e

# All lines beginning with `# DPATCH:' are a description of the patch.
# DP: libffi support for hppa

dir=
if [ $# -eq 3 -a "$2" = '-d' ]; then
    pdir="-d $3"
    dir="$3/"
elif [ $# -ne 1 ]; then
    echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
    exit 1
fi
case "$1" in
    -patch)
        patch $pdir -f --no-backup-if-mismatch -p0 < $0
        cd ${dir}libffi && autoconf2.13
        ;;
    -unpatch)
        patch $pdir -f --no-backup-if-mismatch -R -p0 < $0
        rm ${dir}libffi/configure
        ;;
    *)
        echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
        exit 1
esac
exit 0

2004-02-10  Randolph Chung  <tausq@debian.org>

	* Makefile.am: Add PA support.
	* Makefile.in: Regenerate.
	* include/Makefile.in: Regenerate.
	* configure.in: Add PA target.
	* configure: Regenerate.
	* src/pa/ffi.c: New file.
	* src/pa/ffi.h.in: Add PA support.
	* src/pa/linux.S: New file.
	* prep_cif.c: Add PA support.

diff -urN libffi.old/Makefile.am libffi/Makefile.am
--- libffi.old/Makefile.am	2003-01-28 02:44:57.000000000 +0100
+++ libffi/Makefile.am	2004-03-20 13:12:06.000000000 +0100
@@ -18,7 +18,8 @@
 		src/powerpc/darwin_closure.S src/powerpc/aix_closures.S \
 		src/arm/ffi.c src/arm/sysv.S \
 		src/s390/ffi.c src/s390/sysv.S \
-		src/sh/ffi.c src/sh/sysv.S
+		src/sh/ffi.c src/sh/sysv.S \
+		src/pa/ffi.c src/pa/linux.S
 
 VPATH = @srcdir@:@srcdir@/src:@srcdir@/src/@TARGETDIR@
 
@@ -101,6 +102,7 @@
 TARGET_SRC_S390 =  src/s390/sysv.S src/s390/ffi.c
 TARGET_SRC_X86_64 = src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S
 TARGET_SRC_SH =  src/sh/sysv.S src/sh/ffi.c
+TARGET_SRC_PA =  src/pa/linux.S src/pa/ffi.c
 
 ##libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c $(TARGET_SRC_@TARGET@)
 ## Work around automake deficiency
@@ -170,6 +172,10 @@
 libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_SH)
 libfficonvenience_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_SH)
 endif
+if PA
+libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_PA)
+libffi_convenience_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_PA)
+endif
 
 AM_CFLAGS = -fexceptions
 
diff -urN libffi.old/Makefile.in libffi/Makefile.in
--- libffi.old/Makefile.in	2003-01-28 02:44:57.000000000 +0100
+++ libffi/Makefile.in	2004-03-20 13:12:06.000000000 +0100
@@ -94,6 +94,7 @@
 		src/x86/ffi64.c src/x86/unix64.S \
 		src/alpha/ffi.c src/alpha/osf.S \
 		src/m68k/ffi.c src/m68k/sysv.S \
+		src/pa/ffi.c src/pa/linux.S \
 		src/powerpc/ffi.c src/powerpc/sysv.S \
 		src/powerpc/ppc_closure.S src/powerpc/asm.h \
 		src/powerpc/ffi_darwin.c \
@@ -180,6 +181,7 @@
 TARGET_SRC_S390 = src/s390/sysv.S src/s390/ffi.c
 TARGET_SRC_X86_64 = src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S
 TARGET_SRC_SH = src/sh/sysv.S src/sh/ffi.c
+TARGET_SRC_PA = src/pa/linux.S src/pa/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
@@ -200,6 +202,7 @@
 @S390_TRUE@libffi_la_SOURCES = @S390_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
 @X86_64_TRUE@libffi_la_SOURCES = @X86_64_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64)
 @SH_TRUE@libffi_la_SOURCES = @SH_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_SH)
+@PA_TRUE@libffi_la_SOURCES = @PA_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_PA)
 @MIPS_GCC_TRUE@libffi_convenience_la_SOURCES = @MIPS_GCC_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_GCC)
 @MIPS_LINUX_TRUE@libffi_convenience_la_SOURCES = @MIPS_LINUX_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_LINUX)
 @MIPS_SGI_TRUE@libffi_convenience_la_SOURCES = @MIPS_SGI_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_SGI)
@@ -216,6 +219,7 @@
 @S390_TRUE@libffi_convenience_la_SOURCES = @S390_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_S390)
 @X86_64_TRUE@libffi_convenience_la_SOURCES = @X86_64_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_X86_64)
 @SH_TRUE@libfficonvenience_la_SOURCES = @SH_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_SH)
+@PA_TRUE@libffi_convenience_la_SOURCES = @PA_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_PA)
 
 AM_CFLAGS = -fexceptions
 
@@ -238,6 +242,9 @@
 @ALPHA_TRUE@libffi_convenience_la_OBJECTS =  src/debug.lo \
 @ALPHA_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \
 @ALPHA_TRUE@src/java_raw_api.lo src/alpha/ffi.lo src/alpha/osf.lo
+@PA_TRUE@libffi_convenience_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
+@PA_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
+@PA_TRUE@src/pa/linux.lo src/pa/ffi.lo
 @IA64_TRUE@libffi_convenience_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @IA64_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @IA64_TRUE@src/ia64/ffi.lo src/ia64/unix.lo
@@ -292,6 +299,9 @@
 @SH_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo src/types.lo \
 @SH_TRUE@src/raw_api.lo src/java_raw_api.lo src/sh/sysv.lo \
 @SH_TRUE@src/sh/ffi.lo
+@PA_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo src/types.lo \
+@PA_TRUE@src/raw_api.lo src/java_raw_api.lo \
+@PA_TRUE@src/pa/linux.lo src/pa/ffi.lo
 @IA64_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @IA64_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @IA64_TRUE@src/ia64/ffi.lo src/ia64/unix.lo
@@ -615,7 +625,7 @@
 	mkdir $(distdir)
 	-chmod 777 $(distdir)
 	$(mkinstalldirs) $(distdir)/src/alpha $(distdir)/src/arm \
-	   $(distdir)/src/m68k $(distdir)/src/mips \
+	   $(distdir)/src/m68k $(distdir)/src/mips $(distdir)/src/pa \
 	   $(distdir)/src/powerpc $(distdir)/src/s390 $(distdir)/src/sh \
 	   $(distdir)/src/sparc $(distdir)/src/x86
 	@for file in $(DISTFILES); do \
diff -urN libffi.old/configure.in libffi/configure.in
--- libffi.old/configure.in	2003-08-09 08:59:00.000000000 +0200
+++ libffi/configure.in	2004-03-20 13:12:06.000000000 +0100
@@ -75,6 +75,7 @@
 s390x-*-linux-*) TARGET=S390; TARGETDIR=s390;;
 x86_64-*-linux*) TARGET=X86_64; TARGETDIR=x86;;
 sh-*-linux* | sh[[34]]*-*-linux*) TARGET=SH; TARGETDIR=sh;;
+hppa-*-linux* | parisc-*-linux*) TARGET=PA; TARGETDIR=pa;;
 esac
 
 if test $TARGETDIR = unknown; then
@@ -97,6 +98,7 @@
 AM_CONDITIONAL(S390, test x$TARGET = xS390)
 AM_CONDITIONAL(X86_64, test x$TARGET = xX86_64)
 AM_CONDITIONAL(SH, test x$TARGET = xSH)
+AM_CONDITIONAL(PA, test x$TARGET = xPA)
 
 if test x$TARGET = xMIPS_LINUX; then
   TARGET=MIPS
diff -urN libffi.old/include/ffi.h.in libffi/include/ffi.h.in
--- libffi.old/include/ffi.h.in	2003-03-22 12:57:33.000000000 +0100
+++ libffi/include/ffi.h.in	2004-03-20 13:12:06.000000000 +0100
@@ -283,6 +283,12 @@
   FFI_DEFAULT_ABI = FFI_SYSV,
 #endif
 
+  /* ---- PA ------------------- */
+#ifdef PA
+  FFI_LINUX,
+  FFI_DEFAULT_ABI = FFI_LINUX,
+#endif
+
   /* Leave this for debugging purposes */
   FFI_LAST_ABI
 
@@ -432,6 +438,16 @@
 #define FFI_TRAMPOLINE_SIZE 24
 #define FFI_NATIVE_RAW_API 0
 
+#elif defined(PA)
+
+#define FFI_CLOSURES 1
+#define FFI_NATIVE_RAW_API 0
+
+#define FFI_TRAMPOLINE_SIZE 32
+
+#define FFI_TYPE_SMALL_STRUCT1 -1
+#define FFI_TYPE_SMALL_STRUCT2 -2
+
 #elif defined(POWERPC)
 
 #define FFI_CLOSURES 1
diff -urN libffi.old/src/pa/ffi.c libffi/src/pa/ffi.c
--- libffi.old/src/pa/ffi.c	1970-01-01 01:00:00.000000000 +0100
+++ libffi/src/pa/ffi.c	2004-03-20 13:12:06.000000000 +0100
@@ -0,0 +1,608 @@
+/* -----------------------------------------------------------------------
+   ffi.c - (c) 2003 Randolph Chung <tausq@debian.org>
+
+   HPPA 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.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+#define ROUND_UP(v, a)  (((size_t)(v) + (a) - 1) & ~((a) - 1))
+#define ROUND_DOWN(v, a)  (((size_t)(v) - (a) + 1) & ~((a) - 1))
+#define MIN_STACK_SIZE  64
+#define FIRST_ARG_SLOT  9
+#define DEBUG_LEVEL   0
+
+#define fldw(addr, fpreg) asm volatile ("fldw 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg)
+#define fstw(fpreg, addr) asm volatile ("fstw %%" #fpreg "L, 0(%0)" : : "r"(addr))
+#define fldd(addr, fpreg) asm volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) : #fpreg)
+#define fstd(fpreg, addr) asm volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr))
+
+#define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0)
+
+static inline int ffi_struct_type(ffi_type *t)
+{
+  size_t sz = t->size;
+
+  /* Small structure results are passed in registers,
+   * larger ones are passed by pointer.
+   */
+
+  if (sz <= 1)
+    return FFI_TYPE_UINT8;
+  else if (sz == 2)
+    return FFI_TYPE_UINT16;
+  else if (sz == 3)
+    return FFI_TYPE_SMALL_STRUCT1;
+  else if (sz == 4)
+    return FFI_TYPE_UINT32;
+  else if (sz <= 6)
+    return FFI_TYPE_SMALL_STRUCT2;
+  else if (sz <= 8)
+    return FFI_TYPE_UINT64;
+  else
+    return FFI_TYPE_STRUCT; /* else, we pass it by pointer.. */
+}
+
+/* PA has a downward growing stack, which looks like this:
+ *
+ * Offset
+ *      [ Variable args ]
+ * SP = (4*(n+9))       arg word N
+ * ...
+ * SP-52                arg word 4
+ *      [ Fixed args ]
+ * SP-48                arg word 3
+ * SP-44                arg word 2
+ * SP-40                arg word 1
+ * SP-36                arg word 0
+ *      [ Frame marker ]
+ * ...
+ * SP-20                RP
+ * SP-4                 previous SP
+ *
+ * First 4 non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23
+ * First 2 non-FP 64-bit args are passed in register pairs, starting
+ *   on an even numbered register (i.e. r26/r25 and r24+r23)
+ * First 4 FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L
+ * First 2 FP 64-bit arguments are passed in fr5 and fr7
+ * The rest are passed on the stack starting at SP-52, but 64-bit
+ *   arguments need to be aligned to an 8-byte boundary
+ *
+ * This means we can have holes either in the register allocation,
+ * or in the stack.
+ */
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ * has been allocated for the function's arguments
+ *
+ * The following code will put everything into the stack frame
+ * (which was allocated by the asm routine), and on return
+ * the asm routine will load the arguments that should be
+ * passed by register into the appropriate registers
+ *
+ * NOTE: We load floating point args in this function... that means we
+ * assume gcc will not mess with fp regs in here.
+ */
+
+/*@-exportheader@*/
+void ffi_prep_args_LINUX(UINT32 *stack, extended_cif *ecif, unsigned bytes)
+/*@=exportheader@*/
+{
+  register unsigned int i;
+  register ffi_type **p_arg;
+  register void **p_argv;
+  unsigned int slot = FIRST_ARG_SLOT - 1;
+  char *dest_cpy;
+
+  debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack, ecif, bytes);
+
+  p_arg = ecif->cif->arg_types;
+  p_argv = ecif->avalue;
+
+  for (i = 0; i < ecif->cif->nargs; i++)
+    {
+      int type = (*p_arg)->type;
+
+      switch (type)
+	{
+	case FFI_TYPE_SINT8:
+	  slot++;
+	  *(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv);
+	  break;
+
+	case FFI_TYPE_UINT8:
+	  slot++;
+	  *(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv);
+	  break;
+
+	case FFI_TYPE_SINT16:
+	  slot++;
+	  *(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv);
+	  break;
+
+	case FFI_TYPE_UINT16:
+	  slot++;
+	  *(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv);
+	  break;
+
+	case FFI_TYPE_UINT32:
+	case FFI_TYPE_SINT32:
+	case FFI_TYPE_POINTER:
+	  slot++;
+	  debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv), slot);
+	  *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
+	  break;
+
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_SINT64:
+	  slot += 2;
+	  if (slot & 1)
+	    slot++;
+
+	  *(UINT32 *)(stack - slot) = (*(UINT64 *)(*p_argv)) >> 32;
+	  *(UINT32 *)(stack - slot + 1) = (*(UINT64 *)(*p_argv)) & 0xffffffffUL;
+	  break;
+
+	case FFI_TYPE_FLOAT:
+	  /* First 4 args go in fr4L - fr7L */
+	  slot++;
+	  switch (slot - FIRST_ARG_SLOT)
+	    {
+	    case 0: fldw(*p_argv, fr4); break;
+	    case 1: fldw(*p_argv, fr5); break;
+	    case 2: fldw(*p_argv, fr6); break;
+	    case 3: fldw(*p_argv, fr7); break;
+	    default:
+	      /* other ones are just passed on the stack */
+	      debug(3, "Storing UINT32(float) in slot %u\n", slot);
+	      *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
+	      break;
+	    }
+	    break;
+
+	case FFI_TYPE_DOUBLE:
+	  slot += 2;
+	  if (slot & 1)
+	    slot++;
+	  switch (slot - FIRST_ARG_SLOT + 1)
+	    {
+	      /* First 2 args go in fr5, fr7 */
+	    case 2: fldd(*p_argv, fr5); break;
+	    case 4: fldd(*p_argv, fr7); break;
+	    default:
+	      debug(3, "Storing UINT64(double) at slot %u\n", slot);
+	      *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
+	      break;
+	    }
+	  break;
+
+	case FFI_TYPE_STRUCT:
+
+	  /* Structs smaller or equal than 4 bytes are passed in one
+	     register. Structs smaller or equal 8 bytes are passed in two
+	     registers. Larger structures are passed by pointer.  */
+
+	  if((*p_arg)->size <= 4) {
+	    slot++;
+	    dest_cpy = (char *)(stack - slot);
+	    dest_cpy += 4 - (*p_arg)->size;
+	    memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size);
+	  } else if ((*p_arg)->size <= 8) {
+	    slot += 2;
+	    if (slot & 1)
+	      slot++;
+	    dest_cpy = (char *)(stack - slot);
+	    dest_cpy += 8 - (*p_arg)->size;
+	    memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size);
+	  } else {
+	    slot++;
+	    *(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
+	  }
+	  break;
+
+	default:
+	  FFI_ASSERT(0);
+	}
+
+      p_arg++;
+      p_argv++;
+    }
+
+  /* Make sure we didn't mess up and scribble on the stack */
+#if 1
+  {
+    int n;
+
+    debug(5, "Stack setup:\n");
+    for (n = 0; n < (bytes + 3) / 4; n++)
+      {
+	if ((n%4) == 0) { debug(5, "\n%08x: ", (unsigned int)(stack - n)); }
+	debug(5, "%08x ", *(stack - n));
+      }
+    debug(5, "\n");
+  }
+#endif
+
+  FFI_ASSERT(slot * 4 <= bytes);
+
+  return;
+}
+
+static void ffi_size_stack_LINUX(ffi_cif *cif)
+{
+  ffi_type **ptr;
+  int i;
+  int z = 0; /* # stack slots */
+
+  for (ptr = cif->arg_types, i = 0; i < cif->nargs; ptr++, i++)
+    {
+      int type = (*ptr)->type;
+
+      switch (type)
+	{
+	case FFI_TYPE_DOUBLE:
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_SINT64:
+	  z += 2 + (z & 1); /* must start on even regs, so we may waste one */
+	  break;
+
+	case FFI_TYPE_STRUCT:
+	  z += 1; /* pass by ptr, callee will copy */
+	  break;
+
+	default: /* <= 32-bit values */
+	  z++;
+	}
+    }
+
+  /* We can fit up to 6 args in the default 64-byte stack frame,
+   * if we need more, we need more stack
+   */
+  if (z <= 6)
+    cif->bytes = MIN_STACK_SIZE; /* min stack size */
+  else
+    cif->bytes = 64 + ROUND_UP((z - 6) * sizeof(UINT32), MIN_STACK_SIZE);
+
+  debug(3, "Calculated stack size is %u bytes\n", cif->bytes);
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+  /* Set the return type flag */
+  switch (cif->rtype->type)
+    {
+    case FFI_TYPE_VOID:
+    case FFI_TYPE_FLOAT:
+    case FFI_TYPE_DOUBLE:
+      cif->flags = (unsigned) cif->rtype->type;
+      break;
+
+    case FFI_TYPE_STRUCT:
+      /* For the return type we have to check the size of the structures.
+	 If the size is smaller or equal 4 bytes, the result is given back
+	 in one register. If the size is smaller or equal 8 bytes than we
+	 return the result in two registers. But if the size is bigger than
+	 8 bytes, we work with pointers.  */
+      cif->flags = ffi_struct_type(cif->rtype);
+      break;
+
+    case FFI_TYPE_UINT64:
+    case FFI_TYPE_SINT64:
+      cif->flags = FFI_TYPE_UINT64;
+      break;
+
+    default:
+      cif->flags = FFI_TYPE_INT;
+      break;
+    }
+
+  /* Lucky us, because of the weird PA ABI we get to do our
+   * own stack sizing....
+   */
+  switch (cif->abi)
+    {
+    case FFI_LINUX:
+      ffi_size_stack_LINUX(cif);
+      break;
+
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+
+  return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_LINUX(void (*)(UINT32 *, extended_cif *, unsigned),
+			   /*@out@*/ extended_cif *,
+			   unsigned, unsigned,
+			   /*@out@*/ unsigned *,
+			   void (*fn)());
+/*@=declundef@*/
+/*@=exportheader@*/
+
+void ffi_call(/*@dependent@*/ ffi_cif *cif,
+	      void (*fn)(),
+	      /*@out@*/ void *rvalue,
+	      /*@dependent@*/ 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))
+    {
+      /*@-sysunrecog@*/
+      ecif.rvalue = alloca(cif->rtype->size);
+      /*@=sysunrecog@*/
+    }
+  else
+    ecif.rvalue = rvalue;
+
+
+  switch (cif->abi)
+    {
+    case FFI_LINUX:
+      /*@-usedef@*/
+      debug(2, "Calling ffi_call_LINUX: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn);
+      ffi_call_LINUX(ffi_prep_args_LINUX, &ecif, cif->bytes,
+		     cif->flags, ecif.rvalue, fn);
+      /*@=usedef@*/
+      break;
+
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+}
+
+#if FFI_CLOSURES
+/*
+ * This is more-or-less an inverse of ffi_call -- we have arguments on
+ * the stack, and we need to fill them into a cif structure and invoke
+ * the user function. This really ought to be in asm to make sure
+ * the compiler doesn't do things we don't expect...
+ */
+UINT32 ffi_closure_inner_LINUX(ffi_closure *closure, UINT32 *stack)
+{
+  ffi_cif *cif;
+  void **avalue;
+  void *rvalue;
+  UINT32 ret[2]; /* function can return up to 64-bits in registers */
+  ffi_type **p_arg;
+  char *tmp;
+  int i, avn, slot = FIRST_ARG_SLOT - 1;
+  register UINT32 r28 asm("r28");
+
+  cif = closure->cif;
+
+  /* if returning via structure, callee will write to our pointer */
+  if (cif->flags == FFI_TYPE_STRUCT)
+    rvalue = (void *)r28;
+  else
+    rvalue = &ret[0];
+
+  avalue = (void **)alloca(cif->nargs * sizeof(void *));
+  avn = cif->nargs;
+  p_arg = cif->arg_types;
+
+  for (i = 0; i < avn; i++)
+    {
+      int type = (*p_arg)->type;
+
+      switch (type)
+	{
+	case FFI_TYPE_SINT8:
+	case FFI_TYPE_UINT8:
+	case FFI_TYPE_SINT16:
+	case FFI_TYPE_UINT16:
+	case FFI_TYPE_SINT32:
+	case FFI_TYPE_UINT32:
+	case FFI_TYPE_POINTER:
+	  slot++;
+	  avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size;
+	  break;
+
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT64:
+	  slot += 2;
+	  if (slot & 1)
+	    slot++;
+	  avalue[i] = (void *)(stack - slot);
+	  break;
+
+	case FFI_TYPE_FLOAT:
+	  slot++;
+	  switch (slot - FIRST_ARG_SLOT)
+	    {
+	    case 0: fstw(fr4, (void *)(stack - slot)); break;
+	    case 1: fstw(fr5, (void *)(stack - slot)); break;
+	    case 2: fstw(fr6, (void *)(stack - slot)); break;
+	    case 3: fstw(fr7, (void *)(stack - slot)); break;
+	    }
+	  avalue[i] = (void *)(stack - slot);
+	  break;
+
+	case FFI_TYPE_DOUBLE:
+	  slot += 2;
+	  if (slot & 1)
+	    slot++;
+	  switch (slot - FIRST_ARG_SLOT + 1)
+	    {
+	    case 2: fstd(fr5, (void *)(stack - slot)); break;
+	    case 4: fstd(fr7, (void *)(stack - slot)); break;
+	    }
+	  avalue[i] = (void *)(stack - slot);
+	  break;
+
+	case FFI_TYPE_STRUCT:
+	  /* Structs smaller or equal than 4 bytes are passed in one
+	     register. Structs smaller or equal 8 bytes are passed in two
+	     registers. Larger structures are passed by pointer.  */
+	  if((*p_arg)->size <= 4) {
+	    slot++;
+	    avalue[i] = (void *)(stack - slot) + sizeof(UINT32) -
+	      (*p_arg)->size;
+	  } else if ((*p_arg)->size <= 8) {
+	    slot += 2;
+	    if (slot & 1)
+	      slot++;
+	    avalue[i] = (void *)(stack - slot) + sizeof(UINT64) -
+	      (*p_arg)->size;
+	  } else {
+	    slot++;
+	    avalue[i] = (void *) *(stack - slot);
+	  }
+	  break;
+
+	default:
+	  FFI_ASSERT(0);
+	}
+
+      p_arg++;
+    }
+
+  /* Invoke the closure.  */
+  (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+  debug(3, "after calling function, ret[0] = %d, ret[1] = %d\n", ret[0], ret[1]);
+
+  /* Store the result */
+  switch (cif->flags)
+    {
+    case FFI_TYPE_UINT8:
+      *(stack - FIRST_ARG_SLOT) = *(UINT8 *)&ret[0];
+      break;
+    case FFI_TYPE_SINT8:
+      *(stack - FIRST_ARG_SLOT) = *(SINT8 *)&ret[0];
+      break;
+    case FFI_TYPE_UINT16:
+      *(stack - FIRST_ARG_SLOT) = *(UINT16 *)&ret[0];
+      break;
+    case FFI_TYPE_SINT16:
+      *(stack - FIRST_ARG_SLOT) = *(SINT16 *)&ret[0];
+      break;
+    case FFI_TYPE_INT:
+    case FFI_TYPE_UINT32:
+      *(stack - FIRST_ARG_SLOT) = *(UINT32 *)&ret[0];
+      break;
+    case FFI_TYPE_SINT32:
+      *(stack - FIRST_ARG_SLOT) = *(SINT32 *)&ret[0];
+      break;
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_UINT64:
+      *(stack - FIRST_ARG_SLOT) = *(UINT32 *)&ret[0];
+      *(stack - FIRST_ARG_SLOT - 1) = *(UINT32 *)&ret[1];
+      break;
+
+    case FFI_TYPE_DOUBLE:
+      fldd(rvalue, fr4);
+      break;
+
+    case FFI_TYPE_FLOAT:
+      fldw(rvalue, fr4);
+      break;
+
+    case FFI_TYPE_STRUCT:
+      /* Don't need a return value, done by caller.  */
+      break;
+
+    case FFI_TYPE_SMALL_STRUCT1:
+      tmp = (void*)(stack -  FIRST_ARG_SLOT);
+      tmp += 4 - cif->rtype->size;
+      memcpy((void*)tmp, &ret[0], cif->rtype->size);
+      break;
+
+    case FFI_TYPE_SMALL_STRUCT2:
+      *(stack - FIRST_ARG_SLOT) = ret[0];
+      *(stack - FIRST_ARG_SLOT - 1) = ret[1];
+      break;
+
+    case FFI_TYPE_POINTER:
+    case FFI_TYPE_VOID:
+      break;
+
+    default:
+      debug(0, "assert with cif->flags: %d\n",cif->flags);
+      FFI_ASSERT(0);
+      break;
+    }
+  return FFI_OK;
+}
+
+/* Fill in a closure to refer to the specified fun and user_data.  */
+/* cif specifies the argument and result types for fun.  */
+/* the cif must already be prep'ed */
+
+void ffi_closure_LINUX(void);
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+		  ffi_cif* cif,
+		  void (*fun)(ffi_cif*,void*,void**,void*),
+		  void *user_data)
+{
+  UINT32 *tramp = (UINT32 *)(closure->tramp);
+
+  FFI_ASSERT (cif->abi == FFI_LINUX);
+
+  /* Make a small trampoline that will branch to our
+   * handler function. Use PC-relative addressing.
+   */
+  tramp[0] = 0xeaa00000; /* b,l .+8, %r21     ; %r21 <- pc+8             */
+  tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21  ; mask priv bits           */
+  tramp[2] = 0x4aa10028; /* ldw  20(%r21),%r1 ; load plabel              */
+  tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21 ; get closure addr         */
+  tramp[4] = 0x0c201096; /* ldw  0(%r1),%r22  ; address of handler       */
+  tramp[5] = 0xeac0c000; /* bv	 %r0(%r22)    ; branch to handler        */
+  tramp[6] = 0x0c281093; /* ldw  4(%r1),%r19  ; GP of handler            */
+  tramp[7] = ((UINT32)(ffi_closure_LINUX) & ~2);
+
+  /* Flush d/icache -- have to flush up 2 two lines because of
+   * alignment
+   */
+  asm volatile (
+		"fdc 0(%0)\n"
+		"fdc %1(%0)\n"
+		"fic 0(%%sr4, %0)\n"
+		"fic %1(%%sr4, %0)\n"
+		: : "r"((unsigned long)tramp & ~31), "r"(32 /* stride */));
+
+  closure->cif  = cif;
+  closure->user_data = user_data;
+  closure->fun  = fun;
+
+  return FFI_OK;
+}
+#endif
+
diff -urN libffi.old/src/pa/linux.S libffi/src/pa/linux.S
--- libffi.old/src/pa/linux.S	1970-01-01 01:00:00.000000000 +0100
+++ libffi/src/pa/linux.S	2004-03-20 13:12:06.000000000 +0100
@@ -0,0 +1,310 @@
+/* -----------------------------------------------------------------------
+   linux.S - (c) 2003 Randolph Chung <tausq@debian.org>
+
+   HPPA 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 <fficonfig.h>
+#include <ffi.h>
+
+#define FFI_TYPE_SMALL_STRUCT1 -1
+#define FFI_TYPE_SMALL_STRUCT2 -2
+
+	.text
+	.align 4
+
+	/* void ffi_call_LINUX(void (*)(char *, extended_cif *),
+			       extended_cif *ecif,
+			       unsigned bytes,
+			       unsigned flags,
+			       unsigned *rvalue,
+			       void (*fn)());
+	 */
+
+	.export ffi_call_LINUX,code
+	.import ffi_prep_args_LINUX,code
+
+	.type ffi_call_LINUX, @function
+.LFB1:
+ffi_call_LINUX:
+	.proc
+	.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4
+	.entry
+	stw %rp, -20(%sp)
+	copy %r3, %r1
+.LCFI11:
+
+	copy %sp, %r3
+.LCFI12:
+
+	/* Setup the stack for calling prep_args...
+	   We want the stack to look like this:
+
+	   [ Previous stack                            ] <- %r3
+
+	   [ 64-bytes register save area               ] <- %r4
+
+	   [ Stack space for actual call, passed as    ] <- %arg0
+	   [     arg0 to ffi_prep_args_LINUX           ]
+
+	   [ Stack for calling prep_args               ] <- %sp
+	 */
+
+	stwm %r1, 64(%sp)
+	stw %r4, 12(%r3)
+.LCFI13:
+	copy %sp, %r4
+
+	addl %arg2, %r4, %arg0                  /* arg stack */
+	stw %arg3, -48(%r3)                     /* save flags; we need it later */
+
+	/* Call prep_args:
+	   %arg0(stack) -- set up above
+	   %arg1(ecif) -- same as incoming param
+	   %arg2(bytes) -- same as incoming param */
+	bl ffi_prep_args_LINUX,%r2
+	ldo 64(%arg0), %sp
+	ldo -64(%sp), %sp
+
+	/* now %sp should point where %arg0 was pointing */
+
+	/* Load the arguments that should be passed in registers */
+	/* The fp args were loaded by the prep_args function */
+	ldw -36(%sp), %arg0
+	ldw -40(%sp), %arg1
+	ldw -44(%sp), %arg2
+	ldw -48(%sp), %arg3
+
+	/* in case the function is going to return a structure
+	 * we need to give it a place to put the result...
+	 */
+	ldw -52(%r3), %ret0                     /* %ret0 <- rvalue */
+	ldw -56(%r3), %r22                      /* %r22 <- function to call */
+	bl $$dyncall, %r31                      /* Call the user function */
+	copy %r31, %rp
+
+	/* Prepare to store the result; we need to recover flags and rvalue */
+	ldw -48(%r3), %r21                      /* r21 <- flags */
+	ldw -52(%r3), %r20                      /* r20 <- rvalue */
+
+	/* Store the result according to the return type... */
+
+checksmst1:
+	comib,<>,n FFI_TYPE_SMALL_STRUCT1, %r21, checksmst2
+	/* There is maybe a better way to handle 3 byte structs.  */
+	SH2ADD %ret0,0,%ret0
+	SH2ADD %ret0,0,%ret0
+	SH2ADD %ret0,0,%ret0
+	SH2ADD %ret0,0,%ret0
+	b done
+	stw %ret0, 0(%r20)
+
+checksmst2:
+	comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, checkint8
+	/* Up to now I don't have a way to handle 6/7 byte structs.
+	   The values are left bounded in the registers. In the struct
+	   itself they are left bounded.  */
+	stw %ret0, 0(%r20)
+	b done
+	stw %ret1, 4(%r20)
+
+checkint8:
+	comib,<>,n FFI_TYPE_UINT8, %r21, checkint16
+	b done
+	stb %ret0, 0(%r20)
+
+checkint16:
+	comib,<>,n FFI_TYPE_UINT16, %r21, checkint32
+	b done
+	sth %ret0, 0(%r20)
+
+checkint32:
+	comib,<>,n FFI_TYPE_UINT32, %r21, checkint
+	b done
+	stw %ret0, 0(%r20)
+
+checkint:
+	comib,<>,n FFI_TYPE_INT, %r21, checkll
+	b done
+	stw %ret0, 0(%r20)
+
+checkll:
+	comib,<>,n FFI_TYPE_UINT64, %r21, checkdbl
+	stw %ret0, 0(%r20)
+	b done
+	stw %ret1, 4(%r20)
+
+checkdbl:
+	comib,<>,n FFI_TYPE_DOUBLE, %r21, checkfloat
+	b done
+	fstd %fr4,0(%r20)
+
+checkfloat:
+	comib,<>,n FFI_TYPE_FLOAT, %r21, done
+	fstw %fr4L,0(%r20)
+
+	/* structure returns are either handled by one of the
+	 * INT/UINT64 cases above, or, if passed by pointer,
+	 * is handled by the callee
+	 */
+
+done:
+	/* all done, return */
+	copy %r4, %sp                           /* pop arg stack */
+	ldw 12(%r3), %r4
+	ldwm -64(%sp), %r3                      /* .. and pop stack */
+	ldw -20(%sp), %rp
+	bv %r0(%rp)
+	nop
+	.exit
+	.procend
+.LFE1:
+
+	/* void ffi_closure_LINUX(void);
+	 * Called with closure argument in %r21
+	 */
+	.export ffi_closure_LINUX,code
+	.import ffi_closure_inner_LINUX,code
+
+	.type ffi_closure_LINUX, @function
+.LFB2:
+ffi_closure_LINUX:
+	.proc
+	.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
+	.entry
+
+	stw %rp, -20(%sp)
+.LCFI20:
+	copy %r3, %r1
+.LCFI21:
+	copy %sp, %r3
+.LCFI22:
+	stwm %r1, 64(%sp)
+
+	/* Put arguments onto the stack and call ffi_closure_inner */
+	stw %arg0, -36(%r3)
+	stw %arg1, -40(%r3)
+	stw %arg2, -44(%r3)
+	stw %arg3, -48(%r3)
+
+	copy %r21, %arg0
+	bl ffi_closure_inner_LINUX, %r2
+	copy %r3, %arg1
+
+	ldwm -64(%sp), %r3
+	ldw -20(%sp), %rp
+	ldw -36(%sp), %ret0
+	bv %r0(%r2)
+	ldw -40(%sp), %ret1
+
+	.exit
+	.procend
+.LFE2:
+
+	.section        ".eh_frame","aw",@progbits
+.Lframe1:
+	.word   .LECIE1-.LSCIE1 ;# Length of Common Information Entry
+.LSCIE1:
+	.word   0x0     ;# CIE Identifier Tag
+	.byte   0x1     ;# CIE Version
+#if 0 // defined _RELOCATABLE || defined __PIC__
+	.ascii "zR\0"   ;# CIE Augmentation
+#else
+	.ascii "\0"     ;# CIE Augmentation
+#endif
+	.uleb128 0x1    ;# CIE Code Alignment Factor
+	.sleb128 4      ;# CIE Data Alignment Factor
+	.byte   0x2     ;# CIE RA Column
+#if 0 // defined _RELOCATABLE || defined __PIC__
+	.uleb128  0x1   ;# Augmentation size
+	.byte	0x1b    ;# FDE Encoding (pcrel sdata4)
+#endif
+	.byte   0xc     ;# DW_CFA_def_cfa
+	.uleb128 0x1e
+	.uleb128 0x0
+	.align 4
+.LECIE1:
+.LSFDE1:
+	.word   .LEFDE1-.LASFDE1        ;# FDE Length
+.LASFDE1:
+	.word   .LASFDE1-.Lframe1       ;# FDE CIE offset
+#if 0 // defined _RELOCATABLE || defined __PIC__
+	.word   .LFB1-. ;# FDE initial location
+#else
+	.word   .LFB1   ;# FDE initial location
+#endif
+	.word   .LFE1-.LFB1     ;# FDE address range
+#if 0 // defined _RELOCATABLE || defined __PIC__
+	.uleb128 0x0    ;# Augmentation size
+#endif
+
+	.byte   0x4     ;# DW_CFA_advance_loc4
+	.word   .LCFI11-.LFB1
+	.byte	0x83	;# DW_CFA_offset, column 0x3
+	.uleb128 0x0
+	.byte   0x11    ;# DW_CFA_offset_extended_sf; save r2 at [r30-20]
+	.uleb128 0x2
+	.sleb128 -5
+
+	.byte   0x4     ;# DW_CFA_advance_loc4
+	.word   .LCFI12-.LCFI11
+	.byte   0xd     ;# DW_CFA_def_cfa_register = r3
+	.uleb128 0x3
+
+	.byte   0x4     ;# DW_CFA_advance_loc4
+	.word   .LCFI13-.LCFI12
+	.byte	0x84	;# DW_CFA_offset, column 0x4
+	.uleb128 0x3
+
+	.align 4
+.LEFDE1:
+
+.LSFDE2:
+	.word   .LEFDE2-.LASFDE2        ;# FDE Length
+.LASFDE2:
+	.word   .LASFDE2-.Lframe1       ;# FDE CIE offset
+#if 0 // defined _RELOCATABLE || defined __PIC__
+	.word   .LFB2-. ;# FDE initial location
+#else
+	.word   .LFB2   ;# FDE initial location
+#endif
+	.word   .LFE2-.LFB2     ;# FDE address range
+#if 0 // defined _RELOCATABLE || defined __PIC__
+	.uleb128 0x0    ;# Augmentation size
+#endif
+	.byte   0x4     ;# DW_CFA_advance_loc4
+	.word   .LCFI21-.LFB2
+	.byte   0x83    ;# DW_CFA_offset, column 0x3
+	.uleb128 0x0
+	.byte   0x11    ;# DW_CFA_offset_extended_sf
+	.uleb128 0x2
+	.sleb128 -5
+
+	.byte   0x4     ;# DW_CFA_advance_loc4
+	.word   .LCFI12-.LCFI11
+	.byte   0xd     ;# DW_CFA_def_cfa_register = r3
+	.uleb128 0x3
+
+	.align 4
+.LEFDE2:
+
diff -urN libffi.old/src/prep_cif.c libffi/src/prep_cif.c
--- libffi.old/src/prep_cif.c	2002-09-30 13:59:42.000000000 +0200
+++ libffi/src/prep_cif.c	2004-03-20 13:12:06.000000000 +0100
@@ -104,7 +104,7 @@
   FFI_ASSERT(ffi_type_test(cif->rtype));
 
   /* x86-64 and s390 stack space allocation is handled in prep_machdep.  */
-#if !defined M68K && !defined __x86_64__ && !defined S390
+#if !defined M68K && !defined __x86_64__ && !defined S390 && !defined PA
   /* Make space for the return structure pointer */
   if (cif->rtype->type == FFI_TYPE_STRUCT
 #ifdef SPARC
@@ -123,7 +123,7 @@
       if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
 	return FFI_BAD_TYPEDEF;
 
-#if !defined __x86_64__ && !defined S390
+#if !defined __x86_64__ && !defined S390 && !defined PA
 #ifdef SPARC
       if (((*ptr)->type == FFI_TYPE_STRUCT
 	   && ((*ptr)->size > 16 || cif->abi != FFI_V9))
