#! /bin/sh -e

# 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 && autoconf
        ;;
    -unpatch)
        patch $pdir -f --no-backup-if-mismatch -R -p0 < $0
        ;;
    *)
        echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
        exit 1
esac
exit 0

2004-03-13  Matthias Klose  <doko@debian.org>

	* Makefile.am: Update 
	* Makefile.in: Regenerate.
	* src/pa/ffi.h.in: Remove.
	* src/pa/ffitarget.h: New file.

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	2004-03-20 19:32:43.000000000 +0100
+++ libffi/Makefile.am	2004-03-20 19:38:44.000000000 +0100
@@ -10,6 +10,7 @@
 	src/mips/ffi.c src/mips/n32.S src/mips/o32.S \
 	src/mips/ffitarget.h \
 	src/m68k/ffi.c src/m68k/sysv.S src/m68k/ffitarget.h \
+	src/pa/ffi.c src/pa/linux.S src/pa/ffitarget.h \
 	src/powerpc/ffi.c src/powerpc/sysv.S \
 	src/powerpc/linux64.S src/powerpc/linux64_closure.S \
 	src/powerpc/ppc_closure.S src/powerpc/asm.h \
@@ -95,6 +96,7 @@
 TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S
 TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S
 TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
+TARGET_SRC_PA = src/pa/ffi.c src/pa/linux.S
 TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
 TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S
 TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
@@ -172,6 +174,10 @@
 libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_SH64)
 libffi_convenience_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_SH64)
 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 = -Wall -g -fexceptions
 
diff -urN libffi.old/Makefile.in libffi/Makefile.in
--- libffi.old/Makefile.in	2003-11-24 00:52:28.000000000 +0100
+++ libffi/Makefile.in	2004-03-20 19:47:00.000000000 +0100
@@ -101,6 +101,7 @@
 	src/mips/ffi.c src/mips/n32.S src/mips/o32.S \
 	src/mips/ffitarget.h \
 	src/m68k/ffi.c src/m68k/sysv.S src/m68k/ffitarget.h \
+	src/pa/ffi.c src/pa/linux.S src/pa/ffitarget.h \
 	src/powerpc/ffi.c src/powerpc/sysv.S \
 	src/powerpc/linux64.S src/powerpc/linux64_closure.S \
 	src/powerpc/ppc_closure.S src/powerpc/asm.h \
@@ -179,6 +180,7 @@
 TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S
 TARGET_SRC_IA64 = src/ia64/ffi.c src/ia64/unix.S
 TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
+TARGET_SRC_PA = src/pa/ffi.c src/pa/linux.S
 TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
 TARGET_SRC_POWERPC_AIX = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S
 TARGET_SRC_POWERPC_DARWIN = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S
@@ -199,6 +201,7 @@
 @ALPHA_TRUE@libffi_la_SOURCES = @ALPHA_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ALPHA)
 @IA64_TRUE@libffi_la_SOURCES = @IA64_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_IA64)
 @M68K_TRUE@libffi_la_SOURCES = @M68K_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_M68K)
+@PA_TRUE@libffi_la_SOURCES = @PA_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_PA)
 @POWERPC_TRUE@libffi_la_SOURCES = @POWERPC_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC)
 @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)
@@ -215,6 +218,7 @@
 @ALPHA_TRUE@libffi_convenience_la_SOURCES = @ALPHA_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_ALPHA)
 @IA64_TRUE@libffi_convenience_la_SOURCES = @IA64_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_IA64)
 @M68K_TRUE@libffi_convenience_la_SOURCES = @M68K_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_M68K)
+@PA_TRUE@libffi_convenience_la_SOURCES = @PA_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_PA)
 @POWERPC_TRUE@libffi_convenience_la_SOURCES = @POWERPC_TRUE@$(libffi_la_common_SOURCES) $(TARGET_SRC_POWERPC)
 @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)
@@ -260,6 +264,9 @@
 @ARM_TRUE@libffi_convenience_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @ARM_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @ARM_TRUE@src/arm/sysv.lo src/arm/ffi.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/ffi.lo src/pa/linux.lo
 @POWERPC_AIX_TRUE@libffi_convenience_la_OBJECTS =  src/debug.lo \
 @POWERPC_AIX_TRUE@src/prep_cif.lo src/types.lo src/raw_api.lo \
 @POWERPC_AIX_TRUE@src/java_raw_api.lo src/powerpc/ffi_darwin.lo \
@@ -316,6 +323,9 @@
 @ARM_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo src/types.lo \
 @ARM_TRUE@src/raw_api.lo src/java_raw_api.lo src/arm/sysv.lo \
 @ARM_TRUE@src/arm/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 src/pa/linux.lo \
+@PA_TRUE@src/pa/ffi.lo
 @POWERPC_AIX_TRUE@libffi_la_OBJECTS =  src/debug.lo src/prep_cif.lo \
 @POWERPC_AIX_TRUE@src/types.lo src/raw_api.lo src/java_raw_api.lo \
 @POWERPC_AIX_TRUE@src/powerpc/ffi_darwin.lo src/powerpc/aix.lo \
@@ -608,7 +618,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/sh64 $(distdir)/src/sparc $(distdir)/src/x86
 	@for file in $(DISTFILES); do \
diff -urN libffi.old/configure.in libffi/configure.in
--- libffi.old/configure.in	2004-03-20 19:32:43.000000000 +0100
+++ libffi/configure.in	2004-03-20 19:33:57.000000000 +0100
@@ -85,6 +85,7 @@
 x86_64-*-linux*) TARGET=X86_64; TARGETDIR=x86;;
 sh-*-linux* | sh[[34]]*-*-linux*) TARGET=SH; TARGETDIR=sh;;
 sh64-*-linux* | sh5*-*-linux*) TARGET=SH64; TARGETDIR=sh64;;
+hppa-*-linux* | parisc-*-linux*) TARGET=PA; TARGETDIR=pa;;
 esac
 
 AC_SUBST(AM_RUNTESTFLAGS)
@@ -109,6 +110,7 @@
 AM_CONDITIONAL(X86_64, test x$TARGET = xX86_64)
 AM_CONDITIONAL(SH, test x$TARGET = xSH)
 AM_CONDITIONAL(SH64, test x$TARGET = xSH64)
+AM_CONDITIONAL(PA, test x$TARGET = xPA)
 
 case x$TARGET in
   xMIPS*) TARGET=MIPS ;;
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 19:33:57.000000000 +0100
@@ -0,0 +1,603 @@
+/* -----------------------------------------------------------------------
+   ffi.c - (c) 2003-2004 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.  */
+  {
+    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");
+  }
+
+  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 unique 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 * FFI_SIZEOF_ARG);
+  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"
+		"sync\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/ffitarget.h libffi/src/pa/ffitarget.h
--- libffi.old/src/pa/ffitarget.h	1970-01-01 01:00:00.000000000 +0100
+++ libffi/src/pa/ffitarget.h	2004-03-20 19:33:57.000000000 +0100
@@ -0,0 +1,57 @@
+/* -----------------------------------------------------------------*-C-*-
+   ffitarget.h - Copyright (c) 1996-2003  Red Hat, Inc.
+   Target configuration macros for hppa.
+
+   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.
+
+   ----------------------------------------------------------------------- */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+/* ---- System specific configurations ----------------------------------- */
+
+#ifndef LIBFFI_ASM
+typedef unsigned long          ffi_arg;
+typedef signed long            ffi_sarg;
+
+typedef enum ffi_abi {
+  FFI_FIRST_ABI = 0,
+
+#ifdef PA
+  FFI_LINUX,
+  FFI_DEFAULT_ABI = FFI_LINUX,
+#endif
+
+  FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#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
+#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 19:33:57.000000000 +0100
@@ -0,0 +1,281 @@
+/* -----------------------------------------------------------------------
+   linux.S - (c) 2003-2004 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>
+
+	.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",EH_FRAME_FLAGS,@progbits
+.Lframe1:
+	.word   .LECIE1-.LSCIE1 ;# Length of Common Information Entry
+.LSCIE1:
+	.word   0x0     ;# CIE Identifier Tag
+	.byte   0x1     ;# CIE Version
+	.ascii "\0"     ;# CIE Augmentation
+	.uleb128 0x1    ;# CIE Code Alignment Factor
+	.sleb128 4      ;# CIE Data Alignment Factor
+	.byte   0x2     ;# CIE RA Column
+	.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
+	.word   .LFB1   ;# FDE initial location
+	.word   .LFE1-.LFB1     ;# FDE address range
+
+	.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
+	.word   .LFB2   ;# FDE initial location
+	.word   .LFE2-.LFB2     ;# FDE address range
+	.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	2004-03-20 19:32:43.000000000 +0100
+++ libffi/src/prep_cif.c	2004-03-20 19:33:57.000000000 +0100
@@ -113,7 +113,7 @@
   FFI_ASSERT_VALID_TYPE(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
@@ -134,7 +134,7 @@
 	 check after the initialization.  */
       FFI_ASSERT_VALID_TYPE(*ptr);
 
-#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))
