summaryrefslogtreecommitdiff
path: root/libffi/src
diff options
context:
space:
mode:
Diffstat (limited to 'libffi/src')
-rw-r--r--libffi/src/alpha/ffi.c252
-rw-r--r--libffi/src/alpha/ffitarget.h48
-rw-r--r--libffi/src/alpha/osf.S355
-rw-r--r--libffi/src/arm/ffi.c175
-rw-r--r--libffi/src/arm/ffitarget.h47
-rw-r--r--libffi/src/arm/sysv.S127
-rw-r--r--libffi/src/debug.c59
-rw-r--r--libffi/src/ffitest.c1314
-rw-r--r--libffi/src/ia64/ffi.c671
-rw-r--r--libffi/src/ia64/ffitarget.h58
-rw-r--r--libffi/src/ia64/ia64_flags.h62
-rw-r--r--libffi/src/ia64/unix.S326
-rw-r--r--libffi/src/java_raw_api.c340
-rw-r--r--libffi/src/m68k/ffi.c176
-rw-r--r--libffi/src/m68k/ffitarget.h47
-rw-r--r--libffi/src/m68k/sysv.S97
-rw-r--r--libffi/src/mips/ffi.c461
-rw-r--r--libffi/src/mips/ffitarget.h160
-rw-r--r--libffi/src/mips/n32.S319
-rw-r--r--libffi/src/mips/o32.S172
-rw-r--r--libffi/src/pa/ffi.c603
-rw-r--r--libffi/src/pa/ffitarget.h57
-rw-r--r--libffi/src/pa/linux.S281
-rw-r--r--libffi/src/powerpc/aix.S225
-rw-r--r--libffi/src/powerpc/aix_closure.S247
-rw-r--r--libffi/src/powerpc/asm.h128
-rw-r--r--libffi/src/powerpc/darwin.S225
-rw-r--r--libffi/src/powerpc/darwin_closure.S306
-rw-r--r--libffi/src/powerpc/ffi.c1133
-rw-r--r--libffi/src/powerpc/ffi_darwin.c704
-rw-r--r--libffi/src/powerpc/ffitarget.h91
-rw-r--r--libffi/src/powerpc/linux64.S176
-rw-r--r--libffi/src/powerpc/linux64_closure.S205
-rw-r--r--libffi/src/powerpc/ppc_closure.S250
-rw-r--r--libffi/src/powerpc/sysv.S191
-rw-r--r--libffi/src/prep_cif.c172
-rw-r--r--libffi/src/raw_api.c242
-rw-r--r--libffi/src/s390/ffi.c753
-rw-r--r--libffi/src/s390/ffitarget.h59
-rw-r--r--libffi/src/s390/sysv.S429
-rw-r--r--libffi/src/sh/ffi.c722
-rw-r--r--libffi/src/sh/ffitarget.h48
-rw-r--r--libffi/src/sh/sysv.S775
-rw-r--r--libffi/src/sh64/ffi.c448
-rw-r--r--libffi/src/sh64/ffitarget.h52
-rw-r--r--libffi/src/sh64/sysv.S484
-rw-r--r--libffi/src/sparc/ffi.c595
-rw-r--r--libffi/src/sparc/ffitarget.h65
-rw-r--r--libffi/src/sparc/v8.S257
-rw-r--r--libffi/src/sparc/v9.S302
-rw-r--r--libffi/src/types.c118
-rw-r--r--libffi/src/x86/darwin.S195
-rw-r--r--libffi/src/x86/ffi.c557
-rw-r--r--libffi/src/x86/ffi64.c706
-rw-r--r--libffi/src/x86/ffi_darwin.c584
-rw-r--r--libffi/src/x86/ffitarget.h81
-rw-r--r--libffi/src/x86/sysv.S184
-rw-r--r--libffi/src/x86/unix64.S303
-rw-r--r--libffi/src/x86/win32.S259
59 files changed, 18478 insertions, 0 deletions
diff --git a/libffi/src/alpha/ffi.c b/libffi/src/alpha/ffi.c
new file mode 100644
index 0000000..00d3379
--- /dev/null
+++ b/libffi/src/alpha/ffi.c
@@ -0,0 +1,252 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1998, 2001 Red Hat, Inc.
+
+ Alpha 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>
+
+extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
+extern void ffi_closure_osf(void);
+
+
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ /* Adjust cif->bytes to represent a minimum 6 words for the temporary
+ register argument loading area. */
+ if (cif->bytes < 6*FFI_SIZEOF_ARG)
+ cif->bytes = 6*FFI_SIZEOF_ARG;
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags = cif->rtype->type;
+ break;
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ break;
+ }
+
+ return FFI_OK;
+}
+
+void
+ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+{
+ unsigned long *stack, *argp;
+ long i, avn;
+ ffi_type **arg_types;
+
+ FFI_ASSERT (cif->abi == FFI_OSF);
+
+ /* 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->flags == FFI_TYPE_STRUCT)
+ rvalue = alloca(cif->rtype->size);
+
+ /* Allocate the space for the arguments, plus 4 words of temp
+ space for ffi_call_osf. */
+ argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
+
+ if (cif->flags == FFI_TYPE_STRUCT)
+ *(void **) argp++ = rvalue;
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ while (i < avn)
+ {
+ switch ((*arg_types)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(SINT64 *) argp = *(SINT8 *)(* avalue);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(SINT64 *) argp = *(UINT8 *)(* avalue);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(SINT64 *) argp = *(SINT16 *)(* avalue);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(SINT64 *) argp = *(UINT16 *)(* avalue);
+ break;
+
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ /* Note that unsigned 32-bit quantities are sign extended. */
+ *(SINT64 *) argp = *(SINT32 *)(* avalue);
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ *(UINT64 *) argp = *(UINT64 *)(* avalue);
+ break;
+
+ case FFI_TYPE_FLOAT:
+ if (argp - stack < 6)
+ {
+ /* Note the conversion -- all the fp regs are loaded as
+ doubles. The in-register format is the same. */
+ *(double *) argp = *(float *)(* avalue);
+ }
+ else
+ *(float *) argp = *(float *)(* avalue);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ *(double *) argp = *(double *)(* avalue);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ memcpy(argp, *avalue, (*arg_types)->size);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+
+ argp += ALIGN((*arg_types)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ i++, arg_types++, avalue++;
+ }
+
+ ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
+}
+
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data)
+{
+ unsigned int *tramp;
+
+ FFI_ASSERT (cif->abi == FFI_OSF);
+
+ tramp = (unsigned int *) &closure->tramp[0];
+ tramp[0] = 0x47fb0401; /* mov $27,$1 */
+ tramp[1] = 0xa77b0010; /* ldq $27,16($27) */
+ tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */
+ tramp[3] = 0x47ff041f; /* nop */
+ *(void **) &tramp[4] = ffi_closure_osf;
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ /* Flush the Icache.
+
+ Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
+ instead, since both Compaq as and gas can handle it.
+
+ 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */
+ asm volatile ("call_pal 0x86" : : : "memory");
+
+ return FFI_OK;
+}
+
+int
+ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
+{
+ ffi_cif *cif;
+ void **avalue;
+ ffi_type **arg_types;
+ long i, avn, argn;
+
+ cif = closure->cif;
+ avalue = alloca(cif->nargs * sizeof(void *));
+
+ argn = 0;
+
+ /* Copy the caller's structure return address to that the closure
+ returns the data directly to the caller. */
+ if (cif->flags == FFI_TYPE_STRUCT)
+ {
+ rvalue = (void *) argp[0];
+ argn = 1;
+ }
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ while (i < avn)
+ {
+ switch (arg_types[i]->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_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_STRUCT:
+ avalue[i] = &argp[argn];
+ break;
+
+ case FFI_TYPE_FLOAT:
+ if (argn < 6)
+ {
+ /* Floats coming from registers need conversion from double
+ back to float format. */
+ *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
+ avalue[i] = &argp[argn - 6];
+ }
+ else
+ avalue[i] = &argp[argn];
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+
+ argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ i++;
+ }
+
+ /* Invoke the closure. */
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_osf how to perform return type promotions. */
+ return cif->rtype->type;
+}
diff --git a/libffi/src/alpha/ffitarget.h b/libffi/src/alpha/ffitarget.h
new file mode 100644
index 0000000..00a1217
--- /dev/null
+++ b/libffi/src/alpha/ffitarget.h
@@ -0,0 +1,48 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for Alpha.
+
+ 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
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_OSF,
+ FFI_DEFAULT_ABI = FFI_OSF,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/alpha/osf.S b/libffi/src/alpha/osf.S
new file mode 100644
index 0000000..cfa7a96
--- /dev/null
+++ b/libffi/src/alpha/osf.S
@@ -0,0 +1,355 @@
+/* -----------------------------------------------------------------------
+ osf.S - Copyright (c) 1998, 2001 Red Hat
+
+ Alpha/OSF Foreign Function Interface
+
+ $Id: osf.S,v 1.1.1.1 1998/11/29 16:48:16 green Exp $
+
+ 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>
+
+ .arch ev6
+ .text
+
+/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
+ void *raddr, void (*fnaddr)());
+
+ Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
+ for this function. This has been allocated by ffi_call. We also
+ deallocate some of the stack that has been alloca'd. */
+
+ .align 3
+ .globl ffi_call_osf
+ .ent ffi_call_osf
+ffi_call_osf:
+ .frame $15, 32, $26, 0
+ .mask 0x4008000, -32
+$LFB1:
+ addq $16,$17,$1
+ mov $16, $30
+ stq $26, 0($1)
+$LCFI0:
+ stq $15, 8($1)
+$LCFI1:
+ stq $18, 16($1)
+ mov $1, $15
+$LCFI2:
+ .prologue 0
+
+ stq $19, 24($1)
+ mov $20, $27
+
+ # Load up all of the (potential) argument registers.
+ ldq $16, 0($30)
+ ldt $f16, 0($30)
+ ldt $f17, 8($30)
+ ldq $17, 8($30)
+ ldt $f18, 16($30)
+ ldq $18, 16($30)
+ ldt $f19, 24($30)
+ ldq $19, 24($30)
+ ldt $f20, 32($30)
+ ldq $20, 32($30)
+ ldt $f21, 40($30)
+ ldq $21, 40($30)
+
+ # Deallocate the register argument area.
+ lda $30, 48($30)
+
+ jsr $26, ($27), 0
+ ldgp $29, 0($26)
+
+ # If the return value pointer is NULL, assume no return value.
+ ldq $19, 24($15)
+ ldq $18, 16($15)
+ ldq $26, 0($15)
+ beq $19, $noretval
+
+ # Store the return value out in the proper type.
+ cmpeq $18, FFI_TYPE_INT, $1
+ bne $1, $retint
+ cmpeq $18, FFI_TYPE_FLOAT, $2
+ bne $2, $retfloat
+ cmpeq $18, FFI_TYPE_DOUBLE, $3
+ bne $3, $retdouble
+
+$noretval:
+ ldq $15, 8($15)
+ ret
+
+$retint:
+ stq $0, 0($19)
+ nop
+ ldq $15, 8($15)
+ ret
+
+$retfloat:
+ sts $f0, 0($19)
+ nop
+ ldq $15, 8($15)
+ ret
+
+$retdouble:
+ stt $f0, 0($19)
+ nop
+ ldq $15, 8($15)
+ ret
+$LFE1:
+
+ .end ffi_call_osf
+
+/* ffi_closure_osf(...)
+
+ Receives the closure argument in $1. */
+
+ .align 3
+ .globl ffi_closure_osf
+ .ent ffi_closure_osf
+ffi_closure_osf:
+ .frame $30, 16*8, $26, 0
+ .mask 0x4000000, -16*8
+$LFB2:
+ ldgp $29, 0($27)
+ subq $30, 16*8, $30
+$LCFI5:
+ stq $26, 0($30)
+$LCFI6:
+ .prologue 1
+
+ # Store all of the potential argument registers in va_list format.
+ stt $f16, 4*8($30)
+ stt $f17, 5*8($30)
+ stt $f18, 6*8($30)
+ stt $f19, 7*8($30)
+ stt $f20, 8*8($30)
+ stt $f21, 9*8($30)
+ stq $16, 10*8($30)
+ stq $17, 11*8($30)
+ stq $18, 12*8($30)
+ stq $19, 13*8($30)
+ stq $20, 14*8($30)
+ stq $21, 15*8($30)
+
+ # Call ffi_closure_osf_inner to do the bulk of the work.
+ mov $1, $16
+ lda $17, 2*8($30)
+ lda $18, 10*8($30)
+ jsr $26, ffi_closure_osf_inner
+ ldgp $29, 0($26)
+ ldq $26, 0($30)
+
+ # Load up the return value in the proper type.
+ lda $1, $load_table
+ s4addq $0, $1, $1
+ ldl $1, 0($1)
+ addq $1, $29, $1
+ jmp $31, ($1), $load_32
+
+ .align 4
+$load_none:
+ addq $30, 16*8, $30
+ ret
+
+ .align 4
+$load_float:
+ lds $f0, 16($30)
+ nop
+ addq $30, 16*8, $30
+ ret
+
+ .align 4
+$load_double:
+ ldt $f0, 16($30)
+ nop
+ addq $30, 16*8, $30
+ ret
+
+ .align 4
+$load_u8:
+#ifdef __alpha_bwx__
+ ldbu $0, 16($30)
+ nop
+#else
+ ldq $0, 16($30)
+ and $0, 255, $0
+#endif
+ addq $30, 16*8, $30
+ ret
+
+ .align 4
+$load_s8:
+#ifdef __alpha_bwx__
+ ldbu $0, 16($30)
+ sextb $0, $0
+#else
+ ldq $0, 16($30)
+ sll $0, 56, $0
+ sra $0, 56, $0
+#endif
+ addq $30, 16*8, $30
+ ret
+
+ .align 4
+$load_u16:
+#ifdef __alpha_bwx__
+ ldwu $0, 16($30)
+ nop
+#else
+ ldq $0, 16($30)
+ zapnot $0, 3, $0
+#endif
+ addq $30, 16*8, $30
+ ret
+
+ .align 4
+$load_s16:
+#ifdef __alpha_bwx__
+ ldwu $0, 16($30)
+ sextw $0, $0
+#else
+ ldq $0, 16($30)
+ sll $0, 48, $0
+ sra $0, 48, $0
+#endif
+ addq $30, 16*8, $30
+ ret
+
+ .align 4
+$load_32:
+ ldl $0, 16($30)
+ nop
+ addq $30, 16*8, $30
+ ret
+
+ .align 4
+$load_64:
+ ldq $0, 16($30)
+ nop
+ addq $30, 16*8, $30
+ ret
+$LFE2:
+
+ .end ffi_closure_osf
+
+#ifdef __ELF__
+.section .rodata
+#else
+.rdata
+#endif
+$load_table:
+ .gprel32 $load_none # FFI_TYPE_VOID
+ .gprel32 $load_32 # FFI_TYPE_INT
+ .gprel32 $load_float # FFI_TYPE_FLOAT
+ .gprel32 $load_double # FFI_TYPE_DOUBLE
+ .gprel32 $load_double # FFI_TYPE_LONGDOUBLE
+ .gprel32 $load_u8 # FFI_TYPE_UINT8
+ .gprel32 $load_s8 # FFI_TYPE_SINT8
+ .gprel32 $load_u16 # FFI_TYPE_UINT16
+ .gprel32 $load_s16 # FFI_TYPE_SINT16
+ .gprel32 $load_32 # FFI_TYPE_UINT32
+ .gprel32 $load_32 # FFI_TYPE_SINT32
+ .gprel32 $load_64 # FFI_TYPE_UINT64
+ .gprel32 $load_64 # FFI_TYPE_SINT64
+ .gprel32 $load_none # FFI_TYPE_STRUCT
+ .gprel32 $load_64 # FFI_TYPE_POINTER
+
+/* Assert that the table above is in sync with ffi.h. */
+
+#if FFI_TYPE_FLOAT != 2 \
+ || FFI_TYPE_DOUBLE != 3 \
+ || FFI_TYPE_UINT8 != 5 \
+ || FFI_TYPE_SINT8 != 6 \
+ || FFI_TYPE_UINT16 != 7 \
+ || FFI_TYPE_SINT16 != 8 \
+ || FFI_TYPE_UINT32 != 9 \
+ || FFI_TYPE_SINT32 != 10 \
+ || FFI_TYPE_UINT64 != 11 \
+ || FFI_TYPE_SINT64 != 12 \
+ || FFI_TYPE_STRUCT != 13 \
+ || FFI_TYPE_POINTER != 14 \
+ || FFI_TYPE_LAST != 14
+#error "osf.S out of sync with ffi.h"
+#endif
+
+#ifdef __ELF__
+ .section .eh_frame,EH_FRAME_FLAGS,@progbits
+__FRAME_BEGIN__:
+ .4byte $LECIE1-$LSCIE1 # Length of Common Information Entry
+$LSCIE1:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "zR\0" # CIE Augmentation
+ .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
+ .byte 0x78 # sleb128 -8; CIE Data Alignment Factor
+ .byte 0x1a # CIE RA Column
+ .byte 0x1 # uleb128 0x1; Augmentation size
+ .byte 0x1b # FDE Encoding (pcrel sdata4)
+ .byte 0xc # DW_CFA_def_cfa
+ .byte 0x1e # uleb128 0x1e
+ .byte 0x0 # uleb128 0x0
+ .align 3
+$LECIE1:
+$LSFDE1:
+ .4byte $LEFDE1-$LASFDE1 # FDE Length
+$LASFDE1:
+ .4byte $LASFDE1-__FRAME_BEGIN__ # FDE CIE offset
+ .4byte $LFB1-. # FDE initial location
+ .4byte $LFE1-$LFB1 # FDE address range
+ .byte 0x0 # uleb128 0x0; Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI0-$LFB1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .byte 0x30 # uleb128 0x30
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI1-$LCFI0
+ .byte 0x9a # DW_CFA_offset, column 0x1a
+ .byte 0x6 # uleb128 0x6
+ .byte 0x8f # DW_CFA_offset, column 0xf
+ .byte 0x5 # uleb128 0x5
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI2-$LCFI1
+ .byte 0xc # DW_CFA_def_cfa
+ .byte 0xf # uleb128 0xf
+ .byte 0x30 # uleb128 0x30
+ .align 3
+$LEFDE1:
+
+$LSFDE3:
+ .4byte $LEFDE3-$LASFDE3 # FDE Length
+$LASFDE3:
+ .4byte $LASFDE3-__FRAME_BEGIN__ # FDE CIE offset
+ .4byte $LFB2-. # FDE initial location
+ .4byte $LFE2-$LFB2 # FDE address range
+ .byte 0x0 # uleb128 0x0; Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI5-$LFB2
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .byte 0x90,0x1 # uleb128 0x90
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI6-$LCFI5
+ .byte 0x9a # DW_CFA_offset, column 0x1a
+ .byte 0x12 # uleb128 0x12
+ .align 3
+$LEFDE3:
+#endif
diff --git a/libffi/src/arm/ffi.c b/libffi/src/arm/ffi.c
new file mode 100644
index 0000000..37e3838
--- /dev/null
+++ b/libffi/src/arm/ffi.c
@@ -0,0 +1,175 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1998 Red Hat, Inc.
+
+ ARM 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>
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+/*@-exportheader@*/
+void ffi_prep_args(char *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+ register unsigned int i;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ argp = stack;
+
+ if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) {
+ *(void **) argp = ecif->rvalue;
+ argp += 4;
+ }
+
+ p_argv = ecif->avalue;
+
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
+ (i != 0);
+ i--, p_arg++)
+ {
+ size_t z;
+
+ /* Align if necessary */
+ if (((*p_arg)->alignment - 1) & (unsigned) argp) {
+ argp = (char *) ALIGN(argp, (*p_arg)->alignment);
+ }
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ }
+ else if (z == sizeof(int))
+ {
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ }
+ else
+ {
+ memcpy(argp, *p_argv, z);
+ }
+ p_argv++;
+ argp += z;
+ }
+
+ return;
+}
+
+/* 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_STRUCT:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags = (unsigned) cif->rtype->type;
+ break;
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ break;
+ }
+
+ return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
+ /*@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_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
diff --git a/libffi/src/arm/ffitarget.h b/libffi/src/arm/ffitarget.h
new file mode 100644
index 0000000..96f4bb2
--- /dev/null
+++ b/libffi/src/arm/ffitarget.h
@@ -0,0 +1,47 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for ARM.
+
+ 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
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_DEFAULT_ABI = FFI_SYSV,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 0
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/arm/sysv.S b/libffi/src/arm/sysv.S
new file mode 100644
index 0000000..0e41861
--- /dev/null
+++ b/libffi/src/arm/sysv.S
@@ -0,0 +1,127 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 1998 Red Hat, Inc.
+
+ ARM 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>
+#ifdef HAVE_MACHINE_ASM_H
+#include <machine/asm.h>
+#else
+#ifdef __USER_LABEL_PREFIX__
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+
+/* Use the right prefix for global labels. */
+#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+#else
+#define CNAME(x) x
+#endif
+#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
+#endif
+
+.text
+
+ # a1: ffi_prep_args
+ # a2: &ecif
+ # a3: cif->bytes
+ # a4: fig->flags
+ # sp+0: ecif.rvalue
+ # sp+4: fn
+
+ # This assumes we are using gas.
+ENTRY(ffi_call_SYSV)
+ # Save registers
+ stmfd sp!, {a1-a4, fp, lr}
+ mov fp, sp
+
+ # Make room for all of the new args.
+ sub sp, fp, a3
+
+ # Place all of the ffi_prep_args in position
+ mov ip, a1
+ mov a1, sp
+ # a2 already set
+
+ # And call
+ mov lr, pc
+ mov pc, ip
+
+ # move first 4 parameters in registers
+ ldr a1, [sp, #0]
+ ldr a2, [sp, #4]
+ ldr a3, [sp, #8]
+ ldr a4, [sp, #12]
+
+ # and adjust stack
+ ldr ip, [fp, #8]
+ cmp ip, #16
+ movge ip, #16
+ add sp, sp, ip
+
+ # call function
+ mov lr, pc
+ ldr pc, [fp, #28]
+
+ # Remove the space we pushed for the args
+ mov sp, fp
+
+ # Load a3 with the pointer to storage for the return value
+ ldr a3, [sp, #24]
+
+ # Load a4 with the return type code
+ ldr a4, [sp, #12]
+
+ # If the return value pointer is NULL, assume no return value.
+ cmp a3, #0
+ beq epilogue
+
+# return INT
+ cmp a4, #FFI_TYPE_INT
+ streq a1, [a3]
+ beq epilogue
+
+# return FLOAT
+ cmp a4, #FFI_TYPE_FLOAT
+#ifdef __SOFTFP__
+ streq a1, [a3]
+#else
+ stfeqs f0, [a3]
+#endif
+ beq epilogue
+
+# return DOUBLE or LONGDOUBLE
+ cmp a4, #FFI_TYPE_DOUBLE
+#ifdef __SOFTFP__
+ stmeqia a3, {a1, a2}
+#else
+ stfeqd f0, [a3]
+#endif
+
+epilogue:
+ ldmfd sp!, {a1-a4, fp, pc}
+
+.ffi_call_SYSV_end:
+ .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
+
diff --git a/libffi/src/debug.c b/libffi/src/debug.c
new file mode 100644
index 0000000..98f1f9f
--- /dev/null
+++ b/libffi/src/debug.c
@@ -0,0 +1,59 @@
+/* -----------------------------------------------------------------------
+ debug.c - Copyright (c) 1996 Red Hat, Inc.
+
+ 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>
+#include <stdio.h>
+
+/* General debugging routines */
+
+void ffi_stop_here(void)
+{
+ /* This function is only useful for debugging purposes.
+ Place a breakpoint on ffi_stop_here to be notified of
+ significant events. */
+}
+
+/* This function should only be called via the FFI_ASSERT() macro */
+
+void ffi_assert(char *expr, char *file, int line)
+{
+ fprintf(stderr, "ASSERTION FAILURE: %s at %s:%d\n", expr, file, line);
+ ffi_stop_here();
+ abort();
+}
+
+/* Perform a sanity check on an ffi_type structure */
+
+void ffi_type_test(ffi_type *a, char *file, int line)
+{
+ FFI_ASSERT_AT(a != NULL, file, line);
+
+ /*@-usedef@*/
+ FFI_ASSERT_AT(a->type <= FFI_TYPE_LAST, file, line);
+ FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->size > 0, file, line);
+ FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->alignment > 0, file, line);
+ FFI_ASSERT_AT(a->type != FFI_TYPE_STRUCT || a->elements != NULL, file, line);
+ /*@=usedef@*/
+}
diff --git a/libffi/src/ffitest.c b/libffi/src/ffitest.c
new file mode 100644
index 0000000..223b49c
--- /dev/null
+++ b/libffi/src/ffitest.c
@@ -0,0 +1,1314 @@
+/* -----------------------------------------------------------------------
+ ffitest.c - Copyright (c) 1996, 1997, 1998, 2002, 2003 Red Hat, Inc.
+
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+
+/* This is lame. Long double support is barely there under SunOS 4.x */
+#if defined(SPARC) && (SIZEOF_LONG_DOUBLE != 16)
+#define BROKEN_LONG_DOUBLE
+#endif
+
+#define CHECK(x) !(x) ? fail(__FILE__, __LINE__) : 0
+
+static int fail(char *file, int line)
+{
+ fprintf(stderr, "Test failure: %s line %d\n", file, line);
+ exit(EXIT_FAILURE);
+ /*@notreached@*/
+ return 0;
+}
+
+#define MAX_ARGS 256
+
+static size_t my_strlen(char *s)
+{
+ return (strlen(s));
+}
+
+#ifdef X86_WIN32
+static size_t __attribute__((stdcall)) my_stdcall_strlen(char *s)
+{
+ return (strlen(s));
+}
+#endif /* X86_WIN32 */
+
+static int promotion(signed char sc, signed short ss,
+ unsigned char uc, unsigned short us)
+{
+ int r = (int) sc + (int) ss + (int) uc + (int) us;
+
+ return r;
+}
+
+static signed char return_sc(signed char sc)
+{
+ return sc;
+}
+
+static unsigned char return_uc(unsigned char uc)
+{
+ return uc;
+}
+
+static long long return_ll(long long ll)
+{
+ return ll;
+}
+
+static int floating(int a, float b, double c, long double d, int e)
+{
+ int i;
+
+#if 0
+ /* This is ifdef'd out for now. long double support under SunOS/gcc
+ is pretty much non-existent. You'll get the odd bus error in library
+ routines like printf(). */
+ printf("%d %f %f %Lf %d\n", a, (double)b, c, d, e);
+#endif
+
+ i = (int) ((float)a/b + ((float)c/(float)d));
+
+ return i;
+}
+
+static float many(float f1,
+ float f2,
+ float f3,
+ float f4,
+ float f5,
+ float f6,
+ float f7,
+ float f8,
+ float f9,
+ float f10,
+ float f11,
+ float f12,
+ float f13)
+{
+#if 0
+ printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
+ (double) f1, (double) f2, (double) f3, (double) f4, (double) f5,
+ (double) f6, (double) f7, (double) f8, (double) f9, (double) f10,
+ (double) f11, (double) f12, (double) f13);
+#endif
+
+ return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13);
+}
+
+#ifdef X86_WIN32
+static float __attribute__((stdcall)) stdcall_many(float f1,
+ float f2,
+ float f3,
+ float f4,
+ float f5,
+ float f6,
+ float f7,
+ float f8,
+ float f9,
+ float f10,
+ float f11,
+ float f12,
+ float f13)
+{
+ return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13);
+}
+#endif /* X86_WIN32 */
+
+static double dblit(float f)
+{
+ return f/3.0;
+}
+
+static long double ldblit(float f)
+{
+ return (long double) (((long double) f)/ (long double) 3.0);
+}
+
+typedef struct
+{
+ unsigned char uc;
+ double d;
+ unsigned int ui;
+} test_structure_1;
+
+typedef struct
+{
+ double d1;
+ double d2;
+} test_structure_2;
+
+typedef struct
+{
+ int si;
+} test_structure_3;
+
+typedef struct
+{
+ unsigned ui1;
+ unsigned ui2;
+ unsigned ui3;
+} test_structure_4;
+
+typedef struct
+{
+ char c1;
+ char c2;
+} test_structure_5;
+
+typedef struct
+{
+ float f;
+ double d;
+} test_structure_6;
+
+typedef struct
+{
+ float f1;
+ float f2;
+ double d;
+} test_structure_7;
+
+typedef struct
+{
+ float f1;
+ float f2;
+ float f3;
+ float f4;
+} test_structure_8;
+
+typedef struct
+{
+ float f;
+ int i;
+} test_structure_9;
+
+static test_structure_1 struct1(test_structure_1 ts)
+{
+ /*@-type@*/
+ ts.uc++;
+ /*@=type@*/
+ ts.d--;
+ ts.ui++;
+
+ return ts;
+}
+
+static test_structure_2 struct2(test_structure_2 ts)
+{
+ ts.d1--;
+ ts.d2--;
+
+ return ts;
+}
+
+static test_structure_3 struct3(test_structure_3 ts)
+{
+ ts.si = -(ts.si*2);
+
+ return ts;
+}
+
+static test_structure_4 struct4(test_structure_4 ts)
+{
+ ts.ui3 = ts.ui1 * ts.ui2 * ts.ui3;
+
+ return ts;
+}
+
+static test_structure_5 struct5(test_structure_5 ts1, test_structure_5 ts2)
+{
+ ts1.c1 += ts2.c1;
+ ts1.c2 -= ts2.c2;
+
+ return ts1;
+}
+
+static test_structure_6 struct6 (test_structure_6 ts)
+{
+ ts.f += 1;
+ ts.d += 1;
+
+ return ts;
+}
+
+static test_structure_7 struct7 (test_structure_7 ts)
+{
+ ts.f1 += 1;
+ ts.f2 += 1;
+ ts.d += 1;
+
+ return ts;
+}
+
+static test_structure_8 struct8 (test_structure_8 ts)
+{
+ ts.f1 += 1;
+ ts.f2 += 1;
+ ts.f3 += 1;
+ ts.f4 += 1;
+
+ return ts;
+}
+
+static test_structure_9 struct9 (test_structure_9 ts)
+{
+ ts.f += 1;
+ ts.i += 1;
+
+ return ts;
+}
+
+/* Take an int and a float argument, together with int userdata, and */
+/* return the sum. */
+#if FFI_CLOSURES
+static void
+closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
+{
+ *(ffi_arg*)resp =
+ (int)*(unsigned long long *)args[0] + (int)(*(int *)args[1]) +
+ (int)(*(unsigned long long *)args[2]) + (int)*(int *)args[3] +
+ (int)(*(signed short *)args[4]) +
+ (int)(*(unsigned long long *)args[5]) +
+ (int)*(int *)args[6] + (int)(*(int *)args[7]) +
+ (int)(*(double *)args[8]) + (int)*(int *)args[9] +
+ (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(int *)args[13]) +
+ (int)(*(int *)args[14]) + *(int *)args[15] + (int)(long)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(unsigned long long *)args[0], (int)(*(int *)args[1]),
+ (int)(*(unsigned long long *)args[2]),
+ (int)*(int *)args[3], (int)(*(signed short *)args[4]),
+ (int)(*(unsigned long long *)args[5]),
+ (int)*(int *)args[6], (int)(*(int *)args[7]),
+ (int)(*(double *)args[8]), (int)*(int *)args[9],
+ (int)(*(int *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(int *)args[13]),
+ (int)(*(int *)args[14]),*(int *)args[15],
+ (int)(long)userdata, (int)*(ffi_arg *)resp);
+}
+
+typedef int (*closure_test_type)(unsigned long long, int, unsigned long long,
+ int, signed short, unsigned long long, int,
+ int, double, int, int, float, int, int,
+ int, int);
+
+static void closure_test_fn1(ffi_cif* cif,void* resp,void** args,
+ void* userdata)
+ {
+ *(ffi_arg*)resp =
+ (int)*(float *)args[0] +(int)(*(float *)args[1]) +
+ (int)(*(float *)args[2]) + (int)*(float *)args[3] +
+ (int)(*(signed short *)args[4]) + (int)(*(float *)args[5]) +
+ (int)*(float *)args[6] + (int)(*(int *)args[7]) +
+ (int)(*(double*)args[8]) + (int)*(int *)args[9] +
+ (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(int *)args[13]) +
+ (int)(*(int *)args[14]) + *(int *)args[15] + (int)(long)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(float *)args[0], (int)(*(float *)args[1]),
+ (int)(*(float *)args[2]), (int)*(float *)args[3],
+ (int)(*(signed short *)args[4]), (int)(*(float *)args[5]),
+ (int)*(float *)args[6], (int)(*(int *)args[7]),
+ (int)(*(double *)args[8]), (int)*(int *)args[9],
+ (int)(*(int *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(int *)args[13]),
+ (int)(*(int *)args[14]), *(int *)args[15],
+ (int)(long)userdata, (int)*(ffi_arg *)resp);
+}
+
+typedef int (*closure_test_type1)(float, float, float, float, signed short,
+ float, float, int, double, int, int, float,
+ int, int, int, int);
+
+static void closure_test_fn2(ffi_cif* cif,void* resp,void** args,
+ void* userdata)
+ {
+ *(ffi_arg*)resp =
+ (int)*(double *)args[0] +(int)(*(double *)args[1]) +
+ (int)(*(double *)args[2]) + (int)*(double *)args[3] +
+ (int)(*(signed short *)args[4]) + (int)(*(double *)args[5]) +
+ (int)*(double *)args[6] + (int)(*(int *)args[7]) +
+ (int)(*(double *)args[8]) + (int)*(int *)args[9] +
+ (int)(*(int *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(float *)args[13]) +
+ (int)(*(int *)args[14]) + *(int *)args[15] + (int)(long)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(double *)args[0], (int)(*(double *)args[1]),
+ (int)(*(double *)args[2]), (int)*(double *)args[3],
+ (int)(*(signed short *)args[4]), (int)(*(double *)args[5]),
+ (int)*(double *)args[6], (int)(*(int *)args[7]),
+ (int)(*(double*)args[8]), (int)*(int *)args[9],
+ (int)(*(int *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(float *)args[13]),
+ (int)(*(int *)args[14]), *(int *)args[15], (int)(long)userdata,
+ (int)*(ffi_arg *)resp);
+ }
+
+typedef int (*closure_test_type2)(double, double, double, double, signed short,
+ double, double, int, double, int, int, float,
+ int, float, int, int);
+
+static void closure_test_fn3(ffi_cif* cif,void* resp,void** args,
+ void* userdata)
+ {
+ *(ffi_arg*)resp =
+ (int)*(float *)args[0] +(int)(*(float *)args[1]) +
+ (int)(*(float *)args[2]) + (int)*(float *)args[3] +
+ (int)(*(float *)args[4]) + (int)(*(float *)args[5]) +
+ (int)*(float *)args[6] + (int)(*(float *)args[7]) +
+ (int)(*(double *)args[8]) + (int)*(int *)args[9] +
+ (int)(*(float *)args[10]) + (int)(*(float *)args[11]) +
+ (int)*(int *)args[12] + (int)(*(float *)args[13]) +
+ (int)(*(float *)args[14]) + *(int *)args[15] + (int)(long)userdata;
+
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n",
+ (int)*(float *)args[0], (int)(*(float *)args[1]),
+ (int)(*(float *)args[2]), (int)*(float *)args[3],
+ (int)(*(float *)args[4]), (int)(*(float *)args[5]),
+ (int)*(float *)args[6], (int)(*(float *)args[7]),
+ (int)(*(double *)args[8]), (int)*(int *)args[9],
+ (int)(*(float *)args[10]), (int)(*(float *)args[11]),
+ (int)*(int *)args[12], (int)(*(float *)args[13]),
+ (int)(*(float *)args[14]), *(int *)args[15], (int)(long)userdata,
+ (int)*(ffi_arg *)resp);
+ }
+
+typedef int (*closure_test_type3)(float, float, float, float, float, float,
+ float, float, double, int, float, float, int,
+ float, float, int);
+#endif
+
+int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
+{
+ ffi_cif cif;
+ ffi_type *args[MAX_ARGS];
+ void *values[MAX_ARGS];
+ char *s;
+ signed char sc;
+ unsigned char uc;
+ signed short ss;
+ unsigned short us;
+ unsigned long ul;
+ long long ll;
+ float f;
+ double d;
+ long double ld;
+ signed int si1;
+ signed int si2;
+
+ ffi_arg rint;
+ long long rlonglong;
+
+# if FFI_CLOSURES
+ /* The closure must not be an automatic variable on
+ platforms (Solaris) that forbid stack execution by default. */
+ static ffi_closure cl;
+ ffi_closure *pcl = &cl;
+#endif
+
+ ffi_type * cl_arg_types[17];
+
+ ffi_type ts1_type;
+ ffi_type ts2_type;
+ ffi_type ts3_type;
+ ffi_type ts4_type;
+ ffi_type ts5_type;
+ ffi_type ts6_type;
+ ffi_type ts7_type;
+ ffi_type ts8_type;
+ ffi_type ts9_type;
+ ffi_type *ts1_type_elements[4];
+ ffi_type *ts2_type_elements[3];
+ ffi_type *ts3_type_elements[2];
+ ffi_type *ts4_type_elements[4];
+ ffi_type *ts5_type_elements[3];
+ ffi_type *ts6_type_elements[3];
+ ffi_type *ts7_type_elements[4];
+ ffi_type *ts8_type_elements[5];
+ ffi_type *ts9_type_elements[3];
+
+ ts1_type.size = 0;
+ ts1_type.alignment = 0;
+ ts1_type.type = FFI_TYPE_STRUCT;
+
+ ts2_type.size = 0;
+ ts2_type.alignment = 0;
+ ts2_type.type = FFI_TYPE_STRUCT;
+
+ ts3_type.size = 0;
+ ts3_type.alignment = 0;
+ ts3_type.type = FFI_TYPE_STRUCT;
+
+ ts4_type.size = 0;
+ ts4_type.alignment = 0;
+ ts4_type.type = FFI_TYPE_STRUCT;
+
+ ts5_type.size = 0;
+ ts5_type.alignment = 0;
+ ts5_type.type = FFI_TYPE_STRUCT;
+
+ ts6_type.size = 0;
+ ts6_type.alignment = 0;
+ ts6_type.type = FFI_TYPE_STRUCT;
+
+ ts7_type.size = 0;
+ ts7_type.alignment = 0;
+ ts7_type.type = FFI_TYPE_STRUCT;
+
+ ts8_type.size = 0;
+ ts8_type.alignment = 0;
+ ts8_type.type = FFI_TYPE_STRUCT;
+
+ ts9_type.size = 0;
+ ts9_type.alignment = 0;
+ ts9_type.type = FFI_TYPE_STRUCT;
+
+ /*@-immediatetrans@*/
+ ts1_type.elements = ts1_type_elements;
+ ts2_type.elements = ts2_type_elements;
+ ts3_type.elements = ts3_type_elements;
+ ts4_type.elements = ts4_type_elements;
+ ts5_type.elements = ts5_type_elements;
+ ts6_type.elements = ts6_type_elements;
+ ts7_type.elements = ts7_type_elements;
+ ts8_type.elements = ts8_type_elements;
+ ts9_type.elements = ts9_type_elements;
+ /*@=immediatetrans@*/
+
+ ts1_type_elements[0] = &ffi_type_uchar;
+ ts1_type_elements[1] = &ffi_type_double;
+ ts1_type_elements[2] = &ffi_type_uint;
+ ts1_type_elements[3] = NULL;
+
+ ts2_type_elements[0] = &ffi_type_double;
+ ts2_type_elements[1] = &ffi_type_double;
+ ts2_type_elements[2] = NULL;
+
+ ts3_type_elements[0] = &ffi_type_sint;
+ ts3_type_elements[1] = NULL;
+
+ ts4_type_elements[0] = &ffi_type_uint;
+ ts4_type_elements[1] = &ffi_type_uint;
+ ts4_type_elements[2] = &ffi_type_uint;
+ ts4_type_elements[3] = NULL;
+
+ ts5_type_elements[0] = &ffi_type_schar;
+ ts5_type_elements[1] = &ffi_type_schar;
+ ts5_type_elements[2] = NULL;
+
+ ts6_type_elements[0] = &ffi_type_float;
+ ts6_type_elements[1] = &ffi_type_double;
+ ts6_type_elements[2] = NULL;
+
+ ts7_type_elements[0] = &ffi_type_float;
+ ts7_type_elements[1] = &ffi_type_float;
+ ts7_type_elements[2] = &ffi_type_double;
+ ts7_type_elements[3] = NULL;
+
+ ts8_type_elements[0] = &ffi_type_float;
+ ts8_type_elements[1] = &ffi_type_float;
+ ts8_type_elements[2] = &ffi_type_float;
+ ts8_type_elements[3] = &ffi_type_float;
+ ts8_type_elements[4] = NULL;
+
+ ts9_type_elements[0] = &ffi_type_float;
+ ts9_type_elements[1] = &ffi_type_sint;
+ ts9_type_elements[2] = NULL;
+
+ ul = 0;
+
+ /* return value tests */
+ {
+#if defined(MIPS) /* || defined(ARM) */
+ puts ("long long tests not run. This is a known bug on this architecture.");
+#else
+ args[0] = &ffi_type_sint64;
+ values[0] = &ll;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_sint64, args) == FFI_OK);
+
+ for (ll = 0LL; ll < 100LL; ll++)
+ {
+ ul++;
+ ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
+ CHECK(rlonglong == ll);
+ }
+
+ for (ll = 55555555555000LL; ll < 55555555555100LL; ll++)
+ {
+ ul++;
+ ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
+ CHECK(rlonglong == ll);
+ }
+#endif
+
+ args[0] = &ffi_type_schar;
+ values[0] = &sc;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_schar, args) == FFI_OK);
+
+ for (sc = (signed char) -127;
+ sc < (signed char) 127; /*@-type@*/ sc++ /*@=type@*/)
+ {
+ ul++;
+ ffi_call(&cif, FFI_FN(return_sc), &rint, values);
+ CHECK(rint == (ffi_arg) sc);
+ }
+
+ args[0] = &ffi_type_uchar;
+ values[0] = &uc;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_uchar, args) == FFI_OK);
+
+ for (uc = (unsigned char) '\x00';
+ uc < (unsigned char) '\xff'; /*@-type@*/ uc++ /*@=type@*/)
+ {
+ ul++;
+ ffi_call(&cif, FFI_FN(return_uc), &rint, values);
+ CHECK(rint == (signed int) uc);
+ }
+
+ printf("%lu return value tests run\n", ul);
+ }
+
+#ifdef BROKEN_LONG_DOUBLE
+ printf ("This architecture has broken `long double' support. No floating point\ntests have been run.\n");
+#else
+ /* float arg tests */
+ {
+ args[0] = &ffi_type_float;
+ values[0] = &f;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_longdouble, args) == FFI_OK);
+
+ f = 3.14159;
+
+#if 0
+ /* This is ifdef'd out for now. long double support under SunOS/gcc
+ is pretty much non-existent. You'll get the odd bus error in library
+ routines like printf(). */
+ printf ("%Lf\n", ldblit(f));
+#endif
+ ld = 666;
+ ffi_call(&cif, FFI_FN(ldblit), &ld, values);
+
+#if 0
+ /* This is ifdef'd out for now. long double support under SunOS/gcc
+ is pretty much non-existent. You'll get the odd bus error in library
+ routines like printf(). */
+ printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON);
+#endif
+
+ /* These are not always the same!! Check for a reasonable delta */
+ /*@-realcompare@*/
+ if (ld - ldblit(f) < LDBL_EPSILON)
+ /*@=realcompare@*/
+ puts("long double return value tests ok!");
+ else
+ CHECK(0);
+ }
+
+ /* float arg tests */
+ {
+ args[0] = &ffi_type_sint;
+ values[0] = &si1;
+ args[1] = &ffi_type_float;
+ values[1] = &f;
+ args[2] = &ffi_type_double;
+ values[2] = &d;
+ args[3] = &ffi_type_longdouble;
+ values[3] = &ld;
+ args[4] = &ffi_type_sint;
+ values[4] = &si2;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 5,
+ &ffi_type_sint, args) == FFI_OK);
+
+ si1 = 6;
+ f = 3.14159;
+ d = (double)1.0/(double)3.0;
+ ld = 2.71828182846L;
+ si2 = 10;
+
+ floating (si1, f, d, ld, si2);
+
+ ffi_call(&cif, FFI_FN(floating), &rint, values);
+
+ printf ("%d vs %d\n", (int)rint, floating (si1, f, d, ld, si2));
+
+ CHECK(rint == floating(si1, f, d, ld, si2));
+
+ printf("float arg tests ok!\n");
+ }
+#endif
+
+ /* strlen tests */
+ {
+ args[0] = &ffi_type_pointer;
+ values[0] = (void*) &s;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_sint, args) == FFI_OK);
+
+ s = "a";
+ ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
+ CHECK(rint == 1);
+
+ s = "1234567";
+ ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
+ CHECK(rint == 7);
+
+ s = "1234567890123456789012345";
+ ffi_call(&cif, FFI_FN(my_strlen), &rint, values);
+ CHECK(rint == 25);
+
+ printf("strlen tests passed\n");
+ }
+
+ /* float arg tests */
+ {
+ args[0] = &ffi_type_float;
+ values[0] = &f;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_double, args) == FFI_OK);
+
+ f = 3.14159;
+
+ ffi_call(&cif, FFI_FN(dblit), &d, values);
+
+ /* These are not always the same!! Check for a reasonable delta */
+ /*@-realcompare@*/
+ CHECK(d - dblit(f) < DBL_EPSILON);
+ /*@=realcompare@*/
+
+ printf("double return value tests ok!\n");
+ }
+
+ /* many arg tests */
+ {
+ float ff;
+ float fa[13];
+
+ for (ul = 0; ul < 13; ul++)
+ {
+ args[ul] = &ffi_type_float;
+ values[ul] = &fa[ul];
+ fa[ul] = (float) ul;
+ }
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13,
+ &ffi_type_float, args) == FFI_OK);
+
+ /*@-usedef@*/
+ ff = many (fa[0], fa[1],
+ fa[2], fa[3],
+ fa[4], fa[5],
+ fa[6], fa[7],
+ fa[8], fa[9],
+ fa[10],fa[11],fa[12]);
+ /*@=usedef@*/
+
+ ffi_call(&cif, FFI_FN(many), &f, values);
+
+ /*@-realcompare@*/
+ if (f - ff < FLT_EPSILON)
+ /*@=realcompare@*/
+ printf("many arg tests ok!\n");
+ else
+#ifdef POWERPC
+ printf("many arg tests failed! This is a gcc bug.\n");
+#else
+ CHECK(0);
+#endif
+ }
+
+ /* promotion tests */
+ {
+ args[0] = &ffi_type_schar;
+ args[1] = &ffi_type_sshort;
+ args[2] = &ffi_type_uchar;
+ args[3] = &ffi_type_ushort;
+ values[0] = &sc;
+ values[1] = &ss;
+ values[2] = &uc;
+ values[3] = &us;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4,
+ &ffi_type_sint, args) == FFI_OK);
+
+ us = 0;
+ ul = 0;
+
+ for (sc = (signed char) -127;
+ sc <= (signed char) 120; /*@-type@*/ sc += 1 /*@=type@*/)
+ for (ss = -30000; ss <= 30000; ss += 10000)
+ for (uc = (unsigned char) 0;
+ uc <= (unsigned char) 200; /*@-type@*/ uc += 20 /*@=type@*/)
+ for (us = 0; us <= 60000; us += 10000)
+ {
+ ul++;
+ ffi_call(&cif, FFI_FN(promotion), &rint, values);
+ CHECK((int)rint == (signed char) sc + (signed short) ss +
+ (unsigned char) uc + (unsigned short) us);
+ }
+ printf("%lu promotion tests run\n", ul);
+ }
+
+#ifndef X86_WIN32 /* Structures dont work on Win32 */
+
+ /* struct tests */
+ {
+ test_structure_1 ts1_arg;
+ /* This is a hack to get a properly aligned result buffer */
+ test_structure_1 *ts1_result =
+ (test_structure_1 *) malloc (sizeof(test_structure_1));
+
+ args[0] = &ts1_type;
+ values[0] = &ts1_arg;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ts1_type, args) == FFI_OK);
+
+ ts1_arg.uc = '\x01';
+ ts1_arg.d = 3.14159;
+ ts1_arg.ui = 555;
+
+ ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
+
+ CHECK(ts1_result->ui == 556);
+ CHECK(ts1_result->d == 3.14159 - 1);
+
+ puts ("structure test 1 ok!\n");
+
+ free (ts1_result);
+ }
+
+ /* struct tests */
+ {
+ test_structure_2 ts2_arg;
+
+ /* This is a hack to get a properly aligned result buffer */
+ test_structure_2 *ts2_result =
+ (test_structure_2 *) malloc (sizeof(test_structure_2));
+
+ args[0] = &ts2_type;
+ values[0] = &ts2_arg;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts2_type, args) == FFI_OK);
+
+ ts2_arg.d1 = 5.55;
+ ts2_arg.d2 = 6.66;
+
+ printf ("%g\n", ts2_arg.d1);
+ printf ("%g\n", ts2_arg.d2);
+
+ ffi_call(&cif, FFI_FN(struct2), ts2_result, values);
+
+ printf ("%g\n", ts2_result->d1);
+ printf ("%g\n", ts2_result->d2);
+
+ CHECK(ts2_result->d1 == 5.55 - 1);
+ CHECK(ts2_result->d2 == 6.66 - 1);
+
+ printf("structure test 2 ok!\n");
+
+ free (ts2_result);
+ }
+
+ /* struct tests */
+ {
+ int compare_value;
+ test_structure_3 ts3_arg;
+ test_structure_3 *ts3_result =
+ (test_structure_3 *) malloc (sizeof(test_structure_3));
+
+ args[0] = &ts3_type;
+ values[0] = &ts3_arg;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ts3_type, args) == FFI_OK);
+
+ ts3_arg.si = -123;
+ compare_value = ts3_arg.si;
+
+ ffi_call(&cif, FFI_FN(struct3), ts3_result, values);
+
+ printf ("%d %d\n", ts3_result->si, -(compare_value*2));
+
+ if (ts3_result->si == -(ts3_arg.si*2))
+ puts ("structure test 3 ok!");
+ else
+ {
+ puts ("Structure test 3 found structure passing bug.");
+ puts (" Current versions of GCC are not 100% compliant with the");
+ puts (" n32 ABI. There is a known problem related to passing");
+ puts (" small structures. Send a bug report to the gcc maintainers.");
+ }
+
+ free (ts3_result);
+ }
+
+ /* struct tests */
+ {
+ test_structure_4 ts4_arg;
+
+ /* This is a hack to get a properly aligned result buffer */
+ test_structure_4 *ts4_result =
+ (test_structure_4 *) malloc (sizeof(test_structure_4));
+
+ args[0] = &ts4_type;
+ values[0] = &ts4_arg;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts4_type, args) == FFI_OK);
+
+ ts4_arg.ui1 = 2;
+ ts4_arg.ui2 = 3;
+ ts4_arg.ui3 = 4;
+
+ ffi_call (&cif, FFI_FN(struct4), ts4_result, values);
+
+ if (ts4_result->ui3 == 2U * 3U * 4U)
+ puts ("structure test 4 ok!");
+ else
+ puts ("Structure test 4 found GCC's structure passing bug.");
+
+ free (ts4_result);
+ }
+
+ /* struct tests */
+ {
+ test_structure_5 ts5_arg1, ts5_arg2;
+
+ /* This is a hack to get a properly aligned result buffer */
+ test_structure_5 *ts5_result =
+ (test_structure_5 *) malloc (sizeof(test_structure_5));
+
+ args[0] = &ts5_type;
+ args[1] = &ts5_type;
+ values[0] = &ts5_arg1;
+ values[1] = &ts5_arg2;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ts5_type, args) == FFI_OK);
+
+ ts5_arg1.c1 = 2;
+ ts5_arg1.c2 = 6;
+ ts5_arg2.c1 = 5;
+ ts5_arg2.c2 = 3;
+
+ ffi_call (&cif, FFI_FN(struct5), ts5_result, values);
+
+ if (ts5_result->c1 == 7
+ && ts5_result->c2 == 3)
+ puts ("structure test 5 ok!");
+ else
+ puts ("Structure test 5 found GCC's structure passing bug.");
+
+ free (ts5_result);
+ }
+
+ /* struct tests */
+ {
+ test_structure_6 ts6_arg;
+
+ /* This is a hack to get a properly aligned result buffer */
+ test_structure_6 *ts6_result =
+ (test_structure_6 *) malloc (sizeof(test_structure_6));
+
+ args[0] = &ts6_type;
+ values[0] = &ts6_arg;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts6_type, args) == FFI_OK);
+
+ ts6_arg.f = 5.55f;
+ ts6_arg.d = 6.66;
+
+ printf ("%g\n", ts6_arg.f);
+ printf ("%g\n", ts6_arg.d);
+
+ ffi_call(&cif, FFI_FN(struct6), ts6_result, values);
+
+ printf ("%g\n", ts6_result->f);
+ printf ("%g\n", ts6_result->d);
+
+ CHECK(ts6_result->f == 5.55f + 1);
+ CHECK(ts6_result->d == 6.66 + 1);
+
+ printf("structure test 6 ok!\n");
+
+ free (ts6_result);
+ }
+
+ /* struct tests */
+ {
+ test_structure_7 ts7_arg;
+
+ /* This is a hack to get a properly aligned result buffer */
+ test_structure_7 *ts7_result =
+ (test_structure_7 *) malloc (sizeof(test_structure_7));
+
+ args[0] = &ts7_type;
+ values[0] = &ts7_arg;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts7_type, args) == FFI_OK);
+
+ ts7_arg.f1 = 5.55f;
+ ts7_arg.f2 = 55.5f;
+ ts7_arg.d = 6.66;
+
+ printf ("%g\n", ts7_arg.f1);
+ printf ("%g\n", ts7_arg.f2);
+ printf ("%g\n", ts7_arg.d);
+
+ ffi_call(&cif, FFI_FN(struct7), ts7_result, values);
+
+ printf ("%g\n", ts7_result->f1);
+ printf ("%g\n", ts7_result->f2);
+ printf ("%g\n", ts7_result->d);
+
+ CHECK(ts7_result->f1 == 5.55f + 1);
+ CHECK(ts7_result->f2 == 55.5f + 1);
+ CHECK(ts7_result->d == 6.66 + 1);
+
+ printf("structure test 7 ok!\n");
+
+ free (ts7_result);
+ }
+
+ /* struct tests */
+ {
+ test_structure_8 ts8_arg;
+
+ /* This is a hack to get a properly aligned result buffer */
+ test_structure_8 *ts8_result =
+ (test_structure_8 *) malloc (sizeof(test_structure_8));
+
+ args[0] = &ts8_type;
+ values[0] = &ts8_arg;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts8_type, args) == FFI_OK);
+
+ ts8_arg.f1 = 5.55f;
+ ts8_arg.f2 = 55.5f;
+ ts8_arg.f3 = -5.55f;
+ ts8_arg.f4 = -55.5f;
+
+ printf ("%g\n", ts8_arg.f1);
+ printf ("%g\n", ts8_arg.f2);
+ printf ("%g\n", ts8_arg.f3);
+ printf ("%g\n", ts8_arg.f4);
+
+ ffi_call(&cif, FFI_FN(struct8), ts8_result, values);
+
+ printf ("%g\n", ts8_result->f1);
+ printf ("%g\n", ts8_result->f2);
+ printf ("%g\n", ts8_result->f3);
+ printf ("%g\n", ts8_result->f4);
+
+ CHECK(ts8_result->f1 == 5.55f + 1);
+ CHECK(ts8_result->f2 == 55.5f + 1);
+ CHECK(ts8_result->f3 == -5.55f + 1);
+ CHECK(ts8_result->f4 == -55.5f + 1);
+
+ printf("structure test 8 ok!\n");
+
+ free (ts8_result);
+ }
+
+ /* struct tests */
+ {
+ test_structure_9 ts9_arg;
+
+ /* This is a hack to get a properly aligned result buffer */
+ test_structure_9 *ts9_result =
+ (test_structure_9 *) malloc (sizeof(test_structure_9));
+
+ args[0] = &ts9_type;
+ values[0] = &ts9_arg;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts9_type, args) == FFI_OK);
+
+ ts9_arg.f = 5.55f;
+ ts9_arg.i = 5;
+
+ printf ("%g\n", ts9_arg.f);
+ printf ("%d\n", ts9_arg.i);
+
+ ffi_call(&cif, FFI_FN(struct9), ts9_result, values);
+
+ printf ("%g\n", ts9_result->f);
+ printf ("%d\n", ts9_result->i);
+
+ CHECK(ts9_result->f == 5.55f + 1);
+ CHECK(ts9_result->i == 5 + 1);
+
+ printf("structure test 9 ok!\n");
+
+ free (ts9_result);
+ }
+
+#else
+ printf("Structure passing doesn't work on Win32.\n");
+#endif /* X86_WIN32 */
+
+#ifdef X86_WIN32
+ /* stdcall strlen tests */
+ {
+ args[0] = &ffi_type_pointer;
+ values[0] = (void*) &s;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 1,
+ &ffi_type_sint, args) == FFI_OK);
+
+ s = "a";
+ ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values);
+ CHECK(rint == 1);
+
+ s = "1234567";
+ ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values);
+ CHECK(rint == 7);
+
+ s = "1234567890123456789012345";
+ ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values);
+ CHECK(rint == 25);
+
+ printf("stdcall strlen tests passed\n");
+ }
+
+ /* stdcall many arg tests */
+ {
+ float ff;
+ float fa[13];
+
+ for (ul = 0; ul < 13; ul++)
+ {
+ args[ul] = &ffi_type_float;
+ values[ul] = &fa[ul];
+ fa[ul] = (float) ul;
+ }
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 13,
+ &ffi_type_float, args) == FFI_OK);
+
+ /*@-usedef@*/
+ ff = stdcall_many(fa[0], fa[1],
+ fa[2], fa[3],
+ fa[4], fa[5],
+ fa[6], fa[7],
+ fa[8], fa[9],
+ fa[10],fa[11],fa[12]);
+ /*@=usedef@*/
+
+ ffi_call(&cif, FFI_FN(stdcall_many), &f, values);
+
+ /*@-realcompare@*/
+ if (f - ff < FLT_EPSILON)
+ /*@=realcompare@*/
+ printf("stdcall many arg tests ok!\n");
+ else
+ CHECK(0);
+ }
+#endif /* X86_WIN32 */
+
+# if FFI_CLOSURES
+# if __GNUC__ >= 2
+ /* Hide before the compiler that pcl is &cl, since on
+ some architectures it is not possible to call a data
+ object using direct function call. */
+ asm ("" : "=g" (pcl) : "0" (pcl));
+# endif
+
+ /* A simple closure test */
+ {
+ (void) puts("\nEnter FFI_CLOSURES\n");
+
+ cl_arg_types[0] = &ffi_type_uint64;
+ cl_arg_types[1] = &ffi_type_uint;
+ cl_arg_types[2] = &ffi_type_uint64;
+ cl_arg_types[3] = &ffi_type_uint;
+ cl_arg_types[4] = &ffi_type_sshort;
+ cl_arg_types[5] = &ffi_type_uint64;
+ cl_arg_types[6] = &ffi_type_uint;
+ cl_arg_types[7] = &ffi_type_uint;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_uint;
+ cl_arg_types[10] = &ffi_type_uint;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_uint;
+ cl_arg_types[13] = &ffi_type_uint;
+ cl_arg_types[14] = &ffi_type_uint;
+ cl_arg_types[15] = &ffi_type_uint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn,
+ (void *) 3 /* userdata */) == FFI_OK);
+
+ CHECK((*((closure_test_type)pcl))
+ (1LL, 2, 3LL, 4, 127, 429LL, 7, 8, 9.5, 10, 11, 12, 13,
+ 19, 21, 1) == 680);
+ }
+
+ {
+
+ cl_arg_types[0] = &ffi_type_float;
+ cl_arg_types[1] = &ffi_type_float;
+ cl_arg_types[2] = &ffi_type_float;
+ cl_arg_types[3] = &ffi_type_float;
+ cl_arg_types[4] = &ffi_type_sshort;
+ cl_arg_types[5] = &ffi_type_float;
+ cl_arg_types[6] = &ffi_type_float;
+ cl_arg_types[7] = &ffi_type_uint;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_uint;
+ cl_arg_types[10] = &ffi_type_uint;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_uint;
+ cl_arg_types[13] = &ffi_type_uint;
+ cl_arg_types[14] = &ffi_type_uint;
+ cl_arg_types[15] = &ffi_type_uint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn1,
+ (void *) 3 /* userdata */) == FFI_OK);
+
+ CHECK((*((closure_test_type1)pcl))
+ (1.1, 2.2, 3.3, 4.4, 127, 5.5, 6.6, 8, 9, 10, 11, 12.0, 13,
+ 19, 21, 1) == 255);
+ }
+
+ {
+
+ cl_arg_types[0] = &ffi_type_double;
+ cl_arg_types[1] = &ffi_type_double;
+ cl_arg_types[2] = &ffi_type_double;
+ cl_arg_types[3] = &ffi_type_double;
+ cl_arg_types[4] = &ffi_type_sshort;
+ cl_arg_types[5] = &ffi_type_double;
+ cl_arg_types[6] = &ffi_type_double;
+ cl_arg_types[7] = &ffi_type_uint;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_uint;
+ cl_arg_types[10] = &ffi_type_uint;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_uint;
+ cl_arg_types[13] = &ffi_type_float;
+ cl_arg_types[14] = &ffi_type_uint;
+ cl_arg_types[15] = &ffi_type_uint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn2,
+ (void *) 3 /* userdata */) == FFI_OK);
+
+ CHECK((*((closure_test_type2)pcl))
+ (1, 2, 3, 4, 127, 5, 6, 8, 9, 10, 11, 12.0, 13,
+ 19.0, 21, 1) == 255);
+
+ }
+
+ {
+
+ cl_arg_types[0] = &ffi_type_float;
+ cl_arg_types[1] = &ffi_type_float;
+ cl_arg_types[2] = &ffi_type_float;
+ cl_arg_types[3] = &ffi_type_float;
+ cl_arg_types[4] = &ffi_type_float;
+ cl_arg_types[5] = &ffi_type_float;
+ cl_arg_types[6] = &ffi_type_float;
+ cl_arg_types[7] = &ffi_type_float;
+ cl_arg_types[8] = &ffi_type_double;
+ cl_arg_types[9] = &ffi_type_uint;
+ cl_arg_types[10] = &ffi_type_float;
+ cl_arg_types[11] = &ffi_type_float;
+ cl_arg_types[12] = &ffi_type_uint;
+ cl_arg_types[13] = &ffi_type_float;
+ cl_arg_types[14] = &ffi_type_float;
+ cl_arg_types[15] = &ffi_type_uint;
+ cl_arg_types[16] = NULL;
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16,
+ &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+ CHECK(ffi_prep_closure(pcl, &cif, closure_test_fn3,
+ (void *) 3 /* userdata */) == FFI_OK);
+
+ CHECK((*((closure_test_type3)pcl))
+ (1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9, 10, 11.11, 12.0, 13,
+ 19.19, 21.21, 1) == 135);
+ }
+
+ (void) puts("\nFinished FFI_CLOSURES\n");
+
+# endif
+
+ /* If we arrived here, all is good */
+ (void) puts("\nLooks good. No surprises.\n");
+
+ /*@-compdestroy@*/
+
+ return 0;
+}
+
diff --git a/libffi/src/ia64/ffi.c b/libffi/src/ia64/ffi.c
new file mode 100644
index 0000000..1dc27db
--- /dev/null
+++ b/libffi/src/ia64/ffi.c
@@ -0,0 +1,671 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1998 Red Hat, Inc.
+ Copyright (c) 2000 Hewlett Packard Company
+
+ IA64 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>
+#include <stdbool.h>
+
+#include "ia64_flags.h"
+
+/* Memory image of fp register contents. Should eventually be an fp */
+/* type long enough to hold an entire register. For now we use double. */
+typedef double float80;
+
+/* The stack layout at call to ffi_prep_args. Other_args will remain */
+/* on the stack for the actual call. Everything else we be transferred */
+/* to registers and popped by the assembly code. */
+
+struct ia64_args {
+ long scratch[2]; /* Two scratch words at top of stack. */
+ /* Allows sp to be passed as arg pointer. */
+ void * r8_contents; /* Value to be passed in r8 */
+ long spare; /* Not used. */
+ float80 fp_regs[8]; /* Contents of 8 floating point argument */
+ /* registers. */
+ long out_regs[8]; /* Contents of the 8 out registers used */
+ /* for integer parameters. */
+ long other_args[0]; /* Arguments passed on stack, variable size */
+ /* Treated as continuation of out_regs. */
+};
+
+static size_t float_type_size(unsigned short tp)
+{
+ switch(tp) {
+ case FFI_TYPE_FLOAT:
+ return sizeof(float);
+ case FFI_TYPE_DOUBLE:
+ return sizeof(double);
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ return sizeof(long double);
+#endif
+ default:
+ FFI_ASSERT(0);
+ }
+}
+
+/*
+ * Is type a struct containing at most n floats, doubles, or extended
+ * doubles, all of the same fp type?
+ * If so, set *element_type to the fp type.
+ */
+static bool is_homogeneous_fp_aggregate(ffi_type * type, int n,
+ unsigned short * element_type)
+{
+ ffi_type **ptr;
+ unsigned short element, struct_element;
+
+ int type_set = 0;
+
+ FFI_ASSERT(type != NULL);
+
+ FFI_ASSERT(type->elements != NULL);
+
+ ptr = &(type->elements[0]);
+
+ while ((*ptr) != NULL)
+ {
+ switch((*ptr) -> type) {
+ case FFI_TYPE_FLOAT:
+ if (type_set && element != FFI_TYPE_FLOAT) return 0;
+ if (--n < 0) return false;
+ type_set = 1;
+ element = FFI_TYPE_FLOAT;
+ break;
+ case FFI_TYPE_DOUBLE:
+ if (type_set && element != FFI_TYPE_DOUBLE) return 0;
+ if (--n < 0) return false;
+ type_set = 1;
+ element = FFI_TYPE_DOUBLE;
+ break;
+ case FFI_TYPE_STRUCT:
+ if (!is_homogeneous_fp_aggregate(type, n, &struct_element))
+ return false;
+ if (type_set && struct_element != element) return false;
+ n -= (type -> size)/float_type_size(element);
+ element = struct_element;
+ if (n < 0) return false;
+ break;
+ /* case FFI_TYPE_LONGDOUBLE:
+ Not yet implemented. */
+ default:
+ return false;
+ }
+ ptr++;
+ }
+ *element_type = element;
+ return true;
+
+}
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments. It fills in
+ the arguments in the structure referenced by stack. Returns nonzero
+ if fp registers are used for arguments. */
+
+static bool
+ffi_prep_args(struct ia64_args *stack, extended_cif *ecif, int bytes)
+{
+ register long i, avn;
+ register void **p_argv;
+ register long *argp = stack -> out_regs;
+ register float80 *fp_argp = stack -> fp_regs;
+ register ffi_type **p_arg;
+
+ /* For big return structs, r8 needs to contain the target address. */
+ /* Since r8 is otherwise dead, we set it unconditionally. */
+ stack -> r8_contents = ecif -> rvalue;
+ i = 0;
+ avn = ecif->cif->nargs;
+ p_arg = ecif->cif->arg_types;
+ p_argv = ecif->avalue;
+ while (i < avn)
+ {
+ size_t z; /* z is in units of arg slots or words, not bytes. */
+
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ z = 1;
+ *(SINT64 *) argp = *(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ z = 1;
+ *(UINT64 *) argp = *(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ z = 1;
+ *(SINT64 *) argp = *(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ z = 1;
+ *(UINT64 *) argp = *(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT32:
+ z = 1;
+ *(SINT64 *) argp = *(SINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT32:
+ z = 1;
+ *(UINT64 *) argp = *(UINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ z = 1;
+ *(UINT64 *) argp = *(UINT64 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_FLOAT:
+ z = 1;
+ if (fp_argp - stack->fp_regs < 8)
+ {
+ /* Note the conversion -- all the fp regs are loaded as
+ doubles. */
+ *fp_argp++ = *(float *)(* p_argv);
+ }
+ /* Also put it into the integer registers or memory: */
+ *(UINT64 *) argp = *(UINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ z = 1;
+ if (fp_argp - stack->fp_regs < 8)
+ *fp_argp++ = *(double *)(* p_argv);
+ /* Also put it into the integer registers or memory: */
+ *(double *) argp = *(double *)(* p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ {
+ size_t sz = (*p_arg)->size;
+ unsigned short element_type;
+ z = ((*p_arg)->size + FFI_SIZEOF_ARG - 1)/FFI_SIZEOF_ARG;
+ if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
+ int i;
+ int nelements = sz/float_type_size(element_type);
+ for (i = 0; i < nelements; ++i) {
+ switch (element_type) {
+ case FFI_TYPE_FLOAT:
+ if (fp_argp - stack->fp_regs < 8)
+ *fp_argp++ = ((float *)(* p_argv))[i];
+ break;
+ case FFI_TYPE_DOUBLE:
+ if (fp_argp - stack->fp_regs < 8)
+ *fp_argp++ = ((double *)(* p_argv))[i];
+ break;
+ default:
+ /* Extended precision not yet implemented. */
+ abort();
+ }
+ }
+ }
+ /* And pass it in integer registers as a struct, with */
+ /* its actual field sizes packed into registers. */
+ memcpy(argp, *p_argv, (*p_arg)->size);
+ }
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+
+ argp += z;
+ i++, p_arg++, p_argv++;
+ }
+ return (fp_argp != stack -> fp_regs);
+}
+
+/* Perform machine dependent cif processing */
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ long i, avn;
+ bool is_simple = true;
+ long simple_flag = FFI_SIMPLE_V;
+ /* Adjust cif->bytes to include space for the 2 scratch words,
+ r8 register contents, spare word,
+ the 8 fp register contents, and all 8 integer register contents.
+ This will be removed before the call, though 2 scratch words must
+ remain. */
+
+ cif->bytes += 4*sizeof(long) + 8 *sizeof(float80);
+ if (cif->bytes < sizeof(struct ia64_args))
+ cif->bytes = sizeof(struct ia64_args);
+
+ /* The stack must be double word aligned, so round bytes up
+ appropriately. */
+
+ cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
+
+ avn = cif->nargs;
+ if (avn <= 2) {
+ for (i = 0; i < avn; ++i) {
+ switch(cif -> arg_types[i] -> type) {
+ case FFI_TYPE_SINT32:
+ simple_flag = FFI_ADD_INT_ARG(simple_flag);
+ break;
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ simple_flag = FFI_ADD_LONG_ARG(simple_flag);
+ break;
+ default:
+ is_simple = false;
+ }
+ }
+ } else {
+ is_simple = false;
+ }
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_VOID:
+ cif->flags = FFI_TYPE_VOID;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ {
+ size_t sz = cif -> rtype -> size;
+ unsigned short element_type;
+
+ is_simple = false;
+ if (is_homogeneous_fp_aggregate(cif -> rtype, 8, &element_type)) {
+ int nelements = sz/float_type_size(element_type);
+ if (nelements <= 1) {
+ if (0 == nelements) {
+ cif -> flags = FFI_TYPE_VOID;
+ } else {
+ cif -> flags = element_type;
+ }
+ } else {
+ switch(element_type) {
+ case FFI_TYPE_FLOAT:
+ cif -> flags = FFI_IS_FLOAT_FP_AGGREGATE | nelements;
+ break;
+ case FFI_TYPE_DOUBLE:
+ cif -> flags = FFI_IS_DOUBLE_FP_AGGREGATE | nelements;
+ break;
+ default:
+ /* long double NYI */
+ abort();
+ }
+ }
+ break;
+ }
+ if (sz <= 32) {
+ if (sz <= 8) {
+ cif->flags = FFI_TYPE_INT;
+ } else if (sz <= 16) {
+ cif->flags = FFI_IS_SMALL_STRUCT2;
+ } else if (sz <= 24) {
+ cif->flags = FFI_IS_SMALL_STRUCT3;
+ } else {
+ cif->flags = FFI_IS_SMALL_STRUCT4;
+ }
+ } else {
+ cif->flags = FFI_TYPE_STRUCT;
+ }
+ }
+ break;
+
+ case FFI_TYPE_FLOAT:
+ is_simple = false;
+ cif->flags = FFI_TYPE_FLOAT;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ is_simple = false;
+ cif->flags = FFI_TYPE_DOUBLE;
+ break;
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ /* This seems to depend on little endian mode, and the fact that */
+ /* the return pointer always points to at least 8 bytes. But */
+ /* that also seems to be true for other platforms. */
+ break;
+ }
+
+ if (is_simple) cif -> flags |= simple_flag;
+ return FFI_OK;
+}
+
+extern int ffi_call_unix(bool (*)(struct ia64_args *, extended_cif *, int),
+ extended_cif *, unsigned,
+ unsigned, unsigned *, void (*)());
+
+void
+ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+{
+ extended_cif ecif;
+ long simple = cif -> flags & FFI_SIMPLE;
+
+ /* Should this also check for Unix ABI? */
+ /* This is almost, but not quite, machine independent. Note that */
+ /* we can get away with not caring about length of the result because */
+ /* we assume we are little endian, and the result buffer is large */
+ /* enough. */
+ /* This needs work for HP/UX. */
+ if (simple) {
+ long (*lfn)() = (long (*)())fn;
+ long result;
+ switch(simple) {
+ case FFI_SIMPLE_V:
+ result = lfn();
+ break;
+ case FFI_SIMPLE_I:
+ result = lfn(*(int *)avalue[0]);
+ break;
+ case FFI_SIMPLE_L:
+ result = lfn(*(long *)avalue[0]);
+ break;
+ case FFI_SIMPLE_II:
+ result = lfn(*(int *)avalue[0], *(int *)avalue[1]);
+ break;
+ case FFI_SIMPLE_IL:
+ result = lfn(*(int *)avalue[0], *(long *)avalue[1]);
+ break;
+ case FFI_SIMPLE_LI:
+ result = lfn(*(long *)avalue[0], *(int *)avalue[1]);
+ break;
+ case FFI_SIMPLE_LL:
+ result = lfn(*(long *)avalue[0], *(long *)avalue[1]);
+ break;
+ }
+ if ((cif->flags & ~FFI_SIMPLE) != FFI_TYPE_VOID && 0 != rvalue) {
+ * (long *)rvalue = result;
+ }
+ return;
+ }
+ 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_UNIX:
+ ffi_call_unix(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, rvalue, fn);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+/*
+ * Closures represent a pair consisting of a function pointer, and
+ * some user data. A closure is invoked by reinterpreting the closure
+ * as a function pointer, and branching to it. Thus we can make an
+ * interpreted function callable as a C function: We turn the interpreter
+ * itself, together with a pointer specifying the interpreted procedure,
+ * into a closure.
+ * On X86, the first few words of the closure structure actually contain code,
+ * which will do the right thing. On most other architectures, this
+ * would raise some Icache/Dcache coherence issues (which can be solved, but
+ * often not cheaply).
+ * For IA64, function pointer are already pairs consisting of a code
+ * pointer, and a gp pointer. The latter is needed to access global variables.
+ * Here we set up such a pair as the first two words of the closure (in
+ * the "trampoline" area), but we replace the gp pointer with a pointer
+ * to the closure itself. We also add the real gp pointer to the
+ * closure. This allows the function entry code to both retrieve the
+ * user data, and to restire the correct gp pointer.
+ */
+
+static void
+ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
+ void **avalue, ffi_cif *cif);
+
+/* This function is entered with the doctored gp (r1) value.
+ * This code is extremely gcc specific. There is some argument that
+ * it should really be written in assembly code, since it depends on
+ * gcc properties that might change over time.
+ */
+
+/* ffi_closure_UNIX is an assembly routine, which copies the register */
+/* state into a struct ia64_args, and then invokes */
+/* ffi_closure_UNIX_inner. It also recovers the closure pointer */
+/* from its fake gp pointer. */
+void ffi_closure_UNIX();
+
+#ifndef __GNUC__
+# error This requires gcc
+#endif
+void
+ffi_closure_UNIX_inner (ffi_closure *closure, struct ia64_args * args)
+/* Hopefully declaring this as a varargs function will force all args */
+/* to memory. */
+{
+ // this is our return value storage
+ long double res;
+
+ // our various things...
+ ffi_cif *cif;
+ unsigned short rtype;
+ void *resp;
+ void **arg_area;
+
+ resp = (void*)&res;
+ cif = closure->cif;
+ arg_area = (void**) alloca (cif->nargs * sizeof (void*));
+
+ /* this call will initialize ARG_AREA, such that each
+ * element in that array points to the corresponding
+ * value on the stack; and if the function returns
+ * a structure, it will re-set RESP to point to the
+ * structure return address. */
+
+ ffi_prep_incoming_args_UNIX(args, (void**)&resp, arg_area, cif);
+
+ (closure->fun) (cif, resp, arg_area, closure->user_data);
+
+ rtype = cif->flags;
+
+ /* now, do a generic return based on the value of rtype */
+ if (rtype == FFI_TYPE_INT)
+ {
+ asm volatile ("ld8 r8=[%0]" : : "r" (resp) : "r8");
+ }
+ else if (rtype == FFI_TYPE_FLOAT)
+ {
+ asm volatile ("ldfs f8=[%0]" : : "r" (resp) : "f8");
+ }
+ else if (rtype == FFI_TYPE_DOUBLE)
+ {
+ asm volatile ("ldfd f8=[%0]" : : "r" (resp) : "f8");
+ }
+ else if (rtype == FFI_IS_SMALL_STRUCT2)
+ {
+ asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]"
+ : : "r" (resp), "r" (resp+8) : "r8","r9");
+ }
+ else if (rtype == FFI_IS_SMALL_STRUCT3)
+ {
+ asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]"
+ : : "r" (resp), "r" (resp+8), "r" (resp+16)
+ : "r8","r9","r10");
+ }
+ else if (rtype == FFI_IS_SMALL_STRUCT4)
+ {
+ asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]; ld8 r11=[%3]"
+ : : "r" (resp), "r" (resp+8), "r" (resp+16), "r" (resp+24)
+ : "r8","r9","r10","r11");
+ }
+ else if (rtype != FFI_TYPE_VOID && rtype != FFI_TYPE_STRUCT)
+ {
+ /* Can only happen for homogeneous FP aggregates? */
+ abort();
+ }
+}
+
+static void
+ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
+ void **avalue, ffi_cif *cif)
+{
+ register unsigned int i;
+ register unsigned int avn;
+ register void **p_argv;
+ register long *argp = args -> out_regs;
+ unsigned fp_reg_num = 0;
+ register ffi_type **p_arg;
+
+ avn = cif->nargs;
+ p_argv = avalue;
+
+ for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++)
+ {
+ size_t z; /* In units of words or argument slots. */
+
+ switch ((*p_arg)->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_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ z = 1;
+ *p_argv = (void *)argp;
+ break;
+
+ case FFI_TYPE_FLOAT:
+ z = 1;
+ /* Convert argument back to float in place from the saved value */
+ if (argp - args->out_regs < 8 && fp_reg_num < 8) {
+ *(float *)argp = args -> fp_regs[fp_reg_num++];
+ }
+ *p_argv = (void *)argp;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ z = 1;
+ if (argp - args->out_regs < 8 && fp_reg_num < 8) {
+ *p_argv = args -> fp_regs + fp_reg_num++;
+ } else {
+ *p_argv = (void *)argp;
+ }
+ break;
+
+ case FFI_TYPE_STRUCT:
+ {
+ size_t sz = (*p_arg)->size;
+ unsigned short element_type;
+ z = ((*p_arg)->size + FFI_SIZEOF_ARG - 1)/FFI_SIZEOF_ARG;
+ if (argp - args->out_regs < 8
+ && is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
+ int nelements = sz/float_type_size(element_type);
+ if (nelements + fp_reg_num >= 8) {
+ /* hard case NYI. */
+ abort();
+ }
+ if (element_type == FFI_TYPE_DOUBLE) {
+ *p_argv = args -> fp_regs + fp_reg_num;
+ fp_reg_num += nelements;
+ break;
+ }
+ if (element_type == FFI_TYPE_FLOAT) {
+ int j;
+ for (j = 0; j < nelements; ++ j) {
+ ((float *)argp)[j] = args -> fp_regs[fp_reg_num + j];
+ }
+ *p_argv = (void *)argp;
+ fp_reg_num += nelements;
+ break;
+ }
+ abort(); /* Other fp types NYI */
+ }
+ }
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+
+ argp += z;
+ p_argv++;
+
+ }
+
+ return;
+}
+
+
+/* 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 */
+
+/* The layout of a function descriptor. A C function pointer really */
+/* points to one of these. */
+typedef struct ia64_fd_struct {
+ void *code_pointer;
+ void *gp;
+} ia64_fd;
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data)
+{
+ struct ffi_ia64_trampoline_struct *tramp =
+ (struct ffi_ia64_trampoline_struct *) (closure -> tramp);
+ ia64_fd *fd = (ia64_fd *)(void *)ffi_closure_UNIX;
+
+ FFI_ASSERT (cif->abi == FFI_UNIX);
+
+ tramp -> code_pointer = fd -> code_pointer;
+ tramp -> real_gp = fd -> gp;
+ tramp -> fake_gp = closure;
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+
diff --git a/libffi/src/ia64/ffitarget.h b/libffi/src/ia64/ffitarget.h
new file mode 100644
index 0000000..3b78654
--- /dev/null
+++ b/libffi/src/ia64/ffitarget.h
@@ -0,0 +1,58 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for IA-64.
+
+ 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
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_UNIX, /* Linux and all Unix variants use the same conventions */
+ FFI_DEFAULT_ABI = FFI_UNIX,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */
+ /* can be interpreted as a C function */
+ /* descriptor: */
+
+#ifndef LIBFFI_ASM
+struct ffi_ia64_trampoline_struct {
+ void * code_pointer; /* Pointer to ffi_closure_UNIX */
+ void * fake_gp; /* Pointer to closure, installed as gp */
+ void * real_gp; /* Real gp value, reinstalled by */
+ /* ffi_closure_UNIX. */
+};
+#endif
+
+#endif
+
diff --git a/libffi/src/ia64/ia64_flags.h b/libffi/src/ia64/ia64_flags.h
new file mode 100644
index 0000000..23dbd3e
--- /dev/null
+++ b/libffi/src/ia64/ia64_flags.h
@@ -0,0 +1,62 @@
+/* -----------------------------------------------------------------------
+ ia64_flags.h - Copyright (c) 2000 Hewlett Packard Company
+
+ IA64/unix Foreign Function Interface
+
+ Original author: Hans Boehm, HP Labs
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+
+/* Homogeneous Floating Point Aggregates (HFAs) which are returned */
+/* in FP registers. The least significant bits specify the size in */
+/* words. */
+#define FFI_IS_FLOAT_FP_AGGREGATE 0x1000
+#define FFI_IS_DOUBLE_FP_AGGREGATE 0x0800
+#define FLOAT_FP_AGGREGATE_BIT 12
+#define DOUBLE_FP_AGGREGATE_BIT 11
+
+/* Small structures containing N words. If N=1, they are returned */
+/* as though they were integers. */
+#define FFI_IS_SMALL_STRUCT2 0x40 /* Struct > 8, <=16 bytes */
+#define FFI_IS_SMALL_STRUCT3 0x41 /* Struct > 16 <= 24 bytes */
+#define FFI_IS_SMALL_STRUCT4 0x42 /* Struct > 24, <=32 bytes */
+
+/* Flag values identifying particularly simple cases, which are */
+/* handled specially. We treat functions as simple if they take all */
+/* arguments can be passed as 32 or 64 bit integer quantities, there is */
+/* either no return value or it can be treated as a 64bit integer, and */
+/* if there are at most 2 arguments. */
+/* This is OR'ed with the normal flag values. */
+#define FFI_SIMPLE_V 0x10000 /* () -> X */
+#define FFI_SIMPLE_I 0x20000 /* (int) -> X */
+#define FFI_SIMPLE_L 0x30000 /* (long) -> X */
+#define FFI_SIMPLE_II 0x40000 /* (int,int) -> X */
+#define FFI_SIMPLE_IL 0x50000 /* (int,long) -> X */
+#define FFI_SIMPLE_LI 0x60000 /* (long,int) -> X */
+#define FFI_SIMPLE_LL 0x70000 /* (long,long) -> X */
+
+/* Mask for all of the FFI_SIMPLE bits: */
+#define FFI_SIMPLE 0xf0000
+
+/* An easy way to build FFI_SIMPLE flags from FFI_SIMPLE_V: */
+#define FFI_ADD_LONG_ARG(flag) (((flag) << 1) | 0x10000)
+#define FFI_ADD_INT_ARG(flag) ((flag) << 1)
diff --git a/libffi/src/ia64/unix.S b/libffi/src/ia64/unix.S
new file mode 100644
index 0000000..c0c5058
--- /dev/null
+++ b/libffi/src/ia64/unix.S
@@ -0,0 +1,326 @@
+/* -----------------------------------------------------------------------
+ unix.S - Copyright (c) 1998 Red Hat, Inc.
+ Copyright (c) 2000 Hewlett Packard Company
+
+ IA64/unix Foreign Function Interface
+
+ Primary author: Hans Boehm, HP Labs
+
+ Loosely modeled on Cygnus code for other platforms.
+
+ 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>
+#include "ia64_flags.h"
+
+/* parameters: */
+#define callback in0
+#define ecifp in1
+#define bytes in2
+#define flags in3
+#define raddr in4
+#define fn in5
+
+#define FLOAT_SZ 8 /* in-memory size of fp operands */
+
+/* Allocate an ia64_args structure on the stack; call ffi_prep_args */
+/* to fill it in with argument values; copy those to the real */
+/* registers, leaving overflow arguments on the stack. Then call fn */
+/* and move the result from registers into *raddr. */
+ .pred.safe_across_calls p1-p5,p16-p63
+.text
+ .align 16
+ .global ffi_call_unix
+ .proc ffi_call_unix
+ffi_call_unix:
+ .prologue
+ .save ar.pfs,r38 /* loc0 */
+ alloc loc0=ar.pfs,6,6,8,0
+ .save rp,loc1
+ mov loc1=b0;
+ .vframe loc5
+ mov loc5=sp;
+ .body
+ sub sp=sp,bytes
+ mov loc4=r1 /* Save gp */
+ ld8 r8=[callback],8 /* code address of callback */
+ ;;
+ mov out0=sp
+ mov out1=ecifp
+ mov out2=bytes
+ ld8 r1=[callback] /* Set up gp for callback. Unnecessary? */
+ mov b6=r8
+ ;;
+ br.call.sptk.many b0 = b6 /* call ffi_prep_args */
+ cmp.eq p6,p0=0,r8 /* r8 nonzero ==> need fp regs */
+ ;;
+(p6) add loc2=32+8*FLOAT_SZ,sp
+(p6) br.cond.dptk.many fp_done
+ ;; /* Quiets warning; needed? */
+ add loc2=32,sp
+ add loc3=32+FLOAT_SZ,sp
+ ;;
+ ldfd f8=[loc2],2*FLOAT_SZ
+ ldfd f9=[loc3],2*FLOAT_SZ
+ ;;
+ ldfd f10=[loc2],2*FLOAT_SZ
+ ldfd f11=[loc3],2*FLOAT_SZ
+ ;;
+ ldfd f12=[loc2],2*FLOAT_SZ
+ ldfd f13=[loc3],2*FLOAT_SZ
+ ;;
+ ldfd f14=[loc2],2*FLOAT_SZ
+ ldfd f15=[loc3]
+fp_done:
+ add r9=16,sp /* Pointer to r8_contents */
+ /* loc2 points at first integer register value. */
+ add loc3=8,loc2
+ ;;
+ ld8 r8=[r9] /* Just in case we return large struct */
+ ld8 out0=[loc2],16
+ ld8 out1=[loc3],16
+ ;;
+ ld8 out2=[loc2],16
+ ld8 out3=[loc3],16
+ ;;
+ ld8 out4=[loc2],16
+ ld8 out5=[loc3],16
+ ;;
+ ld8 out6=[loc2]
+ ld8 out7=[loc3]
+ /* Set sp to 16 bytes below the first stack parameter. This */
+ /* is the value currently in loc2. */
+ mov sp=loc2
+
+ ld8 r8=[fn],8
+ ;;
+ ld8 r1=[fn] /* Set up gp */
+ mov b6=r8;;
+ br.call.sptk.many b0 = b6 /* call fn */
+
+ /* Handle return value. */
+ cmp.eq p6,p0=0,raddr
+ cmp.eq p7,p0=FFI_TYPE_INT,flags
+ cmp.eq p10,p0=FFI_IS_SMALL_STRUCT2,flags
+ cmp.eq p11,p0=FFI_IS_SMALL_STRUCT3,flags
+ cmp.eq p12,p0=FFI_IS_SMALL_STRUCT4,flags
+ ;;
+(p6) br.cond.dpnt.few done /* Dont copy ret values if raddr = 0 */
+(p7) br.cond.dptk.few copy1
+(p10) br.cond.dpnt.few copy2
+(p11) br.cond.dpnt.few copy3
+(p12) br.cond.dpnt.few copy4
+ cmp.eq p8,p0=FFI_TYPE_FLOAT,flags
+ cmp.eq p9,p0=FFI_TYPE_DOUBLE,flags
+ tbit.nz p6,p0=flags,FLOAT_FP_AGGREGATE_BIT
+ tbit.nz p7,p0=flags,DOUBLE_FP_AGGREGATE_BIT
+ ;;
+(p8) stfs [raddr]=f8
+(p9) stfd [raddr]=f8
+ ;;
+ .label_state 1
+(p6) br.cond.dpnt.few handle_float_hfa
+(p7) br.cond.dpnt.few handle_double_hfa
+ br done
+
+copy4:
+ add loc3=24,raddr
+ ;;
+ st8 [loc3]=r11
+copy3:
+ add loc3=16,raddr
+ ;;
+ st8 [loc3]=r10
+copy2:
+ add loc3=8,raddr
+ ;;
+ st8 [loc3]=r9
+copy1:
+ st8 [raddr]=r8
+ /* In the big struct case, raddr was passed as an argument. */
+ /* In the void case there was nothing to do. */
+
+done:
+ mov r1=loc4 /* Restore gp */
+ mov ar.pfs = loc0
+ mov b0 = loc1
+ .restore sp
+ mov sp = loc5
+ br.ret.sptk.many b0
+
+handle_double_hfa:
+ .body
+ .copy_state 1
+ /* Homogeneous floating point array of doubles is returned in */
+ /* registers f8-f15. Save one at a time to return area. */
+ and flags=0xf,flags /* Retrieve size */
+ ;;
+ cmp.eq p6,p0=2,flags
+ cmp.eq p7,p0=3,flags
+ cmp.eq p8,p0=4,flags
+ cmp.eq p9,p0=5,flags
+ cmp.eq p10,p0=6,flags
+ cmp.eq p11,p0=7,flags
+ cmp.eq p12,p0=8,flags
+ ;;
+(p6) br.cond.dptk.few dhfa2
+(p7) br.cond.dptk.few dhfa3
+(p8) br.cond.dptk.few dhfa4
+(p9) br.cond.dptk.few dhfa5
+(p10) br.cond.dptk.few dhfa6
+(p11) br.cond.dptk.few dhfa7
+dhfa8: add loc3=7*8,raddr
+ ;;
+ stfd [loc3]=f15
+dhfa7: add loc3=6*8,raddr
+ ;;
+ stfd [loc3]=f14
+dhfa6: add loc3=5*8,raddr
+ ;;
+ stfd [loc3]=f13
+dhfa5: add loc3=4*8,raddr
+ ;;
+ stfd [loc3]=f12
+dhfa4: add loc3=3*8,raddr
+ ;;
+ stfd [loc3]=f11
+dhfa3: add loc3=2*8,raddr
+ ;;
+ stfd [loc3]=f10
+dhfa2: add loc3=1*8,raddr
+ ;;
+ stfd [loc3]=f9
+ stfd [raddr]=f8
+ br done
+
+handle_float_hfa:
+ /* Homogeneous floating point array of floats is returned in */
+ /* registers f8-f15. Save one at a time to return area. */
+ and flags=0xf,flags /* Retrieve size */
+ ;;
+ cmp.eq p6,p0=2,flags
+ cmp.eq p7,p0=3,flags
+ cmp.eq p8,p0=4,flags
+ cmp.eq p9,p0=5,flags
+ cmp.eq p10,p0=6,flags
+ cmp.eq p11,p0=7,flags
+ cmp.eq p12,p0=8,flags
+ ;;
+(p6) br.cond.dptk.few shfa2
+(p7) br.cond.dptk.few shfa3
+(p8) br.cond.dptk.few shfa4
+(p9) br.cond.dptk.few shfa5
+(p10) br.cond.dptk.few shfa6
+(p11) br.cond.dptk.few shfa7
+shfa8: add loc3=7*4,raddr
+ ;;
+ stfd [loc3]=f15
+shfa7: add loc3=6*4,raddr
+ ;;
+ stfd [loc3]=f14
+shfa6: add loc3=5*4,raddr
+ ;;
+ stfd [loc3]=f13
+shfa5: add loc3=4*4,raddr
+ ;;
+ stfd [loc3]=f12
+shfa4: add loc3=3*4,raddr
+ ;;
+ stfd [loc3]=f11
+shfa3: add loc3=2*4,raddr
+ ;;
+ stfd [loc3]=f10
+shfa2: add loc3=1*4,raddr
+ ;;
+ stfd [loc3]=f9
+ stfd [raddr]=f8
+ br done
+
+ .endp ffi_call_unix
+
+
+ .pred.safe_across_calls p1-p5,p16-p63
+.text
+ .align 16
+ .global ffi_closure_UNIX
+ .proc ffi_closure_UNIX
+ffi_closure_UNIX:
+ .prologue
+ .save ar.pfs,r40 /* loc0 */
+ alloc loc0=ar.pfs,8,3,2,0
+ .save rp,loc1
+ mov loc1=b0
+ .vframe loc2
+ mov loc2=sp
+ /* Retrieve closure pointer and real gp. */
+ mov out0=gp
+ add gp=16,gp
+ ;;
+ ld8 gp=[gp]
+ /* Reserve a structia64_args on the stack such that arguments */
+ /* past the first 8 are automatically placed in the right */
+ /* slot. Note that when we start the sp points at 2 8-byte */
+ /* scratch words, followed by the extra arguments. */
+# define BASIC_ARGS_SZ (8*FLOAT_SZ+8*8+2*8)
+# define FIRST_FP_OFFSET (4*8)
+ add r14=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET),sp
+ add r15=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET-FLOAT_SZ),sp
+ add sp=-BASIC_ARGS_SZ,sp
+ /* r14 points to fp_regs[0], r15 points to fp_regs[1] */
+ ;;
+ stfd [r14]=f8,2*FLOAT_SZ
+ stfd [r15]=f9,2*FLOAT_SZ
+ ;;
+ stfd [r14]=f10,2*FLOAT_SZ
+ stfd [r15]=f11,2*FLOAT_SZ
+ ;;
+ stfd [r14]=f12,2*FLOAT_SZ
+ stfd [r15]=f13,2*FLOAT_SZ
+ ;;
+ stfd [r14]=f14,FLOAT_SZ+8
+ stfd [r15]=f15,2*8
+ ;;
+ /* r14 points to first parameter register area, r15 to second. */
+ st8 [r14]=in0,2*8
+ st8 [r15]=in1,2*8
+ ;;
+ st8 [r14]=in2,2*8
+ st8 [r15]=in3,2*8
+ ;;
+ st8 [r14]=in4,2*8
+ st8 [r15]=in5,2*8
+ ;;
+ st8 [r14]=in6,2*8
+ st8 [r15]=in7,2*8
+ /* Call ffi_closure_UNIX_inner */
+ mov out1=sp
+ br.call.sptk.many b0=ffi_closure_UNIX_inner
+ ;;
+ mov b0=loc1
+ mov ar.pfs=loc0
+ .restore sp
+ mov sp=loc2
+ br.ret.sptk.many b0
+ .endp ffi_closure_UNIX
+
+
diff --git a/libffi/src/java_raw_api.c b/libffi/src/java_raw_api.c
new file mode 100644
index 0000000..5b0e347
--- /dev/null
+++ b/libffi/src/java_raw_api.c
@@ -0,0 +1,340 @@
+/* -----------------------------------------------------------------------
+ java_raw_api.c - Copyright (c) 1999 Red Hat, Inc.
+
+ Cloned from raw_api.c
+
+ Raw_api.c author: Kresten Krab Thorup <krab@gnu.org>
+ Java_raw_api.c author: Hans-J. Boehm <hboehm@hpl.hp.com>
+
+ $Id $
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+/* This defines a Java- and 64-bit specific variant of the raw API. */
+/* It assumes that "raw" argument blocks look like Java stacks on a */
+/* 64-bit machine. Arguments that can be stored in a single stack */
+/* stack slots (longs, doubles) occupy 128 bits, but only the first */
+/* 64 bits are actually used. */
+
+#include <ffi.h>
+#include <ffi_common.h>
+#include <stdlib.h>
+
+#if !defined(NO_JAVA_RAW_API) && !defined(FFI_NO_RAW_API)
+
+size_t
+ffi_java_raw_size (ffi_cif *cif)
+{
+ size_t result = 0;
+ int i;
+
+ ffi_type **at = cif->arg_types;
+
+ for (i = cif->nargs-1; i >= 0; i--, at++)
+ {
+ switch((*at) -> type) {
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_DOUBLE:
+ result += 2 * FFI_SIZEOF_ARG;
+ break;
+ case FFI_TYPE_STRUCT:
+ /* No structure parameters in Java. */
+ abort();
+ default:
+ result += FFI_SIZEOF_ARG;
+ }
+ }
+
+ return result;
+}
+
+
+void
+ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
+{
+ unsigned i;
+ ffi_type **tp = cif->arg_types;
+
+#if WORDS_BIGENDIAN
+
+ for (i = 0; i < cif->nargs; i++, tp++, args++)
+ {
+ switch ((*tp)->type)
+ {
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ *args = (void*) ((char*)(raw++) + 3);
+ break;
+
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ *args = (void*) ((char*)(raw++) + 2);
+ break;
+
+#if FFI_SIZEOF_ARG == 8
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_DOUBLE:
+ *args = (void *)raw;
+ raw += 2;
+ break;
+#endif
+
+ case FFI_TYPE_POINTER:
+ *args = (void*) &(raw++)->ptr;
+ break;
+
+ default:
+ *args = raw;
+ raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ }
+ }
+
+#else /* WORDS_BIGENDIAN */
+
+#if !PDP
+
+ /* then assume little endian */
+ for (i = 0; i < cif->nargs; i++, tp++, args++)
+ {
+#if FFI_SIZEOF_ARG == 8
+ switch((*tp)->type) {
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_DOUBLE:
+ *args = (void*) raw;
+ raw += 2;
+ break;
+ default:
+ *args = (void*) raw++;
+ }
+#else /* FFI_SIZEOF_ARG != 8 */
+ *args = (void*) raw;
+ raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
+#endif /* FFI_SIZEOF_ARG == 8 */
+ }
+
+#else
+#error "pdp endian not supported"
+#endif /* ! PDP */
+
+#endif /* WORDS_BIGENDIAN */
+}
+
+void
+ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
+{
+ unsigned i;
+ ffi_type **tp = cif->arg_types;
+
+ for (i = 0; i < cif->nargs; i++, tp++, args++)
+ {
+ switch ((*tp)->type)
+ {
+ case FFI_TYPE_UINT8:
+#if WORDS_BIGENDIAN
+ *(UINT32*)(raw++) = *(UINT8*) (*args);
+#else
+ (raw++)->uint = *(UINT8*) (*args);
+#endif
+ break;
+
+ case FFI_TYPE_SINT8:
+#if WORDS_BIGENDIAN
+ *(SINT32*)(raw++) = *(SINT8*) (*args);
+#else
+ (raw++)->sint = *(SINT8*) (*args);
+#endif
+ break;
+
+ case FFI_TYPE_UINT16:
+#if WORDS_BIGENDIAN
+ *(UINT32*)(raw++) = *(UINT16*) (*args);
+#else
+ (raw++)->uint = *(UINT16*) (*args);
+#endif
+ break;
+
+ case FFI_TYPE_SINT16:
+#if WORDS_BIGENDIAN
+ *(SINT32*)(raw++) = *(SINT16*) (*args);
+#else
+ (raw++)->sint = *(SINT16*) (*args);
+#endif
+ break;
+
+ case FFI_TYPE_UINT32:
+#if WORDS_BIGENDIAN
+ *(UINT32*)(raw++) = *(UINT32*) (*args);
+#else
+ (raw++)->uint = *(UINT32*) (*args);
+#endif
+ break;
+
+ case FFI_TYPE_SINT32:
+#if WORDS_BIGENDIAN
+ *(SINT32*)(raw++) = *(SINT32*) (*args);
+#else
+ (raw++)->sint = *(SINT32*) (*args);
+#endif
+ break;
+
+ case FFI_TYPE_FLOAT:
+ (raw++)->flt = *(FLOAT32*) (*args);
+ break;
+
+#if FFI_SIZEOF_ARG == 8
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_DOUBLE:
+ raw->uint = *(UINT64*) (*args);
+ raw += 2;
+ break;
+#endif
+
+ case FFI_TYPE_POINTER:
+ (raw++)->ptr = **(void***) args;
+ break;
+
+ default:
+#if FFI_SIZEOF_ARG == 8
+ FFI_ASSERT(0); /* Should have covered all cases */
+#else
+ memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
+ raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+#endif
+ }
+ }
+}
+
+#if !FFI_NATIVE_RAW_API
+
+static void
+ffi_java_rvalue_to_raw (ffi_cif *cif, void *rvalue)
+{
+#if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_UINT32:
+ *(UINT64 *)rvalue <<= 32;
+ break;
+
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_INT:
+ *(SINT64 *)rvalue <<= 32;
+ break;
+
+ default:
+ break;
+ }
+#endif
+}
+
+static void
+ffi_java_raw_to_rvalue (ffi_cif *cif, void *rvalue)
+{
+#if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_UINT32:
+ *(UINT64 *)rvalue >>= 32;
+ break;
+
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_INT:
+ *(SINT64 *)rvalue >>= 32;
+ break;
+
+ default:
+ break;
+ }
+#endif
+}
+
+/* This is a generic definition of ffi_raw_call, to be used if the
+ * native system does not provide a machine-specific implementation.
+ * Having this, allows code to be written for the raw API, without
+ * the need for system-specific code to handle input in that format;
+ * these following couple of functions will handle the translation forth
+ * and back automatically. */
+
+void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif,
+ void (*fn)(),
+ /*@out@*/ void *rvalue,
+ /*@dependent@*/ ffi_raw *raw)
+{
+ void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
+ ffi_java_raw_to_ptrarray (cif, raw, avalue);
+ ffi_call (cif, fn, rvalue, avalue);
+ ffi_java_rvalue_to_raw (cif, rvalue);
+}
+
+#if FFI_CLOSURES /* base system provides closures */
+
+static void
+ffi_java_translate_args (ffi_cif *cif, void *rvalue,
+ void **avalue, void *user_data)
+{
+ ffi_raw *raw = (ffi_raw*)alloca (ffi_java_raw_size (cif));
+ ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
+
+ ffi_java_ptrarray_to_raw (cif, avalue, raw);
+ (*cl->fun) (cif, rvalue, raw, cl->user_data);
+ ffi_java_raw_to_rvalue (cif, rvalue);
+}
+
+/* Again, here is the generic version of ffi_prep_raw_closure, which
+ * will install an intermediate "hub" for translation of arguments from
+ * the pointer-array format, to the raw format */
+
+ffi_status
+ffi_prep_java_raw_closure (ffi_raw_closure* cl,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+ void *user_data)
+{
+ ffi_status status;
+
+ status = ffi_prep_closure ((ffi_closure*) cl,
+ cif,
+ &ffi_java_translate_args,
+ (void*)cl);
+ if (status == FFI_OK)
+ {
+ cl->fun = fun;
+ cl->user_data = user_data;
+ }
+
+ return status;
+}
+
+#endif /* FFI_CLOSURES */
+#endif /* !FFI_NATIVE_RAW_API */
+#endif /* !FFI_NO_RAW_API */
diff --git a/libffi/src/m68k/ffi.c b/libffi/src/m68k/ffi.c
new file mode 100644
index 0000000..55f3a98
--- /dev/null
+++ b/libffi/src/m68k/ffi.c
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------
+ ffi.c
+
+ m68k Foreign Function Interface
+ ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+/* ffi_prep_args is called by the assembly routine once stack space has
+ been allocated for the function's arguments. */
+
+static void *
+ffi_prep_args (void *stack, extended_cif *ecif)
+{
+ unsigned int i;
+ void **p_argv;
+ char *argp;
+ ffi_type **p_arg;
+ void *struct_value_ptr;
+
+ argp = stack;
+
+ if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
+ && ecif->cif->rtype->size > 8)
+ struct_value_ptr = ecif->rvalue;
+ else
+ struct_value_ptr = NULL;
+
+ p_argv = ecif->avalue;
+
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
+ i != 0;
+ i--, p_arg++)
+ {
+ size_t z;
+
+ /* Align if necessary. */
+ if (((*p_arg)->alignment - 1) & (unsigned) argp)
+ argp = (char *) ALIGN (argp, (*p_arg)->alignment);
+
+ z = (*p_arg)->size;
+ if (z < sizeof (int))
+ {
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ memcpy (argp + sizeof (int) - z, *p_argv, z);
+ break;
+
+ default:
+ FFI_ASSERT (0);
+ }
+ z = sizeof (int);
+ }
+ else
+ memcpy (argp, *p_argv, z);
+ p_argv++;
+ argp += z;
+ }
+
+ return struct_value_ptr;
+}
+
+#define CIF_FLAGS_INT 1
+#define CIF_FLAGS_DINT 2
+#define CIF_FLAGS_FLOAT 4
+#define CIF_FLAGS_DOUBLE 8
+#define CIF_FLAGS_LDOUBLE 16
+#define CIF_FLAGS_POINTER 32
+#define CIF_FLAGS_STRUCT 64
+
+/* 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:
+ cif->flags = 0;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ if (cif->rtype->size > 4 && cif->rtype->size <= 8)
+ cif->flags = CIF_FLAGS_DINT;
+ else if (cif->rtype->size <= 4)
+ cif->flags = CIF_FLAGS_STRUCT;
+ else
+ cif->flags = 0;
+ break;
+
+ case FFI_TYPE_FLOAT:
+ cif->flags = CIF_FLAGS_FLOAT;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ cif->flags = CIF_FLAGS_DOUBLE;
+ break;
+
+ case FFI_TYPE_LONGDOUBLE:
+ cif->flags = CIF_FLAGS_LDOUBLE;
+ break;
+
+ case FFI_TYPE_POINTER:
+ cif->flags = CIF_FLAGS_POINTER;
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ cif->flags = CIF_FLAGS_DINT;
+ break;
+
+ default:
+ cif->flags = CIF_FLAGS_INT;
+ break;
+ }
+
+ return FFI_OK;
+}
+
+extern void ffi_call_SYSV (void *(*) (void *, extended_cif *),
+ extended_cif *,
+ unsigned, unsigned, unsigned,
+ void *, void (*fn) ());
+
+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
+ && cif->rtype->size > 8)
+ 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, cif->rtype->size * 8,
+ ecif.rvalue, fn);
+ break;
+
+ default:
+ FFI_ASSERT (0);
+ break;
+ }
+}
diff --git a/libffi/src/m68k/ffitarget.h b/libffi/src/m68k/ffitarget.h
new file mode 100644
index 0000000..aca7fac
--- /dev/null
+++ b/libffi/src/m68k/ffitarget.h
@@ -0,0 +1,47 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for Motorola 68K.
+
+ 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
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_DEFAULT_ABI = FFI_SYSV,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 0
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/m68k/sysv.S b/libffi/src/m68k/sysv.S
new file mode 100644
index 0000000..d019a37
--- /dev/null
+++ b/libffi/src/m68k/sysv.S
@@ -0,0 +1,97 @@
+/* -----------------------------------------------------------------------
+ sysv.S
+
+ m68k Foreign Function Interface
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+ .text
+
+ .globl ffi_call_SYSV
+ .type ffi_call_SYSV,@function
+
+ffi_call_SYSV:
+ link %fp,#0
+ move.l %d2,-(%sp)
+
+ | Make room for all of the new args.
+ sub.l 16(%fp),%sp
+
+ | Call ffi_prep_args
+ move.l 12(%fp),-(%sp)
+ pea 4(%sp)
+ move.l 8(%fp),%a0
+ jsr (%a0)
+ addq.l #8,%sp
+
+ | Pass pointer to struct value, if any
+ move.l %a0,%a1
+
+ | Call the function
+ move.l 32(%fp),%a0
+ jsr (%a0)
+
+ | Remove the space we pushed for the args
+ add.l 16(%fp),%sp
+
+ | Load the pointer to storage for the return value
+ move.l 28(%fp),%a1
+
+ | Load the return type code
+ move.l 20(%fp),%d2
+
+ | If the return value pointer is NULL, assume no return value.
+ tst.l %a1
+ jbeq noretval
+
+ btst #0,%d2
+ jbeq retlongint
+ move.l %d0,(%a1)
+ jbra epilogue
+
+retlongint:
+ btst #1,%d2
+ jbeq retfloat
+ move.l %d0,(%a1)
+ move.l %d1,4(%a1)
+ jbra epilogue
+
+retfloat:
+ btst #2,%d2
+ jbeq retdouble
+ fmove.s %fp0,(%a1)
+ jbra epilogue
+
+retdouble:
+ btst #3,%d2
+ jbeq retlongdouble
+ fmove.d %fp0,(%a1)
+ jbra epilogue
+
+retlongdouble:
+ btst #4,%d2
+ jbeq retpointer
+ fmove.x %fp0,(%a1)
+ jbra epilogue
+
+retpointer:
+ btst #5,%d2
+ jbeq retstruct
+ move.l %a0,(%a1)
+ jbra epilogue
+
+retstruct:
+ btst #6,%d2
+ jbeq noretval
+ move.l 24(%fp),%d2
+ bfins %d0,(%a1){#0,%d2}
+
+noretval:
+epilogue:
+ move.l (%sp)+,%d2
+ unlk %a6
+ rts
+ .size ffi_call_SYSV,.-ffi_call_SYSV
diff --git a/libffi/src/mips/ffi.c b/libffi/src/mips/ffi.c
new file mode 100644
index 0000000..cc2078b
--- /dev/null
+++ b/libffi/src/mips/ffi.c
@@ -0,0 +1,461 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1996 Red Hat, Inc.
+
+ MIPS 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>
+
+#if _MIPS_SIM == _ABIN32
+#define FIX_ARGP \
+FFI_ASSERT(argp <= &stack[bytes]); \
+if (argp == &stack[bytes]) \
+{ \
+ argp = stack; \
+ ffi_stop_here(); \
+}
+#else
+#define FIX_ARGP
+#endif
+
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+static void ffi_prep_args(char *stack,
+ extended_cif *ecif,
+ int bytes,
+ int flags)
+{
+ register int i;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+#if _MIPS_SIM == _ABIN32
+ /* If more than 8 double words are used, the remainder go
+ on the stack. We reorder stuff on the stack here to
+ support this easily. */
+ if (bytes > 8 * FFI_SIZEOF_ARG)
+ argp = &stack[bytes - (8 * FFI_SIZEOF_ARG)];
+ else
+ argp = stack;
+#else
+ argp = stack;
+#endif
+
+ memset(stack, 0, bytes);
+
+#if _MIPS_SIM == _ABIN32
+ if ( ecif->cif->rstruct_flag != 0 )
+#else
+ if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
+#endif
+ {
+ *(ffi_arg *) argp = (ffi_arg) ecif->rvalue;
+ argp += sizeof(ffi_arg);
+ FIX_ARGP;
+ }
+
+ p_argv = ecif->avalue;
+
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
+ {
+ size_t z;
+
+ /* Align if necessary */
+ if (((*p_arg)->alignment - 1) & (unsigned) argp) {
+ argp = (char *) ALIGN(argp, (*p_arg)->alignment);
+ FIX_ARGP;
+ }
+
+#if _MIPS_SIM == _ABIO32
+#define OFFSET 0
+#else
+#define OFFSET sizeof(int)
+#endif
+
+ z = (*p_arg)->size;
+ if (z < sizeof(ffi_arg))
+ {
+ z = sizeof(ffi_arg);
+
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT32:
+ *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_POINTER:
+ *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT32 *)(* p_argv);
+ break;
+
+ /* This can only happen with 64bit slots */
+ case FFI_TYPE_FLOAT:
+ *(float *) argp = *(float *)(* p_argv);
+ break;
+
+ /* Handle small structures */
+ case FFI_TYPE_STRUCT:
+ memcpy(argp, *p_argv, (*p_arg)->size);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ }
+ else
+ {
+#if _MIPS_SIM == _ABIO32
+ memcpy(argp, *p_argv, z);
+#else
+ {
+ unsigned end = (unsigned) argp+z;
+ unsigned cap = (unsigned) stack+bytes;
+
+ /* Check if the data will fit within the register
+ space. Handle it if it doesn't. */
+
+ if (end <= cap)
+ memcpy(argp, *p_argv, z);
+ else
+ {
+ unsigned portion = end - cap;
+
+ memcpy(argp, *p_argv, portion);
+ argp = stack;
+ memcpy(argp,
+ (void*)((unsigned)(*p_argv)+portion), z - portion);
+ }
+ }
+#endif
+ }
+ p_argv++;
+ argp += z;
+ FIX_ARGP;
+ }
+
+ return;
+}
+
+#if _MIPS_SIM == _ABIN32
+
+/* The n32 spec says that if "a chunk consists solely of a double
+ float field (but not a double, which is part of a union), it
+ is passed in a floating point register. Any other chunk is
+ passed in an integer register". This code traverses structure
+ definitions and generates the appropriate flags. */
+
+unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift)
+{
+ unsigned flags = 0;
+ unsigned index = 0;
+
+ ffi_type *e;
+
+ while (e = arg->elements[index])
+ {
+ if (e->type == FFI_TYPE_DOUBLE)
+ {
+ flags += (FFI_TYPE_DOUBLE << *shift);
+ *shift += FFI_FLAG_BITS;
+ }
+ else if (e->type == FFI_TYPE_STRUCT)
+ flags += calc_n32_struct_flags(e, shift);
+ else
+ *shift += FFI_FLAG_BITS;
+
+ index++;
+ }
+
+ return flags;
+}
+
+unsigned calc_n32_return_struct_flags(ffi_type *arg)
+{
+ unsigned flags = 0;
+ unsigned index = 0;
+ unsigned small = FFI_TYPE_SMALLSTRUCT;
+ ffi_type *e;
+
+ /* Returning structures under n32 is a tricky thing.
+ A struct with only one or two floating point fields
+ is returned in $f0 (and $f2 if necessary). Any other
+ struct results at most 128 bits are returned in $2
+ (the first 64 bits) and $3 (remainder, if necessary).
+ Larger structs are handled normally. */
+
+ if (arg->size > 16)
+ return 0;
+
+ if (arg->size > 8)
+ small = FFI_TYPE_SMALLSTRUCT2;
+
+ e = arg->elements[0];
+ if (e->type == FFI_TYPE_DOUBLE)
+ flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
+ else if (e->type == FFI_TYPE_FLOAT)
+ flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS;
+
+ if (flags && (e = arg->elements[1]))
+ {
+ if (e->type == FFI_TYPE_DOUBLE)
+ flags += FFI_TYPE_DOUBLE;
+ else if (e->type == FFI_TYPE_FLOAT)
+ flags += FFI_TYPE_FLOAT;
+ else
+ return small;
+
+ if (flags && (arg->elements[2]))
+ {
+ /* There are three arguments and the first two are
+ floats! This must be passed the old way. */
+ return small;
+ }
+ }
+ else
+ if (!flags)
+ return small;
+
+ return flags;
+}
+
+#endif
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ cif->flags = 0;
+
+#if _MIPS_SIM == _ABIO32
+ /* Set the flags necessary for O32 processing */
+
+ if (cif->rtype->type != FFI_TYPE_STRUCT)
+ {
+ if (cif->nargs > 0)
+ {
+ switch ((cif->arg_types)[0]->type)
+ {
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += (cif->arg_types)[0]->type;
+ break;
+
+ default:
+ break;
+ }
+
+ if (cif->nargs > 1)
+ {
+ /* Only handle the second argument if the first
+ is a float or double. */
+ if (cif->flags)
+ {
+ switch ((cif->arg_types)[1]->type)
+ {
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
+ break;
+
+ default:
+ cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
+ break;
+ }
+#endif
+
+#if _MIPS_SIM == _ABIN32
+ /* Set the flags necessary for N32 processing */
+ {
+ unsigned shift = 0;
+ unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
+ unsigned index = 0;
+
+ unsigned struct_flags = 0;
+
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ struct_flags = calc_n32_return_struct_flags(cif->rtype);
+
+ if (struct_flags == 0)
+ {
+ /* This means that the structure is being passed as
+ a hidden argument */
+
+ shift = FFI_FLAG_BITS;
+ count = (cif->nargs < 7) ? cif->nargs : 7;
+
+ cif->rstruct_flag = !0;
+ }
+ else
+ cif->rstruct_flag = 0;
+ }
+ else
+ cif->rstruct_flag = 0;
+
+ while (count-- > 0)
+ {
+ switch ((cif->arg_types)[index]->type)
+ {
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += ((cif->arg_types)[index]->type << shift);
+ shift += FFI_FLAG_BITS;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
+ &shift);
+ break;
+
+ default:
+ shift += FFI_FLAG_BITS;
+ }
+
+ index++;
+ }
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_STRUCT:
+ {
+ if (struct_flags == 0)
+ {
+ /* The structure is returned through a hidden
+ first argument. Do nothing, 'cause FFI_TYPE_VOID
+ is 0 */
+ }
+ else
+ {
+ /* The structure is returned via some tricky
+ mechanism */
+ cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
+ cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8));
+ }
+ break;
+ }
+
+ case FFI_TYPE_VOID:
+ /* Do nothing, 'cause FFI_TYPE_VOID is 0 */
+ break;
+
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
+ break;
+
+ default:
+ cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
+ break;
+ }
+ }
+#endif
+
+ return FFI_OK;
+}
+
+/* Low level routine for calling O32 functions */
+extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int),
+ extended_cif *, unsigned,
+ unsigned, unsigned *, void (*)());
+
+/* Low level routine for calling N32 functions */
+extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int),
+ extended_cif *, unsigned,
+ unsigned, unsigned *, void (*)());
+
+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)
+ {
+#if _MIPS_SIM == _ABIO32
+ case FFI_O32:
+ ffi_call_O32(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ break;
+#endif
+
+#if _MIPS_SIM == _ABIN32
+ case FFI_N32:
+ ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ break;
+#endif
+
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
diff --git a/libffi/src/mips/ffitarget.h b/libffi/src/mips/ffitarget.h
new file mode 100644
index 0000000..9378ed0
--- /dev/null
+++ b/libffi/src/mips/ffitarget.h
@@ -0,0 +1,160 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for MIPS.
+
+ 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
+
+#ifndef LIBFFI_ASM
+#include <sgidefs.h>
+#endif
+
+#if !defined(_MIPS_SIM)
+-- something is very wrong --
+#else
+# if (_MIPS_SIM==_ABIN32 && defined(_ABIN32)) || (_MIPS_SIM==_ABI64 && defined(_ABI64))
+# define FFI_MIPS_N32
+# else
+# if _MIPS_SIM==_ABIO32 && defined(_ABIO32)
+# define FFI_MIPS_O32
+# else
+-- this is an unsupported platform --
+# endif
+# endif
+#endif
+
+#ifdef FFI_MIPS_O32
+/* O32 stack frames have 32bit integer args */
+#define FFI_SIZEOF_ARG 4
+#else
+/* N32 and N64 frames have 64bit integer args */
+#define FFI_SIZEOF_ARG 8
+#endif
+
+#define FFI_FLAG_BITS 2
+
+/* SGI's strange assembler requires that we multiply by 4 rather
+ than shift left by FFI_FLAG_BITS */
+
+#define FFI_ARGS_D FFI_TYPE_DOUBLE
+#define FFI_ARGS_F FFI_TYPE_FLOAT
+#define FFI_ARGS_DD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_DOUBLE
+#define FFI_ARGS_FF FFI_TYPE_FLOAT * 4 + FFI_TYPE_FLOAT
+#define FFI_ARGS_FD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_FLOAT
+#define FFI_ARGS_DF FFI_TYPE_FLOAT * 4 + FFI_TYPE_DOUBLE
+
+/* Needed for N32 structure returns */
+#define FFI_TYPE_SMALLSTRUCT FFI_TYPE_UINT8
+#define FFI_TYPE_SMALLSTRUCT2 FFI_TYPE_SINT8
+
+#if 0
+/* The SGI assembler can't handle this.. */
+#define FFI_TYPE_STRUCT_DD (( FFI_ARGS_DD ) << 4) + FFI_TYPE_STRUCT
+/* (and so on) */
+#else
+/* ...so we calculate these by hand! */
+#define FFI_TYPE_STRUCT_D 61
+#define FFI_TYPE_STRUCT_F 45
+#define FFI_TYPE_STRUCT_DD 253
+#define FFI_TYPE_STRUCT_FF 173
+#define FFI_TYPE_STRUCT_FD 237
+#define FFI_TYPE_STRUCT_DF 189
+#define FFI_TYPE_STRUCT_SMALL 93
+#define FFI_TYPE_STRUCT_SMALL2 109
+#endif
+
+#ifdef LIBFFI_ASM
+#define v0 $2
+#define v1 $3
+#define a0 $4
+#define a1 $5
+#define a2 $6
+#define a3 $7
+#define a4 $8
+#define a5 $9
+#define a6 $10
+#define a7 $11
+#define t0 $8
+#define t1 $9
+#define t2 $10
+#define t3 $11
+#define t4 $12
+#define t5 $13
+#define t6 $14
+#define t7 $15
+#define t8 $24
+#define t9 $25
+#define ra $31
+
+#ifdef FFI_MIPS_O32
+#define REG_L lw
+#define REG_S sw
+#define SUBU subu
+#define ADDU addu
+#define SRL srl
+#define LI li
+#else /* !FFI_MIPS_O32 */
+#define REG_L ld
+#define REG_S sd
+#define SUBU dsubu
+#define ADDU daddu
+#define SRL dsrl
+#define LI dli
+#endif /* !FFI_MIPS_O32 */
+#else /* !LIBFFI_ASM */
+#ifdef FFI_MIPS_O32
+/* O32 stack frames have 32bit integer args */
+typedef unsigned int ffi_arg __attribute__((__mode__(__SI__)));
+typedef signed int ffi_sarg __attribute__((__mode__(__SI__)));
+#else
+/* N32 and N64 frames have 64bit integer args */
+typedef unsigned int ffi_arg __attribute__((__mode__(__DI__)));
+typedef signed int ffi_sarg __attribute__((__mode__(__DI__)));
+#endif
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_O32,
+ FFI_N32,
+ FFI_N64,
+
+#ifdef FFI_MIPS_O32
+ FFI_DEFAULT_ABI = FFI_O32,
+#else
+ FFI_DEFAULT_ABI = FFI_N32,
+#endif
+
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+
+#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag
+#endif /* !LIBFFI_ASM */
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 0
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/mips/n32.S b/libffi/src/mips/n32.S
new file mode 100644
index 0000000..767fa52
--- /dev/null
+++ b/libffi/src/mips/n32.S
@@ -0,0 +1,319 @@
+/* -----------------------------------------------------------------------
+ n32.S - Copyright (c) 1996, 1998 Red Hat, Inc.
+
+ MIPS 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>
+
+/* Only build this code if we are compiling for n32 */
+
+#if defined(FFI_MIPS_N32)
+
+#define callback a0
+#define bytes a2
+#define flags a3
+#define raddr a4
+#define fn a5
+
+#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG )
+
+ .text
+ .align 2
+ .globl ffi_call_N32
+ .ent ffi_call_N32
+ffi_call_N32:
+
+ # Prologue
+ SUBU $sp, SIZEOF_FRAME # Frame size
+ REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
+ REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
+ move $fp, $sp
+
+ move t9, callback # callback function pointer
+ REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
+ REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags
+ REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
+ REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn
+
+ # Allocate at least 4 words in the argstack
+ move v0, bytes
+ bge bytes, 4 * FFI_SIZEOF_ARG, bigger
+ LI v0, 4 * FFI_SIZEOF_ARG
+ b sixteen
+
+ bigger:
+ ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned
+ and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry.
+
+sixteen:
+ SUBU $sp, $sp, v0 # move the stack pointer to reflect the
+ # arg space
+
+ ADDU a0, $sp, 0 # 4 * FFI_SIZEOF_ARG
+ ADDU a3, $fp, 3 * FFI_SIZEOF_ARG
+
+ # Call ffi_prep_args
+ jal t9
+
+ # ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
+
+ # Copy the stack pointer to t9
+ move t9, $sp
+
+ # Fix the stack if there are more than 8 64bit slots worth
+ # of arguments.
+
+ # Load the number of bytes
+ REG_L t6, 2*FFI_SIZEOF_ARG($fp)
+
+ # Is it bigger than 8 * FFI_SIZEOF_ARG?
+ dadd t7, $0, 8 * FFI_SIZEOF_ARG
+ dsub t8, t6, t7
+ bltz t8, loadregs
+
+ add t9, t9, t8
+
+loadregs:
+
+ REG_L t4, 3*FFI_SIZEOF_ARG($fp) # load the flags word
+ add t6, t4, 0 # and copy it into t6
+
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg1_floatp
+ REG_L a0, 0*FFI_SIZEOF_ARG(t9)
+ b arg1_next
+arg1_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg1_doublep
+ l.s $f12, 0*FFI_SIZEOF_ARG(t9)
+ b arg1_next
+arg1_doublep:
+ l.d $f12, 0*FFI_SIZEOF_ARG(t9)
+arg1_next:
+
+ add t4, t6, 0
+ SRL t4, 1*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg2_floatp
+ REG_L a1, 1*FFI_SIZEOF_ARG(t9)
+ b arg2_next
+arg2_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg2_doublep
+ l.s $f13, 1*FFI_SIZEOF_ARG(t9)
+ b arg2_next
+arg2_doublep:
+ l.d $f13, 1*FFI_SIZEOF_ARG(t9)
+arg2_next:
+
+ add t4, t6, 0
+ SRL t4, 2*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg3_floatp
+ REG_L a2, 2*FFI_SIZEOF_ARG(t9)
+ b arg3_next
+arg3_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg3_doublep
+ l.s $f14, 2*FFI_SIZEOF_ARG(t9)
+ b arg3_next
+arg3_doublep:
+ l.d $f14, 2*FFI_SIZEOF_ARG(t9)
+arg3_next:
+
+ add t4, t6, 0
+ SRL t4, 3*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg4_floatp
+ REG_L a3, 3*FFI_SIZEOF_ARG(t9)
+ b arg4_next
+arg4_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg4_doublep
+ l.s $f15, 3*FFI_SIZEOF_ARG(t9)
+ b arg4_next
+arg4_doublep:
+ l.d $f15, 3*FFI_SIZEOF_ARG(t9)
+arg4_next:
+
+ add t4, t6, 0
+ SRL t4, 4*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg5_floatp
+ REG_L a4, 4*FFI_SIZEOF_ARG(t9)
+ b arg5_next
+arg5_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg5_doublep
+ l.s $f16, 4*FFI_SIZEOF_ARG(t9)
+ b arg5_next
+arg5_doublep:
+ l.d $f16, 4*FFI_SIZEOF_ARG(t9)
+arg5_next:
+
+ add t4, t6, 0
+ SRL t4, 5*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg6_floatp
+ REG_L a5, 5*FFI_SIZEOF_ARG(t9)
+ b arg6_next
+arg6_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg6_doublep
+ l.s $f17, 5*FFI_SIZEOF_ARG(t9)
+ b arg6_next
+arg6_doublep:
+ l.d $f17, 5*FFI_SIZEOF_ARG(t9)
+arg6_next:
+
+ add t4, t6, 0
+ SRL t4, 6*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg7_floatp
+ REG_L a6, 6*FFI_SIZEOF_ARG(t9)
+ b arg7_next
+arg7_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg7_doublep
+ l.s $f18, 6*FFI_SIZEOF_ARG(t9)
+ b arg7_next
+arg7_doublep:
+ l.d $f18, 6*FFI_SIZEOF_ARG(t9)
+arg7_next:
+
+ add t4, t6, 0
+ SRL t4, 7*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg8_floatp
+ REG_L a7, 7*FFI_SIZEOF_ARG(t9)
+ b arg8_next
+arg8_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg8_doublep
+ l.s $f19, 7*FFI_SIZEOF_ARG(t9)
+ b arg8_next
+arg8_doublep:
+ l.d $f19, 7*FFI_SIZEOF_ARG(t9)
+arg8_next:
+
+callit:
+ # Load the function pointer
+ REG_L t9, 5*FFI_SIZEOF_ARG($fp)
+
+ # If the return value pointer is NULL, assume no return value.
+ REG_L t5, 4*FFI_SIZEOF_ARG($fp)
+ beqz t5, noretval
+
+ # Shift the return type flag over
+ SRL t6, 8*FFI_FLAG_BITS
+
+ bne t6, FFI_TYPE_INT, retfloat
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ REG_S v0, 0(t4)
+ b epilogue
+
+retfloat:
+ bne t6, FFI_TYPE_FLOAT, retdouble
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t4)
+ b epilogue
+
+retdouble:
+ bne t6, FFI_TYPE_DOUBLE, retstruct_d
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t4)
+ b epilogue
+
+retstruct_d:
+ bne t6, FFI_TYPE_STRUCT_D, retstruct_f
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t4)
+ b epilogue
+
+retstruct_f:
+ bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t4)
+ b epilogue
+
+retstruct_d_d:
+ bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t4)
+ s.d $f2, 8(t4)
+ b epilogue
+
+retstruct_f_f:
+ bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t4)
+ s.s $f2, 4(t4)
+ b epilogue
+
+retstruct_d_f:
+ bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t4)
+ s.s $f2, 8(t4)
+ b epilogue
+
+retstruct_f_d:
+ bne t6, FFI_TYPE_STRUCT_FD, retstruct_small
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t4)
+ s.d $f2, 8(t4)
+ b epilogue
+
+retstruct_small:
+ bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ REG_S v0, 0(t4)
+ b epilogue
+
+retstruct_small2:
+ bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ REG_S v0, 0(t4)
+ REG_S v1, 8(t4)
+ b epilogue
+
+retstruct:
+noretval:
+ jal t9
+
+ # Epilogue
+epilogue:
+ move $sp, $fp
+ REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
+ REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address
+ ADDU $sp, SIZEOF_FRAME # Fix stack pointer
+ j ra
+
+ .end ffi_call_N32
+
+#endif
diff --git a/libffi/src/mips/o32.S b/libffi/src/mips/o32.S
new file mode 100644
index 0000000..295095f
--- /dev/null
+++ b/libffi/src/mips/o32.S
@@ -0,0 +1,172 @@
+/* -----------------------------------------------------------------------
+ o32.S - Copyright (c) 1996, 1998 Red Hat, Inc.
+
+ MIPS 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>
+
+/* Only build this code if we are compiling for o32 */
+
+#if defined(FFI_MIPS_O32)
+
+#define callback a0
+#define bytes a2
+#define flags a3
+
+#define SIZEOF_FRAME ( 4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
+
+ .text
+ .align 2
+ .globl ffi_call_O32
+ .ent ffi_call_O32
+ffi_call_O32:
+
+ # Prologue
+ SUBU $sp, SIZEOF_FRAME # Frame size
+ REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
+ REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
+ move $fp, $sp
+
+ move t9, callback # callback function pointer
+ REG_S flags, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # flags
+
+ # Allocate at least 4 words in the argstack
+ move v0, bytes
+ bge bytes, 4 * FFI_SIZEOF_ARG, bigger
+ LI v0, 4 * FFI_SIZEOF_ARG
+ b sixteen
+
+bigger:
+ ADDU t0, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned
+ and v0, t0, -2 * FFI_SIZEOF_ARG # to an 8 byte boundry
+
+sixteen:
+ SUBU $sp, $sp, v0 # move the stack pointer to reflect the
+ # arg space
+
+ ADDU a0, $sp, 4 * FFI_SIZEOF_ARG
+ ADDU a3, $fp, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG
+
+ jal t9
+
+ REG_L t0, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # load the flags word
+ add t2, t0, 0 # and copy it into t2
+
+ and t0, ((1<<4)-1) # mask out the return type
+ SRL t2, 4 # shift our arg info
+
+ ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
+
+ bnez t0, pass_d # make it quick for int
+ REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
+ REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
+ REG_L a2, 2*FFI_SIZEOF_ARG($sp)
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_d:
+ bne t0, FFI_ARGS_D, pass_f
+ l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_f:
+ bne t0, FFI_ARGS_F, pass_d_d
+ l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float
+ REG_L a2, 2*FFI_SIZEOF_ARG($sp)
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_d_d:
+ bne t0, FFI_ARGS_DD, pass_f_f
+ l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles
+ b call_it
+
+pass_f_f:
+ bne t0, FFI_ARGS_FF, pass_d_f
+ l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats
+ REG_L a2, 2*FFI_SIZEOF_ARG($sp)
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_d_f:
+ bne t0, FFI_ARGS_DF, pass_f_d
+ l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_f_d:
+ # assume that the only other combination must be float then double
+ # bne t0, FFI_ARGS_F_D, call_it
+ l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
+
+call_it:
+ # Load the function pointer
+ REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
+
+ # If the return value pointer is NULL, assume no return value.
+ REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ beqz t1, noretval
+
+ bne t2, FFI_TYPE_INT, retfloat
+ jal t9
+ REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ REG_S v0, 0(t0)
+ b epilogue
+
+retfloat:
+ bne t2, FFI_TYPE_FLOAT, retdouble
+ jal t9
+ REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t0)
+ b epilogue
+
+retdouble:
+ bne t2, FFI_TYPE_DOUBLE, noretval
+ jal t9
+ REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t0)
+ b epilogue
+
+noretval:
+ jal t9
+
+ # Epilogue
+epilogue:
+ move $sp, $fp
+ REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
+ REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address
+ ADDU $sp, SIZEOF_FRAME # Fix stack pointer
+ j ra
+
+ .end ffi_call_O32
+
+#endif
diff --git a/libffi/src/pa/ffi.c b/libffi/src/pa/ffi.c
new file mode 100644
index 0000000..57331fe
--- /dev/null
+++ b/libffi/src/pa/ffi.c
@@ -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 --git a/libffi/src/pa/ffitarget.h b/libffi/src/pa/ffitarget.h
new file mode 100644
index 0000000..b8bcad0
--- /dev/null
+++ b/libffi/src/pa/ffitarget.h
@@ -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 --git a/libffi/src/pa/linux.S b/libffi/src/pa/linux.S
new file mode 100644
index 0000000..1a2ecdb
--- /dev/null
+++ b/libffi/src/pa/linux.S
@@ -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 --git a/libffi/src/powerpc/aix.S b/libffi/src/powerpc/aix.S
new file mode 100644
index 0000000..590717f
--- /dev/null
+++ b/libffi/src/powerpc/aix.S
@@ -0,0 +1,225 @@
+/* -----------------------------------------------------------------------
+ aix.S - Copyright (c) 2002 Free Software Foundation, Inc.
+ based on darwin.S by John Hornkvist
+
+ PowerPC Assembly glue.
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+ .set r0,0
+ .set r1,1
+ .set r2,2
+ .set r3,3
+ .set r4,4
+ .set r5,5
+ .set r6,6
+ .set r7,7
+ .set r8,8
+ .set r9,9
+ .set r10,10
+ .set r11,11
+ .set r12,12
+ .set r13,13
+ .set r14,14
+ .set r15,15
+ .set r16,16
+ .set r17,17
+ .set r18,18
+ .set r19,19
+ .set r20,20
+ .set r21,21
+ .set r22,22
+ .set r23,23
+ .set r24,24
+ .set r25,25
+ .set r26,26
+ .set r27,27
+ .set r28,28
+ .set r29,29
+ .set r30,30
+ .set r31,31
+ .set f0,0
+ .set f1,1
+ .set f2,2
+ .set f3,3
+ .set f4,4
+ .set f5,5
+ .set f6,6
+ .set f7,7
+ .set f8,8
+ .set f9,9
+ .set f10,10
+ .set f11,11
+ .set f12,12
+ .set f13,13
+ .set f14,14
+ .set f15,15
+ .set f16,16
+ .set f17,17
+ .set f18,18
+ .set f19,19
+ .set f20,20
+ .set f21,21
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+#define JUMPTARGET(name) name
+#define L(x) x
+ .file "aix.S"
+ .toc
+ .csect .text[PR]
+ .align 2
+.globl ffi_prep_args
+
+.csect .text[PR]
+ .align 2
+ .globl ffi_call_AIX
+ .globl .ffi_call_AIX
+.csect ffi_call_AIX[DS]
+ffi_call_AIX:
+ .long .ffi_call_AIX, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_call_AIX:
+ mr r12,r8 // We only need r12 until the call, so it doesn't have to be saved...
+ /* Save the old stack pointer as AP. */
+ mr r8,r1
+
+ /* Allocate the stack space we need. */
+ stwux r1,r1,r4
+
+ /* Save registers we use. */
+ mflr r9
+
+ stw r28,-16(r8)
+ stw r29,-12(r8)
+ stw r30, -8(r8)
+ stw r31, -4(r8)
+
+ stw r9, 8(r8)
+ stw r2, 20(r1)
+
+ /* Save arguments over call... */
+ mr r31,r5 /* flags, */
+ mr r30,r6 /* rvalue, */
+ mr r29,r7 /* function address, */
+ mr r28,r8 /* our AP. */
+
+ /* Call ffi_prep_args. */
+ mr r4,r1
+ li r9,0
+
+ lwz r2,4(r12)
+ lwz r12,0(r12)
+ mtctr r12 // r12 holds address of _ffi_prep_args
+ bctrl
+ lwz r2,20(r1)
+
+ /* Now do the call. */
+ lwz r12,0(r29)
+ /* Set up cr1 with bits 4-7 of the flags. */
+ mtcrf 0x40,r31
+ stw r2,20(r1)
+ mtctr r12
+ lwz r2,4(r29)
+ /* Load all those argument registers. */
+ // We have set up a nice stack frame, just load it into registers.
+ lwz r3, 20+(1*4)(r1)
+ lwz r4, 20+(2*4)(r1)
+ lwz r5, 20+(3*4)(r1)
+ lwz r6, 20+(4*4)(r1)
+ nop
+ lwz r7, 20+(5*4)(r1)
+ lwz r8, 20+(6*4)(r1)
+ lwz r9, 20+(7*4)(r1)
+ lwz r10,20+(8*4)(r1)
+
+L1:
+ /* Load all the FP registers. */
+ bf 6,L2 // 2f + 0x18
+ lfd f1,-16-(13*8)(r28)
+ lfd f2,-16-(12*8)(r28)
+ lfd f3,-16-(11*8)(r28)
+ lfd f4,-16-(10*8)(r28)
+ nop
+ lfd f5,-16-(9*8)(r28)
+ lfd f6,-16-(8*8)(r28)
+ lfd f7,-16-(7*8)(r28)
+ lfd f8,-16-(6*8)(r28)
+ nop
+ lfd f9,-16-(5*8)(r28)
+ lfd f10,-16-(4*8)(r28)
+ lfd f11,-16-(3*8)(r28)
+ lfd f12,-16-(2*8)(r28)
+ nop
+ lfd f13,-16-(1*8)(r28)
+
+L2:
+ /* Make the call. */
+ bctrl
+ lwz r2,20(r1)
+
+ /* Now, deal with the return value. */
+ mtcrf 0x01,r31
+
+ bt 30,L(done_return_value)
+ bt 29,L(fp_return_value)
+ stw r3,0(r30)
+ bf 28,L(done_return_value)
+ stw r4,4(r30)
+
+ /* Fall through... */
+
+L(done_return_value):
+ /* Restore the registers we used and return. */
+ lwz r9, 8(r28)
+ lwz r31, -4(r28)
+ mtlr r9
+ lwz r30, -8(r28)
+ lwz r29,-12(r28)
+ lwz r28,-16(r28)
+ lwz r1,0(r1)
+ blr
+
+L(fp_return_value):
+ bf 28,L(float_return_value)
+ stfd f1,0(r30)
+ b L(done_return_value)
+L(float_return_value):
+ stfs f1,0(r30)
+ b L(done_return_value)
+ .long 0
+ .byte 0,0,0,1,128,4,0,0
+//END(ffi_call_AIX)
+
+.csect .text[PR]
+ .align 2
+ .globl ffi_call_DARWIN
+ .globl .ffi_call_DARWIN
+.csect ffi_call_DARWIN[DS]
+ffi_call_DARWIN:
+ .long .ffi_call_DARWIN, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_call_DARWIN:
+ blr
+ .long 0
+ .byte 0,0,0,0,0,0,0,0
+//END(ffi_call_DARWIN)
diff --git a/libffi/src/powerpc/aix_closure.S b/libffi/src/powerpc/aix_closure.S
new file mode 100644
index 0000000..8a26121
--- /dev/null
+++ b/libffi/src/powerpc/aix_closure.S
@@ -0,0 +1,247 @@
+/* -----------------------------------------------------------------------
+ aix_closure.S - Copyright (c) 2002 2003 Free Software Foundation, Inc.
+ based on darwin_closure.S
+
+ PowerPC Assembly glue.
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+ .set r0,0
+ .set r1,1
+ .set r2,2
+ .set r3,3
+ .set r4,4
+ .set r5,5
+ .set r6,6
+ .set r7,7
+ .set r8,8
+ .set r9,9
+ .set r10,10
+ .set r11,11
+ .set r12,12
+ .set r13,13
+ .set r14,14
+ .set r15,15
+ .set r16,16
+ .set r17,17
+ .set r18,18
+ .set r19,19
+ .set r20,20
+ .set r21,21
+ .set r22,22
+ .set r23,23
+ .set r24,24
+ .set r25,25
+ .set r26,26
+ .set r27,27
+ .set r28,28
+ .set r29,29
+ .set r30,30
+ .set r31,31
+ .set f0,0
+ .set f1,1
+ .set f2,2
+ .set f3,3
+ .set f4,4
+ .set f5,5
+ .set f6,6
+ .set f7,7
+ .set f8,8
+ .set f9,9
+ .set f10,10
+ .set f11,11
+ .set f12,12
+ .set f13,13
+ .set f14,14
+ .set f15,15
+ .set f16,16
+ .set f17,17
+ .set f18,18
+ .set f19,19
+ .set f20,20
+ .set f21,21
+
+#define LIBFFI_ASM
+#define JUMPTARGET(name) name
+#define L(x) x
+ .file "aix_closure.S"
+ .toc
+LC..60:
+ .tc L..60[TC],L..60
+ .csect .text[PR]
+ .align 2
+
+.csect .text[PR]
+ .align 2
+ .globl ffi_closure_ASM
+ .globl .ffi_closure_ASM
+.csect ffi_closure_ASM[DS]
+
+ffi_closure_ASM:
+ .long .ffi_closure_ASM, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_closure_ASM:
+
+ mflr r0 /* extract return address */
+ stw r0, 8(r1) /* save the return address */
+
+ /* 24 Bytes (Linkage Area) */
+ /* 32 Bytes (params) */
+ /* 104 Bytes (13*8 from FPR) */
+ /* 8 Bytes (result) */
+ /* 168 Bytes */
+
+ stwu r1,-176(r1) /* skip over caller save area
+ keep stack aligned to 16 */
+
+/* we want to build up an area for the parameters passed */
+/* in registers (both floating point and integer) */
+
+ /* we store gpr 3 to gpr 10 (aligned to 4)
+ in the parents outgoing area */
+ stw r3, 200(r1)
+ stw r4, 204(r1)
+ stw r5, 208(r1)
+ stw r6, 212(r1)
+ stw r7, 216(r1)
+ stw r8, 220(r1)
+ stw r9, 224(r1)
+ stw r10, 228(r1)
+
+ /* next save fpr 1 to fpr 13 (aligned to 8) */
+ stfd f1, 56(r1)
+ stfd f2, 64(r1)
+ stfd f3, 72(r1)
+ stfd f4, 80(r1)
+ stfd f5, 88(r1)
+ stfd f6, 96(r1)
+ stfd f7, 104(r1)
+ stfd f8, 112(r1)
+ stfd f9, 120(r1)
+ stfd f10, 128(r1)
+ stfd f11, 136(r1)
+ stfd f12, 144(r1)
+ stfd f13, 152(r1)
+
+ /* set up registers for the routine that actually does the work */
+ /* get the context pointer from the trampoline */
+ mr r3,r11
+
+ /* now load up the pointer to the result storage */
+ addi r4,r1,160
+
+ /* now load up the pointer to the saved gpr registers */
+ addi r5,r1,200
+
+ /* now load up the pointer to the saved fpr registers */
+ addi r6,r1,56
+
+ /* make the call */
+ bl .ffi_closure_helper_DARWIN
+ nop
+
+ /* now r3 contains the return type */
+ /* so use it to look up in a table */
+ /* so we know how to deal with each type */
+
+ /* look up the proper starting point in table */
+ /* by using return type as offset */
+ addi r5,r1,160 /* get pointer to results area */
+ lwz r4,LC..60(2) /* get address of jump table */
+ slwi r3,r3,2 /* now multiply return type by 4 */
+ lwzx r3,r4,r3 /* get the contents of that table value */
+ add r3,r3,r4 /* add contents of table to table address */
+ mtctr r3
+ bctr /* jump to it */
+
+L..60:
+ .long L..44-L..60 /* FFI_TYPE_VOID */
+ .long L..50-L..60 /* FFI_TYPE_INT */
+ .long L..47-L..60 /* FFI_TYPE_FLOAT */
+ .long L..46-L..60 /* FFI_TYPE_DOUBLE */
+ .long L..46-L..60 /* FFI_TYPE_LONGDOUBLE */
+ .long L..56-L..60 /* FFI_TYPE_UINT8 */
+ .long L..55-L..60 /* FFI_TYPE_SINT8 */
+ .long L..58-L..60 /* FFI_TYPE_UINT16 */
+ .long L..57-L..60 /* FFI_TYPE_SINT16 */
+ .long L..50-L..60 /* FFI_TYPE_UINT32 */
+ .long L..50-L..60 /* FFI_TYPE_SINT32 */
+ .long L..48-L..60 /* FFI_TYPE_UINT64 */
+ .long L..48-L..60 /* FFI_TYPE_SINT64 */
+ .long L..44-L..60 /* FFI_TYPE_STRUCT */
+ .long L..50-L..60 /* FFI_TYPE_POINTER */
+
+
+/* case double */
+L..46:
+ lfd f1,0(r5)
+ b L..44
+
+/* case float */
+L..47:
+ lfs f1,0(r5)
+ b L..44
+
+/* case long long */
+L..48:
+ lwz r3,0(r5)
+ lwz r4,4(r5)
+ b L..44
+
+/* case default / int32 / pointer */
+L..50:
+ lwz r3,0(r5)
+ b L..44
+
+/* case signed int8 */
+L..55:
+ addi r5,r5,3
+ lbz r3,0(r5)
+ slwi r3,r3,24
+ srawi r3,r3,24
+ b L..44
+
+/* case unsigned int8 */
+L..56:
+ addi r5,r5,3
+ lbz r3,0(r5)
+ b L..44
+
+/* case signed int16 */
+L..57:
+ addi r5,r5,2
+ lhz r3,0(r5)
+ extsh r3,r3
+ b L..44
+
+/* case unsigned int16 */
+L..58:
+ addi r5,r5,2
+ lhz r3,0(r5)
+
+/* case void / done */
+L..44:
+ addi r1,r1,176 /* restore stack pointer */
+ lwz r0,8(r1) /* get return address */
+ mtlr r0 /* reset link register */
+ blr
+
+/* END(ffi_closure_ASM) */
diff --git a/libffi/src/powerpc/asm.h b/libffi/src/powerpc/asm.h
new file mode 100644
index 0000000..2ccdc02
--- /dev/null
+++ b/libffi/src/powerpc/asm.h
@@ -0,0 +1,128 @@
+/* -----------------------------------------------------------------------
+ asm.h - Copyright (c) 1998 Geoffrey Keating
+
+ PowerPC Assembly glue.
+
+ $Id: asm.h,v 1.1.1.1 1998/11/29 16:48:16 green Exp $
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+#define ASM_GLOBAL_DIRECTIVE .globl
+
+
+#define C_SYMBOL_NAME(name) name
+/* Macro for a label. */
+#ifdef __STDC__
+#define C_LABEL(name) name##:
+#else
+#define C_LABEL(name) name/**/:
+#endif
+
+/* This seems to always be the case on PPC. */
+#define ALIGNARG(log2) log2
+/* For ELF we need the `.type' directive to make shared libs work right. */
+#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg;
+#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
+
+/* If compiled for profiling, call `_mcount' at the start of each function. */
+#ifdef PROF
+/* The mcount code relies on a the return address being on the stack
+ to locate our caller and so it can restore it; so store one just
+ for its benefit. */
+#ifdef PIC
+#define CALL_MCOUNT \
+ .pushsection; \
+ .section ".data"; \
+ .align ALIGNARG(2); \
+0:.long 0; \
+ .previous; \
+ mflr %r0; \
+ stw %r0,4(%r1); \
+ bl _GLOBAL_OFFSET_TABLE_@local-4; \
+ mflr %r11; \
+ lwz %r0,0b@got(%r11); \
+ bl JUMPTARGET(_mcount);
+#else /* PIC */
+#define CALL_MCOUNT \
+ .section ".data"; \
+ .align ALIGNARG(2); \
+0:.long 0; \
+ .previous; \
+ mflr %r0; \
+ lis %r11,0b@ha; \
+ stw %r0,4(%r1); \
+ addi %r0,%r11,0b@l; \
+ bl JUMPTARGET(_mcount);
+#endif /* PIC */
+#else /* PROF */
+#define CALL_MCOUNT /* Do nothing. */
+#endif /* PROF */
+
+#define ENTRY(name) \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
+ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
+ .align ALIGNARG(2); \
+ C_LABEL(name) \
+ CALL_MCOUNT
+
+#define EALIGN_W_0 /* No words to insert. */
+#define EALIGN_W_1 nop
+#define EALIGN_W_2 nop;nop
+#define EALIGN_W_3 nop;nop;nop
+#define EALIGN_W_4 EALIGN_W_3;nop
+#define EALIGN_W_5 EALIGN_W_4;nop
+#define EALIGN_W_6 EALIGN_W_5;nop
+#define EALIGN_W_7 EALIGN_W_6;nop
+
+/* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes
+ past a 2^align boundary. */
+#ifdef PROF
+#define EALIGN(name, alignt, words) \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
+ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
+ .align ALIGNARG(2); \
+ C_LABEL(name) \
+ CALL_MCOUNT \
+ b 0f; \
+ .align ALIGNARG(alignt); \
+ EALIGN_W_##words; \
+ 0:
+#else /* PROF */
+#define EALIGN(name, alignt, words) \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
+ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
+ .align ALIGNARG(alignt); \
+ EALIGN_W_##words; \
+ C_LABEL(name)
+#endif
+
+#define END(name) \
+ ASM_SIZE_DIRECTIVE(name)
+
+#ifdef PIC
+#define JUMPTARGET(name) name##@plt
+#else
+#define JUMPTARGET(name) name
+#endif
+
+/* Local labels stripped out by the linker. */
+#define L(x) .L##x
+
diff --git a/libffi/src/powerpc/darwin.S b/libffi/src/powerpc/darwin.S
new file mode 100644
index 0000000..2233d8a
--- /dev/null
+++ b/libffi/src/powerpc/darwin.S
@@ -0,0 +1,225 @@
+#ifdef __ppc__
+/* -----------------------------------------------------------------------
+ darwin.S - Copyright (c) 2000 John Hornkvist
+
+ PowerPC Assembly glue.
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+#define JUMPTARGET(name) name
+#define L(x) x
+.text
+ .align 2
+.globl _ffi_prep_args
+
+.text
+ .align 2
+.globl _ffi_call_DARWIN
+.text
+ .align 2
+_ffi_call_DARWIN:
+LFB0:
+ mr r12,r8 /* We only need r12 until the call,
+ so it doesn't have to be saved... */
+LFB1:
+ /* Save the old stack pointer as AP. */
+ mr r8,r1
+LCFI0:
+ /* Allocate the stack space we need. */
+ stwux r1,r1,r4
+
+ /* Save registers we use. */
+ mflr r9
+
+ stw r28,-16(r8)
+ stw r29,-12(r8)
+ stw r30, -8(r8)
+ stw r31, -4(r8)
+
+ stw r9, 8(r8)
+ stw r2, 20(r1)
+LCFI1:
+
+ /* Save arguments over call... */
+ mr r31,r5 /* flags, */
+ mr r30,r6 /* rvalue, */
+ mr r29,r7 /* function address, */
+ mr r28,r8 /* our AP. */
+LCFI2:
+ /* Call ffi_prep_args. */
+ mr r4,r1
+ li r9,0
+
+ mtctr r12 // r12 holds address of _ffi_prep_args
+ bctrl
+ lwz r2,20(r1)
+
+ /* Now do the call.
+ Set up cr1 with bits 4-7 of the flags. */
+ mtcrf 0x40,r31
+ /* Get the address to call into CTR. */
+ mtctr r29
+ /* Load all those argument registers.
+ We have set up a nice stack frame, just load it into registers. */
+ lwz r3, 20+(1*4)(r1)
+ lwz r4, 20+(2*4)(r1)
+ lwz r5, 20+(3*4)(r1)
+ lwz r6, 20+(4*4)(r1)
+ nop
+ lwz r7, 20+(5*4)(r1)
+ lwz r8, 20+(6*4)(r1)
+ lwz r9, 20+(7*4)(r1)
+ lwz r10,20+(8*4)(r1)
+
+L1:
+ /* Load all the FP registers. */
+ bf 6,L2 // 2f + 0x18
+ lfd f1,-16-(13*8)(r28)
+ lfd f2,-16-(12*8)(r28)
+ lfd f3,-16-(11*8)(r28)
+ lfd f4,-16-(10*8)(r28)
+ nop
+ lfd f5,-16-(9*8)(r28)
+ lfd f6,-16-(8*8)(r28)
+ lfd f7,-16-(7*8)(r28)
+ lfd f8,-16-(6*8)(r28)
+ nop
+ lfd f9,-16-(5*8)(r28)
+ lfd f10,-16-(4*8)(r28)
+ lfd f11,-16-(3*8)(r28)
+ lfd f12,-16-(2*8)(r28)
+ nop
+ lfd f13,-16-(1*8)(r28)
+
+L2:
+ mr r12,r29 /* Put the target address in r12 as specified. */
+ mtctr r12
+ nop
+ nop
+ /* Make the call. */
+ bctrl
+
+ /* Now, deal with the return value. */
+ mtcrf 0x01,r31
+
+ bt 30,L(done_return_value)
+ bt 29,L(fp_return_value)
+ stw r3,0(r30)
+ bf 28,L(done_return_value)
+ stw r4,4(r30)
+
+ /* Fall through... */
+
+L(done_return_value):
+ /* Restore the registers we used and return. */
+ lwz r9, 8(r28)
+ lwz r31, -4(r28)
+ mtlr r9
+ lwz r30, -8(r28)
+ lwz r29,-12(r28)
+ lwz r28,-16(r28)
+ lwz r1,0(r1)
+ blr
+
+L(fp_return_value):
+ bf 28,L(float_return_value)
+ stfd f1,0(r30)
+ b L(done_return_value)
+L(float_return_value):
+ stfs f1,0(r30)
+ b L(done_return_value)
+LFE1:
+/* END(_ffi_call_DARWIN) */
+
+/* Provide a null definition of _ffi_call_AIX. */
+.text
+ .align 2
+.globl _ffi_call_AIX
+.text
+ .align 2
+_ffi_call_AIX:
+ blr
+/* END(_ffi_call_AIX) */
+
+.data
+.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms
+EH_frame1:
+ .set L$set$0,LECIE1-LSCIE1
+ .long L$set$0 ; Length of Common Information Entry
+LSCIE1:
+ .long 0x0 ; CIE Identifier Tag
+ .byte 0x1 ; CIE Version
+ .ascii "zR\0" ; CIE Augmentation
+ .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor
+ .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor
+ .byte 0x41 ; CIE RA Column
+ .byte 0x1 ; uleb128 0x1; Augmentation size
+ .byte 0x90 ; FDE Encoding (indirect pcrel)
+ .byte 0xc ; DW_CFA_def_cfa
+ .byte 0x1 ; uleb128 0x1
+ .byte 0x0 ; uleb128 0x0
+ .align 2
+LECIE1:
+.globl _ffi_call_DARWIN.eh
+_ffi_call_DARWIN.eh:
+LSFDE1:
+ .set L$set$1,LEFDE1-LASFDE1
+ .long L$set$1 ; FDE Length
+LASFDE1:
+ .long LASFDE1-EH_frame1 ; FDE CIE offset
+ .long LLFB0$non_lazy_ptr-. ; FDE initial location
+ .set L$set$3,LFE1-LFB0
+ .long L$set$3 ; FDE address range
+ .byte 0x0 ; uleb128 0x0; Augmentation size
+ .byte 0x4 ; DW_CFA_advance_loc4
+ .set L$set$4,LCFI0-LFB1
+ .long L$set$4
+ .byte 0xd ; DW_CFA_def_cfa_register
+ .byte 0x08 ; uleb128 0x08
+ .byte 0x4 ; DW_CFA_advance_loc4
+ .set L$set$5,LCFI1-LCFI0
+ .long L$set$5
+ .byte 0x11 ; DW_CFA_offset_extended_sf
+ .byte 0x41 ; uleb128 0x41
+ .byte 0x7e ; sleb128 -2
+ .byte 0x9f ; DW_CFA_offset, column 0x1f
+ .byte 0x1 ; uleb128 0x1
+ .byte 0x9e ; DW_CFA_offset, column 0x1e
+ .byte 0x2 ; uleb128 0x2
+ .byte 0x9d ; DW_CFA_offset, column 0x1d
+ .byte 0x3 ; uleb128 0x3
+ .byte 0x9c ; DW_CFA_offset, column 0x1c
+ .byte 0x4 ; uleb128 0x4
+ .byte 0x4 ; DW_CFA_advance_loc4
+ .set L$set$6,LCFI2-LCFI1
+ .long L$set$6
+ .byte 0xd ; DW_CFA_def_cfa_register
+ .byte 0x1c ; uleb128 0x1c
+ .align 2
+LEFDE1:
+.data
+ .align 2
+LLFB0$non_lazy_ptr:
+ .long LFB0
+#endif
diff --git a/libffi/src/powerpc/darwin_closure.S b/libffi/src/powerpc/darwin_closure.S
new file mode 100644
index 0000000..317172c
--- /dev/null
+++ b/libffi/src/powerpc/darwin_closure.S
@@ -0,0 +1,306 @@
+#ifdef __ppc__
+/* -----------------------------------------------------------------------
+ darwin_closure.S - Copyright (c) 2002 2003 Free Software Foundation,
+ Inc. based on ppc_closure.S
+
+ PowerPC Assembly glue.
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#define L(x) x
+
+ .file "darwin_closure.S"
+.text
+ .align 2
+.globl _ffi_closure_ASM
+
+.text
+ .align 2
+_ffi_closure_ASM:
+LFB1:
+ mflr r0 /* extract return address */
+ stw r0, 8(r1) /* save the return address */
+LCFI0:
+ /* 24 Bytes (Linkage Area)
+ 32 Bytes (outgoing parameter area, always reserved)
+ 104 Bytes (13*8 from FPR)
+ 8 Bytes (result)
+ 168 Bytes */
+
+ stwu r1,-176(r1) /* skip over caller save area
+ keep stack aligned to 16. */
+LCFI1:
+ /* We want to build up an area for the parameters passed
+ in registers. (both floating point and integer) */
+
+ /* We store gpr 3 to gpr 10 (aligned to 4)
+ in the parents outgoing area. */
+ stw r3, 200(r1)
+ stw r4, 204(r1)
+ stw r5, 208(r1)
+ stw r6, 212(r1)
+ stw r7, 216(r1)
+ stw r8, 220(r1)
+ stw r9, 224(r1)
+ stw r10, 228(r1)
+
+ /* We save fpr 1 to fpr 13. (aligned to 8) */
+ stfd f1, 56(r1)
+ stfd f2, 64(r1)
+ stfd f3, 72(r1)
+ stfd f4, 80(r1)
+ stfd f5, 88(r1)
+ stfd f6, 96(r1)
+ stfd f7, 104(r1)
+ stfd f8, 112(r1)
+ stfd f9, 120(r1)
+ stfd f10, 128(r1)
+ stfd f11, 136(r1)
+ stfd f12, 144(r1)
+ stfd f13, 152(r1)
+
+ /* Set up registers for the routine that actually does the work
+ get the context pointer from the trampoline. */
+ mr r3,r11
+
+ /* Now load up the pointer to the result storage. */
+ addi r4,r1,160
+
+ /* Now load up the pointer to the saved gpr registers. */
+ addi r5,r1,200
+
+ /* Now load up the pointer to the saved fpr registers. */
+ addi r6,r1,56
+
+ /* Make the call. */
+ bl Lffi_closure_helper_DARWIN$stub
+
+ /* Now r3 contains the return type
+ so use it to look up in a table
+ so we know how to deal with each type. */
+
+ /* Look up the proper starting point in table
+ by using return type as offset. */
+ addi r5,r1,160 /* Get pointer to results area. */
+ bl Lget_ret_type0_addr /* Get pointer to Lret_type0 into LR. */
+ mflr r4 /* Move to r4. */
+ slwi r3,r3,4 /* Now multiply return type by 16. */
+ add r3,r3,r4 /* Add contents of table to table address. */
+ mtctr r3
+ bctr /* Jump to it. */
+LFE1:
+/* Each of the ret_typeX code fragments has to be exactly 16 bytes long
+ (4 instructions). For cache effectiveness we align to a 16 byte boundary
+ first. */
+
+ .align 4
+
+ nop
+ nop
+ nop
+Lget_ret_type0_addr:
+ blrl
+
+/* case FFI_TYPE_VOID */
+Lret_type0:
+ b Lfinish
+ nop
+ nop
+ nop
+
+/* case FFI_TYPE_INT */
+Lret_type1:
+ lwz r3,0(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case FFI_TYPE_FLOAT */
+Lret_type2:
+ lfs f1,0(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case FFI_TYPE_DOUBLE */
+Lret_type3:
+ lfd f1,0(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case FFI_TYPE_LONGDOUBLE */
+Lret_type4:
+ lfd f1,0(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case FFI_TYPE_UINT8 */
+Lret_type5:
+ lbz r3,3(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case FFI_TYPE_SINT8 */
+Lret_type6:
+ lbz r3,3(r5)
+ extsb r3,r3
+ b Lfinish
+ nop
+
+/* case FFI_TYPE_UINT16 */
+Lret_type7:
+ lhz r3,2(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case FFI_TYPE_SINT16 */
+Lret_type8:
+ lha r3,2(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case FFI_TYPE_UINT32 */
+Lret_type9:
+ lwz r3,0(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case FFI_TYPE_SINT32 */
+Lret_type10:
+ lwz r3,0(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case FFI_TYPE_UINT64 */
+Lret_type11:
+ lwz r3,0(r5)
+ lwz r4,4(r5)
+ b Lfinish
+ nop
+
+/* case FFI_TYPE_SINT64 */
+Lret_type12:
+ lwz r3,0(r5)
+ lwz r4,4(r5)
+ b Lfinish
+ nop
+
+/* case FFI_TYPE_STRUCT */
+Lret_type13:
+ b Lfinish
+ nop
+ nop
+ nop
+
+/* case FFI_TYPE_POINTER */
+Lret_type14:
+ lwz r3,0(r5)
+ b Lfinish
+ nop
+ nop
+
+/* case done */
+Lfinish:
+ addi r1,r1,176 /* Restore stack pointer. */
+ lwz r0,8(r1) /* Get return address. */
+ mtlr r0 /* Reset link register. */
+ blr
+
+/* END(ffi_closure_ASM) */
+
+.data
+.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms
+EH_frame1:
+ .set L$set$0,LECIE1-LSCIE1
+ .long L$set$0 ; Length of Common Information Entry
+LSCIE1:
+ .long 0x0 ; CIE Identifier Tag
+ .byte 0x1 ; CIE Version
+ .ascii "zR\0" ; CIE Augmentation
+ .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor
+ .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor
+ .byte 0x41 ; CIE RA Column
+ .byte 0x1 ; uleb128 0x1; Augmentation size
+ .byte 0x90 ; FDE Encoding (indirect pcrel)
+ .byte 0xc ; DW_CFA_def_cfa
+ .byte 0x1 ; uleb128 0x1
+ .byte 0x0 ; uleb128 0x0
+ .align 2
+LECIE1:
+.globl _ffi_closure_ASM.eh
+_ffi_closure_ASM.eh:
+LSFDE1:
+ .set L$set$1,LEFDE1-LASFDE1
+ .long L$set$1 ; FDE Length
+
+LASFDE1:
+ .long LASFDE1-EH_frame1 ; FDE CIE offset
+ .long LLFB1$non_lazy_ptr-. ; FDE initial location
+ .set L$set$3,LFE1-LFB1
+ .long L$set$3 ; FDE address range
+ .byte 0x0 ; uleb128 0x0; Augmentation size
+ .byte 0x4 ; DW_CFA_advance_loc4
+ .set L$set$3,LCFI1-LCFI0
+ .long L$set$3
+ .byte 0xe ; DW_CFA_def_cfa_offset
+ .byte 176,1 ; uleb128 176
+ .byte 0x4 ; DW_CFA_advance_loc4
+ .set L$set$4,LCFI0-LFB1
+ .long L$set$4
+ .byte 0x11 ; DW_CFA_offset_extended_sf
+ .byte 0x41 ; uleb128 0x41
+ .byte 0x7e ; sleb128 -2
+ .align 2
+LEFDE1:
+.data
+ .align 2
+LDFCM0:
+.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
+ .align 2
+Lffi_closure_helper_DARWIN$stub:
+ .indirect_symbol _ffi_closure_helper_DARWIN
+ mflr r0
+ bcl 20,31,LO$ffi_closure_helper_DARWIN
+LO$ffi_closure_helper_DARWIN:
+ mflr r11
+ addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN)
+ mtlr r0
+ lwzu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN)(r11)
+ mtctr r12
+ bctr
+.data
+.lazy_symbol_pointer
+L_ffi_closure_helper_DARWIN$lazy_ptr:
+ .indirect_symbol _ffi_closure_helper_DARWIN
+ .long dyld_stub_binding_helper
+.data
+ .align 2
+LLFB1$non_lazy_ptr:
+ .long LFB1
+#endif
diff --git a/libffi/src/powerpc/ffi.c b/libffi/src/powerpc/ffi.c
new file mode 100644
index 0000000..29f7dba
--- /dev/null
+++ b/libffi/src/powerpc/ffi.c
@@ -0,0 +1,1133 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1998 Geoffrey Keating
+
+ PowerPC Foreign Function Interface
+
+ $Id: ffi.c,v 1.1.1.1 1998/11/29 16:48:16 green Exp $
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 1)
+# define hidden __attribute__ ((visibility ("hidden")))
+#else
+# define hidden
+#endif
+
+
+extern void ffi_closure_SYSV(void);
+extern void hidden ffi_closure_LINUX64(void);
+
+enum {
+ /* The assembly depends on these exact flags. */
+ FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */
+ FLAG_RETURNS_FP = 1 << (31-29),
+ FLAG_RETURNS_64BITS = 1 << (31-28),
+
+ FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
+ FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
+ FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
+ FLAG_RETVAL_REFERENCE = 1 << (31- 4)
+};
+
+/* About the SYSV ABI. */
+enum {
+ NUM_GPR_ARG_REGISTERS = 8,
+ NUM_FPR_ARG_REGISTERS = 8
+};
+enum { ASM_NEEDS_REGISTERS = 4 };
+
+/* ffi_prep_args_SYSV 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:
+
+ | Return address from ffi_call_SYSV 4bytes | higher addresses
+ |--------------------------------------------|
+ | Previous backchain pointer 4 | stack pointer here
+ |--------------------------------------------|<+ <<< on entry to
+ | Saved r28-r31 4*4 | | ffi_call_SYSV
+ |--------------------------------------------| |
+ | GPR registers r3-r10 8*4 | | ffi_call_SYSV
+ |--------------------------------------------| |
+ | FPR registers f1-f8 (optional) 8*8 | |
+ |--------------------------------------------| | stack |
+ | Space for copied structures | | grows |
+ |--------------------------------------------| | down V
+ | Parameters that didn't fit in registers | |
+ |--------------------------------------------| | lower addresses
+ | Space for callee's LR 4 | |
+ |--------------------------------------------| | stack pointer here
+ | Current backchain pointer 4 |-/ during
+ |--------------------------------------------| <<< ffi_call_SYSV
+
+ */
+
+/*@-exportheader@*/
+void ffi_prep_args_SYSV(extended_cif *ecif, unsigned *const stack)
+/*@=exportheader@*/
+{
+ const unsigned bytes = ecif->cif->bytes;
+ const unsigned flags = ecif->cif->flags;
+
+ /* 'stacktop' points at the previous backchain pointer. */
+ unsigned *const stacktop = stack + (bytes / sizeof(unsigned));
+
+ /* 'gpr_base' points at the space for gpr3, and grows upwards as
+ we use GPR registers. */
+ unsigned *gpr_base = stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
+ int intarg_count = 0;
+
+ /* 'fpr_base' points at the space for fpr1, and grows upwards as
+ we use FPR registers. */
+ double *fpr_base = (double *)gpr_base - NUM_FPR_ARG_REGISTERS;
+ int fparg_count = 0;
+
+ /* 'copy_space' grows down as we put structures in it. It should
+ stay 16-byte aligned. */
+ char *copy_space = ((flags & FLAG_FP_ARGUMENTS)
+ ? (char *)fpr_base
+ : (char *)gpr_base);
+
+ /* 'next_arg' grows up as we put parameters in it. */
+ unsigned *next_arg = stack + 2;
+
+ int i;
+ ffi_type **ptr;
+ double double_tmp;
+ void **p_argv;
+ size_t struct_copy_size;
+ unsigned gprvalue;
+
+ /* Check that everything starts aligned properly. */
+ FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0);
+ FFI_ASSERT(((unsigned)(char *)copy_space & 0xF) == 0);
+ FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0);
+ FFI_ASSERT((bytes & 0xF) == 0);
+ FFI_ASSERT(copy_space >= (char *)next_arg);
+
+ /* Deal with return values that are actually pass-by-reference. */
+ if (flags & FLAG_RETVAL_REFERENCE)
+ {
+ *gpr_base++ = (unsigned long)(char *)ecif->rvalue;
+ intarg_count++;
+ }
+
+ /* Now for the arguments. */
+ p_argv = ecif->avalue;
+ for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
+ i > 0;
+ i--, ptr++, p_argv++)
+ {
+ switch ((*ptr)->type)
+ {
+ case FFI_TYPE_FLOAT:
+ double_tmp = *(float *)*p_argv;
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ {
+ *(float *)next_arg = (float)double_tmp;
+ next_arg += 1;
+ }
+ else
+ *fpr_base++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ double_tmp = *(double *)*p_argv;
+
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ {
+ if (intarg_count%2 != 0)
+ {
+ intarg_count++;
+ next_arg++;
+ }
+ *(double *)next_arg = double_tmp;
+ next_arg += 2;
+ }
+ else
+ *fpr_base++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
+ intarg_count++;
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS)
+ {
+ if (intarg_count%2 != 0)
+ {
+ intarg_count++;
+ next_arg++;
+ }
+ *(long long *)next_arg = *(long long *)*p_argv;
+ next_arg += 2;
+ }
+ else
+ {
+ /* whoops: abi states only certain register pairs
+ * can be used for passing long long int
+ * specifically (r3,r4), (r5,r6), (r7,r8),
+ * (r9,r10) and if next arg is long long but
+ * not correct starting register of pair then skip
+ * until the proper starting register
+ */
+ if (intarg_count%2 != 0)
+ {
+ intarg_count ++;
+ gpr_base++;
+ }
+ *(long long *)gpr_base = *(long long *)*p_argv;
+ gpr_base += 2;
+ }
+ intarg_count += 2;
+ break;
+
+ case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ struct_copy_size = ((*ptr)->size + 15) & ~0xF;
+ copy_space -= struct_copy_size;
+ memcpy(copy_space, (char *)*p_argv, (*ptr)->size);
+
+ gprvalue = (unsigned long)copy_space;
+
+ FFI_ASSERT(copy_space > (char *)next_arg);
+ FFI_ASSERT(flags & FLAG_ARG_NEEDS_COPY);
+ goto putgpr;
+
+ case FFI_TYPE_UINT8:
+ gprvalue = *(unsigned char *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_SINT8:
+ gprvalue = *(signed char *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_UINT16:
+ gprvalue = *(unsigned short *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_SINT16:
+ gprvalue = *(signed short *)*p_argv;
+ goto putgpr;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_POINTER:
+ gprvalue = *(unsigned *)*p_argv;
+ putgpr:
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS)
+ *next_arg++ = gprvalue;
+ else
+ *gpr_base++ = gprvalue;
+ intarg_count++;
+ break;
+ }
+ }
+
+ /* Check that we didn't overrun the stack... */
+ FFI_ASSERT(copy_space >= (char *)next_arg);
+ FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
+ FFI_ASSERT((unsigned *)fpr_base
+ <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
+ FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
+}
+
+/* About the LINUX64 ABI. */
+enum {
+ NUM_GPR_ARG_REGISTERS64 = 8,
+ NUM_FPR_ARG_REGISTERS64 = 13
+};
+enum { ASM_NEEDS_REGISTERS64 = 4 };
+
+/* ffi_prep_args64 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:
+
+ | Ret addr from ffi_call_LINUX64 8bytes | higher addresses
+ |--------------------------------------------|
+ | CR save area 8bytes |
+ |--------------------------------------------|
+ | Previous backchain pointer 8 | stack pointer here
+ |--------------------------------------------|<+ <<< on entry to
+ | Saved r28-r31 4*8 | | ffi_call_LINUX64
+ |--------------------------------------------| |
+ | GPR registers r3-r10 8*8 | |
+ |--------------------------------------------| |
+ | FPR registers f1-f13 (optional) 13*8 | |
+ |--------------------------------------------| |
+ | Parameter save area | |
+ |--------------------------------------------| |
+ | TOC save area 8 | |
+ |--------------------------------------------| | stack |
+ | Linker doubleword 8 | | grows |
+ |--------------------------------------------| | down V
+ | Compiler doubleword 8 | |
+ |--------------------------------------------| | lower addresses
+ | Space for callee's LR 8 | |
+ |--------------------------------------------| |
+ | CR save area 8 | |
+ |--------------------------------------------| | stack pointer here
+ | Current backchain pointer 8 |-/ during
+ |--------------------------------------------| <<< ffi_call_LINUX64
+
+ */
+
+/*@-exportheader@*/
+void hidden ffi_prep_args64(extended_cif *ecif, unsigned long *const stack)
+/*@=exportheader@*/
+{
+ const unsigned long bytes = ecif->cif->bytes;
+ const unsigned long flags = ecif->cif->flags;
+
+ /* 'stacktop' points at the previous backchain pointer. */
+ unsigned long *const stacktop = stack + (bytes / sizeof(unsigned long));
+
+ /* 'next_arg' points at the space for gpr3, and grows upwards as
+ we use GPR registers, then continues at rest. */
+ unsigned long *const gpr_base = stacktop - ASM_NEEDS_REGISTERS64
+ - NUM_GPR_ARG_REGISTERS64;
+ unsigned long *const gpr_end = gpr_base + NUM_GPR_ARG_REGISTERS64;
+ unsigned long *const rest = stack + 6 + NUM_GPR_ARG_REGISTERS64;
+ unsigned long *next_arg = gpr_base;
+
+ /* 'fpr_base' points at the space for fpr3, and grows upwards as
+ we use FPR registers. */
+ double *fpr_base = (double *)gpr_base - NUM_FPR_ARG_REGISTERS64;
+ int fparg_count = 0;
+
+ int i, words;
+ ffi_type **ptr;
+ double double_tmp;
+ void **p_argv;
+ unsigned long gprvalue;
+
+ /* Check that everything starts aligned properly. */
+ FFI_ASSERT(((unsigned long)(char *)stack & 0xF) == 0);
+ FFI_ASSERT(((unsigned long)(char *)stacktop & 0xF) == 0);
+ FFI_ASSERT((bytes & 0xF) == 0);
+
+ /* Deal with return values that are actually pass-by-reference. */
+ if (flags & FLAG_RETVAL_REFERENCE)
+ *next_arg++ = (unsigned long)(char *)ecif->rvalue;
+
+ /* Now for the arguments. */
+ p_argv = ecif->avalue;
+ for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
+ i > 0;
+ i--, ptr++, p_argv++)
+ {
+ switch ((*ptr)->type)
+ {
+ case FFI_TYPE_FLOAT:
+ double_tmp = *(float *)*p_argv;
+ *(float *)next_arg = (float)double_tmp;
+ if (++next_arg == gpr_end)
+ next_arg = rest;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ double_tmp = *(double *)*p_argv;
+ *(double *)next_arg = double_tmp;
+ if (++next_arg == gpr_end)
+ next_arg = rest;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ double_tmp = ((double *) *p_argv)[0];
+ *(double *) next_arg = double_tmp;
+ if (++next_arg == gpr_end)
+ next_arg = rest;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base++ = double_tmp;
+ fparg_count++;
+ double_tmp = ((double *) *p_argv)[1];
+ *(double *) next_arg = double_tmp;
+ if (++next_arg == gpr_end)
+ next_arg = rest;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+#endif
+
+ case FFI_TYPE_STRUCT:
+ words = ((*ptr)->size + 7) / 8;
+ if (next_arg >= gpr_base && next_arg + words > gpr_end)
+ {
+ size_t first = (char *) gpr_end - (char *) next_arg;
+ memcpy((char *) next_arg, (char *) *p_argv, first);
+ memcpy((char *) rest, (char *) *p_argv + first,
+ (*ptr)->size - first);
+ next_arg = (unsigned long *) ((char *) rest + words * 8 - first);
+ }
+ else
+ {
+ char *where = (char *) next_arg;
+
+ /* Structures with size less than eight bytes are passed
+ left-padded. */
+ if ((*ptr)->size < 8)
+ where += 8 - (*ptr)->size;
+
+ memcpy (where, (char *) *p_argv, (*ptr)->size);
+ next_arg += words;
+ if (next_arg == gpr_end)
+ next_arg = rest;
+ }
+ break;
+
+ case FFI_TYPE_UINT8:
+ gprvalue = *(unsigned char *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_SINT8:
+ gprvalue = *(signed char *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_UINT16:
+ gprvalue = *(unsigned short *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_SINT16:
+ gprvalue = *(signed short *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_UINT32:
+ gprvalue = *(unsigned int *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ gprvalue = *(signed int *)*p_argv;
+ goto putgpr;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_POINTER:
+ gprvalue = *(unsigned long *)*p_argv;
+ putgpr:
+ *next_arg++ = gprvalue;
+ if (next_arg == gpr_end)
+ next_arg = rest;
+ break;
+ }
+ }
+
+ FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS
+ || (next_arg >= gpr_base && next_arg <= gpr_base + 4));
+}
+
+
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ /* All this is for the SYSV and LINUX64 ABI. */
+ int i;
+ ffi_type **ptr;
+ unsigned bytes;
+ int fparg_count = 0, intarg_count = 0;
+ unsigned flags = 0;
+ unsigned struct_copy_size = 0;
+ unsigned type = cif->rtype->type;
+
+ if (cif->abi != FFI_LINUX64)
+ {
+ /* All the machine-independent calculation of cif->bytes will be wrong.
+ Redo the calculation for SYSV. */
+
+ /* Space for the frame pointer, callee's LR, and the asm's temp regs. */
+ bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof(int);
+
+ /* Space for the GPR registers. */
+ bytes += NUM_GPR_ARG_REGISTERS * sizeof(int);
+ }
+ else
+ {
+ /* 64-bit ABI. */
+
+ /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
+ regs. */
+ bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof(long);
+
+ /* Space for the mandatory parm save area and general registers. */
+ bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof(long);
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (type == FFI_TYPE_LONGDOUBLE)
+ type = FFI_TYPE_DOUBLE;
+#endif
+ }
+
+ /* Return value handling. The rules for SYSV are as follows:
+ - 32-bit (or less) integer values are returned in gpr3;
+ - Structures of size <= 4 bytes also returned in gpr3;
+ - 64-bit integer values and structures between 5 and 8 bytes are returned
+ in gpr3 and gpr4;
+ - Single/double FP values are returned in fpr1;
+ - Larger structures and long double (if not equivalent to double) values
+ are allocated space and a pointer is passed as the first argument.
+ For LINUX64:
+ - integer values in gpr3;
+ - Structures/Unions by reference;
+ - Single/double FP values in fpr1, long double in fpr1,fpr2. */
+ switch (type)
+ {
+ case FFI_TYPE_DOUBLE:
+ flags |= FLAG_RETURNS_64BITS;
+ /* Fall through. */
+ case FFI_TYPE_FLOAT:
+ flags |= FLAG_RETURNS_FP;
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ flags |= FLAG_RETURNS_64BITS;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ if (cif->abi != FFI_GCC_SYSV && cif->abi != FFI_LINUX64)
+ {
+ if (cif->rtype->size <= 4)
+ break;
+ else if (cif->rtype->size <= 8)
+ {
+ flags |= FLAG_RETURNS_64BITS;
+ break;
+ }
+ }
+ /* else fall through. */
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ intarg_count++;
+ flags |= FLAG_RETVAL_REFERENCE;
+ /* Fall through. */
+ case FFI_TYPE_VOID:
+ flags |= FLAG_RETURNS_NOTHING;
+ break;
+
+ default:
+ /* Returns 32-bit integer, or similar. Nothing to do here. */
+ break;
+ }
+
+ if (cif->abi != FFI_LINUX64)
+ /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
+ first NUM_FPR_ARG_REGISTERS fp 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:
+ fparg_count++;
+ /* floating singles are not 8-aligned on stack */
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ fparg_count++;
+ /* If this FP arg is going on the stack, it must be
+ 8-byte-aligned. */
+ if (fparg_count > NUM_FPR_ARG_REGISTERS
+ && intarg_count%2 != 0)
+ intarg_count++;
+ 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 (intarg_count == NUM_GPR_ARG_REGISTERS-1
+ || (intarg_count >= NUM_GPR_ARG_REGISTERS
+ && intarg_count%2 != 0))
+ intarg_count++;
+ intarg_count += 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). */
+ struct_copy_size += ((*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. */
+ intarg_count++;
+ break;
+ }
+ }
+ else
+ for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+ {
+ switch ((*ptr)->type)
+ {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ fparg_count += 2;
+ intarg_count += 2;
+ break;
+#endif
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ fparg_count++;
+ intarg_count++;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ intarg_count += ((*ptr)->size + 7) / 8;
+ break;
+
+ default:
+ /* Everything else is passed as a 8-byte word in a GPR, either
+ the object itself or a pointer to it. */
+ intarg_count++;
+ break;
+ }
+ }
+
+ if (fparg_count != 0)
+ flags |= FLAG_FP_ARGUMENTS;
+ if (intarg_count > 4)
+ flags |= FLAG_4_GPR_ARGUMENTS;
+ if (struct_copy_size != 0)
+ flags |= FLAG_ARG_NEEDS_COPY;
+
+ if (cif->abi != FFI_LINUX64)
+ {
+ /* Space for the FPR registers, if needed. */
+ if (fparg_count != 0)
+ bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
+
+ /* Stack space. */
+ if (intarg_count > NUM_GPR_ARG_REGISTERS)
+ bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof(int);
+ if (fparg_count > NUM_FPR_ARG_REGISTERS)
+ bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof(double);
+ }
+ else
+ {
+ /* Space for the FPR registers, if needed. */
+ if (fparg_count != 0)
+ bytes += NUM_FPR_ARG_REGISTERS64 * sizeof(double);
+
+ /* Stack space. */
+ if (intarg_count > NUM_GPR_ARG_REGISTERS64)
+ bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof(long);
+ }
+
+ /* 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 += struct_copy_size;
+
+ cif->flags = flags;
+ cif->bytes = bytes;
+
+ return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_SYSV(/*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+extern void hidden ffi_call_LINUX64(/*@out@*/ extended_cif *,
+ unsigned long, unsigned long,
+ /*@out@*/ unsigned long *,
+ 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)
+ {
+#ifndef POWERPC64
+ case FFI_SYSV:
+ case FFI_GCC_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(&ecif, -cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#else
+ case FFI_LINUX64:
+ /*@-usedef@*/
+ ffi_call_LINUX64(&ecif, -(long) cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#endif
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+
+#ifndef POWERPC64
+static void flush_icache(char *, int);
+
+#define MIN_CACHE_LINE_SIZE 8
+
+static void flush_icache(char * addr1, int size)
+{
+ int i;
+ char * addr;
+ for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) {
+ addr = addr1 + i;
+ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" : : "r"(addr) : "memory");
+ }
+ addr = addr1 + size - 1;
+ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" : : "r"(addr) : "memory");
+}
+#endif
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data)
+{
+#ifdef POWERPC64
+ void **tramp = (void **) &closure->tramp[0];
+
+ FFI_ASSERT (cif->abi == FFI_LINUX64);
+ /* Copy function address and TOC from ffi_closure_LINUX64. */
+ memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
+ tramp[2] = (void *) closure;
+#else
+ unsigned int *tramp;
+
+ FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
+
+ tramp = (unsigned int *) &closure->tramp[0];
+ tramp[0] = 0x7c0802a6; /* mflr r0 */
+ tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */
+ tramp[4] = 0x7d6802a6; /* mflr r11 */
+ tramp[5] = 0x7c0803a6; /* mtlr r0 */
+ tramp[6] = 0x800b0000; /* lwz r0,0(r11) */
+ tramp[7] = 0x816b0004; /* lwz r11,4(r11) */
+ tramp[8] = 0x7c0903a6; /* mtctr r0 */
+ tramp[9] = 0x4e800420; /* bctr */
+ *(void **) &tramp[2] = (void *)ffi_closure_SYSV; /* function */
+ *(void **) &tramp[3] = (void *)closure; /* context */
+
+ /* Flush the icache. */
+ flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
+#endif
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ return FFI_OK;
+}
+
+typedef union
+{
+ float f;
+ double d;
+} ffi_dblfl;
+
+int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*,
+ ffi_dblfl*, unsigned long*);
+
+/* Basically the trampoline invokes ffi_closure_SYSV, and on
+ * entry, r11 holds the address of the closure.
+ * After storing the registers that could possibly contain
+ * parameters to be passed into the stack frame and setting
+ * up space for a return value, ffi_closure_SYSV invokes the
+ * following helper function to do most of the work
+ */
+
+int
+ffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue,
+ unsigned long * pgr, ffi_dblfl * pfr,
+ unsigned long * pst)
+{
+ /* rvalue is the pointer to space for return value in closure assembly */
+ /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */
+ /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */
+ /* pst is the pointer to outgoing parameter stack in original caller */
+
+ void ** avalue;
+ ffi_type ** arg_types;
+ long i, avn;
+ long nf; /* number of floating registers already used */
+ long ng; /* number of general registers already used */
+ ffi_cif * cif;
+ double temp;
+
+ cif = closure->cif;
+ avalue = alloca(cif->nargs * sizeof(void *));
+
+ nf = 0;
+ ng = 0;
+
+ /* Copy the caller's structure return value address so that the closure
+ returns the data directly to the caller. */
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ rvalue = (void *) *pgr;
+ ng++;
+ pgr++;
+ }
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ while (i < avn)
+ {
+ switch (arg_types[i]->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ /* there are 8 gpr registers used to pass values */
+ if (ng < 8) {
+ avalue[i] = (((char *)pgr)+3);
+ ng++;
+ pgr++;
+ } else {
+ avalue[i] = (((char *)pst)+3);
+ pst++;
+ }
+ break;
+
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ /* there are 8 gpr registers used to pass values */
+ if (ng < 8) {
+ avalue[i] = (((char *)pgr)+2);
+ ng++;
+ pgr++;
+ } else {
+ avalue[i] = (((char *)pst)+2);
+ pst++;
+ }
+ break;
+
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_POINTER:
+ /* there are 8 gpr registers used to pass values */
+ if (ng < 8) {
+ avalue[i] = pgr;
+ ng++;
+ pgr++;
+ } else {
+ avalue[i] = pst;
+ pst++;
+ }
+ break;
+
+ case FFI_TYPE_STRUCT:
+ /* Structs are passed by reference. The address will appear in a
+ gpr if it is one of the first 8 arguments. */
+ if (ng < 8) {
+ avalue[i] = (void *) *pgr;
+ ng++;
+ pgr++;
+ } else {
+ avalue[i] = (void *) *pst;
+ pst++;
+ }
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ /* passing long long ints are complex, they must
+ * be passed in suitable register pairs such as
+ * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
+ * and if the entire pair aren't available then the outgoing
+ * parameter stack is used for both but an alignment of 8
+ * must will be kept. So we must either look in pgr
+ * or pst to find the correct address for this type
+ * of parameter.
+ */
+ if (ng < 7) {
+ if (ng & 0x01) {
+ /* skip r4, r6, r8 as starting points */
+ ng++;
+ pgr++;
+ }
+ avalue[i] = pgr;
+ ng+=2;
+ pgr+=2;
+ } else {
+ if (((long)pst) & 4) pst++;
+ avalue[i] = pst;
+ pst+=2;
+ }
+ break;
+
+ case FFI_TYPE_FLOAT:
+ /* unfortunately float values are stored as doubles
+ * in the ffi_closure_SYSV code (since we don't check
+ * the type in that routine).
+ */
+
+ /* there are 8 64bit floating point registers */
+
+ if (nf < 8) {
+ temp = pfr->d;
+ pfr->f = (float)temp;
+ avalue[i] = pfr;
+ nf++;
+ pfr++;
+ } else {
+ /* FIXME? here we are really changing the values
+ * stored in the original calling routines outgoing
+ * parameter stack. This is probably a really
+ * naughty thing to do but...
+ */
+ avalue[i] = pst;
+ nf++;
+ pst+=1;
+ }
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ /* On the outgoing stack all values are aligned to 8 */
+ /* there are 8 64bit floating point registers */
+
+ if (nf < 8) {
+ avalue[i] = pfr;
+ nf++;
+ pfr++;
+ } else {
+ if (((long)pst) & 4) pst++;
+ avalue[i] = pst;
+ nf++;
+ pst+=2;
+ }
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+
+ i++;
+ }
+
+
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_SYSV how to perform return type promotions. */
+ return cif->rtype->type;
+
+}
+
+int hidden ffi_closure_helper_LINUX64 (ffi_closure*, void*, unsigned long*,
+ ffi_dblfl*);
+
+int hidden
+ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
+ unsigned long *pst, ffi_dblfl *pfr)
+{
+ /* rvalue is the pointer to space for return value in closure assembly */
+ /* pst is the pointer to parameter save area
+ (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
+ /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
+
+ void **avalue;
+ ffi_type **arg_types;
+ long i, avn;
+ ffi_cif *cif;
+ ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
+
+ cif = closure->cif;
+ avalue = alloca (cif->nargs * sizeof (void *));
+
+ /* Copy the caller's structure return value address so that the closure
+ returns the data directly to the caller. */
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ rvalue = (void *) *pst;
+ pst++;
+ }
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ while (i < avn)
+ {
+ switch (arg_types[i]->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ avalue[i] = (char *) pst + 7;
+ pst++;
+ break;
+
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ avalue[i] = (char *) pst + 6;
+ pst++;
+ break;
+
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ avalue[i] = (char *) pst + 4;
+ pst++;
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ avalue[i] = pst;
+ pst++;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ /* Structures with size less than eight bytes are passed
+ left-padded. */
+ if (arg_types[i]->size < 8)
+ avalue[i] = (char *) pst + 8 - arg_types[i]->size;
+ else
+ avalue[i] = pst;
+ pst += (arg_types[i]->size + 7) / 8;
+ break;
+
+ case FFI_TYPE_FLOAT:
+ /* unfortunately float values are stored as doubles
+ * in the ffi_closure_LINUX64 code (since we don't check
+ * the type in that routine).
+ */
+
+ /* there are 13 64bit floating point registers */
+
+ if (pfr < end_pfr)
+ {
+ double temp = pfr->d;
+ pfr->f = (float) temp;
+ avalue[i] = pfr;
+ pfr++;
+ }
+ else
+ avalue[i] = pst;
+ pst++;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ /* On the outgoing stack all values are aligned to 8 */
+ /* there are 13 64bit floating point registers */
+
+ if (pfr < end_pfr)
+ {
+ avalue[i] = pfr;
+ pfr++;
+ }
+ else
+ avalue[i] = pst;
+ pst++;
+ break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if (pfr + 1 < end_pfr)
+ {
+ avalue[i] = pfr;
+ pfr += 2;
+ }
+ else
+ {
+ if (pfr < end_pfr)
+ {
+ /* Passed partly in f13 and partly on the stack.
+ Move it all to the stack. */
+ *pst = *(unsigned long *) pfr;
+ pfr++;
+ }
+ avalue[i] = pst;
+ }
+ pst += 2;
+ break;
+#endif
+
+ default:
+ FFI_ASSERT(0);
+ }
+
+ i++;
+ }
+
+
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_LINUX64 how to perform return type promotions. */
+ return cif->rtype->type;
+}
diff --git a/libffi/src/powerpc/ffi_darwin.c b/libffi/src/powerpc/ffi_darwin.c
new file mode 100644
index 0000000..116f9cb
--- /dev/null
+++ b/libffi/src/powerpc/ffi_darwin.c
@@ -0,0 +1,704 @@
+#ifdef __ppc__
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1998 Geoffrey Keating
+
+ PowerPC Foreign Function Interface
+
+ Darwin ABI support (c) 2001 John Hornkvist
+ AIX ABI support (c) 2002 Free Software Foundation, Inc.
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+extern void ffi_closure_ASM(void);
+
+enum {
+ /* The assembly depends on these exact flags. */
+ FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */
+ FLAG_RETURNS_FP = 1 << (31-29),
+ FLAG_RETURNS_64BITS = 1 << (31-28),
+
+ FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
+ FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
+ FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
+ FLAG_RETVAL_REFERENCE = 1 << (31- 4)
+};
+
+/* About the DARWIN ABI. */
+enum {
+ NUM_GPR_ARG_REGISTERS = 8,
+ NUM_FPR_ARG_REGISTERS = 13
+};
+enum { ASM_NEEDS_REGISTERS = 4 };
+
+/* 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:
+
+ | Return address from ffi_call_DARWIN | higher addresses
+ |--------------------------------------------|
+ | Previous backchain pointer 4 | stack pointer here
+ |--------------------------------------------|<+ <<< on entry to
+ | Saved r28-r31 4*4 | | ffi_call_DARWIN
+ |--------------------------------------------| |
+ | Parameters (at least 8*4=32) | |
+ |--------------------------------------------| |
+ | Space for GPR2 4 | |
+ |--------------------------------------------| | stack |
+ | Reserved 2*4 | | grows |
+ |--------------------------------------------| | down V
+ | Space for callee's LR 4 | |
+ |--------------------------------------------| | lower addresses
+ | Saved CR 4 | |
+ |--------------------------------------------| | stack pointer here
+ | Current backchain pointer 4 |-/ during
+ |--------------------------------------------| <<< ffi_call_DARWIN
+
+ */
+
+/*@-exportheader@*/
+void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
+/*@=exportheader@*/
+{
+ const unsigned bytes = ecif->cif->bytes;
+ const unsigned flags = ecif->cif->flags;
+
+ /* 'stacktop' points at the previous backchain pointer. */
+ unsigned *const stacktop = stack + (ecif->cif->bytes / sizeof(unsigned));
+
+ /* 'fpr_base' points at the space for fpr1, and grows upwards as
+ we use FPR registers. */
+ double *fpr_base = (double*) (stacktop - ASM_NEEDS_REGISTERS) - NUM_FPR_ARG_REGISTERS;
+ int fparg_count = 0;
+
+
+ /* 'next_arg' grows up as we put parameters in it. */
+ unsigned *next_arg = stack + 6; /* 6 reserved posistions. */
+
+ int i = ecif->cif->nargs;
+ double double_tmp;
+ void **p_argv = ecif->avalue;
+ unsigned gprvalue;
+ ffi_type** ptr = ecif->cif->arg_types;
+ char *dest_cpy;
+ unsigned size_al = 0;
+
+ /* Check that everything starts aligned properly. */
+ FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0);
+ FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0);
+ FFI_ASSERT((bytes & 0xF) == 0);
+
+ /* Deal with return values that are actually pass-by-reference.
+ Rule:
+ Return values are referenced by r3, so r4 is the first parameter. */
+
+ if (flags & FLAG_RETVAL_REFERENCE)
+ *next_arg++ = (unsigned)(char *)ecif->rvalue;
+
+ /* Now for the arguments. */
+ for (;
+ i > 0;
+ i--, ptr++, p_argv++)
+ {
+ switch ((*ptr)->type)
+ {
+ /* If a floating-point parameter appears before all of the general-
+ purpose registers are filled, the corresponding GPRs that match
+ the size of the floating-point parameter are skipped. */
+ case FFI_TYPE_FLOAT:
+ double_tmp = *(float *)*p_argv;
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ *(double *)next_arg = double_tmp;
+ else
+ *fpr_base++ = double_tmp;
+ next_arg++;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+ case FFI_TYPE_DOUBLE:
+ double_tmp = *(double *)*p_argv;
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ *(double *)next_arg = double_tmp;
+ else
+ *fpr_base++ = double_tmp;
+ next_arg += 2;
+ fparg_count++;
+ FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ *(long long *)next_arg = *(long long *)*p_argv;
+ next_arg+=2;
+ break;
+ case FFI_TYPE_UINT8:
+ gprvalue = *(unsigned char *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_SINT8:
+ gprvalue = *(signed char *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_UINT16:
+ gprvalue = *(unsigned short *)*p_argv;
+ goto putgpr;
+ case FFI_TYPE_SINT16:
+ gprvalue = *(signed short *)*p_argv;
+ goto putgpr;
+
+ case FFI_TYPE_STRUCT:
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ dest_cpy = (char *) next_arg;
+
+ /* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
+ SI 4 bytes) are aligned as if they were those modes.
+ Structures with 3 byte in size are padded upwards. */
+ size_al = (*ptr)->size;
+ /* If the first member of the struct is a double, then align
+ the struct to double-word.
+ Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */
+ if ((*ptr)->elements[0]->type == 3)
+ size_al = ALIGN((*ptr)->size, 8);
+ if (size_al < 3 && ecif->cif->abi == FFI_DARWIN)
+ dest_cpy += 4 - size_al;
+
+ memcpy((char *)dest_cpy, (char *)*p_argv, size_al);
+ next_arg += (size_al + 3) / 4;
+ break;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_POINTER:
+ gprvalue = *(unsigned *)*p_argv;
+ putgpr:
+ *next_arg++ = gprvalue;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Check that we didn't overrun the stack... */
+ //FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
+ //FFI_ASSERT((unsigned *)fpr_base
+ // <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
+ //FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
+}
+
+/* Perform machine dependent cif processing. */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ /* All this is for the DARWIN ABI. */
+ int i;
+ ffi_type **ptr;
+ unsigned bytes;
+ int fparg_count = 0, intarg_count = 0;
+ unsigned flags = 0;
+ unsigned size_al = 0;
+
+ /* All the machine-independent calculation of cif->bytes will be wrong.
+ Redo the calculation for DARWIN. */
+
+ /* Space for the frame pointer, callee's LR, CR, etc, and for
+ the asm's temp regs. */
+
+ bytes = (6 + ASM_NEEDS_REGISTERS) * sizeof(long);
+
+ /* Return value handling. The rules are as follows:
+ - 32-bit (or less) integer values are returned in gpr3;
+ - Structures of size <= 4 bytes also returned in gpr3;
+ - 64-bit integer values and structures between 5 and 8 bytes are returned
+ in gpr3 and gpr4;
+ - Single/double FP values are returned in fpr1;
+ - Long double FP (if not equivalent to double) values are returned in
+ fpr1 and fpr2;
+ - Larger structures values are allocated space and a pointer is passed
+ as the first argument. */
+ switch (cif->rtype->type)
+ {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ /* Fall through. */
+ case FFI_TYPE_DOUBLE:
+ flags |= FLAG_RETURNS_64BITS;
+ /* Fall through. */
+ case FFI_TYPE_FLOAT:
+ flags |= FLAG_RETURNS_FP;
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ flags |= FLAG_RETURNS_64BITS;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ flags |= FLAG_RETVAL_REFERENCE;
+ flags |= FLAG_RETURNS_NOTHING;
+ intarg_count++;
+ break;
+ case FFI_TYPE_VOID:
+ flags |= FLAG_RETURNS_NOTHING;
+ break;
+
+ default:
+ /* Returns 32-bit integer, or similar. Nothing to do here. */
+ break;
+ }
+
+ /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
+ first NUM_FPR_ARG_REGISTERS fp 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:
+ fparg_count++;
+ /* If this FP arg is going on the stack, it must be
+ 8-byte-aligned. */
+ if (fparg_count > NUM_FPR_ARG_REGISTERS
+ && intarg_count%2 != 0)
+ intarg_count++;
+ 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 (intarg_count == NUM_GPR_ARG_REGISTERS-1
+ || (intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0))
+ intarg_count++;
+ intarg_count += 2;
+ break;
+
+ case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ size_al = (*ptr)->size;
+ /* If the first member of the struct is a double, then align
+ the struct to double-word.
+ Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */
+ if ((*ptr)->elements[0]->type == 3)
+ size_al = ALIGN((*ptr)->size, 8);
+ intarg_count += (size_al + 3) / 4;
+ break;
+
+ default:
+ /* Everything else is passed as a 4-byte word in a GPR, either
+ the object itself or a pointer to it. */
+ intarg_count++;
+ break;
+ }
+ }
+
+ if (fparg_count != 0)
+ flags |= FLAG_FP_ARGUMENTS;
+
+ /* Space for the FPR registers, if needed. */
+ if (fparg_count != 0)
+ bytes += NUM_FPR_ARG_REGISTERS * sizeof(double);
+
+ /* Stack space. */
+ if ((intarg_count + 2 * fparg_count) > NUM_GPR_ARG_REGISTERS)
+ bytes += (intarg_count + 2 * fparg_count) * sizeof(long);
+ else
+ bytes += NUM_GPR_ARG_REGISTERS * sizeof(long);
+
+ /* The stack space allocated needs to be a multiple of 16 bytes. */
+ bytes = (bytes + 15) & ~0xF;
+
+ cif->flags = flags;
+ cif->bytes = bytes;
+
+ return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_AIX(/*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)(),
+ void (*fn2)());
+extern void ffi_call_DARWIN(/*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)(),
+ void (*fn2)());
+/*@=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_AIX:
+ /*@-usedef@*/
+ ffi_call_AIX(&ecif, -cif->bytes,
+ cif->flags, ecif.rvalue, fn, ffi_prep_args);
+ /*@=usedef@*/
+ break;
+ case FFI_DARWIN:
+ /*@-usedef@*/
+ ffi_call_DARWIN(&ecif, -cif->bytes,
+ cif->flags, ecif.rvalue, fn, ffi_prep_args);
+ /*@=usedef@*/
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+static void flush_icache(char *);
+static void flush_range(char *, int);
+
+/* The layout of a function descriptor. A C function pointer really
+ points to one of these. */
+
+typedef struct aix_fd_struct {
+ void *code_pointer;
+ void *toc;
+} aix_fd;
+
+/* here I'd like to add the stack frame layout we use in darwin_closure.S
+ and aix_clsoure.S
+
+ SP previous -> +---------------------------------------+ <--- child frame
+ | back chain to caller 4 |
+ +---------------------------------------+ 4
+ | saved CR 4 |
+ +---------------------------------------+ 8
+ | saved LR 4 |
+ +---------------------------------------+ 12
+ | reserved for compilers 4 |
+ +---------------------------------------+ 16
+ | reserved for binders 4 |
+ +---------------------------------------+ 20
+ | saved TOC pointer 4 |
+ +---------------------------------------+ 24
+ | always reserved 8*4=32 (previous GPRs)|
+ | according to the linkage convention |
+ | from AIX |
+ +---------------------------------------+ 56
+ | our FPR area 13*8=104 |
+ | f1 |
+ | . |
+ | f13 |
+ +---------------------------------------+ 160
+ | result area 8 |
+ +---------------------------------------+ 168
+ | alignement to the next multiple of 16 |
+SP current --> +---------------------------------------+ 176 <- parent frame
+ | back chain to caller 4 |
+ +---------------------------------------+ 180
+ | saved CR 4 |
+ +---------------------------------------+ 184
+ | saved LR 4 |
+ +---------------------------------------+ 188
+ | reserved for compilers 4 |
+ +---------------------------------------+ 192
+ | reserved for binders 4 |
+ +---------------------------------------+ 196
+ | saved TOC pointer 4 |
+ +---------------------------------------+ 200
+ | always reserved 8*4=32 we store our |
+ | GPRs here |
+ | r3 |
+ | . |
+ | r10 |
+ +---------------------------------------+ 232
+ | overflow part |
+ +---------------------------------------+ xxx
+ | ???? |
+ +---------------------------------------+ xxx
+
+*/
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data)
+{
+ unsigned int *tramp;
+ struct ffi_aix_trampoline_struct *tramp_aix;
+ aix_fd *fd;
+
+ switch (cif->abi)
+ {
+ case FFI_DARWIN:
+
+ FFI_ASSERT (cif->abi == FFI_DARWIN);
+
+ tramp = (unsigned int *) &closure->tramp[0];
+ tramp[0] = 0x7c0802a6; /* mflr r0 */
+ tramp[1] = 0x429f000d; /* bcl- 20,4*cr7+so,0x10 */
+ tramp[4] = 0x7d6802a6; /* mflr r11 */
+ tramp[5] = 0x818b0000; /* lwz r12,0(r11) function address */
+ tramp[6] = 0x7c0803a6; /* mtlr r0 */
+ tramp[7] = 0x7d8903a6; /* mtctr r12 */
+ tramp[8] = 0x816b0004; /* lwz r11,4(r11) static chain */
+ tramp[9] = 0x4e800420; /* bctr */
+ tramp[2] = (unsigned long) ffi_closure_ASM; /* function */
+ tramp[3] = (unsigned long) closure; /* context */
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ /* Flush the icache. Only necessary on Darwin. */
+ flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
+
+ break;
+
+ case FFI_AIX:
+
+ tramp_aix = (struct ffi_aix_trampoline_struct *) (closure->tramp);
+ fd = (aix_fd *)(void *)ffi_closure_ASM;
+
+ FFI_ASSERT (cif->abi == FFI_AIX);
+
+ tramp_aix->code_pointer = fd->code_pointer;
+ tramp_aix->toc = fd->toc;
+ tramp_aix->static_chain = closure;
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ default:
+
+ FFI_ASSERT(0);
+ break;
+ }
+ return FFI_OK;
+}
+
+static void
+flush_icache(char *addr)
+{
+#ifndef _AIX
+ __asm__ volatile (
+ "dcbf 0,%0;"
+ "sync;"
+ "icbi 0,%0;"
+ "sync;"
+ "isync;"
+ : : "r"(addr) : "memory");
+#endif
+}
+
+static void
+flush_range(char * addr1, int size)
+{
+#define MIN_LINE_SIZE 32
+ int i;
+ for (i = 0; i < size; i += MIN_LINE_SIZE)
+ flush_icache(addr1+i);
+ flush_icache(addr1+size-1);
+}
+
+typedef union
+{
+ float f;
+ double d;
+} ffi_dblfl;
+
+int ffi_closure_helper_DARWIN (ffi_closure*, void*,
+ unsigned long*, ffi_dblfl*);
+
+/* Basically the trampoline invokes ffi_closure_ASM, and on
+ entry, r11 holds the address of the closure.
+ After storing the registers that could possibly contain
+ parameters to be passed into the stack frame and setting
+ up space for a return value, ffi_closure_ASM invokes the
+ following helper function to do most of the work. */
+
+int ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue,
+ unsigned long * pgr, ffi_dblfl * pfr)
+{
+ /* rvalue is the pointer to space for return value in closure assembly
+ pgr is the pointer to where r3-r10 are stored in ffi_closure_ASM
+ pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM. */
+
+
+ void ** avalue;
+ ffi_type ** arg_types;
+ long i, avn;
+ long nf; /* number of floating registers already used. */
+ long ng; /* number of general registers already used. */
+ ffi_cif * cif;
+ double temp;
+ unsigned size_al;
+
+ cif = closure->cif;
+ avalue = alloca(cif->nargs * sizeof(void *));
+
+ nf = 0;
+ ng = 0;
+
+ /* Copy the caller's structure return value address so that the closure
+ returns the data directly to the caller. */
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ rvalue = (void *) *pgr;
+ pgr++;
+ ng++;
+ }
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ while (i < avn)
+ {
+ switch (arg_types[i]->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ avalue[i] = (char *) pgr + 3;
+ ng++;
+ pgr++;
+ break;
+
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ avalue[i] = (char *) pgr + 2;
+ ng++;
+ pgr++;
+ break;
+
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_POINTER:
+ avalue[i] = pgr;
+ ng++;
+ pgr++;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ /* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
+ SI 4 bytes) are aligned as if they were those modes. */
+ size_al = arg_types[i]->size;
+ /* If the first member of the struct is a double, then align
+ the struct to double-word.
+ Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */
+ if (arg_types[i]->elements[0]->type == 3)
+ size_al = ALIGN(arg_types[i]->size, 8);
+ if (size_al < 3 && cif->abi == FFI_DARWIN)
+ avalue[i] = (void*) pgr + 4 - size_al;
+ else
+ avalue[i] = (void*) pgr;
+ ng += (size_al + 3) / 4;
+ pgr += (size_al + 3) / 4;
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ /* Long long ints are passed in two gpr's. */
+ avalue[i] = pgr;
+ ng += 2;
+ pgr += 2;
+ break;
+
+ case FFI_TYPE_FLOAT:
+ /* A float value consumes a GPR.
+ There are 13 64bit floating point registers. */
+ if (nf < NUM_FPR_ARG_REGISTERS)
+ {
+ temp = pfr->d;
+ pfr->f = (float)temp;
+ avalue[i] = pfr;
+ pfr++;
+ }
+ else
+ {
+ avalue[i] = pgr;
+ }
+ nf++;
+ ng++;
+ pgr++;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ /* A double value consumes two GPRs.
+ There are 13 64bit floating point registers. */
+ if (nf < NUM_FPR_ARG_REGISTERS)
+ {
+ avalue[i] = pfr;
+ pfr++;
+ }
+ else
+ {
+ avalue[i] = pgr;
+ }
+ nf++;
+ ng += 2;
+ pgr += 2;
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ i++;
+ }
+
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_ASM to perform return type promotions. */
+ return cif->rtype->type;
+}
+#endif
diff --git a/libffi/src/powerpc/ffitarget.h b/libffi/src/powerpc/ffitarget.h
new file mode 100644
index 0000000..101ea78
--- /dev/null
+++ b/libffi/src/powerpc/ffitarget.h
@@ -0,0 +1,91 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for PowerPC.
+
+ 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 ----------------------------------- */
+
+#if defined (POWERPC) && defined (__powerpc64__)
+#define POWERPC64
+#endif
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+
+#ifdef POWERPC
+ FFI_SYSV,
+ FFI_GCC_SYSV,
+ FFI_LINUX64,
+# ifdef POWERPC64
+ FFI_DEFAULT_ABI = FFI_LINUX64,
+# else
+ FFI_DEFAULT_ABI = FFI_GCC_SYSV,
+# endif
+#endif
+
+#ifdef POWERPC_AIX
+ FFI_AIX,
+ FFI_DARWIN,
+ FFI_DEFAULT_ABI = FFI_AIX,
+#endif
+
+#ifdef POWERPC_DARWIN
+ FFI_AIX,
+ FFI_DARWIN,
+ FFI_DEFAULT_ABI = FFI_DARWIN,
+#endif
+
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_NATIVE_RAW_API 0
+
+#if defined(POWERPC64) || defined(POWERPC_AIX)
+#define FFI_TRAMPOLINE_SIZE 24
+#else /* POWERPC || POWERPC_AIX */
+#define FFI_TRAMPOLINE_SIZE 40
+#endif
+
+#ifndef LIBFFI_ASM
+#if defined(POWERPC_DARWIN) || defined(POWERPC_AIX)
+struct ffi_aix_trampoline_struct {
+ void * code_pointer; /* Pointer to ffi_closure_ASM */
+ void * toc; /* TOC */
+ void * static_chain; /* Pointer to closure */
+};
+#endif
+#endif
+
+#endif
+
diff --git a/libffi/src/powerpc/linux64.S b/libffi/src/powerpc/linux64.S
new file mode 100644
index 0000000..11cf926
--- /dev/null
+++ b/libffi/src/powerpc/linux64.S
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------
+ sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com>
+
+ PowerPC64 Assembly glue.
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+#ifdef __powerpc64__
+ .hidden ffi_call_LINUX64, .ffi_call_LINUX64
+ .globl ffi_call_LINUX64, .ffi_call_LINUX64
+ .section ".opd","aw"
+ .align 3
+ffi_call_LINUX64:
+ .quad .ffi_call_LINUX64,.TOC.@tocbase,0
+ .size ffi_call_LINUX64,24
+ .type .ffi_call_LINUX64,@function
+ .text
+.ffi_call_LINUX64:
+.LFB1:
+ mflr %r0
+ std %r28, -32(%r1)
+ std %r29, -24(%r1)
+ std %r30, -16(%r1)
+ std %r31, -8(%r1)
+ std %r0, 16(%r1)
+
+ mr %r28, %r1 /* our AP. */
+ stdux %r1, %r1, %r4
+.LCFI0:
+ mr %r31, %r5 /* flags, */
+ mr %r30, %r6 /* rvalue, */
+ mr %r29, %r7 /* function address. */
+ std %r2, 40(%r1)
+
+ /* Call ffi_prep_args64. */
+ mr %r4, %r1
+ bl .ffi_prep_args64
+
+ ld %r0, 0(%r29)
+ ld %r2, 8(%r29)
+ ld %r11, 16(%r29)
+
+ /* Now do the call. */
+ /* Set up cr1 with bits 4-7 of the flags. */
+ mtcrf 0x40, %r31
+
+ /* Get the address to call into CTR. */
+ mtctr %r0
+ /* Load all those argument registers. */
+ ld %r3, -32-(8*8)(%r28)
+ ld %r4, -32-(7*8)(%r28)
+ ld %r5, -32-(6*8)(%r28)
+ ld %r6, -32-(5*8)(%r28)
+ bf- 5, 1f
+ ld %r7, -32-(4*8)(%r28)
+ ld %r8, -32-(3*8)(%r28)
+ ld %r9, -32-(2*8)(%r28)
+ ld %r10, -32-(1*8)(%r28)
+1:
+
+ /* Load all the FP registers. */
+ bf- 6, 2f
+ lfd %f1, -32-(21*8)(%r28)
+ lfd %f2, -32-(20*8)(%r28)
+ lfd %f3, -32-(19*8)(%r28)
+ lfd %f4, -32-(18*8)(%r28)
+ lfd %f5, -32-(17*8)(%r28)
+ lfd %f6, -32-(16*8)(%r28)
+ lfd %f7, -32-(15*8)(%r28)
+ lfd %f8, -32-(14*8)(%r28)
+ lfd %f9, -32-(13*8)(%r28)
+ lfd %f10, -32-(12*8)(%r28)
+ lfd %f11, -32-(11*8)(%r28)
+ lfd %f12, -32-(10*8)(%r28)
+ lfd %f13, -32-(9*8)(%r28)
+2:
+
+ /* Make the call. */
+ bctrl
+
+ /* Now, deal with the return value. */
+ mtcrf 0x01, %r31
+ bt- 30, .Ldone_return_value
+ bt- 29, .Lfp_return_value
+ std %r3, 0(%r30)
+ /* Fall through... */
+
+.Ldone_return_value:
+ /* Restore the registers we used and return. */
+ ld %r2, 40(%r1)
+ mr %r1, %r28
+ ld %r0, 16(%r28)
+ ld %r28, -32(%r1)
+ mtlr %r0
+ ld %r29, -24(%r1)
+ ld %r30, -16(%r1)
+ ld %r31, -8(%r1)
+ blr
+
+.Lfp_return_value:
+ bf 28, .Lfloat_return_value
+ stfd %f1, 0(%r30)
+ stfd %f2, 8(%r30) /* It might be a long double */
+ b .Ldone_return_value
+.Lfloat_return_value:
+ stfs %f1, 0(%r30)
+ b .Ldone_return_value
+.LFE1:
+ .long 0
+ .byte 0,12,0,1,128,4,0,0
+ .size .ffi_call_LINUX64,.-.ffi_call_LINUX64
+
+ .section .eh_frame,EH_FRAME_FLAGS,@progbits
+.Lframe1:
+ .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
+.LSCIE1:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "zR\0" # CIE Augmentation
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 -8 # CIE Data Alignment Factor
+ .byte 0x41 # CIE RA Column
+ .uleb128 0x1 # Augmentation size
+ .byte 0x14 # FDE Encoding (pcrel udata8)
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1
+ .uleb128 0x0
+ .align 3
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 # FDE Length
+.LASFDE1:
+ .4byte .LASFDE1-.Lframe1 # FDE CIE offset
+ .8byte .LFB1-. # FDE initial location
+ .8byte .LFE1-.LFB1 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x2 # DW_CFA_advance_loc1
+ .byte .LCFI0-.LFB1
+ .byte 0xd # DW_CFA_def_cfa_register
+ .uleb128 0x1c
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x41
+ .sleb128 -2
+ .byte 0x9f # DW_CFA_offset, column 0x1f
+ .uleb128 0x1
+ .byte 0x9e # DW_CFA_offset, column 0x1e
+ .uleb128 0x2
+ .byte 0x9d # DW_CFA_offset, column 0x1d
+ .uleb128 0x3
+ .byte 0x9c # DW_CFA_offset, column 0x1c
+ .uleb128 0x4
+ .align 3
+.LEFDE1:
+#endif
diff --git a/libffi/src/powerpc/linux64_closure.S b/libffi/src/powerpc/linux64_closure.S
new file mode 100644
index 0000000..fa331db
--- /dev/null
+++ b/libffi/src/powerpc/linux64_closure.S
@@ -0,0 +1,205 @@
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+ .file "linux64_closure.S"
+
+#ifdef __powerpc64__
+ .hidden ffi_closure_LINUX64, .ffi_closure_LINUX64
+ .globl ffi_closure_LINUX64, .ffi_closure_LINUX64
+ .section ".opd","aw"
+ .align 3
+ffi_closure_LINUX64:
+ .quad .ffi_closure_LINUX64,.TOC.@tocbase,0
+ .size ffi_closure_LINUX64,24
+ .type .ffi_closure_LINUX64,@function
+ .text
+.ffi_closure_LINUX64:
+.LFB1:
+ # save general regs into parm save area
+ std %r3, 48(%r1)
+ std %r4, 56(%r1)
+ std %r5, 64(%r1)
+ std %r6, 72(%r1)
+ mflr %r0
+
+ std %r7, 80(%r1)
+ std %r8, 88(%r1)
+ std %r9, 96(%r1)
+ std %r10, 104(%r1)
+ std %r0, 16(%r1)
+
+ # mandatory 48 bytes special reg save area + 64 bytes parm save area
+ # + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
+ stdu %r1, -240(%r1)
+.LCFI0:
+
+ # next save fpr 1 to fpr 13
+ stfd %f1, 128+(0*8)(%r1)
+ stfd %f2, 128+(1*8)(%r1)
+ stfd %f3, 128+(2*8)(%r1)
+ stfd %f4, 128+(3*8)(%r1)
+ stfd %f5, 128+(4*8)(%r1)
+ stfd %f6, 128+(5*8)(%r1)
+ stfd %f7, 128+(6*8)(%r1)
+ stfd %f8, 128+(7*8)(%r1)
+ stfd %f9, 128+(8*8)(%r1)
+ stfd %f10, 128+(9*8)(%r1)
+ stfd %f11, 128+(10*8)(%r1)
+ stfd %f12, 128+(11*8)(%r1)
+ stfd %f13, 128+(12*8)(%r1)
+
+ # set up registers for the routine that actually does the work
+ # get the context pointer from the trampoline
+ mr %r3, %r11
+
+ # now load up the pointer to the result storage
+ addi %r4, %r1, 112
+
+ # now load up the pointer to the parameter save area
+ # in the previous frame
+ addi %r5, %r1, 240 + 48
+
+ # now load up the pointer to the saved fpr registers */
+ addi %r6, %r1, 128
+
+ # make the call
+ bl .ffi_closure_helper_LINUX64
+.Lret:
+
+ # now r3 contains the return type
+ # so use it to look up in a table
+ # so we know how to deal with each type
+
+ # look up the proper starting point in table
+ # by using return type as offset
+ mflr %r4 # move address of .Lret to r4
+ sldi %r3, %r3, 4 # now multiply return type by 16
+ addi %r4, %r4, .Lret_type0 - .Lret
+ ld %r0, 240+16(%r1)
+ add %r3, %r3, %r4 # add contents of table to table address
+ mtctr %r3
+ bctr # jump to it
+
+# Each of the ret_typeX code fragments has to be exactly 16 bytes long
+# (4 instructions). For cache effectiveness we align to a 16 byte boundary
+# first.
+ .align 4
+
+.Lret_type0:
+# case FFI_TYPE_VOID
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+ nop
+# case FFI_TYPE_INT
+ lwa %r3, 112+4(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_FLOAT
+ lfs %f1, 112+0(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_DOUBLE
+ lfd %f1, 112+0(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_LONGDOUBLE
+ lfd %f1, 112+0(%r1)
+ mtlr %r0
+ lfd %f2, 112+8(%r1)
+ b .Lfinish
+# case FFI_TYPE_UINT8
+ lbz %r3, 112+7(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_SINT8
+ lbz %r3, 112+7(%r1)
+ extsb %r3,%r3
+ mtlr %r0
+ b .Lfinish
+# case FFI_TYPE_UINT16
+ lhz %r3, 112+6(%r1)
+ mtlr %r0
+.Lfinish:
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_SINT16
+ lha %r3, 112+6(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_UINT32
+ lwz %r3, 112+4(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_SINT32
+ lwa %r3, 112+4(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_UINT64
+ ld %r3, 112+0(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_SINT64
+ ld %r3, 112+0(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# case FFI_TYPE_STRUCT
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+ nop
+# case FFI_TYPE_POINTER
+ ld %r3, 112+0(%r1)
+ mtlr %r0
+ addi %r1, %r1, 240
+ blr
+# esac
+.LFE1:
+ .long 0
+ .byte 0,12,0,1,128,0,0,0
+ .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64
+
+ .section .eh_frame,EH_FRAME_FLAGS,@progbits
+.Lframe1:
+ .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
+.LSCIE1:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "zR\0" # CIE Augmentation
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 -8 # CIE Data Alignment Factor
+ .byte 0x41 # CIE RA Column
+ .uleb128 0x1 # Augmentation size
+ .byte 0x14 # FDE Encoding (pcrel udata8)
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1
+ .uleb128 0x0
+ .align 3
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 # FDE Length
+.LASFDE1:
+ .4byte .LASFDE1-.Lframe1 # FDE CIE offset
+ .8byte .LFB1-. # FDE initial location
+ .8byte .LFE1-.LFB1 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x2 # DW_CFA_advance_loc1
+ .byte .LCFI0-.LFB1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 240
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x41
+ .sleb128 -2
+ .align 3
+.LEFDE1:
+#endif
diff --git a/libffi/src/powerpc/ppc_closure.S b/libffi/src/powerpc/ppc_closure.S
new file mode 100644
index 0000000..dce9dab
--- /dev/null
+++ b/libffi/src/powerpc/ppc_closure.S
@@ -0,0 +1,250 @@
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+#include <powerpc/asm.h>
+
+ .file "ppc_closure.S"
+
+#ifndef __powerpc64__
+
+ENTRY(ffi_closure_SYSV)
+.LFB1:
+ stwu %r1,-144(%r1)
+.LCFI0:
+ mflr %r0
+.LCFI1:
+ stw %r0,148(%r1)
+
+# we want to build up an areas for the parameters passed
+# in registers (both floating point and integer)
+
+ # so first save gpr 3 to gpr 10 (aligned to 4)
+ stw %r3, 16(%r1)
+ stw %r4, 20(%r1)
+ stw %r5, 24(%r1)
+ stw %r6, 28(%r1)
+ stw %r7, 32(%r1)
+ stw %r8, 36(%r1)
+ stw %r9, 40(%r1)
+ stw %r10,44(%r1)
+
+ # next save fpr 1 to fpr 8 (aligned to 8)
+ stfd %f1, 48(%r1)
+ stfd %f2, 56(%r1)
+ stfd %f3, 64(%r1)
+ stfd %f4, 72(%r1)
+ stfd %f5, 80(%r1)
+ stfd %f6, 88(%r1)
+ stfd %f7, 96(%r1)
+ stfd %f8, 104(%r1)
+
+ # set up registers for the routine that actually does the work
+ # get the context pointer from the trampoline
+ mr %r3,%r11
+
+ # now load up the pointer to the result storage
+ addi %r4,%r1,112
+
+ # now load up the pointer to the saved gpr registers
+ addi %r5,%r1,16
+
+ # now load up the pointer to the saved fpr registers */
+ addi %r6,%r1,48
+
+ # now load up the pointer to the outgoing parameter
+ # stack in the previous frame
+ # i.e. the previous frame pointer + 8
+ addi %r7,%r1,152
+
+ # make the call
+ bl JUMPTARGET(ffi_closure_helper_SYSV)
+
+ # now r3 contains the return type
+ # so use it to look up in a table
+ # so we know how to deal with each type
+
+ # look up the proper starting point in table
+ # by using return type as offset
+ addi %r5,%r1,112 # get pointer to results area
+ bl .Lget_ret_type0_addr # get pointer to .Lret_type0 into LR
+ mflr %r4 # move to r4
+ slwi %r3,%r3,4 # now multiply return type by 16
+ add %r3,%r3,%r4 # add contents of table to table address
+ mtctr %r3
+ bctr # jump to it
+.LFE1:
+
+# Each of the ret_typeX code fragments has to be exactly 16 bytes long
+# (4 instructions). For cache effectiveness we align to a 16 byte boundary
+# first.
+ .align 4
+
+ nop
+ nop
+ nop
+.Lget_ret_type0_addr:
+ blrl
+
+# case FFI_TYPE_VOID
+.Lret_type0:
+ b .Lfinish
+ nop
+ nop
+ nop
+
+# case FFI_TYPE_INT
+.Lret_type1:
+ lwz %r3,0(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case FFI_TYPE_FLOAT
+.Lret_type2:
+ lfs %f1,0(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case FFI_TYPE_DOUBLE
+.Lret_type3:
+ lfd %f1,0(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case FFI_TYPE_LONGDOUBLE
+.Lret_type4:
+ lfd %f1,0(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case FFI_TYPE_UINT8
+.Lret_type5:
+ lbz %r3,3(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case FFI_TYPE_SINT8
+.Lret_type6:
+ lbz %r3,3(%r5)
+ extsb %r3,%r3
+ b .Lfinish
+ nop
+
+# case FFI_TYPE_UINT16
+.Lret_type7:
+ lhz %r3,2(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case FFI_TYPE_SINT16
+.Lret_type8:
+ lha %r3,2(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case FFI_TYPE_UINT32
+.Lret_type9:
+ lwz %r3,0(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case FFI_TYPE_SINT32
+.Lret_type10:
+ lwz %r3,0(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case FFI_TYPE_UINT64
+.Lret_type11:
+ lwz %r3,0(%r5)
+ lwz %r4,4(%r5)
+ b .Lfinish
+ nop
+
+# case FFI_TYPE_SINT64
+.Lret_type12:
+ lwz %r3,0(%r5)
+ lwz %r4,4(%r5)
+ b .Lfinish
+ nop
+
+# case FFI_TYPE_STRUCT
+.Lret_type13:
+ b .Lfinish
+ nop
+ nop
+ nop
+
+# case FFI_TYPE_POINTER
+.Lret_type14:
+ lwz %r3,0(%r5)
+ b .Lfinish
+ nop
+ nop
+
+# case done
+.Lfinish:
+
+ lwz %r0,148(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+END(ffi_closure_SYSV)
+
+ .section ".eh_frame",EH_FRAME_FLAGS,@progbits
+.Lframe1:
+ .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
+.LSCIE1:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+#if 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 0x41 # CIE RA Column
+#if defined _RELOCATABLE || defined __PIC__
+ .uleb128 0x1 # Augmentation size
+ .byte 0x1b # FDE Encoding (pcrel sdata4)
+#endif
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1
+ .uleb128 0x0
+ .align 2
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 # FDE Length
+.LASFDE1:
+ .4byte .LASFDE1-.Lframe1 # FDE CIE offset
+#if defined _RELOCATABLE || defined __PIC__
+ .4byte .LFB1-. # FDE initial location
+#else
+ .4byte .LFB1 # FDE initial location
+#endif
+ .4byte .LFE1-.LFB1 # FDE address range
+#if defined _RELOCATABLE || defined __PIC__
+ .uleb128 0x0 # Augmentation size
+#endif
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI0-.LFB1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 144
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI1-.LCFI0
+ .byte 0x2f # DW_CFA_GNU_negative_offset_extended
+ .uleb128 0x41
+ .uleb128 0x1
+ .align 2
+.LEFDE1:
+
+#endif
diff --git a/libffi/src/powerpc/sysv.S b/libffi/src/powerpc/sysv.S
new file mode 100644
index 0000000..a7aaa3f
--- /dev/null
+++ b/libffi/src/powerpc/sysv.S
@@ -0,0 +1,191 @@
+/* -----------------------------------------------------------------------
+ sysv.h - Copyright (c) 1998 Geoffrey Keating
+
+ PowerPC Assembly glue.
+
+ $Id: sysv.S,v 1.1.1.1 1998/11/29 16:48:16 green Exp $
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+#include <powerpc/asm.h>
+
+#ifndef __powerpc64__
+ .globl ffi_prep_args_SYSV
+ENTRY(ffi_call_SYSV)
+.LFB1:
+ /* Save the old stack pointer as AP. */
+ mr %r8,%r1
+
+.LCFI0:
+ /* Allocate the stack space we need. */
+ stwux %r1,%r1,%r4
+ /* Save registers we use. */
+ mflr %r9
+ stw %r28,-16(%r8)
+.LCFI1:
+ stw %r29,-12(%r8)
+.LCFI2:
+ stw %r30, -8(%r8)
+.LCFI3:
+ stw %r31, -4(%r8)
+.LCFI4:
+ stw %r9, 4(%r8)
+.LCFI5:
+
+ /* Save arguments over call... */
+ mr %r31,%r5 /* flags, */
+ mr %r30,%r6 /* rvalue, */
+ mr %r29,%r7 /* function address, */
+ mr %r28,%r8 /* our AP. */
+.LCFI6:
+
+ /* Call ffi_prep_args_SYSV. */
+ mr %r4,%r1
+ bl JUMPTARGET(ffi_prep_args_SYSV)
+
+ /* Now do the call. */
+ /* Set up cr1 with bits 4-7 of the flags. */
+ mtcrf 0x40,%r31
+ /* Get the address to call into CTR. */
+ mtctr %r29
+ /* Load all those argument registers. */
+ lwz %r3,-16-(8*4)(%r28)
+ lwz %r4,-16-(7*4)(%r28)
+ lwz %r5,-16-(6*4)(%r28)
+ lwz %r6,-16-(5*4)(%r28)
+ bf- 5,1f
+ nop
+ lwz %r7,-16-(4*4)(%r28)
+ lwz %r8,-16-(3*4)(%r28)
+ lwz %r9,-16-(2*4)(%r28)
+ lwz %r10,-16-(1*4)(%r28)
+ nop
+1:
+
+ /* Load all the FP registers. */
+ bf- 6,2f
+ lfd %f1,-16-(8*4)-(8*8)(%r28)
+ lfd %f2,-16-(8*4)-(7*8)(%r28)
+ lfd %f3,-16-(8*4)-(6*8)(%r28)
+ lfd %f4,-16-(8*4)-(5*8)(%r28)
+ nop
+ lfd %f5,-16-(8*4)-(4*8)(%r28)
+ lfd %f6,-16-(8*4)-(3*8)(%r28)
+ lfd %f7,-16-(8*4)-(2*8)(%r28)
+ lfd %f8,-16-(8*4)-(1*8)(%r28)
+2:
+
+ /* Make the call. */
+ bctrl
+
+ /* Now, deal with the return value. */
+ mtcrf 0x01,%r31
+ bt- 30,L(done_return_value)
+ bt- 29,L(fp_return_value)
+ stw %r3,0(%r30)
+ bf+ 28,L(done_return_value)
+ stw %r4,4(%r30)
+ /* Fall through... */
+
+L(done_return_value):
+ /* Restore the registers we used and return. */
+ lwz %r9, 4(%r28)
+ lwz %r31, -4(%r28)
+ mtlr %r9
+ lwz %r30, -8(%r28)
+ lwz %r29,-12(%r28)
+ lwz %r28,-16(%r28)
+ lwz %r1,0(%r1)
+ blr
+
+L(fp_return_value):
+ bf 28,L(float_return_value)
+ stfd %f1,0(%r30)
+ b L(done_return_value)
+L(float_return_value):
+ stfs %f1,0(%r30)
+ b L(done_return_value)
+.LFE1:
+END(ffi_call_SYSV)
+
+ .section ".eh_frame",EH_FRAME_FLAGS,@progbits
+.Lframe1:
+ .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
+.LSCIE1:
+ .4byte 0x0 /* CIE Identifier Tag */
+ .byte 0x1 /* CIE Version */
+#if 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 0x41 /* CIE RA Column */
+#if defined _RELOCATABLE || defined __PIC__
+ .uleb128 0x1 /* Augmentation size */
+ .byte 0x1b /* FDE Encoding (pcrel sdata4) */
+#endif
+ .byte 0xc /* DW_CFA_def_cfa */
+ .uleb128 0x1
+ .uleb128 0x0
+ .align 2
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 /* FDE Length */
+.LASFDE1:
+ .4byte .LASFDE1-.Lframe1 /* FDE CIE offset */
+#if defined _RELOCATABLE || defined __PIC__
+ .4byte .LFB1-. /* FDE initial location */
+#else
+ .4byte .LFB1 /* FDE initial location */
+#endif
+ .4byte .LFE1-.LFB1 /* FDE address range */
+#if defined _RELOCATABLE || defined __PIC__
+ .uleb128 0x0 /* Augmentation size */
+#endif
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI0-.LFB1
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .uleb128 0x08
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI5-.LCFI0
+ .byte 0x2f /* DW_CFA_GNU_negative_offset_extended */
+ .uleb128 0x41
+ .uleb128 0x1
+ .byte 0x9f /* DW_CFA_offset, column 0x1f */
+ .uleb128 0x1
+ .byte 0x9e /* DW_CFA_offset, column 0x1e */
+ .uleb128 0x2
+ .byte 0x9d /* DW_CFA_offset, column 0x1d */
+ .uleb128 0x3
+ .byte 0x9c /* DW_CFA_offset, column 0x1c */
+ .uleb128 0x4
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI6-.LCFI5
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .uleb128 0x1c
+ .align 2
+.LEFDE1:
+#endif
diff --git a/libffi/src/prep_cif.c b/libffi/src/prep_cif.c
new file mode 100644
index 0000000..43326ad
--- /dev/null
+++ b/libffi/src/prep_cif.c
@@ -0,0 +1,172 @@
+/* -----------------------------------------------------------------------
+ prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc.
+
+ 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>
+
+
+/* Round up to FFI_SIZEOF_ARG. */
+
+#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
+
+/* Perform machine independent initialization of aggregate type
+ specifications. */
+
+static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg)
+{
+ ffi_type **ptr;
+
+ FFI_ASSERT(arg != NULL);
+
+ /*@-usedef@*/
+
+ FFI_ASSERT(arg->elements != NULL);
+ FFI_ASSERT(arg->size == 0);
+ FFI_ASSERT(arg->alignment == 0);
+
+ ptr = &(arg->elements[0]);
+
+ while ((*ptr) != NULL)
+ {
+ if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
+ return FFI_BAD_TYPEDEF;
+
+ /* Perform a sanity check on the argument type */
+ FFI_ASSERT_VALID_TYPE(*ptr);
+
+ arg->size = ALIGN(arg->size, (*ptr)->alignment);
+ arg->size += (*ptr)->size;
+
+ arg->alignment = (arg->alignment > (*ptr)->alignment) ?
+ arg->alignment : (*ptr)->alignment;
+
+ ptr++;
+ }
+
+ /* Structure size includes tail padding. This is important for
+ structures that fit in one register on ABIs like the PowerPC64
+ Linux ABI that right justify small structs in a register.
+ It's also needed for nested structure layout, for example
+ struct A { long a; char b; }; struct B { struct A x; char y; };
+ should find y at an offset of 2*sizeof(long) and result in a
+ total size of 3*sizeof(long). */
+ arg->size = ALIGN (arg->size, arg->alignment);
+
+ if (arg->size == 0)
+ return FFI_BAD_TYPEDEF;
+ else
+ return FFI_OK;
+
+ /*@=usedef@*/
+}
+
+/* Perform machine independent ffi_cif preparation, then call
+ machine dependent routine. */
+
+ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
+ ffi_abi abi, unsigned int nargs,
+ /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype,
+ /*@dependent@*/ ffi_type **atypes)
+{
+ unsigned bytes = 0;
+ unsigned int i;
+ ffi_type **ptr;
+
+ FFI_ASSERT(cif != NULL);
+ FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
+
+ cif->abi = abi;
+ cif->arg_types = atypes;
+ cif->nargs = nargs;
+ cif->rtype = rtype;
+
+ cif->flags = 0;
+
+ /* Initialize the return type if necessary */
+ /*@-usedef@*/
+ if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
+ return FFI_BAD_TYPEDEF;
+ /*@=usedef@*/
+
+ /* Perform a sanity check on the return type */
+ 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 && !defined PA
+ /* Make space for the return structure pointer */
+ if (cif->rtype->type == FFI_TYPE_STRUCT
+#ifdef SPARC
+ && (cif->abi != FFI_V9 || cif->rtype->size > 32)
+#endif
+#ifdef __i386__ /* FIXME: only on darwin */
+ && (cif->rtype->size > 8)
+#endif
+ )
+ bytes = STACK_ARG_SIZE(sizeof(void*));
+#endif
+
+ for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+ {
+
+ /* Initialize any uninitialized aggregate type definitions */
+ if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
+ return FFI_BAD_TYPEDEF;
+
+ /* Perform a sanity check on the argument type, do this
+ check after the initialization. */
+ FFI_ASSERT_VALID_TYPE(*ptr);
+
+#ifdef X86_DARWIN
+ {
+ /* Add padding, but at most to 4 bytes */
+ int align = (*ptr)->alignment;
+ if (align>4) align = 4;
+ if ((align - 1) & bytes)
+ bytes = ALIGN(bytes, align);
+ bytes += STACK_ARG_SIZE((*ptr)->size);
+ }
+#elif !defined __x86_64__ && !defined S390 && !defined PA
+#ifdef SPARC
+ if (((*ptr)->type == FFI_TYPE_STRUCT
+ && ((*ptr)->size > 16 || cif->abi != FFI_V9))
+ || ((*ptr)->type == FFI_TYPE_LONGDOUBLE
+ && cif->abi != FFI_V9))
+ bytes += sizeof(void*);
+ else
+#endif
+ {
+ /* Add any padding if necessary */
+ if (((*ptr)->alignment - 1) & bytes)
+ bytes = ALIGN(bytes, (*ptr)->alignment);
+
+ bytes += STACK_ARG_SIZE((*ptr)->size);
+ }
+#endif
+ }
+
+ cif->bytes = bytes;
+
+ /* Perform machine dependent cif processing */
+ return ffi_prep_cif_machdep(cif);
+}
diff --git a/libffi/src/raw_api.c b/libffi/src/raw_api.c
new file mode 100644
index 0000000..f4f4d80
--- /dev/null
+++ b/libffi/src/raw_api.c
@@ -0,0 +1,242 @@
+/* -----------------------------------------------------------------------
+ raw_api.c - Copyright (c) 1999 Red Hat, Inc.
+
+ Author: Kresten Krab Thorup <krab@gnu.org>
+
+ $Id $
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+/* This file defines generic functions for use with the raw api. */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#if !FFI_NO_RAW_API
+
+size_t
+ffi_raw_size (ffi_cif *cif)
+{
+ size_t result = 0;
+ int i;
+
+ ffi_type **at = cif->arg_types;
+
+ for (i = cif->nargs-1; i >= 0; i--, at++)
+ {
+#if !FFI_NO_STRUCTS
+ if ((*at)->type == FFI_TYPE_STRUCT)
+ result += ALIGN (sizeof (void*), FFI_SIZEOF_ARG);
+ else
+#endif
+ result += ALIGN ((*at)->size, FFI_SIZEOF_ARG);
+ }
+
+ return result;
+}
+
+
+void
+ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
+{
+ unsigned i;
+ ffi_type **tp = cif->arg_types;
+
+#if WORDS_BIGENDIAN
+
+ for (i = 0; i < cif->nargs; i++, tp++, args++)
+ {
+ switch ((*tp)->type)
+ {
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 1);
+ break;
+
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 2);
+ break;
+
+#if FFI_SIZEOF_ARG >= 4
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 4);
+ break;
+#endif
+
+#if !FFI_NO_STRUCTS
+ case FFI_TYPE_STRUCT:
+ *args = (raw++)->ptr;
+ break;
+#endif
+
+ case FFI_TYPE_POINTER:
+ *args = (void*) &(raw++)->ptr;
+ break;
+
+ default:
+ *args = raw;
+ raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ }
+ }
+
+#else /* WORDS_BIGENDIAN */
+
+#if !PDP
+
+ /* then assume little endian */
+ for (i = 0; i < cif->nargs; i++, tp++, args++)
+ {
+#if !FFI_NO_STRUCTS
+ if ((*tp)->type == FFI_TYPE_STRUCT)
+ {
+ *args = (raw++)->ptr;
+ }
+ else
+#endif
+ {
+ *args = (void*) raw;
+ raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
+ }
+ }
+
+#else
+#error "pdp endian not supported"
+#endif /* ! PDP */
+
+#endif /* WORDS_BIGENDIAN */
+}
+
+void
+ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
+{
+ unsigned i;
+ ffi_type **tp = cif->arg_types;
+
+ for (i = 0; i < cif->nargs; i++, tp++, args++)
+ {
+ switch ((*tp)->type)
+ {
+ case FFI_TYPE_UINT8:
+ (raw++)->uint = *(UINT8*) (*args);
+ break;
+
+ case FFI_TYPE_SINT8:
+ (raw++)->sint = *(SINT8*) (*args);
+ break;
+
+ case FFI_TYPE_UINT16:
+ (raw++)->uint = *(UINT16*) (*args);
+ break;
+
+ case FFI_TYPE_SINT16:
+ (raw++)->sint = *(SINT16*) (*args);
+ break;
+
+#if FFI_SIZEOF_ARG >= 4
+ case FFI_TYPE_UINT32:
+ (raw++)->uint = *(UINT32*) (*args);
+ break;
+
+ case FFI_TYPE_SINT32:
+ (raw++)->sint = *(SINT32*) (*args);
+ break;
+#endif
+
+#if !FFI_NO_STRUCTS
+ case FFI_TYPE_STRUCT:
+ (raw++)->ptr = *args;
+ break;
+#endif
+
+ case FFI_TYPE_POINTER:
+ (raw++)->ptr = **(void***) args;
+ break;
+
+ default:
+ memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
+ raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ }
+ }
+}
+
+#if !FFI_NATIVE_RAW_API
+
+
+/* This is a generic definition of ffi_raw_call, to be used if the
+ * native system does not provide a machine-specific implementation.
+ * Having this, allows code to be written for the raw API, without
+ * the need for system-specific code to handle input in that format;
+ * these following couple of functions will handle the translation forth
+ * and back automatically. */
+
+void ffi_raw_call (/*@dependent@*/ ffi_cif *cif,
+ void (*fn)(),
+ /*@out@*/ void *rvalue,
+ /*@dependent@*/ ffi_raw *raw)
+{
+ void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
+ ffi_raw_to_ptrarray (cif, raw, avalue);
+ ffi_call (cif, fn, rvalue, avalue);
+}
+
+#if FFI_CLOSURES /* base system provides closures */
+
+static void
+ffi_translate_args (ffi_cif *cif, void *rvalue,
+ void **avalue, void *user_data)
+{
+ ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif));
+ ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
+
+ ffi_ptrarray_to_raw (cif, avalue, raw);
+ (*cl->fun) (cif, rvalue, raw, cl->user_data);
+}
+
+/* Again, here is the generic version of ffi_prep_raw_closure, which
+ * will install an intermediate "hub" for translation of arguments from
+ * the pointer-array format, to the raw format */
+
+ffi_status
+ffi_prep_raw_closure (ffi_raw_closure* cl,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+ void *user_data)
+{
+ ffi_status status;
+
+ status = ffi_prep_closure ((ffi_closure*) cl,
+ cif,
+ &ffi_translate_args,
+ (void*)cl);
+ if (status == FFI_OK)
+ {
+ cl->fun = fun;
+ cl->user_data = user_data;
+ }
+
+ return status;
+}
+
+#endif /* FFI_CLOSURES */
+#endif /* !FFI_NATIVE_RAW_API */
+#endif /* !FFI_NO_RAW_API */
diff --git a/libffi/src/s390/ffi.c b/libffi/src/s390/ffi.c
new file mode 100644
index 0000000..d672b3c
--- /dev/null
+++ b/libffi/src/s390/ffi.c
@@ -0,0 +1,753 @@
+/* -----------------------------------------------------------------------
+ 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 */
+/* ------- */
+/*====================================================================*/
+
+/* Maximum number of GPRs available for argument passing. */
+#define MAX_GPRARGS 5
+
+/* Maximum number of FPRs available for argument passing. */
+#ifdef __s390x__
+#define MAX_FPRARGS 4
+#else
+#define MAX_FPRARGS 2
+#endif
+
+/* Round to multiple of 16. */
+#define ROUND_SIZE(size) (((size) + 15) & ~15)
+
+/* If these values change, sysv.S must be adapted! */
+#define FFI390_RET_VOID 0
+#define FFI390_RET_STRUCT 1
+#define FFI390_RET_FLOAT 2
+#define FFI390_RET_DOUBLE 3
+#define FFI390_RET_INT32 4
+#define FFI390_RET_INT64 5
+
+/*===================== End of Defines ===============================*/
+
+/*====================================================================*/
+/* Prototypes */
+/* ---------- */
+/*====================================================================*/
+
+static void ffi_prep_args (unsigned char *, extended_cif *);
+static int ffi_check_float_struct (ffi_type *);
+void
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+__attribute__ ((visibility ("hidden")))
+#endif
+ffi_closure_helper_SYSV (ffi_closure *, unsigned long *,
+ unsigned long long *, unsigned long *);
+
+/*====================== End of Prototypes ===========================*/
+
+/*====================================================================*/
+/* Externals */
+/* --------- */
+/*====================================================================*/
+
+extern void ffi_call_SYSV(unsigned,
+ extended_cif *,
+ void (*)(unsigned char *, extended_cif *),
+ unsigned,
+ void *,
+ void (*fn)());
+
+extern void ffi_closure_SYSV(void);
+
+/*====================== End of Externals ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_check_struct_type. */
+/* */
+/* Function - Determine if a structure can be passed within a */
+/* general purpose or floating point register. */
+/* */
+/*====================================================================*/
+
+static int
+ffi_check_struct_type (ffi_type *arg)
+{
+ size_t size = arg->size;
+
+ /* If the struct has just one element, look at that element
+ to find out whether to consider the struct as floating point. */
+ while (arg->type == FFI_TYPE_STRUCT
+ && arg->elements[0] && !arg->elements[1])
+ arg = arg->elements[0];
+
+ /* Structs of size 1, 2, 4, and 8 are passed in registers,
+ just like the corresponding int/float types. */
+ switch (size)
+ {
+ case 1:
+ return FFI_TYPE_UINT8;
+
+ case 2:
+ return FFI_TYPE_UINT16;
+
+ case 4:
+ if (arg->type == FFI_TYPE_FLOAT)
+ return FFI_TYPE_FLOAT;
+ else
+ return FFI_TYPE_UINT32;
+
+ case 8:
+ if (arg->type == FFI_TYPE_DOUBLE)
+ return FFI_TYPE_DOUBLE;
+ else
+ return FFI_TYPE_UINT64;
+
+ default:
+ break;
+ }
+
+ /* Other structs are passed via a pointer to the data. */
+ return FFI_TYPE_POINTER;
+}
+
+/*======================== 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. */
+/* */
+/*====================================================================*/
+
+static void
+ffi_prep_args (unsigned char *stack, extended_cif *ecif)
+{
+ /* The stack space will be filled with those areas:
+
+ FPR argument register save area (highest addresses)
+ GPR argument register save area
+ temporary struct copies
+ overflow argument area (lowest addresses)
+
+ We set up the following pointers:
+
+ p_fpr: bottom of the FPR area (growing upwards)
+ p_gpr: bottom of the GPR area (growing upwards)
+ p_ov: bottom of the overflow area (growing upwards)
+ p_struct: top of the struct copy area (growing downwards)
+
+ All areas are kept aligned to twice the word size. */
+
+ int gpr_off = ecif->cif->bytes;
+ int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));
+
+ unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off);
+ unsigned long *p_gpr = (unsigned long *)(stack + gpr_off);
+ unsigned char *p_struct = (unsigned char *)p_gpr;
+ unsigned long *p_ov = (unsigned long *)stack;
+
+ int n_fpr = 0;
+ int n_gpr = 0;
+ int n_ov = 0;
+
+ ffi_type **ptr;
+ void **p_argv = ecif->avalue;
+ int i;
+
+ /* If we returning a structure then we set the first parameter register
+ to the address of where we are returning this structure. */
+
+ if (ecif->cif->flags == FFI390_RET_STRUCT)
+ p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
+
+ /* Now for the arguments. */
+
+ for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
+ i > 0;
+ i--, ptr++, p_argv++)
+ {
+ void *arg = *p_argv;
+ int type = (*ptr)->type;
+
+ /* Check how a structure type is passed. */
+ if (type == FFI_TYPE_STRUCT)
+ {
+ type = ffi_check_struct_type (*ptr);
+
+ /* If we pass the struct via pointer, copy the data. */
+ if (type == FFI_TYPE_POINTER)
+ {
+ p_struct -= ROUND_SIZE ((*ptr)->size);
+ memcpy (p_struct, (char *)arg, (*ptr)->size);
+ arg = &p_struct;
+ }
+ }
+
+ /* Pointers are passed like UINTs of the same size. */
+ if (type == FFI_TYPE_POINTER)
+#ifdef __s390x__
+ type = FFI_TYPE_UINT64;
+#else
+ type = FFI_TYPE_UINT32;
+#endif
+
+ /* Now handle all primitive int/float data types. */
+ switch (type)
+ {
+ case FFI_TYPE_DOUBLE:
+ if (n_fpr < MAX_FPRARGS)
+ p_fpr[n_fpr++] = *(unsigned long long *) arg;
+ else
+#ifdef __s390x__
+ p_ov[n_ov++] = *(unsigned long *) arg;
+#else
+ p_ov[n_ov++] = ((unsigned long *) arg)[0],
+ p_ov[n_ov++] = ((unsigned long *) arg)[1];
+#endif
+ break;
+
+ case FFI_TYPE_FLOAT:
+ if (n_fpr < MAX_FPRARGS)
+ p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32;
+ else
+ p_ov[n_ov++] = *(unsigned int *) arg;
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+#ifdef __s390x__
+ if (n_gpr < MAX_GPRARGS)
+ p_gpr[n_gpr++] = *(unsigned long *) arg;
+ else
+ p_ov[n_ov++] = *(unsigned long *) arg;
+#else
+ if (n_gpr == MAX_GPRARGS-1)
+ n_gpr = MAX_GPRARGS;
+ if (n_gpr < MAX_GPRARGS)
+ p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
+ p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
+ else
+ p_ov[n_ov++] = ((unsigned long *) arg)[0],
+ p_ov[n_ov++] = ((unsigned long *) arg)[1];
+#endif
+ break;
+
+ case FFI_TYPE_UINT32:
+ if (n_gpr < MAX_GPRARGS)
+ p_gpr[n_gpr++] = *(unsigned int *) arg;
+ else
+ p_ov[n_ov++] = *(unsigned int *) arg;
+ break;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ if (n_gpr < MAX_GPRARGS)
+ p_gpr[n_gpr++] = *(signed int *) arg;
+ else
+ p_ov[n_ov++] = *(signed int *) arg;
+ break;
+
+ case FFI_TYPE_UINT16:
+ if (n_gpr < MAX_GPRARGS)
+ p_gpr[n_gpr++] = *(unsigned short *) arg;
+ else
+ p_ov[n_ov++] = *(unsigned short *) arg;
+ break;
+
+ case FFI_TYPE_SINT16:
+ if (n_gpr < MAX_GPRARGS)
+ p_gpr[n_gpr++] = *(signed short *) arg;
+ else
+ p_ov[n_ov++] = *(signed short *) arg;
+ break;
+
+ case FFI_TYPE_UINT8:
+ if (n_gpr < MAX_GPRARGS)
+ p_gpr[n_gpr++] = *(unsigned char *) arg;
+ else
+ p_ov[n_ov++] = *(unsigned char *) arg;
+ break;
+
+ case FFI_TYPE_SINT8:
+ if (n_gpr < MAX_GPRARGS)
+ p_gpr[n_gpr++] = *(signed char *) arg;
+ else
+ p_ov[n_ov++] = *(signed char *) arg;
+ break;
+
+ default:
+ FFI_ASSERT (0);
+ break;
+ }
+ }
+}
+
+/*======================== End of Routine ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_prep_cif_machdep. */
+/* */
+/* Function - Perform machine dependent CIF processing. */
+/* */
+/*====================================================================*/
+
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ size_t struct_size = 0;
+ int n_gpr = 0;
+ int n_fpr = 0;
+ int n_ov = 0;
+
+ ffi_type **ptr;
+ int i;
+
+ /* Determine return value handling. */
+
+ switch (cif->rtype->type)
+ {
+ /* Void is easy. */
+ case FFI_TYPE_VOID:
+ cif->flags = FFI390_RET_VOID;
+ break;
+
+ /* Structures are returned via a hidden pointer. */
+ case FFI_TYPE_STRUCT:
+ cif->flags = FFI390_RET_STRUCT;
+ n_gpr++; /* We need one GPR to pass the pointer. */
+ break;
+
+ /* Floating point values are returned in fpr 0. */
+ case FFI_TYPE_FLOAT:
+ cif->flags = FFI390_RET_FLOAT;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ cif->flags = FFI390_RET_DOUBLE;
+ break;
+
+ /* Integer values are returned in gpr 2 (and gpr 3
+ for 64-bit values on 31-bit machines). */
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ cif->flags = FFI390_RET_INT64;
+ break;
+
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ /* These are to be extended to word size. */
+#ifdef __s390x__
+ cif->flags = FFI390_RET_INT64;
+#else
+ cif->flags = FFI390_RET_INT32;
+#endif
+ break;
+
+ default:
+ FFI_ASSERT (0);
+ break;
+ }
+
+ /* Now for the arguments. */
+
+ for (ptr = cif->arg_types, i = cif->nargs;
+ i > 0;
+ i--, ptr++)
+ {
+ int type = (*ptr)->type;
+
+ /* Check how a structure type is passed. */
+ if (type == FFI_TYPE_STRUCT)
+ {
+ type = ffi_check_struct_type (*ptr);
+
+ /* If we pass the struct via pointer, we must reserve space
+ to copy its data for proper call-by-value semantics. */
+ if (type == FFI_TYPE_POINTER)
+ struct_size += ROUND_SIZE ((*ptr)->size);
+ }
+
+ /* Now handle all primitive int/float data types. */
+ switch (type)
+ {
+ /* The first MAX_FPRARGS floating point arguments
+ go in FPRs, the rest overflow to the stack. */
+
+ case FFI_TYPE_DOUBLE:
+ if (n_fpr < MAX_FPRARGS)
+ n_fpr++;
+ else
+ n_ov += sizeof (double) / sizeof (long);
+ break;
+
+ case FFI_TYPE_FLOAT:
+ if (n_fpr < MAX_FPRARGS)
+ n_fpr++;
+ else
+ n_ov++;
+ break;
+
+ /* On 31-bit machines, 64-bit integers are passed in GPR pairs,
+ if one is still available, or else on the stack. If only one
+ register is free, skip the register (it won't be used for any
+ subsequent argument either). */
+
+#ifndef __s390x__
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ if (n_gpr == MAX_GPRARGS-1)
+ n_gpr = MAX_GPRARGS;
+ if (n_gpr < MAX_GPRARGS)
+ n_gpr += 2;
+ else
+ n_ov += 2;
+ break;
+#endif
+
+ /* Everything else is passed in GPRs (until MAX_GPRARGS
+ have been used) or overflows to the stack. */
+
+ default:
+ if (n_gpr < MAX_GPRARGS)
+ n_gpr++;
+ else
+ n_ov++;
+ break;
+ }
+ }
+
+ /* Total stack space as required for overflow arguments
+ and temporary structure copies. */
+
+ cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
+
+ 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)
+{
+ int ret_type = cif->flags;
+ extended_cif ecif;
+
+ ecif.cif = cif;
+ ecif.avalue = avalue;
+ ecif.rvalue = rvalue;
+
+ /* If we don't have a return value, we need to fake one. */
+ if (rvalue == NULL)
+ {
+ if (ret_type == FFI390_RET_STRUCT)
+ ecif.rvalue = alloca (cif->rtype->size);
+ else
+ ret_type = FFI390_RET_VOID;
+ }
+
+ switch (cif->abi)
+ {
+ case FFI_SYSV:
+ ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
+ ret_type, ecif.rvalue, fn);
+ break;
+
+ default:
+ FFI_ASSERT (0);
+ break;
+ }
+}
+
+/*======================== End of Routine ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_closure_helper_SYSV. */
+/* */
+/* Function - Call a FFI closure target function. */
+/* */
+/*====================================================================*/
+
+void
+ffi_closure_helper_SYSV (ffi_closure *closure,
+ unsigned long *p_gpr,
+ unsigned long long *p_fpr,
+ unsigned long *p_ov)
+{
+ unsigned long long ret_buffer;
+
+ void *rvalue = &ret_buffer;
+ void **avalue;
+ void **p_arg;
+
+ int n_gpr = 0;
+ int n_fpr = 0;
+ int n_ov = 0;
+
+ ffi_type **ptr;
+ int i;
+
+ /* Allocate buffer for argument list pointers. */
+
+ p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));
+
+ /* If we returning a structure, pass the structure address
+ directly to the target function. Otherwise, have the target
+ function store the return value to the GPR save area. */
+
+ if (closure->cif->flags == FFI390_RET_STRUCT)
+ rvalue = (void *) p_gpr[n_gpr++];
+
+ /* Now for the arguments. */
+
+ for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
+ i > 0;
+ i--, p_arg++, ptr++)
+ {
+ int deref_struct_pointer = 0;
+ int type = (*ptr)->type;
+
+ /* Check how a structure type is passed. */
+ if (type == FFI_TYPE_STRUCT)
+ {
+ type = ffi_check_struct_type (*ptr);
+
+ /* If we pass the struct via pointer, remember to
+ retrieve the pointer later. */
+ if (type == FFI_TYPE_POINTER)
+ deref_struct_pointer = 1;
+ }
+
+ /* Pointers are passed like UINTs of the same size. */
+ if (type == FFI_TYPE_POINTER)
+#ifdef __s390x__
+ type = FFI_TYPE_UINT64;
+#else
+ type = FFI_TYPE_UINT32;
+#endif
+
+ /* Now handle all primitive int/float data types. */
+ switch (type)
+ {
+ case FFI_TYPE_DOUBLE:
+ if (n_fpr < MAX_FPRARGS)
+ *p_arg = &p_fpr[n_fpr++];
+ else
+ *p_arg = &p_ov[n_ov],
+ n_ov += sizeof (double) / sizeof (long);
+ break;
+
+ case FFI_TYPE_FLOAT:
+ if (n_fpr < MAX_FPRARGS)
+ *p_arg = &p_fpr[n_fpr++];
+ else
+ *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+#ifdef __s390x__
+ if (n_gpr < MAX_GPRARGS)
+ *p_arg = &p_gpr[n_gpr++];
+ else
+ *p_arg = &p_ov[n_ov++];
+#else
+ if (n_gpr == MAX_GPRARGS-1)
+ n_gpr = MAX_GPRARGS;
+ if (n_gpr < MAX_GPRARGS)
+ *p_arg = &p_gpr[n_gpr], n_gpr += 2;
+ else
+ *p_arg = &p_ov[n_ov], n_ov += 2;
+#endif
+ break;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ if (n_gpr < MAX_GPRARGS)
+ *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4;
+ else
+ *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
+ break;
+
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ if (n_gpr < MAX_GPRARGS)
+ *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2;
+ else
+ *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2;
+ break;
+
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ if (n_gpr < MAX_GPRARGS)
+ *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1;
+ else
+ *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
+ break;
+
+ default:
+ FFI_ASSERT (0);
+ break;
+ }
+
+ /* If this is a struct passed via pointer, we need to
+ actually retrieve that pointer. */
+ if (deref_struct_pointer)
+ *p_arg = *(void **)*p_arg;
+ }
+
+
+ /* Call the target function. */
+ (closure->fun) (closure->cif, rvalue, avalue, closure->user_data);
+
+ /* Convert the return value. */
+ switch (closure->cif->rtype->type)
+ {
+ /* Void is easy, and so is struct. */
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_STRUCT:
+ break;
+
+ /* Floating point values are returned in fpr 0. */
+ case FFI_TYPE_FLOAT:
+ p_fpr[0] = (long long) *(unsigned int *) rvalue << 32;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ p_fpr[0] = *(unsigned long long *) rvalue;
+ break;
+
+ /* Integer values are returned in gpr 2 (and gpr 3
+ for 64-bit values on 31-bit machines). */
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+#ifdef __s390x__
+ p_gpr[0] = *(unsigned long *) rvalue;
+#else
+ p_gpr[0] = ((unsigned long *) rvalue)[0],
+ p_gpr[1] = ((unsigned long *) rvalue)[1];
+#endif
+ break;
+
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_UINT8:
+ p_gpr[0] = *(unsigned long *) rvalue;
+ break;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_SINT8:
+ p_gpr[0] = *(signed long *) rvalue;
+ break;
+
+ default:
+ FFI_ASSERT (0);
+ break;
+ }
+}
+
+/*======================== End of Routine ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_prep_closure. */
+/* */
+/* Function - Prepare a FFI closure. */
+/* */
+/*====================================================================*/
+
+ffi_status
+ffi_prep_closure (ffi_closure *closure,
+ ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data)
+{
+ FFI_ASSERT (cif->abi == FFI_SYSV);
+
+#ifndef __s390x__
+ *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
+ *(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */
+ *(short *)&closure->tramp [4] = 0x1006;
+ *(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */
+ *(long *)&closure->tramp [8] = (long)closure;
+ *(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
+#else
+ *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
+ *(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */
+ *(short *)&closure->tramp [4] = 0x100e;
+ *(short *)&closure->tramp [6] = 0x0004;
+ *(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */
+ *(long *)&closure->tramp[16] = (long)closure;
+ *(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
+#endif
+
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+/*======================== End of Routine ============================*/
+
diff --git a/libffi/src/s390/ffitarget.h b/libffi/src/s390/ffitarget.h
new file mode 100644
index 0000000..5ec8ade
--- /dev/null
+++ b/libffi/src/s390/ffitarget.h
@@ -0,0 +1,59 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for S390.
+
+ 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
+
+#if defined (__s390x__)
+#define S390X
+#endif
+
+/* ---- System specific configurations ----------------------------------- */
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_DEFAULT_ABI = FFI_SYSV,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#ifdef S390X
+#define FFI_TRAMPOLINE_SIZE 32
+#else
+#define FFI_TRAMPOLINE_SIZE 16
+#endif
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/s390/sysv.S b/libffi/src/s390/sysv.S
new file mode 100644
index 0000000..e9cbed9
--- /dev/null
+++ b/libffi/src/s390/sysv.S
@@ -0,0 +1,429 @@
+/* -----------------------------------------------------------------------
+ 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 <fficonfig.h>
+#include <ffi.h>
+
+#ifndef __s390x__
+
+.text
+
+ # r2: cif->bytes
+ # r3: &ecif
+ # r4: ffi_prep_args
+ # r5: ret_type
+ # r6: ecif.rvalue
+ # ov: fn
+
+ # This assumes we are using gas.
+ .globl ffi_call_SYSV
+ .type ffi_call_SYSV,%function
+ffi_call_SYSV:
+.LFB1:
+ stm %r6,%r15,24(%r15) # Save registers
+.LCFI0:
+ basr %r13,0 # Set up base register
+.Lbase:
+ lr %r11,%r15 # Set up frame pointer
+.LCFI1:
+ sr %r15,%r2
+ ahi %r15,-96-48 # Allocate stack
+ lr %r8,%r6 # Save ecif.rvalue
+ sr %r9,%r9
+ ic %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address
+ l %r7,96(%r11) # Load function address
+ st %r11,0(%r15) # Set up back chain
+ ahi %r11,-48 # Register save area
+.LCFI2:
+
+ la %r2,96(%r15) # Save area
+ # r3 already holds &ecif
+ basr %r14,%r4 # Call ffi_prep_args
+
+ lm %r2,%r6,0(%r11) # Load arguments
+ ld %f0,32(%r11)
+ ld %f2,40(%r11)
+ la %r14,0(%r13,%r9) # Set return address
+ br %r7 # ... and call function
+
+.LretNone: # Return void
+ l %r4,48+56(%r11)
+ lm %r6,%r15,48+24(%r11)
+ br %r4
+
+.LretFloat:
+ l %r4,48+56(%r11)
+ ste %f0,0(%r8) # Return float
+ lm %r6,%r15,48+24(%r11)
+ br %r4
+
+.LretDouble:
+ l %r4,48+56(%r11)
+ std %f0,0(%r8) # Return double
+ lm %r6,%r15,48+24(%r11)
+ br %r4
+
+.LretInt32:
+ l %r4,48+56(%r11)
+ st %r2,0(%r8) # Return int
+ lm %r6,%r15,48+24(%r11)
+ br %r4
+
+.LretInt64:
+ l %r4,48+56(%r11)
+ stm %r2,%r3,0(%r8) # Return long long
+ lm %r6,%r15,48+24(%r11)
+ br %r4
+
+.Ltable:
+ .byte .LretNone-.Lbase # FFI390_RET_VOID
+ .byte .LretNone-.Lbase # FFI390_RET_STRUCT
+ .byte .LretFloat-.Lbase # FFI390_RET_FLOAT
+ .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE
+ .byte .LretInt32-.Lbase # FFI390_RET_INT32
+ .byte .LretInt64-.Lbase # FFI390_RET_INT64
+
+.LFE1:
+.ffi_call_SYSV_end:
+ .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
+
+
+ .globl ffi_closure_SYSV
+ .type ffi_closure_SYSV,%function
+ffi_closure_SYSV:
+.LFB2:
+ stm %r12,%r15,48(%r15) # Save registers
+.LCFI10:
+ basr %r13,0 # Set up base register
+.Lcbase:
+ stm %r2,%r6,8(%r15) # Save arguments
+ std %f0,64(%r15)
+ std %f2,72(%r15)
+ lr %r1,%r15 # Set up stack frame
+ ahi %r15,-96
+.LCFI11:
+ l %r12,.Lchelper-.Lcbase(%r13) # Get helper function
+ lr %r2,%r0 # Closure
+ la %r3,8(%r1) # GPRs
+ la %r4,64(%r1) # FPRs
+ la %r5,96(%r1) # Overflow
+ st %r1,0(%r15) # Set up back chain
+
+ bas %r14,0(%r12,%r13) # Call helper
+
+ l %r4,96+56(%r15)
+ ld %f0,96+64(%r15) # Load return registers
+ lm %r2,%r3,96+8(%r15)
+ lm %r12,%r15,96+48(%r15)
+ br %r4
+
+ .align 4
+.Lchelper:
+ .long ffi_closure_helper_SYSV-.Lcbase
+
+.LFE2:
+
+.ffi_closure_SYSV_end:
+ .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
+
+
+ .section .eh_frame,EH_FRAME_FLAGS,@progbits
+.Lframe1:
+ .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
+.LSCIE1:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "zR\0" # CIE Augmentation
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 -4 # CIE Data Alignment Factor
+ .byte 0xe # CIE RA Column
+ .uleb128 0x1 # Augmentation size
+ .byte 0x1b # FDE Encoding (pcrel sdata4)
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0xf
+ .uleb128 0x60
+ .align 4
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 # FDE Length
+.LASFDE1:
+ .4byte .LASFDE1-.Lframe1 # FDE CIE offset
+ .4byte .LFB1-. # FDE initial location
+ .4byte .LFE1-.LFB1 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI0-.LFB1
+ .byte 0x8f # DW_CFA_offset, column 0xf
+ .uleb128 0x9
+ .byte 0x8e # DW_CFA_offset, column 0xe
+ .uleb128 0xa
+ .byte 0x8d # DW_CFA_offset, column 0xd
+ .uleb128 0xb
+ .byte 0x8c # DW_CFA_offset, column 0xc
+ .uleb128 0xc
+ .byte 0x8b # DW_CFA_offset, column 0xb
+ .uleb128 0xd
+ .byte 0x8a # DW_CFA_offset, column 0xa
+ .uleb128 0xe
+ .byte 0x89 # DW_CFA_offset, column 0x9
+ .uleb128 0xf
+ .byte 0x88 # DW_CFA_offset, column 0x8
+ .uleb128 0x10
+ .byte 0x87 # DW_CFA_offset, column 0x7
+ .uleb128 0x11
+ .byte 0x86 # DW_CFA_offset, column 0x6
+ .uleb128 0x12
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI1-.LCFI0
+ .byte 0xd # DW_CFA_def_cfa_register
+ .uleb128 0xb
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI2-.LCFI1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x90
+ .align 4
+.LEFDE1:
+.LSFDE2:
+ .4byte .LEFDE2-.LASFDE2 # FDE Length
+.LASFDE2:
+ .4byte .LASFDE2-.Lframe1 # FDE CIE offset
+ .4byte .LFB2-. # FDE initial location
+ .4byte .LFE2-.LFB2 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI10-.LFB2
+ .byte 0x8f # DW_CFA_offset, column 0xf
+ .uleb128 0x9
+ .byte 0x8e # DW_CFA_offset, column 0xe
+ .uleb128 0xa
+ .byte 0x8d # DW_CFA_offset, column 0xd
+ .uleb128 0xb
+ .byte 0x8c # DW_CFA_offset, column 0xc
+ .uleb128 0xc
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI11-.LCFI10
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0xc0
+ .align 4
+.LEFDE2:
+
+#else
+
+.text
+
+ # r2: cif->bytes
+ # r3: &ecif
+ # r4: ffi_prep_args
+ # r5: ret_type
+ # r6: ecif.rvalue
+ # ov: fn
+
+ # This assumes we are using gas.
+ .globl ffi_call_SYSV
+ .type ffi_call_SYSV,%function
+ffi_call_SYSV:
+.LFB1:
+ stmg %r6,%r15,48(%r15) # Save registers
+.LCFI0:
+ larl %r13,.Lbase # Set up base register
+ lgr %r11,%r15 # Set up frame pointer
+.LCFI1:
+ sgr %r15,%r2
+ aghi %r15,-160-80 # Allocate stack
+ lgr %r8,%r6 # Save ecif.rvalue
+ llgc %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address
+ lg %r7,160(%r11) # Load function address
+ stg %r11,0(%r15) # Set up back chain
+ aghi %r11,-80 # Register save area
+.LCFI2:
+
+ la %r2,160(%r15) # Save area
+ # r3 already holds &ecif
+ basr %r14,%r4 # Call ffi_prep_args
+
+ lmg %r2,%r6,0(%r11) # Load arguments
+ ld %f0,48(%r11)
+ ld %f2,56(%r11)
+ ld %f4,64(%r11)
+ ld %f6,72(%r11)
+ la %r14,0(%r13,%r9) # Set return address
+ br %r7 # ... and call function
+
+.Lbase:
+.LretNone: # Return void
+ lg %r4,80+112(%r11)
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+.LretFloat:
+ lg %r4,80+112(%r11)
+ ste %f0,0(%r8) # Return float
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+.LretDouble:
+ lg %r4,80+112(%r11)
+ std %f0,0(%r8) # Return double
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+.LretInt32:
+ lg %r4,80+112(%r11)
+ st %r2,0(%r8) # Return int
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+.LretInt64:
+ lg %r4,80+112(%r11)
+ stg %r2,0(%r8) # Return long
+ lmg %r6,%r15,80+48(%r11)
+ br %r4
+
+.Ltable:
+ .byte .LretNone-.Lbase # FFI390_RET_VOID
+ .byte .LretNone-.Lbase # FFI390_RET_STRUCT
+ .byte .LretFloat-.Lbase # FFI390_RET_FLOAT
+ .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE
+ .byte .LretInt32-.Lbase # FFI390_RET_INT32
+ .byte .LretInt64-.Lbase # FFI390_RET_INT64
+
+.LFE1:
+.ffi_call_SYSV_end:
+ .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
+
+
+ .globl ffi_closure_SYSV
+ .type ffi_closure_SYSV,%function
+ffi_closure_SYSV:
+.LFB2:
+ stmg %r14,%r15,112(%r15) # Save registers
+.LCFI10:
+ stmg %r2,%r6,16(%r15) # Save arguments
+ std %f0,128(%r15)
+ std %f2,136(%r15)
+ std %f4,144(%r15)
+ std %f6,152(%r15)
+ lgr %r1,%r15 # Set up stack frame
+ aghi %r15,-160
+.LCFI11:
+ lgr %r2,%r0 # Closure
+ la %r3,16(%r1) # GPRs
+ la %r4,128(%r1) # FPRs
+ la %r5,160(%r1) # Overflow
+ stg %r1,0(%r15) # Set up back chain
+
+ brasl %r14,ffi_closure_helper_SYSV # Call helper
+
+ lg %r14,160+112(%r15)
+ ld %f0,160+128(%r15) # Load return registers
+ lg %r2,160+16(%r15)
+ la %r15,160(%r15)
+ br %r14
+.LFE2:
+
+.ffi_closure_SYSV_end:
+ .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV
+
+
+
+ .section .eh_frame,EH_FRAME_FLAGS,@progbits
+.Lframe1:
+ .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
+.LSCIE1:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "zR\0" # CIE Augmentation
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 -8 # CIE Data Alignment Factor
+ .byte 0xe # CIE RA Column
+ .uleb128 0x1 # Augmentation size
+ .byte 0x1b # FDE Encoding (pcrel sdata4)
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0xf
+ .uleb128 0xa0
+ .align 8
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 # FDE Length
+.LASFDE1:
+ .4byte .LASFDE1-.Lframe1 # FDE CIE offset
+ .4byte .LFB1-. # FDE initial location
+ .4byte .LFE1-.LFB1 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI0-.LFB1
+ .byte 0x8f # DW_CFA_offset, column 0xf
+ .uleb128 0x5
+ .byte 0x8e # DW_CFA_offset, column 0xe
+ .uleb128 0x6
+ .byte 0x8d # DW_CFA_offset, column 0xd
+ .uleb128 0x7
+ .byte 0x8c # DW_CFA_offset, column 0xc
+ .uleb128 0x8
+ .byte 0x8b # DW_CFA_offset, column 0xb
+ .uleb128 0x9
+ .byte 0x8a # DW_CFA_offset, column 0xa
+ .uleb128 0xa
+ .byte 0x89 # DW_CFA_offset, column 0x9
+ .uleb128 0xb
+ .byte 0x88 # DW_CFA_offset, column 0x8
+ .uleb128 0xc
+ .byte 0x87 # DW_CFA_offset, column 0x7
+ .uleb128 0xd
+ .byte 0x86 # DW_CFA_offset, column 0x6
+ .uleb128 0xe
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI1-.LCFI0
+ .byte 0xd # DW_CFA_def_cfa_register
+ .uleb128 0xb
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI2-.LCFI1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0xf0
+ .align 8
+.LEFDE1:
+.LSFDE2:
+ .4byte .LEFDE2-.LASFDE2 # FDE Length
+.LASFDE2:
+ .4byte .LASFDE2-.Lframe1 # FDE CIE offset
+ .4byte .LFB2-. # FDE initial location
+ .4byte .LFE2-.LFB2 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI10-.LFB2
+ .byte 0x8f # DW_CFA_offset, column 0xf
+ .uleb128 0x5
+ .byte 0x8e # DW_CFA_offset, column 0xe
+ .uleb128 0x6
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte .LCFI11-.LCFI10
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x140
+ .align 8
+.LEFDE2:
+
+#endif
+
diff --git a/libffi/src/sh/ffi.c b/libffi/src/sh/ffi.c
new file mode 100644
index 0000000..8aa96a1
--- /dev/null
+++ b/libffi/src/sh/ffi.c
@@ -0,0 +1,722 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2002, 2003 Kaz Kojima
+
+ SuperH 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 NGREGARG 4
+#if defined(__SH4__)
+#define NFREGARG 8
+#endif
+
+#if defined(__HITACHI__)
+#define STRUCT_VALUE_ADDRESS_WITH_ARG 1
+#else
+#define STRUCT_VALUE_ADDRESS_WITH_ARG 0
+#endif
+
+/* If the structure has essentialy an unique element, return its type. */
+static int
+simple_type (ffi_type *arg)
+{
+ if (arg->type != FFI_TYPE_STRUCT)
+ return arg->type;
+ else if (arg->elements[1])
+ return FFI_TYPE_STRUCT;
+
+ return simple_type (arg->elements[0]);
+}
+
+static int
+return_type (ffi_type *arg)
+{
+ unsigned short type;
+
+ if (arg->type != FFI_TYPE_STRUCT)
+ return arg->type;
+
+ type = simple_type (arg->elements[0]);
+ if (! arg->elements[1])
+ {
+ 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:
+ return FFI_TYPE_INT;
+
+ default:
+ return type;
+ }
+ }
+
+ /* gcc uses r0/r1 pair for some kind of structures. */
+ if (arg->size <= 2 * sizeof (int))
+ {
+ int i = 0;
+ ffi_type *e;
+
+ while ((e = arg->elements[i++]))
+ {
+ type = simple_type (e);
+ switch (type)
+ {
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_INT:
+ case FFI_TYPE_FLOAT:
+ return FFI_TYPE_UINT64;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return FFI_TYPE_STRUCT;
+}
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+/*@-exportheader@*/
+void ffi_prep_args(char *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+ register unsigned int i;
+ register int tmp;
+ register unsigned int avn;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+ int greg, ireg;
+#if defined(__SH4__)
+ int freg = 0;
+#endif
+
+ tmp = 0;
+ argp = stack;
+
+ if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
+ {
+ *(void **) argp = ecif->rvalue;
+ argp += 4;
+ ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
+ }
+ else
+ ireg = 0;
+
+ /* Set arguments for registers. */
+ greg = ireg;
+ avn = ecif->cif->nargs;
+ p_argv = ecif->avalue;
+
+ for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ if (greg++ >= NGREGARG)
+ continue;
+
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ argp += z;
+ }
+ else if (z == sizeof(int))
+ {
+#if defined(__SH4__)
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg++ >= NFREGARG)
+ continue;
+ }
+ else
+#endif
+ {
+ if (greg++ >= NGREGARG)
+ continue;
+ }
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ argp += z;
+ }
+#if defined(__SH4__)
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 >= NFREGARG)
+ continue;
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ memcpy (argp, *p_argv, z);
+ argp += z;
+ }
+#endif
+ else
+ {
+ int n = (z + sizeof (int) - 1) / sizeof (int);
+#if defined(__SH4__)
+ if (greg + n - 1 >= NGREGARG)
+ continue;
+ greg += n;
+#else
+ if (greg >= NGREGARG)
+ continue;
+ else if (greg + n - 1 >= NGREGARG)
+ greg = NGREGARG;
+ else
+ greg += n;
+#endif
+ memcpy (argp, *p_argv, z);
+ argp += n * sizeof (int);
+ }
+ }
+
+ /* Set arguments on stack. */
+ greg = ireg;
+#if defined(__SH4__)
+ freg = 0;
+#endif
+ p_argv = ecif->avalue;
+
+ for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ if (greg++ < NGREGARG)
+ continue;
+
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ argp += z;
+ }
+ else if (z == sizeof(int))
+ {
+#if defined(__SH4__)
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg++ < NFREGARG)
+ continue;
+ }
+ else
+#endif
+ {
+ if (greg++ < NGREGARG)
+ continue;
+ }
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ argp += z;
+ }
+#if defined(__SH4__)
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 < NFREGARG)
+ {
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ continue;
+ }
+ memcpy (argp, *p_argv, z);
+ argp += z;
+ }
+#endif
+ else
+ {
+ int n = (z + sizeof (int) - 1) / sizeof (int);
+ if (greg + n - 1 < NGREGARG)
+ {
+ greg += n;
+ continue;
+ }
+#if (! defined(__SH4__))
+ else if (greg < NGREGARG)
+ {
+ greg = NGREGARG;
+ continue;
+ }
+#endif
+ memcpy (argp, *p_argv, z);
+ argp += n * sizeof (int);
+ }
+ }
+
+ return;
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ int i, j;
+ int size, type;
+ int n, m;
+ int greg;
+#if defined(__SH4__)
+ int freg = 0;
+#endif
+
+ cif->flags = 0;
+
+ greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) &&
+ STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0;
+
+#if defined(__SH4__)
+ for (i = j = 0; i < cif->nargs && j < 12; i++)
+ {
+ type = (cif->arg_types)[i]->type;
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT:
+ if (freg >= NFREGARG)
+ continue;
+ freg++;
+ cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
+ j++;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ if ((freg + 1) >= NFREGARG)
+ continue;
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
+ j++;
+ break;
+
+ default:
+ size = (cif->arg_types)[i]->size;
+ n = (size + sizeof (int) - 1) / sizeof (int);
+ if (greg + n - 1 >= NGREGARG)
+ continue;
+ greg += n;
+ for (m = 0; m < n; m++)
+ cif->flags += FFI_TYPE_INT << (2 * j++);
+ break;
+ }
+ }
+#else
+ for (i = j = 0; i < cif->nargs && j < 4; i++)
+ {
+ size = (cif->arg_types)[i]->size;
+ n = (size + sizeof (int) - 1) / sizeof (int);
+ if (greg >= NGREGARG)
+ continue;
+ else if (greg + n - 1 >= NGREGARG)
+ greg = NGREGARG;
+ else
+ greg += n;
+ for (m = 0; m < n; m++)
+ cif->flags += FFI_TYPE_INT << (2 * j++);
+ }
+#endif
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_STRUCT:
+ cif->flags += (unsigned) (return_type (cif->rtype)) << 24;
+ break;
+
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ cif->flags += (unsigned) cif->rtype->type << 24;
+ break;
+
+ default:
+ cif->flags += FFI_TYPE_INT << 24;
+ break;
+ }
+
+ return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
+ /*@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_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+extern void ffi_closure_SYSV (void);
+#if defined(__SH4__)
+extern void __ic_invalidate (void *line);
+#endif
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data)
+{
+ unsigned int *tramp;
+
+ FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
+
+ tramp = (unsigned int *) &closure->tramp[0];
+#ifdef __LITTLE_ENDIAN__
+ tramp[0] = 0xd301d202;
+ tramp[1] = 0x0009422b;
+#else
+ tramp[0] = 0xd202d301;
+ tramp[1] = 0x422b0009;
+#endif
+ *(void **) &tramp[2] = (void *)closure; /* ctx */
+ *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+#if defined(__SH4__)
+ /* Flush the icache. */
+ __ic_invalidate(&closure->tramp[0]);
+#endif
+
+ return FFI_OK;
+}
+
+/* Basically the trampoline invokes ffi_closure_SYSV, and on
+ * entry, r3 holds the address of the closure.
+ * After storing the registers that could possibly contain
+ * parameters to be passed into the stack frame and setting
+ * up space for a return value, ffi_closure_SYSV invokes the
+ * following helper function to do most of the work.
+ */
+
+#ifdef __LITTLE_ENDIAN__
+#define OFS_INT8 0
+#define OFS_INT16 0
+#else
+#define OFS_INT8 3
+#define OFS_INT16 2
+#endif
+
+int
+ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
+ unsigned long *pgr, unsigned long *pfr,
+ unsigned long *pst)
+{
+ void **avalue;
+ ffi_type **p_arg;
+ int i, avn;
+ int ireg, greg = 0;
+#if defined(__SH4__)
+ int freg = 0;
+#endif
+ ffi_cif *cif;
+ double temp;
+
+ cif = closure->cif;
+ avalue = alloca(cif->nargs * sizeof(void *));
+
+ /* Copy the caller's structure return value address so that the closure
+ returns the data directly to the caller. */
+ if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG)
+ {
+ rvalue = *pgr++;
+ ireg = 1;
+ }
+ else
+ ireg = 0;
+
+ cif = closure->cif;
+ greg = ireg;
+ avn = cif->nargs;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ if (greg++ >= NGREGARG)
+ continue;
+
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ avalue[i] = (((char *)pgr) + OFS_INT8);
+ break;
+
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ avalue[i] = (((char *)pgr) + OFS_INT16);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ avalue[i] = pgr;
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ pgr++;
+ }
+ else if (z == sizeof(int))
+ {
+#if defined(__SH4__)
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg++ >= NFREGARG)
+ continue;
+ avalue[i] = pfr;
+ pfr++;
+ }
+ else
+#endif
+ {
+ if (greg++ >= NGREGARG)
+ continue;
+ avalue[i] = pgr;
+ pgr++;
+ }
+ }
+#if defined(__SH4__)
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 >= NFREGARG)
+ continue;
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ avalue[i] = pfr;
+ pfr += 2;
+ }
+#endif
+ else
+ {
+ int n = (z + sizeof (int) - 1) / sizeof (int);
+#if defined(__SH4__)
+ if (greg + n - 1 >= NGREGARG)
+ continue;
+ greg += n;
+#else
+ if (greg >= NGREGARG)
+ continue;
+ else if (greg + n - 1 >= NGREGARG)
+ greg = NGREGARG;
+ else
+ greg += n;
+#endif
+ avalue[i] = pgr;
+ pgr += n;
+ }
+ }
+
+ greg = ireg;
+#if defined(__SH4__)
+ freg = 0;
+#endif
+
+ for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ if (greg++ < NGREGARG)
+ continue;
+
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ avalue[i] = (((char *)pst) + OFS_INT8);
+ break;
+
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ avalue[i] = (((char *)pst) + OFS_INT16);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ avalue[i] = pst;
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ pst++;
+ }
+ else if (z == sizeof(int))
+ {
+#if defined(__SH4__)
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg++ < NFREGARG)
+ continue;
+ }
+ else
+#endif
+ {
+ if (greg++ < NGREGARG)
+ continue;
+ }
+ avalue[i] = pst;
+ pst++;
+ }
+#if defined(__SH4__)
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 < NFREGARG)
+ {
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ continue;
+ }
+ avalue[i] = pst;
+ pst += 2;
+ }
+#endif
+ else
+ {
+ int n = (z + sizeof (int) - 1) / sizeof (int);
+ if (greg + n - 1 < NGREGARG)
+ {
+ greg += n;
+ continue;
+ }
+#if (! defined(__SH4__))
+ else if (greg < NGREGARG)
+ {
+ greg = NGREGARG;
+ continue;
+ }
+#endif
+ avalue[i] = pst;
+ pst += n;
+ }
+ }
+
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_SYSV how to perform return type promotions. */
+ return return_type (cif->rtype);
+}
diff --git a/libffi/src/sh/ffitarget.h b/libffi/src/sh/ffitarget.h
new file mode 100644
index 0000000..f8492a1
--- /dev/null
+++ b/libffi/src/sh/ffitarget.h
@@ -0,0 +1,48 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for SuperH.
+
+ 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
+
+/* ---- Generic type definitions ----------------------------------------- */
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_DEFAULT_ABI = FFI_SYSV,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 16
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/sh/sysv.S b/libffi/src/sh/sysv.S
new file mode 100644
index 0000000..a7121c5
--- /dev/null
+++ b/libffi/src/sh/sysv.S
@@ -0,0 +1,775 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 2002, 2003 Kaz Kojima
+
+ SuperH 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>
+#ifdef HAVE_MACHINE_ASM_H
+#include <machine/asm.h>
+#else
+/* XXX these lose for some platforms, I'm sure. */
+#define CNAME(x) x
+#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
+#endif
+
+#if defined(__HITACHI__)
+#define STRUCT_VALUE_ADDRESS_WITH_ARG 1
+#else
+#define STRUCT_VALUE_ADDRESS_WITH_ARG 0
+#endif
+
+.text
+
+ # r4: ffi_prep_args
+ # r5: &ecif
+ # r6: bytes
+ # r7: flags
+ # sp+0: rvalue
+ # sp+4: fn
+
+ # This assumes we are using gas.
+ENTRY(ffi_call_SYSV)
+ # Save registers
+.LFB1:
+ mov.l r8,@-r15
+.LCFI0:
+ mov.l r9,@-r15
+.LCFI1:
+ mov.l r10,@-r15
+.LCFI2:
+ mov.l r12,@-r15
+.LCFI3:
+ mov.l r14,@-r15
+.LCFI4:
+ sts.l pr,@-r15
+.LCFI5:
+ mov r15,r14
+.LCFI6:
+#if defined(__SH4__)
+ mov r6,r8
+ mov r7,r9
+
+ sub r6,r15
+ add #-16,r15
+ mov #~7,r0
+ and r0,r15
+
+ mov r4,r0
+ jsr @r0
+ mov r15,r4
+
+ mov r9,r1
+ shlr8 r9
+ shlr8 r9
+ shlr8 r9
+
+ mov #FFI_TYPE_STRUCT,r2
+ cmp/eq r2,r9
+ bf 1f
+#if STRUCT_VALUE_ADDRESS_WITH_ARG
+ mov.l @r15+,r4
+ bra 2f
+ mov #5,r2
+#else
+ mov.l @r15+,r10
+#endif
+1:
+ mov #4,r2
+2:
+ mov #4,r3
+
+L_pass:
+ cmp/pl r8
+ bf L_call_it
+
+ mov r1,r0
+ and #3,r0
+
+L_pass_d:
+ cmp/eq #FFI_TYPE_DOUBLE,r0
+ bf L_pass_f
+
+ mov r3,r0
+ and #1,r0
+ tst r0,r0
+ bt 1f
+ add #1,r3
+1:
+ mov r15,r0
+ and #7,r0
+ tst r0,r0
+ bt 2f
+ add #4,r15
+2:
+ mov #12,r0
+ cmp/hs r0,r3
+ bt/s 3f
+ shlr2 r1
+ bsr L_pop_d
+ nop
+3:
+ add #2,r3
+ bra L_pass
+ add #-8,r8
+
+L_pop_d:
+ mov r3,r0
+ add r0,r0
+ add r3,r0
+ add #-12,r0
+ braf r0
+ nop
+#ifdef __LITTLE_ENDIAN__
+ fmov.s @r15+,fr5
+ rts
+ fmov.s @r15+,fr4
+ fmov.s @r15+,fr7
+ rts
+ fmov.s @r15+,fr6
+ fmov.s @r15+,fr9
+ rts
+ fmov.s @r15+,fr8
+ fmov.s @r15+,fr11
+ rts
+ fmov.s @r15+,fr10
+#else
+ fmov.s @r15+,fr4
+ rts
+ fmov.s @r15+,fr5
+ fmov.s @r15+,fr6
+ rts
+ fmov.s @r15+,fr7
+ fmov.s @r15+,fr8
+ rts
+ fmov.s @r15+,fr9
+ fmov.s @r15+,fr10
+ rts
+ fmov.s @r15+,fr11
+#endif
+
+L_pass_f:
+ cmp/eq #FFI_TYPE_FLOAT,r0
+ bf L_pass_i
+
+ mov #12,r0
+ cmp/hs r0,r3
+ bt/s 2f
+ shlr2 r1
+ bsr L_pop_f
+ nop
+2:
+ add #1,r3
+ bra L_pass
+ add #-4,r8
+
+L_pop_f:
+ mov r3,r0
+ shll2 r0
+ add #-16,r0
+ braf r0
+ nop
+#ifdef __LITTLE_ENDIAN__
+ rts
+ fmov.s @r15+,fr5
+ rts
+ fmov.s @r15+,fr4
+ rts
+ fmov.s @r15+,fr7
+ rts
+ fmov.s @r15+,fr6
+ rts
+ fmov.s @r15+,fr9
+ rts
+ fmov.s @r15+,fr8
+ rts
+ fmov.s @r15+,fr11
+ rts
+ fmov.s @r15+,fr10
+#else
+ rts
+ fmov.s @r15+,fr4
+ rts
+ fmov.s @r15+,fr5
+ rts
+ fmov.s @r15+,fr6
+ rts
+ fmov.s @r15+,fr7
+ rts
+ fmov.s @r15+,fr8
+ rts
+ fmov.s @r15+,fr9
+ rts
+ fmov.s @r15+,fr10
+ rts
+ fmov.s @r15+,fr11
+#endif
+
+L_pass_i:
+ cmp/eq #FFI_TYPE_INT,r0
+ bf L_call_it
+
+ mov #8,r0
+ cmp/hs r0,r2
+ bt/s 2f
+ shlr2 r1
+ bsr L_pop_i
+ nop
+2:
+ add #1,r2
+ bra L_pass
+ add #-4,r8
+
+L_pop_i:
+ mov r2,r0
+ shll2 r0
+ add #-16,r0
+ braf r0
+ nop
+ rts
+ mov.l @r15+,r4
+ rts
+ mov.l @r15+,r5
+ rts
+ mov.l @r15+,r6
+ rts
+ mov.l @r15+,r7
+
+L_call_it:
+ # call function
+#if (! STRUCT_VALUE_ADDRESS_WITH_ARG)
+ mov r10, r2
+#endif
+ mov.l @(28,r14),r1
+ jsr @r1
+ nop
+
+L_ret_d:
+ mov #FFI_TYPE_DOUBLE,r2
+ cmp/eq r2,r9
+ bf L_ret_ll
+
+ mov.l @(24,r14),r1
+#ifdef __LITTLE_ENDIAN__
+ fmov.s fr1,@r1
+ add #4,r1
+ bra L_epilogue
+ fmov.s fr0,@r1
+#else
+ fmov.s fr0,@r1
+ add #4,r1
+ bra L_epilogue
+ fmov.s fr1,@r1
+#endif
+
+L_ret_ll:
+ mov #FFI_TYPE_SINT64,r2
+ cmp/eq r2,r9
+ bt/s 1f
+ mov #FFI_TYPE_UINT64,r2
+ cmp/eq r2,r9
+ bf L_ret_f
+
+1:
+ mov.l @(24,r14),r2
+ mov.l r0,@r2
+ bra L_epilogue
+ mov.l r1,@(4,r2)
+
+L_ret_f:
+ mov #FFI_TYPE_FLOAT,r2
+ cmp/eq r2,r9
+ bf L_ret_i
+
+ mov.l @(24,r14),r1
+ bra L_epilogue
+ fmov.s fr0,@r1
+
+L_ret_i:
+ mov #FFI_TYPE_INT,r2
+ cmp/eq r2,r9
+ bf L_epilogue
+
+ mov.l @(24,r14),r1
+ bra L_epilogue
+ mov.l r0,@r1
+
+L_epilogue:
+ # Remove the space we pushed for the args
+ mov r14,r15
+
+ lds.l @r15+,pr
+ mov.l @r15+,r14
+ mov.l @r15+,r12
+ mov.l @r15+,r10
+ mov.l @r15+,r9
+ rts
+ mov.l @r15+,r8
+#else
+ mov r6,r8
+ mov r7,r9
+
+ sub r6,r15
+ add #-16,r15
+ mov #~7,r0
+ and r0,r15
+
+ mov r4,r0
+ jsr @r0
+ mov r15,r4
+
+ mov r9,r3
+ shlr8 r9
+ shlr8 r9
+ shlr8 r9
+
+ mov #FFI_TYPE_STRUCT,r2
+ cmp/eq r2,r9
+ bf 1f
+#if STRUCT_VALUE_ADDRESS_WITH_ARG
+ mov.l @r15+,r4
+ bra 2f
+ mov #5,r2
+#else
+ mov.l @r15+,r10
+#endif
+1:
+ mov #4,r2
+2:
+
+L_pass:
+ cmp/pl r8
+ bf L_call_it
+
+ mov r3,r0
+ and #3,r0
+
+L_pass_d:
+ cmp/eq #FFI_TYPE_DOUBLE,r0
+ bf L_pass_i
+
+ mov r15,r0
+ and #7,r0
+ tst r0,r0
+ bt 1f
+ add #4,r15
+1:
+ mov #8,r0
+ cmp/hs r0,r2
+ bt/s 2f
+ shlr2 r3
+ bsr L_pop_d
+ nop
+2:
+ add #2,r2
+ bra L_pass
+ add #-8,r8
+
+L_pop_d:
+ mov r2,r0
+ add r0,r0
+ add r2,r0
+ add #-12,r0
+ add r0,r0
+ braf r0
+ nop
+ mov.l @r15+,r4
+ rts
+ mov.l @r15+,r5
+ mov.l @r15+,r5
+ rts
+ mov.l @r15+,r6
+ mov.l @r15+,r6
+ rts
+ mov.l @r15+,r7
+ rts
+ mov.l @r15+,r7
+
+L_pass_i:
+ mov #8,r0
+ cmp/hs r0,r2
+ bt/s 2f
+ shlr2 r3
+ bsr L_pop_i
+ nop
+2:
+ add #1,r2
+ bra L_pass
+ add #-4,r8
+
+L_pop_i:
+ mov r2,r0
+ shll2 r0
+ add #-16,r0
+ braf r0
+ nop
+ rts
+ mov.l @r15+,r4
+ rts
+ mov.l @r15+,r5
+ rts
+ mov.l @r15+,r6
+ rts
+ mov.l @r15+,r7
+
+L_call_it:
+ # call function
+#if (! STRUCT_VALUE_ADDRESS_WITH_ARG)
+ mov r10, r2
+#endif
+ mov.l @(28,r14),r1
+ jsr @r1
+ nop
+
+L_ret_d:
+ mov #FFI_TYPE_DOUBLE,r2
+ cmp/eq r2,r9
+ bf L_ret_ll
+
+ mov.l @(24,r14),r2
+ mov.l r0,@r2
+ bra L_epilogue
+ mov.l r1,@(4,r2)
+
+L_ret_ll:
+ mov #FFI_TYPE_SINT64,r2
+ cmp/eq r2,r9
+ bt/s 1f
+ mov #FFI_TYPE_UINT64,r2
+ cmp/eq r2,r9
+ bf L_ret_i
+
+1:
+ mov.l @(24,r14),r2
+ mov.l r0,@r2
+ bra L_epilogue
+ mov.l r1,@(4,r2)
+
+L_ret_i:
+ mov #FFI_TYPE_FLOAT,r2
+ cmp/eq r2,r9
+ bt 1f
+ mov #FFI_TYPE_INT,r2
+ cmp/eq r2,r9
+ bf L_epilogue
+1:
+ mov.l @(24,r14),r1
+ bra L_epilogue
+ mov.l r0,@r1
+
+L_epilogue:
+ # Remove the space we pushed for the args
+ mov r14,r15
+
+ lds.l @r15+,pr
+ mov.l @r15+,r14
+ mov.l @r15+,r12
+ mov.l @r15+,r10
+ mov.l @r15+,r9
+ rts
+ mov.l @r15+,r8
+#endif
+.LFE1:
+.ffi_call_SYSV_end:
+ .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
+
+.globl ffi_closure_helper_SYSV
+
+ENTRY(ffi_closure_SYSV)
+.LFB2:
+ mov.l r14,@-r15
+.LCFI7:
+ sts.l pr,@-r15
+
+ /* Stack layout:
+ ...
+ 32 bytes (floating register parameters, SH-4 only)
+ 16 bytes (register parameters)
+ 8 bytes (result)
+ 4 bytes (pad)
+ 4 bytes (5th arg)
+ <- new stack pointer
+ */
+.LCFI8:
+#if defined(__SH4__)
+ add #-64,r15
+#else
+ add #-32,r15
+#endif
+.LCFI9:
+ mov r15,r14
+.LCFIA:
+ mov r14,r1
+ add #32,r1
+ mov.l r7,@-r1
+ mov.l r6,@-r1
+ mov.l r5,@-r1
+ mov.l r4,@-r1
+ mov r1,r6
+
+#if defined(__SH4__)
+ mov r14,r1
+ add #64,r1
+#ifdef __LITTLE_ENDIAN__
+ fmov.s fr10,@-r1
+ fmov.s fr11,@-r1
+ fmov.s fr8,@-r1
+ fmov.s fr9,@-r1
+ fmov.s fr6,@-r1
+ fmov.s fr7,@-r1
+ fmov.s fr4,@-r1
+ fmov.s fr5,@-r1
+#else
+ fmov.s fr11,@-r1
+ fmov.s fr10,@-r1
+ fmov.s fr9,@-r1
+ fmov.s fr8,@-r1
+ fmov.s fr7,@-r1
+ fmov.s fr6,@-r1
+ fmov.s fr5,@-r1
+ fmov.s fr4,@-r1
+#endif
+ mov r1,r7
+#endif
+
+ mov r14,r1
+ add #8,r1
+ mov r1,r5
+
+ mov r14,r1
+#if defined(__SH4__)
+ add #72,r1
+#else
+ add #40,r1
+#endif
+ mov.l r1,@r14
+
+ mov.l L_helper,r0
+ jsr @r0
+ mov r3,r4
+
+ shll r0
+ mov r0,r1
+ mova L_table,r0
+ add r1,r0
+ mov.w @r0,r0
+ mov r14,r2
+ braf r0
+ add #8,r2
+0:
+ .align 2
+L_helper:
+ .long ffi_closure_helper_SYSV
+L_table:
+ .short L_case_v - 0b /* FFI_TYPE_VOID */
+ .short L_case_i - 0b /* FFI_TYPE_INT */
+#if defined(__SH4__)
+ .short L_case_f - 0b /* FFI_TYPE_FLOAT */
+ .short L_case_d - 0b /* FFI_TYPE_DOUBLE */
+ .short L_case_d - 0b /* FFI_TYPE_LONGDOUBLE */
+#else
+ .short L_case_i - 0b /* FFI_TYPE_FLOAT */
+ .short L_case_ll - 0b /* FFI_TYPE_DOUBLE */
+ .short L_case_ll - 0b /* FFI_TYPE_LONGDOUBLE */
+#endif
+ .short L_case_uq - 0b /* FFI_TYPE_UINT8 */
+ .short L_case_q - 0b /* FFI_TYPE_SINT8 */
+ .short L_case_uh - 0b /* FFI_TYPE_UINT16 */
+ .short L_case_h - 0b /* FFI_TYPE_SINT16 */
+ .short L_case_i - 0b /* FFI_TYPE_UINT32 */
+ .short L_case_i - 0b /* FFI_TYPE_SINT32 */
+ .short L_case_ll - 0b /* FFI_TYPE_UINT64 */
+ .short L_case_ll - 0b /* FFI_TYPE_SINT64 */
+ .short L_case_v - 0b /* FFI_TYPE_STRUCT */
+ .short L_case_i - 0b /* FFI_TYPE_POINTER */
+
+#if defined(__SH4__)
+L_case_d:
+#ifdef __LITTLE_ENDIAN__
+ fmov.s @r2+,fr1
+ bra L_case_v
+ fmov.s @r2,fr0
+#else
+ fmov.s @r2+,fr0
+ bra L_case_v
+ fmov.s @r2,fr1
+#endif
+
+L_case_f:
+ bra L_case_v
+ fmov.s @r2,fr0
+#endif
+
+L_case_ll:
+ mov.l @r2+,r0
+ bra L_case_v
+ mov.l @r2,r1
+
+L_case_i:
+ bra L_case_v
+ mov.l @r2,r0
+
+L_case_q:
+#ifdef __LITTLE_ENDIAN__
+#else
+ add #3,r2
+#endif
+ bra L_case_v
+ mov.b @r2,r0
+
+L_case_uq:
+#ifdef __LITTLE_ENDIAN__
+#else
+ add #3,r2
+#endif
+ mov.b @r2,r0
+ bra L_case_v
+ extu.b r0,r0
+
+L_case_h:
+#ifdef __LITTLE_ENDIAN__
+#else
+ add #2,r2
+#endif
+ bra L_case_v
+ mov.w @r2,r0
+
+L_case_uh:
+#ifdef __LITTLE_ENDIAN__
+#else
+ add #2,r2
+#endif
+ mov.w @r2,r0
+ extu.w r0,r0
+ /* fall through */
+
+L_case_v:
+#if defined(__SH4__)
+ add #64,r15
+#else
+ add #32,r15
+#endif
+ lds.l @r15+,pr
+ rts
+ mov.l @r15+,r14
+.LFE2:
+.ffi_closure_SYSV_end:
+ .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
+
+ .section ".eh_frame","aw",@progbits
+__FRAME_BEGIN__:
+ .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
+.LSCIE1:
+ .4byte 0x0 /* CIE Identifier Tag */
+ .byte 0x1 /* CIE Version */
+ .byte 0x0 /* CIE Augmentation */
+ .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
+ .byte 0x7c /* sleb128 -4; CIE Data Alignment Factor */
+ .byte 0x11 /* CIE RA Column */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .byte 0xf /* uleb128 0xf */
+ .byte 0x0 /* uleb128 0x0 */
+ .align 2
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 /* FDE Length */
+.LASFDE1:
+ .4byte .LASFDE1-__FRAME_BEGIN__ /* FDE CIE offset */
+ .4byte .LFB1 /* FDE initial location */
+ .4byte .LFE1-.LFB1 /* FDE address range */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI0-.LFB1
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x4 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI1-.LCFI0
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x8 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI2-.LCFI1
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0xc /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI3-.LCFI2
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x10 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI4-.LCFI3
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x14 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI5-.LCFI4
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x18 /* uleb128 0x4 */
+ .byte 0x91 /* DW_CFA_offset, column 0x11 */
+ .byte 0x6 /* uleb128 0x6 */
+ .byte 0x8e /* DW_CFA_offset, column 0xe */
+ .byte 0x5 /* uleb128 0x5 */
+ .byte 0x8c /* DW_CFA_offset, column 0xc */
+ .byte 0x4 /* uleb128 0x4 */
+ .byte 0x8a /* DW_CFA_offset, column 0xa */
+ .byte 0x3 /* uleb128 0x3 */
+ .byte 0x89 /* DW_CFA_offset, column 0x9 */
+ .byte 0x2 /* uleb128 0x2 */
+ .byte 0x88 /* DW_CFA_offset, column 0x8 */
+ .byte 0x1 /* uleb128 0x1 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI6-.LCFI5
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0xe /* uleb128 0xe */
+ .align 2
+.LEFDE1:
+
+.LSFDE3:
+ .4byte .LEFDE3-.LASFDE3 /* FDE Length */
+.LASFDE3:
+ .4byte .LASFDE3-__FRAME_BEGIN__ /* FDE CIE offset */
+ .4byte .LFB2 /* FDE initial location */
+ .4byte .LFE2-.LFB2 /* FDE address range */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI7-.LFB2
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x4 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI8-.LCFI7
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x8 /* uleb128 0x8 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI9-.LCFI8
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+#if defined(__SH4__)
+ .byte 8+64 /* uleb128 8+64 */
+#else
+ .byte 8+32 /* uleb128 8+32 */
+#endif
+ .byte 0x91 /* DW_CFA_offset, column 0x11 */
+ .byte 0x2
+ .byte 0x8e /* DW_CFA_offset, column 0xe */
+ .byte 0x1
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFIA-.LCFI9
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0xe /* uleb128 0xe */
+ .align 2
+.LEFDE3:
diff --git a/libffi/src/sh64/ffi.c b/libffi/src/sh64/ffi.c
new file mode 100644
index 0000000..7709603
--- /dev/null
+++ b/libffi/src/sh64/ffi.c
@@ -0,0 +1,448 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2003 Kaz Kojima
+
+ SuperH SHmedia 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 NGREGARG 8
+#define NFREGARG 12
+
+/* If the structure has essentialy an unique element, return its type. */
+static int
+simple_type (ffi_type *arg)
+{
+ if (arg->type != FFI_TYPE_STRUCT)
+ return arg->type;
+ else if (arg->elements[1])
+ return FFI_TYPE_STRUCT;
+
+ return simple_type (arg->elements[0]);
+}
+
+static int
+return_type (ffi_type *arg)
+{
+ unsigned short type;
+
+ if (arg->type != FFI_TYPE_STRUCT)
+ return arg->type;
+
+ type = simple_type (arg->elements[0]);
+ if (! arg->elements[1])
+ {
+ 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_SINT64:
+ case FFI_TYPE_UINT64:
+ return FFI_TYPE_UINT64;
+
+ default:
+ return type;
+ }
+ }
+
+ /* gcc uses r2 if the result can be packed in on register. */
+ if (arg->size <= sizeof (UINT64))
+ return FFI_TYPE_UINT64;
+
+ return FFI_TYPE_STRUCT;
+}
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+/*@-exportheader@*/
+void ffi_prep_args(char *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+ register unsigned int i;
+ register unsigned int avn;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ argp = stack;
+
+ if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
+ {
+ *(void **) argp = ecif->rvalue;
+ argp += sizeof (UINT64);
+ }
+
+ avn = ecif->cif->nargs;
+ p_argv = ecif->avalue;
+
+ for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof (UINT32))
+ {
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ *(UINT64 *) argp = (UINT64) *(UINT32 *)(*p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ argp += sizeof (UINT64);
+ }
+ else if (z == sizeof (UINT32))
+ {
+ *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
+ argp += sizeof (UINT64);
+ }
+ else if (z == sizeof (UINT64))
+ {
+ *(UINT64 *) argp = *(UINT64 *) (*p_argv);
+ argp += sizeof (UINT64);
+ }
+ else
+ {
+ int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
+
+ memcpy (argp, *p_argv, z);
+ argp += n * sizeof (UINT64);
+ }
+ }
+
+ return;
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ int i, j;
+ int size, type;
+ int n, m;
+ int greg;
+ int freg;
+
+ greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
+ freg = 0;
+ cif->flags2 = 0;
+
+ for (i = j = 0; i < cif->nargs; i++)
+ {
+ type = (cif->arg_types)[i]->type;
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT:
+ greg++;
+ cif->bytes += sizeof (UINT64) - sizeof (float);
+ if (freg >= NFREGARG - 1)
+ continue;
+ freg++;
+ cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
+ continue;
+ if ((freg + 1) < NFREGARG)
+ {
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
+ }
+ else
+ cif->flags2 += FFI_TYPE_INT << (2 * j++);
+ break;
+
+ default:
+ size = (cif->arg_types)[i]->size;
+ if (size < sizeof (UINT64))
+ cif->bytes += sizeof (UINT64) - size;
+ n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
+ if (greg >= NGREGARG)
+ continue;
+ else if (greg + n - 1 >= NGREGARG)
+ greg = NGREGARG;
+ else
+ greg += n;
+ for (m = 0; m < n; m++)
+ cif->flags2 += FFI_TYPE_INT << (2 * j++);
+ break;
+ }
+ }
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_STRUCT:
+ cif->flags = return_type (cif->rtype);
+ break;
+
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ cif->flags = cif->rtype->type;
+ break;
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ break;
+ }
+
+ return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned, long long,
+ /*@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_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, cif->flags2, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+extern void ffi_closure_SYSV (void);
+extern void __ic_invalidate (void *line);
+
+ffi_status
+ffi_prep_closure (ffi_closure *closure,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data)
+{
+ unsigned int *tramp;
+
+ FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
+
+ tramp = (unsigned int *) &closure->tramp[0];
+ /* Since ffi_closure is an aligned object, the ffi trampoline is
+ called as an SHcompact code. Sigh.
+ SHcompact part:
+ mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
+ SHmedia part:
+ movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
+ movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
+#ifdef __LITTLE_ENDIAN__
+ tramp[0] = 0x7001c701;
+ tramp[1] = 0x0009402b;
+#else
+ tramp[0] = 0xc7017001;
+ tramp[1] = 0x402b0009;
+#endif
+ tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
+ tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
+ tramp[4] = 0x6bf10600;
+ tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
+ tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
+ tramp[7] = 0x4401fff0;
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ /* Flush the icache. */
+ asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
+
+ return FFI_OK;
+}
+
+/* Basically the trampoline invokes ffi_closure_SYSV, and on
+ * entry, r3 holds the address of the closure.
+ * After storing the registers that could possibly contain
+ * parameters to be passed into the stack frame and setting
+ * up space for a return value, ffi_closure_SYSV invokes the
+ * following helper function to do most of the work.
+ */
+
+int
+ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
+ UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
+{
+ void **avalue;
+ ffi_type **p_arg;
+ int i, avn;
+ int greg, freg;
+ ffi_cif *cif;
+
+ cif = closure->cif;
+ avalue = alloca (cif->nargs * sizeof (void *));
+
+ /* Copy the caller's structure return value address so that the closure
+ returns the data directly to the caller. */
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ rvalue = *pgr;
+ greg = 1;
+ }
+ else
+ greg = 0;
+
+ freg = 0;
+ cif = closure->cif;
+ avn = cif->nargs;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
+ {
+ size_t z;
+ void *p;
+
+ z = (*p_arg)->size;
+ if (z < sizeof (UINT32))
+ {
+ p = pgr + greg++;
+
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_STRUCT:
+#ifdef __LITTLE_ENDIAN__
+ avalue[i] = p;
+#else
+ avalue[i] = ((char *) p) + sizeof (UINT32) - z;
+#endif
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ }
+ else if (z == sizeof (UINT32))
+ {
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg < NFREGARG - 1)
+#ifdef __LITTLE_ENDIAN__
+ avalue[i] = (UINT32 *) pfr + (1 ^ freg++);
+#else
+ avalue[i] = (UINT32 *) pfr + freg++;
+#endif
+ else
+#ifdef __LITTLE_ENDIAN__
+ avalue[i] = pgr + greg;
+#else
+ avalue[i] = (UINT32 *) (pgr + greg) + 1;
+#endif
+ }
+ else
+#ifdef __LITTLE_ENDIAN__
+ avalue[i] = pgr + greg;
+#else
+ avalue[i] = (UINT32 *) (pgr + greg) + 1;
+#endif
+ greg++;
+ }
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 >= NFREGARG)
+ avalue[i] = pgr + greg;
+ else
+ {
+ freg = (freg + 1) & ~1;
+ avalue[i] = pfr + (freg >> 1);
+ freg += 2;
+ }
+ greg++;
+ }
+ else
+ {
+ int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
+
+ avalue[i] = pgr + greg;
+ greg += n;
+ }
+ }
+
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_SYSV how to perform return type promotions. */
+ return cif->rtype->type;
+}
+
diff --git a/libffi/src/sh64/ffitarget.h b/libffi/src/sh64/ffitarget.h
new file mode 100644
index 0000000..a174d09
--- /dev/null
+++ b/libffi/src/sh64/ffitarget.h
@@ -0,0 +1,52 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for SuperH - SHmedia.
+
+ 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
+
+/* ---- Generic type definitions ----------------------------------------- */
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_DEFAULT_ABI = FFI_SYSV,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+
+#define FFI_EXTRA_CIF_FIELDS long long flags2
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 32
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/sh64/sysv.S b/libffi/src/sh64/sysv.S
new file mode 100644
index 0000000..949f69f
--- /dev/null
+++ b/libffi/src/sh64/sysv.S
@@ -0,0 +1,484 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 2003 Kaz Kojima
+
+ SuperH SHmedia 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>
+#ifdef HAVE_MACHINE_ASM_H
+#include <machine/asm.h>
+#else
+/* XXX these lose for some platforms, I'm sure. */
+#define CNAME(x) x
+#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
+#endif
+
+#ifdef __LITTLE_ENDIAN__
+#define OFS_FLT 0
+#else
+#define OFS_FLT 4
+#endif
+
+ .section .text..SHmedia32,"ax"
+
+ # r2: ffi_prep_args
+ # r3: &ecif
+ # r4: bytes
+ # r5: flags
+ # r6: flags2
+ # r7: rvalue
+ # r8: fn
+
+ # This assumes we are using gas.
+ .align 5
+ENTRY(ffi_call_SYSV)
+ # Save registers
+.LFB1:
+ addi.l r15, -48, r15
+.LCFI0:
+ st.q r15, 40, r32
+ st.q r15, 32, r31
+ st.q r15, 24, r30
+ st.q r15, 16, r29
+ st.q r15, 8, r28
+ st.l r15, 4, r18
+ st.l r15, 0, r14
+ add.l r15, r63, r14
+.LCFI1:
+# add r4, r63, r28
+ add r5, r63, r29
+ add r6, r63, r30
+ add r7, r63, r31
+ add r8, r63, r32
+
+ addi r4, (64 + 7), r4
+ andi r4, ~7, r4
+ sub.l r15, r4, r15
+
+ ptabs/l r2, tr0
+ add r15, r63, r2
+ blink tr0, r18
+
+ addi r15, 64, r22
+ movi 0, r0
+ movi 0, r1
+
+ pt/l 1f, tr1
+ bnei/l r29, FFI_TYPE_STRUCT, tr1
+ ld.l r15, 0, r19
+ addi r15, 8, r15
+ addi r0, 1, r0
+1:
+
+.L_pass:
+ andi r30, 3, r20
+ shlri r30, 2, r30
+
+ pt/l .L_call_it, tr0
+ pt/l .L_pass_i, tr1
+ pt/l .L_pass_f, tr2
+
+ beqi/l r20, FFI_TYPE_VOID, tr0
+ beqi/l r20, FFI_TYPE_INT, tr1
+ beqi/l r20, FFI_TYPE_FLOAT, tr2
+
+.L_pass_d:
+ addi r0, 1, r0
+ addi r1, 1, r1
+ andi r1, ~1, r1
+
+ pt/l 3f, tr0
+ movi 12, r20
+ bge/l r1, r20, tr0
+
+ pt/l .L_pop_d, tr1
+ pt/l 2f, tr0
+ blink tr1, r63
+2:
+ addi.l r15, 8, r15
+3:
+ pt/l .L_pass, tr0
+ addi r1, 2, r1
+ blink tr0, r63
+
+.L_pop_d:
+ pt/l .L_pop_d_tbl, tr1
+ gettr tr1, r20
+ shlli r1, 2, r21
+ add r20, r21, r20
+ ptabs/l r20, tr1
+ blink tr1, r63
+
+.L_pop_d_tbl:
+ fld.d r15, 0, dr0
+ blink tr0, r63
+ fld.d r15, 0, dr2
+ blink tr0, r63
+ fld.d r15, 0, dr4
+ blink tr0, r63
+ fld.d r15, 0, dr6
+ blink tr0, r63
+ fld.d r15, 0, dr8
+ blink tr0, r63
+ fld.d r15, 0, dr10
+ blink tr0, r63
+
+.L_pass_f:
+ addi r0, 1, r0
+ pt/l 3f, tr0
+ movi 12, r20
+ bge/l r1, r20, tr0
+
+ pt/l .L_pop_f, tr1
+ pt/l 2f, tr0
+ blink tr1, r63
+2:
+ addi.l r15, 8, r15
+3:
+ pt/l .L_pass, tr0
+ addi r1, 1, r1
+ blink tr0, r63
+
+.L_pop_f:
+ pt/l .L_pop_f_tbl, tr1
+ gettr tr1, r20
+ shlli r1, 3, r21
+ add r20, r21, r20
+ ptabs/l r20, tr1
+ blink tr1, r63
+
+.L_pop_f_tbl:
+ fld.s r15, OFS_FLT, fr0
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr1
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr2
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr3
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr4
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr5
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr6
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr7
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr8
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr9
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr10
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr11
+ blink tr0, r63
+
+.L_pass_i:
+ pt/l 3f, tr0
+ movi 8, r20
+ bge/l r0, r20, tr0
+
+ pt/l .L_pop_i, tr1
+ pt/l 2f, tr0
+ blink tr1, r63
+2:
+ addi.l r15, 8, r15
+3:
+ pt/l .L_pass, tr0
+ addi r0, 1, r0
+ blink tr0, r63
+
+.L_pop_i:
+ pt/l .L_pop_i_tbl, tr1
+ gettr tr1, r20
+ shlli r0, 3, r21
+ add r20, r21, r20
+ ptabs/l r20, tr1
+ blink tr1, r63
+
+.L_pop_i_tbl:
+ ld.q r15, 0, r2
+ blink tr0, r63
+ ld.q r15, 0, r3
+ blink tr0, r63
+ ld.q r15, 0, r4
+ blink tr0, r63
+ ld.q r15, 0, r5
+ blink tr0, r63
+ ld.q r15, 0, r6
+ blink tr0, r63
+ ld.q r15, 0, r7
+ blink tr0, r63
+ ld.q r15, 0, r8
+ blink tr0, r63
+ ld.q r15, 0, r9
+ blink tr0, r63
+
+.L_call_it:
+ # call function
+ pt/l 1f, tr1
+ bnei/l r29, FFI_TYPE_STRUCT, tr1
+ add r19, r63, r2
+1:
+ add r22, r63, r15
+ ptabs/l r32, tr0
+ blink tr0, r18
+
+ pt/l .L_ret_i, tr0
+ pt/l .L_ret_ll, tr1
+ pt/l .L_ret_d, tr2
+ pt/l .L_ret_f, tr3
+ pt/l .L_epilogue, tr4
+
+ beqi/l r29, FFI_TYPE_INT, tr0
+ beqi/l r29, FFI_TYPE_SINT64, tr1
+ beqi/l r29, FFI_TYPE_UINT64, tr1
+ beqi/l r29, FFI_TYPE_DOUBLE, tr2
+ beqi/l r29, FFI_TYPE_FLOAT, tr3
+ blink tr4, r63
+
+.L_ret_d:
+ fst.d r31, 0, dr0
+ blink tr4, r63
+
+.L_ret_ll:
+ st.q r31, 0, r2
+ blink tr4, r63
+
+.L_ret_f:
+ fst.s r31, OFS_FLT, fr0
+ blink tr4, r63
+
+.L_ret_i:
+ st.l r31, 0, r2
+ # Fall
+
+.L_epilogue:
+ # Remove the space we pushed for the args
+ add r14, r63, r15
+
+ ld.l r15, 0, r14
+ ld.l r15, 4, r18
+ ld.q r15, 8, r28
+ ld.q r15, 16, r29
+ ld.q r15, 24, r30
+ ld.q r15, 32, r31
+ ld.q r15, 40, r32
+ addi.l r15, 48, r15
+ ptabs r18, tr0
+ blink tr0, r63
+
+.LFE1:
+.ffi_call_SYSV_end:
+ .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
+
+ .align 5
+ENTRY(ffi_closure_SYSV)
+.LFB2:
+ addi.l r15, -136, r15
+.LCFI2:
+ st.l r15, 12, r18
+ st.l r15, 8, r14
+ st.l r15, 4, r12
+ add r15, r63, r14
+.LCFI3:
+ /* Stack layout:
+ ...
+ 64 bytes (register parameters)
+ 48 bytes (floating register parameters)
+ 8 bytes (result)
+ 4 bytes (r18)
+ 4 bytes (r14)
+ 4 bytes (r12)
+ 4 bytes (for align)
+ <- new stack pointer
+ */
+ fst.d r14, 24, dr0
+ fst.d r14, 32, dr2
+ fst.d r14, 40, dr4
+ fst.d r14, 48, dr6
+ fst.d r14, 56, dr8
+ fst.d r14, 64, dr10
+ st.q r14, 72, r2
+ st.q r14, 80, r3
+ st.q r14, 88, r4
+ st.q r14, 96, r5
+ st.q r14, 104, r6
+ st.q r14, 112, r7
+ st.q r14, 120, r8
+ st.q r14, 128, r9
+
+ add r1, r63, r2
+ addi r14, 16, r3
+ addi r14, 72, r4
+ addi r14, 24, r5
+ addi r14, 136, r6
+#ifdef PIC
+ movi (((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) >> 16) & 65535), r12
+ shori ((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) & 65535), r12
+.LPCS0: ptrel/u r12, tr0
+ movi ((ffi_closure_helper_SYSV@GOTPLT) & 65535), r1
+ gettr tr0, r12
+ ldx.l r1, r12, r1
+ ptabs r1, tr0
+#else
+ pt/l ffi_closure_helper_SYSV, tr0
+#endif
+ blink tr0, r18
+
+ shlli r2, 1, r1
+ movi (((datalabel .L_table) >> 16) & 65535), r2
+ shori ((datalabel .L_table) & 65535), r2
+ ldx.w r2, r1, r1
+ add r1, r2, r1
+ pt/l .L_case_v, tr1
+ ptabs r1, tr0
+ blink tr0, r63
+
+ .align 2
+.L_table:
+ .word .L_case_v - datalabel .L_table /* FFI_TYPE_VOID */
+ .word .L_case_i - datalabel .L_table /* FFI_TYPE_INT */
+ .word .L_case_f - datalabel .L_table /* FFI_TYPE_FLOAT */
+ .word .L_case_d - datalabel .L_table /* FFI_TYPE_DOUBLE */
+ .word .L_case_d - datalabel .L_table /* FFI_TYPE_LONGDOUBLE */
+ .word .L_case_uq - datalabel .L_table /* FFI_TYPE_UINT8 */
+ .word .L_case_q - datalabel .L_table /* FFI_TYPE_SINT8 */
+ .word .L_case_uh - datalabel .L_table /* FFI_TYPE_UINT16 */
+ .word .L_case_h - datalabel .L_table /* FFI_TYPE_SINT16 */
+ .word .L_case_i - datalabel .L_table /* FFI_TYPE_UINT32 */
+ .word .L_case_i - datalabel .L_table /* FFI_TYPE_SINT32 */
+ .word .L_case_ll - datalabel .L_table /* FFI_TYPE_UINT64 */
+ .word .L_case_ll - datalabel .L_table /* FFI_TYPE_SINT64 */
+ .word .L_case_v - datalabel .L_table /* FFI_TYPE_STRUCT */
+ .word .L_case_i - datalabel .L_table /* FFI_TYPE_POINTER */
+
+ .align 2
+.L_case_d:
+ fld.d r14, 16, dr0
+ blink tr1, r63
+.L_case_f:
+ fld.s r14, 16, fr0
+ blink tr1, r63
+.L_case_ll:
+ ld.q r14, 16, r2
+ blink tr1, r63
+.L_case_i:
+ ld.l r14, 16, r2
+ blink tr1, r63
+.L_case_q:
+ ld.b r14, 16, r2
+ blink tr1, r63
+.L_case_uq:
+ ld.ub r14, 16, r2
+ blink tr1, r63
+.L_case_h:
+ ld.w r14, 16, r2
+ blink tr1, r63
+.L_case_uh:
+ ld.uw r14, 16, r2
+ blink tr1, r63
+.L_case_v:
+ add.l r14, r63, r15
+ ld.l r15, 4, r12
+ ld.l r15, 8, r14
+ ld.l r15, 12, r18
+ addi.l r15, 136, r15
+ ptabs r18, tr0
+ blink tr0, r63
+
+.LFE2:
+.ffi_closure_SYSV_end:
+ .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
+
+ .section ".eh_frame","aw",@progbits
+__FRAME_BEGIN__:
+ .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
+.LSCIE1:
+ .4byte 0x0 /* CIE Identifier Tag */
+ .byte 0x1 /* CIE Version */
+ .ascii "zR\0" /* CIE Augmentation */
+ .uleb128 0x1 /* CIE Code Alignment Factor */
+ .sleb128 -4 /* CIE Data Alignment Factor */
+ .byte 0x12 /* CIE RA Column */
+ .uleb128 0x1 /* Augmentation size */
+ .byte 0x1b /* FDE Encoding (pcrel sdata4) */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .uleb128 0xf
+ .uleb128 0x0
+ .align 2
+.LECIE1:
+.LSFDE1:
+ .4byte datalabel .LEFDE1-datalabel .LASFDE1 /* FDE Length */
+.LASFDE1:
+ .4byte datalabel .LASFDE1-datalabel __FRAME_BEGIN__
+ .4byte datalabel .LFB1-. /* FDE initial location */
+ .4byte datalabel .LFE1-datalabel .LFB1 /* FDE address range */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte datalabel .LCFI0-datalabel .LFB1
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .uleb128 0x30
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte datalabel .LCFI1-datalabel .LCFI0
+ .byte 0x8e /* DW_CFA_offset, column 0xe */
+ .uleb128 0xc
+ .byte 0x92 /* DW_CFA_offset, column 0x12 */
+ .uleb128 0xb
+ .byte 0x9c /* DW_CFA_offset, column 0x1c */
+ .uleb128 0xa
+ .byte 0x9d /* DW_CFA_offset, column 0x1d */
+ .uleb128 0x8
+ .byte 0x9e /* DW_CFA_offset, column 0x1e */
+ .uleb128 0x6
+ .byte 0x9f /* DW_CFA_offset, column 0x1f */
+ .uleb128 0x4
+ .byte 0xa0 /* DW_CFA_offset, column 0x20 */
+ .uleb128 0x2
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .uleb128 0xe
+ .align 2
+.LEFDE1:
+
+.LSFDE3:
+ .4byte datalabel .LEFDE3-datalabel .LASFDE3 /* FDE Length */
+.LASFDE3:
+ .4byte datalabel .LASFDE3-datalabel __FRAME_BEGIN__
+ .4byte datalabel .LFB2-. /* FDE initial location */
+ .4byte datalabel .LFE2-datalabel .LFB2 /* FDE address range */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte datalabel .LCFI2-datalabel .LFB2
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .uleb128 0x88
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte datalabel .LCFI3-datalabel .LCFI2
+ .byte 0x8c /* DW_CFA_offset, column 0xc */
+ .uleb128 0x21
+ .byte 0x8e /* DW_CFA_offset, column 0xe */
+ .uleb128 0x20
+ .byte 0x92 /* DW_CFA_offset, column 0x12 */
+ .uleb128 0x1f
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .uleb128 0xe
+ .align 2
+.LEFDE3:
diff --git a/libffi/src/sparc/ffi.c b/libffi/src/sparc/ffi.c
new file mode 100644
index 0000000..ad15bee
--- /dev/null
+++ b/libffi/src/sparc/ffi.c
@@ -0,0 +1,595 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1996, 2003, 2004 Red Hat, Inc.
+
+ SPARC 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>
+
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+void ffi_prep_args_v8(char *stack, extended_cif *ecif)
+{
+ int i;
+ void **p_argv;
+ char *argp;
+ ffi_type **p_arg;
+
+ /* Skip 16 words for the window save area */
+ argp = stack + 16*sizeof(int);
+
+ /* This should only really be done when we are returning a structure,
+ however, it's faster just to do it all the time...
+
+ if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
+ *(int *) argp = (long)ecif->rvalue;
+
+ /* And 1 word for the structure return value. */
+ argp += sizeof(int);
+
+#ifdef USING_PURIFY
+ /* Purify will probably complain in our assembly routine, unless we
+ zero out this memory. */
+
+ ((int*)argp)[0] = 0;
+ ((int*)argp)[1] = 0;
+ ((int*)argp)[2] = 0;
+ ((int*)argp)[3] = 0;
+ ((int*)argp)[4] = 0;
+ ((int*)argp)[5] = 0;
+#endif
+
+ p_argv = ecif->avalue;
+
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
+ {
+ size_t z;
+
+ if ((*p_arg)->type == FFI_TYPE_STRUCT
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
+#endif
+ )
+ {
+ *(unsigned int *) argp = (unsigned long)(* p_argv);
+ z = sizeof(int);
+ }
+ else
+ {
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = *(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = *(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = *(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = *(UINT16 *)(* p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ }
+ else
+ {
+ memcpy(argp, *p_argv, z);
+ }
+ }
+ p_argv++;
+ argp += z;
+ }
+
+ return;
+}
+
+int ffi_prep_args_v9(char *stack, extended_cif *ecif)
+{
+ int i, ret = 0;
+ int tmp;
+ void **p_argv;
+ char *argp;
+ ffi_type **p_arg;
+
+ tmp = 0;
+
+ /* Skip 16 words for the window save area */
+ argp = stack + 16*sizeof(long long);
+
+#ifdef USING_PURIFY
+ /* Purify will probably complain in our assembly routine, unless we
+ zero out this memory. */
+
+ ((long long*)argp)[0] = 0;
+ ((long long*)argp)[1] = 0;
+ ((long long*)argp)[2] = 0;
+ ((long long*)argp)[3] = 0;
+ ((long long*)argp)[4] = 0;
+ ((long long*)argp)[5] = 0;
+#endif
+
+ p_argv = ecif->avalue;
+
+ if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
+ ecif->cif->rtype->size > 32)
+ {
+ *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
+ argp += sizeof(long long);
+ tmp = 1;
+ }
+
+ for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
+ i++, p_arg++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_STRUCT:
+ if (z > 16)
+ {
+ /* For structures larger than 16 bytes we pass reference. */
+ *(unsigned long long *) argp = (unsigned long)* p_argv;
+ argp += sizeof(long long);
+ tmp++;
+ p_argv++;
+ continue;
+ }
+ /* FALLTHROUGH */
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ ret = 1; /* We should promote into FP regs as well as integer. */
+ break;
+ }
+ if (z < sizeof(long long))
+ {
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed long long *) argp = *(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed long long *) argp = *(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT32:
+ *(signed long long *) argp = *(SINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT32:
+ *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_FLOAT:
+ *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
+ break;
+
+ case FFI_TYPE_STRUCT:
+ memcpy(argp, *p_argv, z);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ z = sizeof(long long);
+ tmp++;
+ }
+ else if (z == sizeof(long long))
+ {
+ memcpy(argp, *p_argv, z);
+ z = sizeof(long long);
+ tmp++;
+ }
+ else
+ {
+ if ((tmp & 1) && (*p_arg)->alignment > 8)
+ {
+ tmp++;
+ argp += sizeof(long long);
+ }
+ memcpy(argp, *p_argv, z);
+ z = 2 * sizeof(long long);
+ tmp += 2;
+ }
+ p_argv++;
+ argp += z;
+ }
+
+ return ret;
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ int wordsize;
+
+ if (cif->abi != FFI_V9)
+ {
+ wordsize = 4;
+
+ /* If we are returning a struct, this will already have been added.
+ Otherwise we need to add it because it's always got to be there! */
+
+ if (cif->rtype->type != FFI_TYPE_STRUCT)
+ cif->bytes += wordsize;
+
+ /* sparc call frames require that space is allocated for 6 args,
+ even if they aren't used. Make that space if necessary. */
+
+ if (cif->bytes < 4*6+4)
+ cif->bytes = 4*6+4;
+ }
+ else
+ {
+ wordsize = 8;
+
+ /* sparc call frames require that space is allocated for 6 args,
+ even if they aren't used. Make that space if necessary. */
+
+ if (cif->bytes < 8*6)
+ cif->bytes = 8*6;
+ }
+
+ /* Adjust cif->bytes. to include 16 words for the window save area,
+ and maybe the struct/union return pointer area, */
+
+ cif->bytes += 16 * wordsize;
+
+ /* The stack must be 2 word aligned, so round bytes up
+ appropriately. */
+
+ cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ cif->flags = cif->rtype->type;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ if (cif->abi == FFI_V9 && cif->rtype->size > 32)
+ cif->flags = FFI_TYPE_VOID;
+ else
+ cif->flags = FFI_TYPE_STRUCT;
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ if (cif->abi != FFI_V9)
+ {
+ cif->flags = FFI_TYPE_SINT64;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ cif->flags = FFI_TYPE_INT;
+ break;
+ }
+ return FFI_OK;
+}
+
+int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
+{
+ ffi_type **ptr = &arg->elements[0];
+
+ while (*ptr != NULL)
+ {
+ if (off & ((*ptr)->alignment - 1))
+ off = ALIGN(off, (*ptr)->alignment);
+
+ switch ((*ptr)->type)
+ {
+ case FFI_TYPE_STRUCT:
+ off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
+ off = ALIGN(off, FFI_SIZEOF_ARG);
+ break;
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ memmove(ret + off, flt + off, (*ptr)->size);
+ off += (*ptr)->size;
+ break;
+ default:
+ memmove(ret + off, intg + off, (*ptr)->size);
+ off += (*ptr)->size;
+ break;
+ }
+ ptr++;
+ }
+ return off;
+}
+
+
+#ifdef SPARC64
+extern int ffi_call_v9(void *, extended_cif *, unsigned,
+ unsigned, unsigned *, void (*fn)());
+#else
+extern int ffi_call_v8(void *, extended_cif *, unsigned,
+ unsigned, unsigned *, void (*fn)());
+#endif
+
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+{
+ extended_cif ecif;
+ void *rval = rvalue;
+
+ 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 */
+
+ ecif.rvalue = rvalue;
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ if (cif->rtype->size <= 32)
+ rval = alloca(64);
+ else
+ {
+ rval = NULL;
+ if (rvalue == NULL)
+ ecif.rvalue = alloca(cif->rtype->size);
+ }
+ }
+
+ switch (cif->abi)
+ {
+ case FFI_V8:
+#ifdef SPARC64
+ /* We don't yet support calling 32bit code from 64bit */
+ FFI_ASSERT(0);
+#else
+ ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
+ cif->flags, rvalue, fn);
+#endif
+ break;
+ case FFI_V9:
+#ifdef SPARC64
+ ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
+ cif->flags, rval, fn);
+ if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
+ ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
+#else
+ /* And vice versa */
+ FFI_ASSERT(0);
+#endif
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+
+}
+
+
+#ifdef SPARC64
+extern void ffi_closure_v9(void);
+#else
+extern void ffi_closure_v8(void);
+#endif
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data)
+{
+ unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+ unsigned long fn;
+#ifdef SPARC64
+ /* Trampoline address is equal to the closure address. We take advantage
+ of that to reduce the trampoline size by 8 bytes. */
+ FFI_ASSERT (cif->abi == FFI_V9);
+ fn = (unsigned long) ffi_closure_v9;
+ tramp[0] = 0x83414000; /* rd %pc, %g1 */
+ tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
+ tramp[2] = 0x81c14000; /* jmp %g5 */
+ tramp[3] = 0x01000000; /* nop */
+ *((unsigned long *) &tramp[4]) = fn;
+#else
+ unsigned long ctx = (unsigned long) closure;
+ FFI_ASSERT (cif->abi == FFI_V8);
+ fn = (unsigned long) ffi_closure_v8;
+ tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
+ tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
+ tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
+ tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
+#endif
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ /* Flush the Icache. FIXME: alignment isn't certain, assume 8 bytes */
+#ifdef SPARC64
+ asm volatile ("flush %0" : : "r" (closure) : "memory");
+ asm volatile ("flush %0" : : "r" (((char *) closure) + 8) : "memory");
+#else
+ asm volatile ("iflush %0" : : "r" (closure) : "memory");
+ asm volatile ("iflush %0" : : "r" (((char *) closure) + 8) : "memory");
+#endif
+
+ return FFI_OK;
+}
+
+int
+ffi_closure_sparc_inner_v8(ffi_closure *closure,
+ void *rvalue, unsigned long *gpr)
+{
+ ffi_cif *cif;
+ ffi_type **arg_types;
+ void **avalue;
+ int i, argn;
+
+ cif = closure->cif;
+ arg_types = cif->arg_types;
+ avalue = alloca(cif->nargs * sizeof(void *));
+
+ /* Copy the caller's structure return address so that the closure
+ returns the data directly to the caller. */
+ if (cif->flags == FFI_TYPE_STRUCT
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || cif->flags == FFI_TYPE_LONGDOUBLE
+#endif
+ )
+ rvalue = (void *) gpr[0];
+
+ /* Always skip the structure return address. */
+ argn = 1;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ for (i = 0; i < cif->nargs; i++)
+ {
+ if (arg_types[i]->type == FFI_TYPE_STRUCT
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
+#endif
+ )
+ {
+ /* Straight copy of invisible reference. */
+ avalue[i] = (void *)gpr[argn++];
+ }
+ else
+ {
+ /* Always right-justify. */
+ argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
+ }
+ }
+
+ /* Invoke the closure. */
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_sparc how to perform return type promotions. */
+ return cif->rtype->type;
+}
+
+int
+ffi_closure_sparc_inner_v9(ffi_closure *closure,
+ void *rvalue, unsigned long *gpr, double *fpr)
+{
+ ffi_cif *cif;
+ ffi_type **arg_types;
+ void **avalue;
+ int i, argn, fp_slot_max;
+
+ cif = closure->cif;
+ arg_types = cif->arg_types;
+ avalue = alloca(cif->nargs * sizeof(void *));
+
+ /* Copy the caller's structure return address so that the closure
+ returns the data directly to the caller. */
+ if (cif->flags == FFI_TYPE_VOID
+ && cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ rvalue = (void *) gpr[0];
+ /* Skip the structure return address. */
+ argn = 1;
+ }
+ else
+ argn = 0;
+
+ fp_slot_max = 16 - argn;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ for (i = 0; i < cif->nargs; i++)
+ {
+ if (arg_types[i]->type == FFI_TYPE_STRUCT)
+ {
+ if (arg_types[i]->size > 16)
+ {
+ /* Straight copy of invisible reference. */
+ avalue[i] = (void *)gpr[argn++];
+ }
+ else
+ {
+ /* Left-justify. */
+ ffi_v9_layout_struct(arg_types[i],
+ 0,
+ (char *) &gpr[argn],
+ (char *) &gpr[argn],
+ (char *) &fpr[argn]);
+ avalue[i] = &gpr[argn];
+ argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ }
+ }
+ else
+ {
+ /* Right-justify. */
+ argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+
+ if (i < fp_slot_max
+ && (arg_types[i]->type == FFI_TYPE_FLOAT
+ || arg_types[i]->type == FFI_TYPE_DOUBLE
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
+#endif
+ ))
+ avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
+ else
+ avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
+ }
+ }
+
+ /* Invoke the closure. */
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_sparc how to perform return type promotions. */
+ return cif->rtype->type;
+}
diff --git a/libffi/src/sparc/ffitarget.h b/libffi/src/sparc/ffitarget.h
new file mode 100644
index 0000000..f4514e5
--- /dev/null
+++ b/libffi/src/sparc/ffitarget.h
@@ -0,0 +1,65 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for SPARC.
+
+ 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 ----------------------------------- */
+
+#if defined(__arch64__) || defined(__sparcv9)
+#define SPARC64
+#endif
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_V8,
+ FFI_V8PLUS,
+ FFI_V9,
+#ifdef SPARC64
+ FFI_DEFAULT_ABI = FFI_V9,
+#else
+ FFI_DEFAULT_ABI = FFI_V8,
+#endif
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_NATIVE_RAW_API 0
+
+#ifdef SPARC64
+#define FFI_TRAMPOLINE_SIZE 24
+#else
+#define FFI_TRAMPOLINE_SIZE 16
+#endif
+
+#endif
+
diff --git a/libffi/src/sparc/v8.S b/libffi/src/sparc/v8.S
new file mode 100644
index 0000000..aaa7be7
--- /dev/null
+++ b/libffi/src/sparc/v8.S
@@ -0,0 +1,257 @@
+/* -----------------------------------------------------------------------
+ v8.S - Copyright (c) 1996, 1997, 2003, 2004 Red Hat, Inc.
+
+ SPARC 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 STACKFRAME 96 /* Minimum stack framesize for SPARC */
+#define ARGS (64+4) /* Offset of register area in frame */
+
+.text
+ .align 8
+.globl ffi_call_v8
+.globl _ffi_call_v8
+
+ffi_call_v8:
+_ffi_call_v8:
+.LLFB1:
+ save %sp, -STACKFRAME, %sp
+.LLCFI0:
+
+ sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
+ add %sp, STACKFRAME, %l0 ! %l0 has start of
+ ! frame to set up
+
+ mov %l0, %o0 ! call routine to set up frame
+ call %i0
+ mov %i1, %o1 ! (delay)
+
+ ld [%l0+ARGS], %o0 ! call foreign function
+ ld [%l0+ARGS+4], %o1
+ ld [%l0+ARGS+8], %o2
+ ld [%l0+ARGS+12], %o3
+ ld [%l0+ARGS+16], %o4
+ ld [%l0+ARGS+20], %o5
+ call %i5
+ mov %l0, %sp ! (delay) switch to frame
+ nop ! STRUCT returning functions skip 12 instead of 8 bytes
+
+ ! If the return value pointer is NULL, assume no return value.
+ tst %i4
+ bz done
+ nop
+
+ cmp %i3, FFI_TYPE_INT
+ be,a done
+ st %o0, [%i4] ! (delay)
+
+ cmp %i3, FFI_TYPE_FLOAT
+ be,a done
+ st %f0, [%i4+0] ! (delay)
+
+ cmp %i3, FFI_TYPE_SINT64
+ be longlong
+
+ cmp %i3, FFI_TYPE_DOUBLE
+ bne done
+ nop
+ st %f0, [%i4+0]
+ st %f1, [%i4+4]
+
+done:
+ ret
+ restore
+
+longlong:
+ st %o0, [%i4+0]
+ st %o1, [%i4+4]
+ ret
+ restore
+.LLFE1:
+
+.ffi_call_v8_end:
+ .size ffi_call_v8,.ffi_call_v8_end-ffi_call_v8
+
+
+#undef STACKFRAME
+#define STACKFRAME 104 /* 16*4 register window +
+ 1*4 struct return +
+ 6*4 args backing store +
+ 3*4 locals */
+
+/* ffi_closure_v8(...)
+
+ Receives the closure argument in %g2. */
+
+ .text
+ .align 8
+ .globl ffi_closure_v8
+
+ffi_closure_v8:
+#ifdef HAVE_AS_REGISTER_PSEUDO_OP
+ .register %g2, #scratch
+#endif
+.LLFB2:
+ save %sp, -STACKFRAME, %sp
+.LLCFI1:
+
+ ! Store all of the potential argument registers in va_list format.
+ st %i0, [%fp+68+0]
+ st %i1, [%fp+68+4]
+ st %i2, [%fp+68+8]
+ st %i3, [%fp+68+12]
+ st %i4, [%fp+68+16]
+ st %i5, [%fp+68+20]
+
+ ! Call ffi_closure_sparc_inner to do the bulk of the work.
+ mov %g2, %o0
+ add %fp, -8, %o1
+ call ffi_closure_sparc_inner_v8
+ add %fp, 64, %o2
+
+ ! Load up the return value in the proper type.
+ ! See ffi_prep_cif_machdep for the list of cases.
+ cmp %o0, FFI_TYPE_VOID
+ be done1
+
+ cmp %o0, FFI_TYPE_INT
+ be integer
+
+ cmp %o0, FFI_TYPE_FLOAT
+ be,a done1
+ ld [%fp-8], %f0
+
+ cmp %o0, FFI_TYPE_DOUBLE
+ be,a done1
+ ldd [%fp-8], %f0
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ cmp %o0, FFI_TYPE_LONGDOUBLE
+ be done2
+#endif
+
+ cmp %o0, FFI_TYPE_STRUCT
+ be done2
+
+ ! FFI_TYPE_SINT64
+ ld [%fp-4], %i1
+
+integer:
+ ld [%fp-8], %i0
+
+done1:
+ jmp %i7+8
+ restore
+done2:
+ ! Skip 'unimp'.
+ jmp %i7+12
+ restore
+.LLFE2:
+
+.ffi_closure_v8_end:
+ .size ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8
+
+#ifdef SPARC64
+#define WS 8
+#define nword xword
+#define uanword uaxword
+#else
+#define WS 4
+#define nword long
+#define uanword uaword
+#endif
+
+#ifdef HAVE_RO_EH_FRAME
+ .section ".eh_frame",#alloc
+#else
+ .section ".eh_frame",#alloc,#write
+#endif
+.LLframe1:
+ .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
+.LLSCIE1:
+ .uaword 0x0 ! CIE Identifier Tag
+ .byte 0x1 ! CIE Version
+ .ascii "zR\0" ! CIE Augmentation
+ .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor
+ .byte 0x80-WS ! sleb128 -WS; CIE Data Alignment Factor
+ .byte 0xf ! CIE RA Column
+ .byte 0x1 ! uleb128 0x1; Augmentation size
+#ifdef HAVE_AS_SPARC_UA_PCREL
+ .byte 0x1b ! FDE Encoding (pcrel sdata4)
+#else
+ .byte 0x50 ! FDE Encoding (aligned absolute)
+#endif
+ .byte 0xc ! DW_CFA_def_cfa
+ .byte 0xe ! uleb128 0xe
+ .byte 0x0 ! uleb128 0x0
+ .align WS
+.LLECIE1:
+.LLSFDE1:
+ .uaword .LLEFDE1-.LLASFDE1 ! FDE Length
+.LLASFDE1:
+ .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset
+#ifdef HAVE_AS_SPARC_UA_PCREL
+ .uaword %r_disp32(.LLFB1)
+ .uaword .LLFE1-.LLFB1 ! FDE address range
+#else
+ .align WS
+ .nword .LLFB1
+ .uanword .LLFE1-.LLFB1 ! FDE address range
+#endif
+ .byte 0x0 ! uleb128 0x0; Augmentation size
+ .byte 0x4 ! DW_CFA_advance_loc4
+ .uaword .LLCFI0-.LLFB1
+ .byte 0xd ! DW_CFA_def_cfa_register
+ .byte 0x1e ! uleb128 0x1e
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9 ! DW_CFA_register
+ .byte 0xf ! uleb128 0xf
+ .byte 0x1f ! uleb128 0x1f
+ .align WS
+.LLEFDE1:
+.LLSFDE2:
+ .uaword .LLEFDE2-.LLASFDE2 ! FDE Length
+.LLASFDE2:
+ .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
+#ifdef HAVE_AS_SPARC_UA_PCREL
+ .uaword %r_disp32(.LLFB2)
+ .uaword .LLFE2-.LLFB2 ! FDE address range
+#else
+ .align WS
+ .nword .LLFB2
+ .uanword .LLFE2-.LLFB2 ! FDE address range
+#endif
+ .byte 0x0 ! uleb128 0x0; Augmentation size
+ .byte 0x4 ! DW_CFA_advance_loc4
+ .uaword .LLCFI1-.LLFB2
+ .byte 0xd ! DW_CFA_def_cfa_register
+ .byte 0x1e ! uleb128 0x1e
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9 ! DW_CFA_register
+ .byte 0xf ! uleb128 0xf
+ .byte 0x1f ! uleb128 0x1f
+ .align WS
+.LLEFDE2:
diff --git a/libffi/src/sparc/v9.S b/libffi/src/sparc/v9.S
new file mode 100644
index 0000000..d640e02
--- /dev/null
+++ b/libffi/src/sparc/v9.S
@@ -0,0 +1,302 @@
+/* -----------------------------------------------------------------------
+ v9.S - Copyright (c) 2000, 2003, 2004 Red Hat, Inc.
+
+ SPARC 64-bit 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>
+
+#ifdef SPARC64
+/* Only compile this in for 64bit builds, because otherwise the object file
+ will have inproper architecture due to used instructions. */
+
+#define STACKFRAME 128 /* Minimum stack framesize for SPARC */
+#define STACK_BIAS 2047
+#define ARGS (128) /* Offset of register area in frame */
+
+.text
+ .align 8
+.globl ffi_call_v9
+.globl _ffi_call_v9
+
+ffi_call_v9:
+_ffi_call_v9:
+.LLFB1:
+ save %sp, -STACKFRAME, %sp
+.LLCFI0:
+
+ sub %sp, %i2, %sp ! alloca() space in stack for frame to set up
+ add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of
+ ! frame to set up
+
+ mov %l0, %o0 ! call routine to set up frame
+ call %i0
+ mov %i1, %o1 ! (delay)
+ brz,pt %o0, 1f
+ ldx [%l0+ARGS], %o0 ! call foreign function
+
+ ldd [%l0+ARGS], %f0
+ ldd [%l0+ARGS+8], %f2
+ ldd [%l0+ARGS+16], %f4
+ ldd [%l0+ARGS+24], %f6
+ ldd [%l0+ARGS+32], %f8
+ ldd [%l0+ARGS+40], %f10
+ ldd [%l0+ARGS+48], %f12
+ ldd [%l0+ARGS+56], %f14
+ ldd [%l0+ARGS+64], %f16
+ ldd [%l0+ARGS+72], %f18
+ ldd [%l0+ARGS+80], %f20
+ ldd [%l0+ARGS+88], %f22
+ ldd [%l0+ARGS+96], %f24
+ ldd [%l0+ARGS+104], %f26
+ ldd [%l0+ARGS+112], %f28
+ ldd [%l0+ARGS+120], %f30
+
+1: ldx [%l0+ARGS+8], %o1
+ ldx [%l0+ARGS+16], %o2
+ ldx [%l0+ARGS+24], %o3
+ ldx [%l0+ARGS+32], %o4
+ ldx [%l0+ARGS+40], %o5
+ call %i5
+ sub %l0, STACK_BIAS, %sp ! (delay) switch to frame
+
+ ! If the return value pointer is NULL, assume no return value.
+ brz,pn %i4, done
+ nop
+
+ cmp %i3, FFI_TYPE_INT
+ be,a,pt %icc, done
+ stx %o0, [%i4+0] ! (delay)
+
+ cmp %i3, FFI_TYPE_FLOAT
+ be,a,pn %icc, done
+ st %f0, [%i4+0] ! (delay)
+
+ cmp %i3, FFI_TYPE_DOUBLE
+ be,a,pn %icc, done
+ std %f0, [%i4+0] ! (delay)
+
+ cmp %i3, FFI_TYPE_STRUCT
+ be,pn %icc, dostruct
+
+ cmp %i3, FFI_TYPE_LONGDOUBLE
+ bne,pt %icc, done
+ nop
+ std %f0, [%i4+0]
+ std %f2, [%i4+8]
+
+done: ret
+ restore
+
+dostruct:
+ /* This will not work correctly for unions. */
+ stx %o0, [%i4+0]
+ stx %o1, [%i4+8]
+ stx %o2, [%i4+16]
+ stx %o3, [%i4+24]
+ std %f0, [%i4+32]
+ std %f2, [%i4+40]
+ std %f4, [%i4+48]
+ std %f6, [%i4+56]
+ ret
+ restore
+.LLFE1:
+
+.ffi_call_v9_end:
+ .size ffi_call_v9,.ffi_call_v9_end-ffi_call_v9
+
+
+#undef STACKFRAME
+#define STACKFRAME 336 /* 16*8 register window +
+ 6*8 args backing store +
+ 20*8 locals */
+#define FP %fp+STACK_BIAS
+
+/* ffi_closure_v9(...)
+
+ Receives the closure argument in %g1. */
+
+ .text
+ .align 8
+ .globl ffi_closure_v9
+
+ffi_closure_v9:
+.LLFB2:
+ save %sp, -STACKFRAME, %sp
+.LLCFI1:
+
+ ! Store all of the potential argument registers in va_list format.
+ stx %i0, [FP+128+0]
+ stx %i1, [FP+128+8]
+ stx %i2, [FP+128+16]
+ stx %i3, [FP+128+24]
+ stx %i4, [FP+128+32]
+ stx %i5, [FP+128+40]
+
+ ! Store possible floating point argument registers too.
+ std %f0, [FP-128]
+ std %f2, [FP-120]
+ std %f4, [FP-112]
+ std %f6, [FP-104]
+ std %f8, [FP-96]
+ std %f10, [FP-88]
+ std %f12, [FP-80]
+ std %f14, [FP-72]
+ std %f16, [FP-64]
+ std %f18, [FP-56]
+ std %f20, [FP-48]
+ std %f22, [FP-40]
+ std %f24, [FP-32]
+ std %f26, [FP-24]
+ std %f28, [FP-16]
+ std %f30, [FP-8]
+
+ ! Call ffi_closure_sparc_inner to do the bulk of the work.
+ mov %g1, %o0
+ add %fp, STACK_BIAS-160, %o1
+ add %fp, STACK_BIAS+128, %o2
+ call ffi_closure_sparc_inner_v9
+ add %fp, STACK_BIAS-128, %o3
+
+ ! Load up the return value in the proper type.
+ ! See ffi_prep_cif_machdep for the list of cases.
+ cmp %o0, FFI_TYPE_VOID
+ be,pn %icc, done1
+
+ cmp %o0, FFI_TYPE_INT
+ be,pn %icc, integer
+
+ cmp %o0, FFI_TYPE_FLOAT
+ be,a,pn %icc, done1
+ ld [FP-160], %f0
+
+ cmp %o0, FFI_TYPE_DOUBLE
+ be,a,pn %icc, done1
+ ldd [FP-160], %f0
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ cmp %o0, FFI_TYPE_LONGDOUBLE
+ be,a,pn %icc, longdouble1
+ ldd [FP-160], %f0
+#endif
+
+ ! FFI_TYPE_STRUCT
+ ldx [FP-152], %i1
+ ldx [FP-144], %i2
+ ldx [FP-136], %i3
+ ldd [FP-160], %f0
+ ldd [FP-152], %f2
+ ldd [FP-144], %f4
+ ldd [FP-136], %f6
+
+integer:
+ ldx [FP-160], %i0
+
+done1:
+ ret
+ restore
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+longdouble1:
+ ldd [FP-152], %f2
+ ret
+ restore
+#endif
+.LLFE2:
+
+.ffi_closure_v9_end:
+ .size ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9
+
+#ifdef HAVE_RO_EH_FRAME
+ .section ".eh_frame",#alloc
+#else
+ .section ".eh_frame",#alloc,#write
+#endif
+.LLframe1:
+ .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry
+.LLSCIE1:
+ .uaword 0x0 ! CIE Identifier Tag
+ .byte 0x1 ! CIE Version
+ .ascii "zR\0" ! CIE Augmentation
+ .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor
+ .byte 0x78 ! sleb128 -8; CIE Data Alignment Factor
+ .byte 0xf ! CIE RA Column
+ .byte 0x1 ! uleb128 0x1; Augmentation size
+#ifdef HAVE_AS_SPARC_UA_PCREL
+ .byte 0x1b ! FDE Encoding (pcrel sdata4)
+#else
+ .byte 0x50 ! FDE Encoding (aligned absolute)
+#endif
+ .byte 0xc ! DW_CFA_def_cfa
+ .byte 0xe ! uleb128 0xe
+ .byte 0xff,0xf ! uleb128 0x7ff
+ .align 8
+.LLECIE1:
+.LLSFDE1:
+ .uaword .LLEFDE1-.LLASFDE1 ! FDE Length
+.LLASFDE1:
+ .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset
+#ifdef HAVE_AS_SPARC_UA_PCREL
+ .uaword %r_disp32(.LLFB1)
+ .uaword .LLFE1-.LLFB1 ! FDE address range
+#else
+ .align 8
+ .xword .LLFB1
+ .uaxword .LLFE1-.LLFB1 ! FDE address range
+#endif
+ .byte 0x0 ! uleb128 0x0; Augmentation size
+ .byte 0x4 ! DW_CFA_advance_loc4
+ .uaword .LLCFI0-.LLFB1
+ .byte 0xd ! DW_CFA_def_cfa_register
+ .byte 0x1e ! uleb128 0x1e
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9 ! DW_CFA_register
+ .byte 0xf ! uleb128 0xf
+ .byte 0x1f ! uleb128 0x1f
+ .align 8
+.LLEFDE1:
+.LLSFDE2:
+ .uaword .LLEFDE2-.LLASFDE2 ! FDE Length
+.LLASFDE2:
+ .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset
+#ifdef HAVE_AS_SPARC_UA_PCREL
+ .uaword %r_disp32(.LLFB2)
+ .uaword .LLFE2-.LLFB2 ! FDE address range
+#else
+ .align 8
+ .xword .LLFB2
+ .uaxword .LLFE2-.LLFB2 ! FDE address range
+#endif
+ .byte 0x0 ! uleb128 0x0; Augmentation size
+ .byte 0x4 ! DW_CFA_advance_loc4
+ .uaword .LLCFI1-.LLFB2
+ .byte 0xd ! DW_CFA_def_cfa_register
+ .byte 0x1e ! uleb128 0x1e
+ .byte 0x2d ! DW_CFA_GNU_window_save
+ .byte 0x9 ! DW_CFA_register
+ .byte 0xf ! uleb128 0xf
+ .byte 0x1f ! uleb128 0x1f
+ .align 8
+.LLEFDE2:
+#endif
diff --git a/libffi/src/types.c b/libffi/src/types.c
new file mode 100644
index 0000000..d25423f
--- /dev/null
+++ b/libffi/src/types.c
@@ -0,0 +1,118 @@
+/* -----------------------------------------------------------------------
+ types.c - Copyright (c) 1996, 1998 Red Hat, Inc.
+
+ Predefined ffi_types needed by libffi.
+
+ 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>
+
+/* Type definitions */
+
+#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL }
+#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e }
+
+/* Size and alignment are fake here. They must not be 0. */
+FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID);
+
+FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8);
+FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8);
+FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16);
+FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16);
+FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32);
+FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32);
+FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
+
+#if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \
+ || defined IA64 || defined POWERPC64
+
+FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
+
+#else
+
+FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER);
+
+#endif
+
+#if defined X86_DARWIN
+
+FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64);
+FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64);
+
+#elif defined X86 || defined ARM || defined M68K || defined(POWERPC_DARWIN)
+
+FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
+FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
+
+#elif defined SH
+
+FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
+FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
+
+#else
+
+FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64);
+FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64);
+
+#endif
+
+
+#if defined X86 || defined X86_WIN32 || defined M68K
+
+#ifdef X86_WIN32
+FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
+#else
+FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
+#endif
+
+#ifdef X86_DARWIN
+FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
+#else
+FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
+#endif
+
+#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
+FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE);
+
+#elif defined SPARC
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
+#ifdef SPARC64
+FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
+#else
+FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE);
+#endif
+
+#elif defined X86_64 || defined POWERPC64
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
+FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
+
+#else
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
+FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE);
+
+#endif
+
diff --git a/libffi/src/x86/darwin.S b/libffi/src/x86/darwin.S
new file mode 100644
index 0000000..c5e55b5
--- /dev/null
+++ b/libffi/src/x86/darwin.S
@@ -0,0 +1,195 @@
+#ifdef __i386__
+/* -----------------------------------------------------------------------
+ darwin.S - Copyright (c) 1996, 1998, 2001, 2002, 2003 Red Hat, Inc.
+
+ X86 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.
+ ----------------------------------------------------------------------- */
+
+/*
+ * This file is based on sysv.S and then hacked up by Ronald who hasn't done
+ * assembly programming in 8 years.
+ */
+
+#ifndef __x86_64__
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+.text
+
+.globl _ffi_prep_args
+
+.align 4
+.globl _ffi_call_SYSV
+
+_ffi_call_SYSV:
+.LFB1:
+ pushl %ebp
+.LCFI0:
+ movl %esp,%ebp
+.LCFI1:
+ /* Make room for all of the new args. */
+ movl 16(%ebp),%ecx
+ subl %ecx,%esp
+
+ movl %esp,%eax
+
+ /* Place all of the ffi_prep_args in position */
+ pushl 12(%ebp)
+ pushl %eax
+ call *8(%ebp)
+
+ /* Return stack to previous state and call the function */
+ addl $8,%esp
+
+ call *28(%ebp)
+
+ /* Remove the space we pushed for the args */
+ movl 16(%ebp),%ecx
+ addl %ecx,%esp
+
+ /* Load %ecx with the return type code */
+ movl 20(%ebp),%ecx
+
+ /* If the return value pointer is NULL, assume no return value. */
+ cmpl $0,24(%ebp)
+ jne retint
+
+ /* Even if there is no space for the return value, we are
+ obliged to handle floating-point values. */
+ cmpl $FFI_TYPE_FLOAT,%ecx
+ jne noretval
+ fstp %st(0)
+
+ jmp epilogue
+
+retint:
+ cmpl $FFI_TYPE_INT,%ecx
+ jne retfloat
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ movl %eax,0(%ecx)
+ jmp epilogue
+
+retfloat:
+ cmpl $FFI_TYPE_FLOAT,%ecx
+ jne retdouble
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ fstps (%ecx)
+ jmp epilogue
+
+retdouble:
+ cmpl $FFI_TYPE_DOUBLE,%ecx
+ jne retlongdouble
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ fstpl (%ecx)
+ jmp epilogue
+
+retlongdouble:
+ cmpl $FFI_TYPE_LONGDOUBLE,%ecx
+ jne retint64
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ fstpt (%ecx)
+ jmp epilogue
+
+retint64:
+ cmpl $FFI_TYPE_SINT64,%ecx
+ jne retstruct
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ movl %eax,0(%ecx)
+ movl %edx,4(%ecx)
+
+retstruct:
+ /* Nothing to do! */
+
+noretval:
+epilogue:
+ movl %ebp,%esp
+ popl %ebp
+ ret
+.LFE1:
+.ffi_call_SYSV_end:
+#if 0
+ .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
+#endif
+
+#if 0
+ .section .eh_frame,EH_FRAME_FLAGS,@progbits
+.Lframe1:
+ .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */
+.LSCIE1:
+ .long 0x0 /* CIE Identifier Tag */
+ .byte 0x1 /* CIE Version */
+#ifdef __PIC__
+ .ascii "zR\0" /* CIE Augmentation */
+#else
+ .ascii "\0" /* CIE Augmentation */
+#endif
+ .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
+ .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
+ .byte 0x8 /* CIE RA Column */
+#ifdef __PIC__
+ .byte 0x1 /* .uleb128 0x1; Augmentation size */
+ .byte 0x1b /* FDE Encoding (pcrel sdata4) */
+#endif
+ .byte 0xc /* DW_CFA_def_cfa */
+ .byte 0x4 /* .uleb128 0x4 */
+ .byte 0x4 /* .uleb128 0x4 */
+ .byte 0x88 /* DW_CFA_offset, column 0x8 */
+ .byte 0x1 /* .uleb128 0x1 */
+ .align 4
+.LECIE1:
+.LSFDE1:
+ .long .LEFDE1-.LASFDE1 /* FDE Length */
+.LASFDE1:
+ .long .LASFDE1-.Lframe1 /* FDE CIE offset */
+#ifdef __PIC__
+ .long .LFB1-. /* FDE initial location */
+#else
+ .long .LFB1 /* FDE initial location */
+#endif
+ .long .LFE1-.LFB1 /* FDE address range */
+#ifdef __PIC__
+ .byte 0x0 /* .uleb128 0x0; Augmentation size */
+#endif
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .long .LCFI0-.LFB1
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x8 /* .uleb128 0x8 */
+ .byte 0x85 /* DW_CFA_offset, column 0x5 */
+ .byte 0x2 /* .uleb128 0x2 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .long .LCFI1-.LCFI0
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0x5 /* .uleb128 0x5 */
+ .align 4
+.LEFDE1:
+#endif
+
+#endif /* ifndef __x86_64__ */
+
+#endif /* defined __i386__ */
diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c
new file mode 100644
index 0000000..633e549
--- /dev/null
+++ b/libffi/src/x86/ffi.c
@@ -0,0 +1,557 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc.
+ Copyright (c) 2002 Ranjit Mathew
+ Copyright (c) 2002 Bo Thorsen
+ Copyright (c) 2002 Roger Sayle
+
+ x86 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.
+ ----------------------------------------------------------------------- */
+
+#ifndef __x86_64__
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+/*@-exportheader@*/
+void ffi_prep_args(char *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+ register unsigned int i;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ argp = stack;
+
+ if (ecif->cif->flags == FFI_TYPE_STRUCT)
+ {
+ *(void **) argp = ecif->rvalue;
+ argp += 4;
+ }
+
+ p_argv = ecif->avalue;
+
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
+ i != 0;
+ i--, p_arg++)
+ {
+ size_t z;
+
+ /* Align if necessary */
+ if ((sizeof(int) - 1) & (unsigned) argp)
+ argp = (char *) ALIGN(argp, sizeof(int));
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT32:
+ *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT32:
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ }
+ else
+ {
+ memcpy(argp, *p_argv, z);
+ }
+ p_argv++;
+ argp += z;
+ }
+
+ return;
+}
+
+/* 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:
+#ifndef X86_WIN32
+ case FFI_TYPE_STRUCT:
+#endif
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ cif->flags = (unsigned) cif->rtype->type;
+ break;
+
+ case FFI_TYPE_UINT64:
+ cif->flags = FFI_TYPE_SINT64;
+ break;
+
+#ifdef X86_WIN32
+ case FFI_TYPE_STRUCT:
+ if (cif->rtype->size == 1)
+ {
+ cif->flags = FFI_TYPE_SINT8; /* same as char size */
+ }
+ else if (cif->rtype->size == 2)
+ {
+ cif->flags = FFI_TYPE_SINT16; /* same as short size */
+ }
+ else if (cif->rtype->size == 4)
+ {
+ cif->flags = FFI_TYPE_INT; /* same as int type */
+ }
+ else if (cif->rtype->size == 8)
+ {
+ cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
+ }
+ else
+ {
+ cif->flags = FFI_TYPE_STRUCT;
+ }
+ break;
+#endif
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ break;
+ }
+
+ return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+/*@=declundef@*/
+/*@=exportheader@*/
+
+#ifdef X86_WIN32
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_STDCALL(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+/*@=declundef@*/
+/*@=exportheader@*/
+#endif /* X86_WIN32 */
+
+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->flags == FFI_TYPE_STRUCT))
+ {
+ /*@-sysunrecog@*/
+ ecif.rvalue = alloca(cif->rtype->size);
+ /*@=sysunrecog@*/
+ }
+ else
+ ecif.rvalue = rvalue;
+
+
+ switch (cif->abi)
+ {
+ case FFI_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#ifdef X86_WIN32
+ case FFI_STDCALL:
+ /*@-usedef@*/
+ ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#endif /* X86_WIN32 */
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+
+/** private members **/
+
+static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
+ void** args, ffi_cif* cif);
+static void ffi_closure_SYSV (ffi_closure *)
+ __attribute__ ((regparm(1)));
+static void ffi_closure_raw_SYSV (ffi_raw_closure *)
+ __attribute__ ((regparm(1)));
+
+/* This function is jumped to by the trampoline */
+
+static void
+ffi_closure_SYSV (closure)
+ ffi_closure *closure;
+{
+ // this is our return value storage
+ long double res;
+
+ // our various things...
+ ffi_cif *cif;
+ void **arg_area;
+ unsigned short rtype;
+ void *resp = (void*)&res;
+ void *args = __builtin_dwarf_cfa ();
+
+ cif = closure->cif;
+ arg_area = (void**) alloca (cif->nargs * sizeof (void*));
+
+ /* this call will initialize ARG_AREA, such that each
+ * element in that array points to the corresponding
+ * value on the stack; and if the function returns
+ * a structure, it will re-set RESP to point to the
+ * structure return address. */
+
+ ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
+
+ (closure->fun) (cif, resp, arg_area, closure->user_data);
+
+ rtype = cif->flags;
+
+ /* now, do a generic return based on the value of rtype */
+ if (rtype == FFI_TYPE_INT)
+ {
+ asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
+ }
+ else if (rtype == FFI_TYPE_FLOAT)
+ {
+ asm ("flds (%0)" : : "r" (resp) : "st" );
+ }
+ else if (rtype == FFI_TYPE_DOUBLE)
+ {
+ asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
+ }
+ else if (rtype == FFI_TYPE_LONGDOUBLE)
+ {
+ asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
+ }
+ else if (rtype == FFI_TYPE_SINT64)
+ {
+ asm ("movl 0(%0),%%eax;"
+ "movl 4(%0),%%edx"
+ : : "r"(resp)
+ : "eax", "edx");
+ }
+#ifdef X86_WIN32
+ else if (rtype == FFI_TYPE_SINT8) /* 1-byte struct */
+ {
+ asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax");
+ }
+ else if (rtype == FFI_TYPE_SINT16) /* 2-bytes struct */
+ {
+ asm ("movswl (%0),%%eax" : : "r" (resp) : "eax");
+ }
+#endif
+}
+
+/*@-exportheader@*/
+static void
+ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
+ void **avalue, ffi_cif *cif)
+/*@=exportheader@*/
+{
+ register unsigned int i;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ argp = stack;
+
+ if ( cif->flags == FFI_TYPE_STRUCT ) {
+ *rvalue = *(void **) argp;
+ argp += 4;
+ }
+
+ p_argv = avalue;
+
+ for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
+ {
+ size_t z;
+
+ /* Align if necessary */
+ if ((sizeof(int) - 1) & (unsigned) argp) {
+ argp = (char *) ALIGN(argp, sizeof(int));
+ }
+
+ z = (*p_arg)->size;
+
+ /* because we're little endian, this is what it turns into. */
+
+ *p_argv = (void*) argp;
+
+ p_argv++;
+ argp += z;
+ }
+
+ return;
+}
+
+/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
+
+#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
+({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
+ unsigned int __fun = (unsigned int)(FUN); \
+ unsigned int __ctx = (unsigned int)(CTX); \
+ unsigned int __dis = __fun - ((unsigned int) __tramp + FFI_TRAMPOLINE_SIZE); \
+ *(unsigned char*) &__tramp[0] = 0xb8; \
+ *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
+ *(unsigned char *) &__tramp[5] = 0xe9; \
+ *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
+ })
+
+
+/* the cif must already be prep'ed */
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data)
+{
+ FFI_ASSERT (cif->abi == FFI_SYSV);
+
+ FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
+ &ffi_closure_SYSV, \
+ (void*)closure);
+
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+/* ------- Native raw API support -------------------------------- */
+
+#if !FFI_NO_RAW_API
+
+static void
+ffi_closure_raw_SYSV (closure)
+ ffi_raw_closure *closure;
+{
+ // this is our return value storage
+ long double res;
+
+ // our various things...
+ ffi_raw *raw_args;
+ ffi_cif *cif;
+ unsigned short rtype;
+ void *resp = (void*)&res;
+
+ /* get the cif */
+ cif = closure->cif;
+
+ /* the SYSV/X86 abi matches the RAW API exactly, well.. almost */
+ raw_args = (ffi_raw*) __builtin_dwarf_cfa ();
+
+ (closure->fun) (cif, resp, raw_args, closure->user_data);
+
+ rtype = cif->flags;
+
+ /* now, do a generic return based on the value of rtype */
+ if (rtype == FFI_TYPE_INT)
+ {
+ asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
+ }
+ else if (rtype == FFI_TYPE_FLOAT)
+ {
+ asm ("flds (%0)" : : "r" (resp) : "st" );
+ }
+ else if (rtype == FFI_TYPE_DOUBLE)
+ {
+ asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
+ }
+ else if (rtype == FFI_TYPE_LONGDOUBLE)
+ {
+ asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
+ }
+ else if (rtype == FFI_TYPE_SINT64)
+ {
+ asm ("movl 0(%0),%%eax; movl 4(%0),%%edx"
+ : : "r"(resp)
+ : "eax", "edx");
+ }
+}
+
+
+
+
+ffi_status
+ffi_prep_raw_closure (ffi_raw_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+ void *user_data)
+{
+ int i;
+
+ FFI_ASSERT (cif->abi == FFI_SYSV);
+
+ // we currently don't support certain kinds of arguments for raw
+ // closures. This should be implemented by a separate assembly language
+ // routine, since it would require argument processing, something we
+ // don't do now for performance.
+
+ for (i = cif->nargs-1; i >= 0; i--)
+ {
+ FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
+ FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
+ }
+
+
+ FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
+ (void*)closure);
+
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+static void
+ffi_prep_args_raw(char *stack, extended_cif *ecif)
+{
+ memcpy (stack, ecif->avalue, ecif->cif->bytes);
+}
+
+/* we borrow this routine from libffi (it must be changed, though, to
+ * actually call the function passed in the first argument. as of
+ * libffi-1.20, this is not the case.)
+ */
+
+extern void
+ffi_call_SYSV(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+
+#ifdef X86_WIN32
+extern void
+ffi_call_STDCALL(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+#endif /* X86_WIN32 */
+
+void
+ffi_raw_call(/*@dependent@*/ ffi_cif *cif,
+ void (*fn)(),
+ /*@out@*/ void *rvalue,
+ /*@dependent@*/ ffi_raw *fake_avalue)
+{
+ extended_cif ecif;
+ void **avalue = (void **)fake_avalue;
+
+ 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_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#ifdef X86_WIN32
+ case FFI_STDCALL:
+ /*@-usedef@*/
+ ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#endif /* X86_WIN32 */
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+#endif
+
+#endif /* __x86_64__ */
diff --git a/libffi/src/x86/ffi64.c b/libffi/src/x86/ffi64.c
new file mode 100644
index 0000000..343ee92
--- /dev/null
+++ b/libffi/src/x86/ffi64.c
@@ -0,0 +1,706 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
+
+ x86-64 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>
+#include <stdarg.h>
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+#ifdef __x86_64__
+
+#define MAX_GPR_REGS 6
+#define MAX_SSE_REGS 8
+typedef struct
+{
+ /* Registers for argument passing. */
+ long gpr[MAX_GPR_REGS];
+ __int128_t sse[MAX_SSE_REGS];
+
+ /* Stack space for arguments. */
+ char argspace[0];
+} stackLayout;
+
+/* All reference to register classes here is identical to the code in
+ gcc/config/i386/i386.c. Do *not* change one without the other. */
+
+/* Register class used for passing given 64bit part of the argument.
+ These represent classes as documented by the PS ABI, with the exception
+ of SSESF, SSEDF classes, that are basically SSE class, just gcc will
+ use SF or DFmode move instead of DImode to avoid reformating penalties.
+
+ Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
+ whenever possible (upper half does contain padding).
+ */
+enum x86_64_reg_class
+ {
+ X86_64_NO_CLASS,
+ X86_64_INTEGER_CLASS,
+ X86_64_INTEGERSI_CLASS,
+ X86_64_SSE_CLASS,
+ X86_64_SSESF_CLASS,
+ X86_64_SSEDF_CLASS,
+ X86_64_SSEUP_CLASS,
+ X86_64_X87_CLASS,
+ X86_64_X87UP_CLASS,
+ X86_64_MEMORY_CLASS
+ };
+
+#define MAX_CLASSES 4
+
+/* x86-64 register passing implementation. See x86-64 ABI for details. Goal
+ of this code is to classify each 8bytes of incoming argument by the register
+ class and assign registers accordingly. */
+
+/* Return the union class of CLASS1 and CLASS2.
+ See the x86-64 PS ABI for details. */
+
+static enum x86_64_reg_class
+merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
+{
+ /* Rule #1: If both classes are equal, this is the resulting class. */
+ if (class1 == class2)
+ return class1;
+
+ /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
+ the other class. */
+ if (class1 == X86_64_NO_CLASS)
+ return class2;
+ if (class2 == X86_64_NO_CLASS)
+ return class1;
+
+ /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
+ if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
+ return X86_64_MEMORY_CLASS;
+
+ /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
+ if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
+ || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
+ return X86_64_INTEGERSI_CLASS;
+ if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
+ || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
+ return X86_64_INTEGER_CLASS;
+
+ /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */
+ if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
+ || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
+ return X86_64_MEMORY_CLASS;
+
+ /* Rule #6: Otherwise class SSE is used. */
+ return X86_64_SSE_CLASS;
+}
+
+/* Classify the argument of type TYPE and mode MODE.
+ CLASSES will be filled by the register class used to pass each word
+ of the operand. The number of words is returned. In case the parameter
+ should be passed in memory, 0 is returned. As a special case for zero
+ sized containers, classes[0] will be NO_CLASS and 1 is returned.
+
+ See the x86-64 PS ABI for details.
+*/
+static int
+classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
+ int *byte_offset)
+{
+ /* First, align to the right place. */
+ *byte_offset = ALIGN(*byte_offset, type->alignment);
+
+ switch (type->type)
+ {
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_POINTER:
+ if (((*byte_offset) % 8 + type->size) <= 4)
+ classes[0] = X86_64_INTEGERSI_CLASS;
+ else
+ classes[0] = X86_64_INTEGER_CLASS;
+ return 1;
+ case FFI_TYPE_FLOAT:
+ if (((*byte_offset) % 8) == 0)
+ classes[0] = X86_64_SSESF_CLASS;
+ else
+ classes[0] = X86_64_SSE_CLASS;
+ return 1;
+ case FFI_TYPE_DOUBLE:
+ classes[0] = X86_64_SSEDF_CLASS;
+ return 1;
+ case FFI_TYPE_LONGDOUBLE:
+ classes[0] = X86_64_X87_CLASS;
+ classes[1] = X86_64_X87UP_CLASS;
+ return 2;
+ case FFI_TYPE_STRUCT:
+ {
+ const int UNITS_PER_WORD = 8;
+ int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ ffi_type **ptr;
+ int i;
+ enum x86_64_reg_class subclasses[MAX_CLASSES];
+
+ /* If the struct is larger than 16 bytes, pass it on the stack. */
+ if (type->size > 16)
+ return 0;
+
+ for (i = 0; i < words; i++)
+ classes[i] = X86_64_NO_CLASS;
+
+ /* Merge the fields of structure. */
+ for (ptr=type->elements; (*ptr)!=NULL; ptr++)
+ {
+ int num;
+
+ num = classify_argument (*ptr, subclasses, byte_offset);
+ if (num == 0)
+ return 0;
+ for (i = 0; i < num; i++)
+ {
+ int pos = *byte_offset / 8;
+ classes[i + pos] =
+ merge_classes (subclasses[i], classes[i + pos]);
+ }
+
+ if ((*ptr)->type != FFI_TYPE_STRUCT)
+ *byte_offset += (*ptr)->size;
+ }
+
+ /* Final merger cleanup. */
+ for (i = 0; i < words; i++)
+ {
+ /* If one class is MEMORY, everything should be passed in
+ memory. */
+ if (classes[i] == X86_64_MEMORY_CLASS)
+ return 0;
+
+ /* The X86_64_SSEUP_CLASS should be always preceded by
+ X86_64_SSE_CLASS. */
+ if (classes[i] == X86_64_SSEUP_CLASS
+ && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
+ classes[i] = X86_64_SSE_CLASS;
+
+ /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */
+ if (classes[i] == X86_64_X87UP_CLASS
+ && (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
+ classes[i] = X86_64_SSE_CLASS;
+ }
+ return words;
+ }
+
+ default:
+ FFI_ASSERT(0);
+ }
+ return 0; /* Never reached. */
+}
+
+/* Examine the argument and return set number of register required in each
+ class. Return 0 iff parameter should be passed in memory. */
+static int
+examine_argument (ffi_type *type, int in_return, int *int_nregs,int *sse_nregs)
+{
+ enum x86_64_reg_class class[MAX_CLASSES];
+ int offset = 0;
+ int n;
+
+ n = classify_argument (type, class, &offset);
+
+ if (n == 0)
+ return 0;
+
+ *int_nregs = 0;
+ *sse_nregs = 0;
+ for (n--; n>=0; n--)
+ switch (class[n])
+ {
+ case X86_64_INTEGER_CLASS:
+ case X86_64_INTEGERSI_CLASS:
+ (*int_nregs)++;
+ break;
+ case X86_64_SSE_CLASS:
+ case X86_64_SSESF_CLASS:
+ case X86_64_SSEDF_CLASS:
+ (*sse_nregs)++;
+ break;
+ case X86_64_NO_CLASS:
+ case X86_64_SSEUP_CLASS:
+ break;
+ case X86_64_X87_CLASS:
+ case X86_64_X87UP_CLASS:
+ if (!in_return)
+ return 0;
+ break;
+ default:
+ abort ();
+ }
+ return 1;
+}
+
+/* Functions to load floats and double to an SSE register placeholder. */
+extern void float2sse (float, __int128_t *);
+extern void double2sse (double, __int128_t *);
+extern void floatfloat2sse (void *, __int128_t *);
+
+/* Functions to put the floats and doubles back. */
+extern float sse2float (__int128_t *);
+extern double sse2double (__int128_t *);
+extern void sse2floatfloat(__int128_t *, void *);
+
+/*@-exportheader@*/
+void
+ffi_prep_args (stackLayout *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+ int gprcount, ssecount, i, g, s;
+ void **p_argv;
+ void *argp = &stack->argspace;
+ ffi_type **p_arg;
+
+ /* First check if the return value should be passed in memory. If so,
+ pass the pointer as the first argument. */
+ gprcount = ssecount = 0;
+ if (ecif->cif->rtype->type != FFI_TYPE_VOID
+ && examine_argument (ecif->cif->rtype, 1, &g, &s) == 0)
+ stack->gpr[gprcount++] = (long) ecif->rvalue;
+
+ for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue;
+ i!=0; i--, p_arg++, p_argv++)
+ {
+ int in_register = 0;
+
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ if (gprcount < MAX_GPR_REGS)
+ {
+ stack->gpr[gprcount] = 0;
+ stack->gpr[gprcount++] = *(long long *)(*p_argv);
+ in_register = 1;
+ }
+ break;
+
+ case FFI_TYPE_FLOAT:
+ if (ssecount < MAX_SSE_REGS)
+ {
+ float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]);
+ in_register = 1;
+ }
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ if (ssecount < MAX_SSE_REGS)
+ {
+ double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]);
+ in_register = 1;
+ }
+ break;
+ }
+
+ if (in_register)
+ continue;
+
+ /* Either all places in registers where filled, or this is a
+ type that potentially goes into a memory slot. */
+ if (examine_argument (*p_arg, 0, &g, &s) == 0
+ || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
+ {
+ /* Pass this argument in memory. */
+ argp = (void *)ALIGN(argp, (*p_arg)->alignment);
+ memcpy (argp, *p_argv, (*p_arg)->size);
+ argp += (*p_arg)->size;
+ }
+ else
+ {
+ /* All easy cases are eliminated. Now fire the big guns. */
+
+ enum x86_64_reg_class classes[MAX_CLASSES];
+ int offset = 0, j, num;
+ void *a;
+
+ num = classify_argument (*p_arg, classes, &offset);
+ for (j=0, a=*p_argv; j<num; j++, a+=8)
+ {
+ switch (classes[j])
+ {
+ case X86_64_INTEGER_CLASS:
+ case X86_64_INTEGERSI_CLASS:
+ stack->gpr[gprcount++] = *(long long *)a;
+ break;
+ case X86_64_SSE_CLASS:
+ floatfloat2sse (a, &stack->sse[ssecount++]);
+ break;
+ case X86_64_SSESF_CLASS:
+ float2sse (*(float *)a, &stack->sse[ssecount++]);
+ break;
+ case X86_64_SSEDF_CLASS:
+ double2sse (*(double *)a, &stack->sse[ssecount++]);
+ break;
+ default:
+ abort();
+ }
+ }
+ }
+ }
+}
+
+/* Perform machine dependent cif processing. */
+ffi_status
+ffi_prep_cif_machdep (ffi_cif *cif)
+{
+ int gprcount, ssecount, i, g, s;
+
+ gprcount = ssecount = 0;
+
+ /* Reset the byte count. We handle this size estimation here. */
+ cif->bytes = 0;
+
+ /* If the return value should be passed in memory, pass the pointer
+ as the first argument. The actual memory isn't allocated here. */
+ if (cif->rtype->type != FFI_TYPE_VOID
+ && examine_argument (cif->rtype, 1, &g, &s) == 0)
+ gprcount = 1;
+
+ /* Go over all arguments and determine the way they should be passed.
+ If it's in a register and there is space for it, let that be so. If
+ not, add it's size to the stack byte count. */
+ for (i=0; i<cif->nargs; i++)
+ {
+ if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0
+ || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
+ {
+ /* This is passed in memory. First align to the basic type. */
+ cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment);
+
+ /* Stack arguments are *always* at least 8 byte aligned. */
+ cif->bytes = ALIGN(cif->bytes, 8);
+
+ /* Now add the size of this argument. */
+ cif->bytes += cif->arg_types[i]->size;
+ }
+ else
+ {
+ gprcount += g;
+ ssecount += s;
+ }
+ }
+
+ /* Set the flag for the closures return. */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ cif->flags = (unsigned) cif->rtype->type;
+ break;
+
+ case FFI_TYPE_UINT64:
+ cif->flags = FFI_TYPE_SINT64;
+ break;
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ break;
+ }
+
+ return FFI_OK;
+}
+
+typedef struct
+{
+ long gpr[2];
+ __int128_t sse[2];
+ long double st0;
+} return_value;
+
+void
+ffi_fill_return_value (return_value *rv, extended_cif *ecif)
+{
+ enum x86_64_reg_class classes[MAX_CLASSES];
+ int i = 0, num;
+ long *gpr = rv->gpr;
+ __int128_t *sse = rv->sse;
+ signed char sc;
+ signed short ss;
+
+ /* This is needed because of the way x86-64 handles signed short
+ integers. */
+ switch (ecif->cif->rtype->type)
+ {
+ case FFI_TYPE_SINT8:
+ sc = *(signed char *)gpr;
+ *(long long *)ecif->rvalue = (long long)sc;
+ return;
+ case FFI_TYPE_SINT16:
+ ss = *(signed short *)gpr;
+ *(long long *)ecif->rvalue = (long long)ss;
+ return;
+ default:
+ /* Just continue. */
+ ;
+ }
+
+ num = classify_argument (ecif->cif->rtype, classes, &i);
+
+ if (num == 0)
+ /* Return in memory. */
+ ecif->rvalue = (void *) rv->gpr[0];
+ else if (num == 2 && classes[0] == X86_64_X87_CLASS &&
+ classes[1] == X86_64_X87UP_CLASS)
+ /* This is a long double (this is easiest to handle this way instead
+ of an eightbyte at a time as in the loop below. */
+ *((long double *)ecif->rvalue) = rv->st0;
+ else
+ {
+ void *a;
+
+ for (i=0, a=ecif->rvalue; i<num; i++, a+=8)
+ {
+ switch (classes[i])
+ {
+ case X86_64_INTEGER_CLASS:
+ case X86_64_INTEGERSI_CLASS:
+ *(long long *)a = *gpr;
+ gpr++;
+ break;
+ case X86_64_SSE_CLASS:
+ sse2floatfloat (sse++, a);
+ break;
+ case X86_64_SSESF_CLASS:
+ *(float *)a = sse2float (sse++);
+ break;
+ case X86_64_SSEDF_CLASS:
+ *(double *)a = sse2double (sse++);
+ break;
+ default:
+ abort();
+ }
+ }
+ }
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_UNIX64(void (*)(stackLayout *, extended_cif *),
+ void (*) (return_value *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ 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;
+ int dummy;
+
+ 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) &&
+ (examine_argument (cif->rtype, 1, &dummy, &dummy) == 0))
+ {
+ /*@-sysunrecog@*/
+ ecif.rvalue = alloca(cif->rtype->size);
+ /*@=sysunrecog@*/
+ }
+ else
+ ecif.rvalue = rvalue;
+
+ /* Stack must always be 16byte aligned. Make it so. */
+ cif->bytes = ALIGN(cif->bytes, 16);
+
+ switch (cif->abi)
+ {
+ case FFI_SYSV:
+ /* Calling 32bit code from 64bit is not possible */
+ FFI_ASSERT(0);
+ break;
+
+ case FFI_UNIX64:
+ /*@-usedef@*/
+ ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif,
+ cif->bytes, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+extern void ffi_closure_UNIX64(void);
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data)
+{
+ volatile unsigned short *tramp;
+
+ /* FFI_ASSERT (cif->abi == FFI_OSF); */
+
+ tramp = (volatile unsigned short *) &closure->tramp[0];
+ tramp[0] = 0xbb49; /* mov <code>, %r11 */
+ tramp[5] = 0xba49; /* mov <data>, %r10 */
+ tramp[10] = 0xff49; /* jmp *%r11 */
+ tramp[11] = 0x00e3;
+ *(void * volatile *) &tramp[1] = ffi_closure_UNIX64;
+ *(void * volatile *) &tramp[6] = closure;
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ return FFI_OK;
+}
+
+int
+ffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp)
+{
+ ffi_cif *cif;
+ void **avalue;
+ ffi_type **arg_types;
+ long i, avn, argn;
+
+ cif = closure->cif;
+ avalue = alloca(cif->nargs * sizeof(void *));
+
+ argn = 0;
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ while (i < avn)
+ {
+ switch (arg_types[i]->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_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ {
+ if (l->gp_offset > 48-8)
+ {
+ avalue[i] = l->overflow_arg_area;
+ l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
+ }
+ else
+ {
+ avalue[i] = (char *)l->reg_save_area + l->gp_offset;
+ l->gp_offset += 8;
+ }
+ }
+ break;
+
+ case FFI_TYPE_STRUCT:
+ /* FIXME */
+ FFI_ASSERT(0);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ {
+ if (l->fp_offset > 176-16)
+ {
+ avalue[i] = l->overflow_arg_area;
+ l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
+ }
+ else
+ {
+ avalue[i] = (char *)l->reg_save_area + l->fp_offset;
+ l->fp_offset += 16;
+ }
+ }
+#if DEBUG_FFI
+ fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]);
+#endif
+ break;
+
+ case FFI_TYPE_FLOAT:
+ {
+ if (l->fp_offset > 176-16)
+ {
+ avalue[i] = l->overflow_arg_area;
+ l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
+ }
+ else
+ {
+ avalue[i] = (char *)l->reg_save_area + l->fp_offset;
+ l->fp_offset += 16;
+ }
+ }
+#if DEBUG_FFI
+ fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]);
+#endif
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+
+ argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ i++;
+ }
+
+ /* Invoke the closure. */
+ (closure->fun) (cif, rp, avalue, closure->user_data);
+
+ /* FIXME: Structs not supported. */
+ FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT);
+
+ /* Tell ffi_closure_UNIX64 how to perform return type promotions. */
+
+ return cif->rtype->type;
+}
+#endif /* ifndef __x86_64__ */
diff --git a/libffi/src/x86/ffi_darwin.c b/libffi/src/x86/ffi_darwin.c
new file mode 100644
index 0000000..bf79c56
--- /dev/null
+++ b/libffi/src/x86/ffi_darwin.c
@@ -0,0 +1,584 @@
+#ifdef __i386__
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc.
+ Copyright (c) 2002 Ranjit Mathew
+ Copyright (c) 2002 Bo Thorsen
+ Copyright (c) 2002 Roger Sayle
+
+ x86 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.
+ ----------------------------------------------------------------------- */
+
+#ifndef __x86_64__
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+/*@-exportheader@*/
+void ffi_prep_args(char *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+ register unsigned int i;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ argp = stack;
+
+ if (ecif->cif->flags == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 8)
+ {
+ *(void **) argp = ecif->rvalue;
+ argp += 4;
+ }
+
+ p_argv = ecif->avalue;
+
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
+ i != 0;
+ i--, p_arg++)
+ {
+ size_t z;
+
+ /* Align if necessary */
+ if ((sizeof(int) - 1) & (unsigned) argp)
+ argp = (char *) ALIGN(argp, sizeof(int));
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT32:
+ *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT32:
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ }
+ else
+ {
+ memcpy(argp, *p_argv, z);
+ }
+ p_argv++;
+ argp += z;
+ }
+
+ return;
+}
+
+/* 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:
+#if !defined(X86_WIN32)
+ case FFI_TYPE_STRUCT:
+#endif
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ cif->flags = (unsigned) cif->rtype->type;
+ break;
+
+ case FFI_TYPE_UINT64:
+ cif->flags = FFI_TYPE_SINT64;
+ break;
+
+#if defined X86_WIN32
+
+ case FFI_TYPE_STRUCT:
+ if (cif->rtype->size == 1)
+ {
+ cif->flags = FFI_TYPE_SINT8; /* same as char size */
+ }
+ else if (cif->rtype->size == 2)
+ {
+ cif->flags = FFI_TYPE_SINT16; /* same as short size */
+ }
+ else if (cif->rtype->size == 4)
+ {
+ cif->flags = FFI_TYPE_INT; /* same as int type */
+ }
+ else if (cif->rtype->size == 8)
+ {
+ cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
+ }
+ else
+ {
+ cif->flags = FFI_TYPE_STRUCT;
+ }
+ break;
+#endif
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ break;
+ }
+
+ /* Darwin: The stack needs to be aligned to a multiple of 16 bytes */
+ cif->bytes = (cif->bytes + 15) & ~0xF;
+
+ return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+/*@=declundef@*/
+/*@=exportheader@*/
+
+#ifdef X86_WIN32
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_STDCALL(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+/*@=declundef@*/
+/*@=exportheader@*/
+#endif /* X86_WIN32 */
+
+void ffi_call(/*@dependent@*/ ffi_cif *cif,
+ void (*fn)(),
+ /*@out@*/ void *rvalue,
+ /*@dependent@*/ void **avalue)
+{
+ extended_cif ecif;
+ int flags;
+
+ 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->flags == FFI_TYPE_STRUCT) && (cif->rtype->size > 8))
+ {
+ /*@-sysunrecog@*/
+ ecif.rvalue = alloca(cif->rtype->size);
+ /*@=sysunrecog@*/
+ }
+ else
+ ecif.rvalue = rvalue;
+
+ flags = cif->flags;
+ if (flags == FFI_TYPE_STRUCT) {
+ if (cif->rtype->size == 8) {
+ flags = FFI_TYPE_SINT64;
+ } else if (cif->rtype->size < 8) {
+ flags = FFI_TYPE_INT;
+ }
+ }
+
+
+ switch (cif->abi)
+ {
+ case FFI_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
+ flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#ifdef X86_WIN32
+ case FFI_STDCALL:
+ /*@-usedef@*/
+ ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#endif /* X86_WIN32 */
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+
+/** private members **/
+
+static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
+ void** args, ffi_cif* cif);
+static void ffi_closure_SYSV (ffi_closure *)
+ __attribute__ ((regparm(1)));
+#if !FFI_NO_RAW_API
+static void ffi_closure_raw_SYSV (ffi_raw_closure *)
+ __attribute__ ((regparm(1)));
+#endif
+
+/* This function is jumped to by the trampoline */
+
+static void
+ffi_closure_SYSV (closure)
+ ffi_closure *closure;
+{
+ // this is our return value storage
+ long double res;
+
+ // our various things...
+ ffi_cif *cif;
+ void **arg_area;
+ unsigned short rtype;
+ void *resp = (void*)&res;
+ void *args = __builtin_dwarf_cfa ();
+
+ cif = closure->cif;
+ arg_area = (void**) alloca (cif->nargs * sizeof (void*));
+
+ /* this call will initialize ARG_AREA, such that each
+ * element in that array points to the corresponding
+ * value on the stack; and if the function returns
+ * a structure, it will re-set RESP to point to the
+ * structure return address. */
+
+ ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
+
+ (closure->fun) (cif, resp, arg_area, closure->user_data);
+
+ rtype = cif->flags;
+
+ if (rtype == FFI_TYPE_STRUCT && cif->rtype->size <= 8) {
+ if (cif->rtype->size == 8) {
+ rtype = FFI_TYPE_SINT64;
+ } else {
+ rtype = FFI_TYPE_INT;
+ }
+ }
+
+ /* now, do a generic return based on the value of rtype */
+ if (rtype == FFI_TYPE_INT)
+ {
+ asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
+ }
+ else if (rtype == FFI_TYPE_FLOAT)
+ {
+ asm ("flds (%0)" : : "r" (resp) : "st" );
+ }
+ else if (rtype == FFI_TYPE_DOUBLE)
+ {
+ asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
+ }
+ else if (rtype == FFI_TYPE_LONGDOUBLE)
+ {
+ asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
+ }
+ else if (rtype == FFI_TYPE_SINT64)
+ {
+ asm ("movl 0(%0),%%eax;"
+ "movl 4(%0),%%edx"
+ : : "r"(resp)
+ : "eax", "edx");
+ }
+#ifdef X86_WIN32
+ else if (rtype == FFI_TYPE_SINT8) /* 1-byte struct */
+ {
+ asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax");
+ }
+ else if (rtype == FFI_TYPE_SINT16) /* 2-bytes struct */
+ {
+ asm ("movswl (%0),%%eax" : : "r" (resp) : "eax");
+ }
+#endif
+}
+
+/*@-exportheader@*/
+static void
+ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
+ void **avalue, ffi_cif *cif)
+/*@=exportheader@*/
+{
+ register unsigned int i;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ argp = stack;
+
+ if ( cif->flags == FFI_TYPE_STRUCT && (cif->rtype->size > 8)) {
+ *rvalue = *(void **) argp;
+ argp += 4;
+ }
+
+ p_argv = avalue;
+
+ for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
+ {
+ size_t z;
+
+ /* Align if necessary */
+ if ((sizeof(int) - 1) & (unsigned) argp) {
+ argp = (char *) ALIGN(argp, sizeof(int));
+ }
+
+ z = (*p_arg)->size;
+
+ /* because we're little endian, this is what it turns into. */
+
+ *p_argv = (void*) argp;
+
+ p_argv++;
+ argp += z;
+ }
+
+ return;
+}
+
+/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
+
+#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
+({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
+ unsigned int __fun = (unsigned int)(FUN); \
+ unsigned int __ctx = (unsigned int)(CTX); \
+ unsigned int __dis = __fun - ((unsigned int) __tramp + FFI_TRAMPOLINE_SIZE); \
+ *(unsigned char*) &__tramp[0] = 0xb8; \
+ *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
+ *(unsigned char *) &__tramp[5] = 0xe9; \
+ *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
+ })
+
+
+/* the cif must already be prep'ed */
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data)
+{
+ FFI_ASSERT (cif->abi == FFI_SYSV);
+
+ FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
+ &ffi_closure_SYSV, \
+ (void*)closure);
+
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+/* ------- Native raw API support -------------------------------- */
+
+#if !FFI_NO_RAW_API
+
+static void
+ffi_closure_raw_SYSV (closure)
+ ffi_raw_closure *closure;
+{
+ // this is our return value storage
+ long double res;
+
+ // our various things...
+ ffi_raw *raw_args;
+ ffi_cif *cif;
+ unsigned short rtype;
+ void *resp = (void*)&res;
+
+ /* get the cif */
+ cif = closure->cif;
+
+ /* the SYSV/X86 abi matches the RAW API exactly, well.. almost */
+ raw_args = (ffi_raw*) __builtin_dwarf_cfa ();
+
+ (closure->fun) (cif, resp, raw_args, closure->user_data);
+
+ rtype = cif->flags;
+
+ /* now, do a generic return based on the value of rtype */
+ if (rtype == FFI_TYPE_INT)
+ {
+ asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
+ }
+ else if (rtype == FFI_TYPE_FLOAT)
+ {
+ asm ("flds (%0)" : : "r" (resp) : "st" );
+ }
+ else if (rtype == FFI_TYPE_DOUBLE)
+ {
+ asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
+ }
+ else if (rtype == FFI_TYPE_LONGDOUBLE)
+ {
+ asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
+ }
+ else if (rtype == FFI_TYPE_SINT64)
+ {
+ asm ("movl 0(%0),%%eax; movl 4(%0),%%edx"
+ : : "r"(resp)
+ : "eax", "edx");
+ }
+}
+
+
+
+
+ffi_status
+ffi_prep_raw_closure (ffi_raw_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+ void *user_data)
+{
+ int i;
+
+ FFI_ASSERT (cif->abi == FFI_SYSV);
+
+ // we currently don't support certain kinds of arguments for raw
+ // closures. This should be implemented by a separate assembly language
+ // routine, since it would require argument processing, something we
+ // don't do now for performance.
+
+ for (i = cif->nargs-1; i >= 0; i--)
+ {
+ FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
+ FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
+ }
+
+
+ FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
+ (void*)closure);
+
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+static void
+ffi_prep_args_raw(char *stack, extended_cif *ecif)
+{
+ memcpy (stack, ecif->avalue, ecif->cif->bytes);
+}
+
+/* we borrow this routine from libffi (it must be changed, though, to
+ * actually call the function passed in the first argument. as of
+ * libffi-1.20, this is not the case.)
+ */
+
+extern void
+ffi_call_SYSV(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+
+#ifdef X86_WIN32
+extern void
+ffi_call_STDCALL(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+#endif /* X86_WIN32 */
+
+void
+ffi_raw_call(/*@dependent@*/ ffi_cif *cif,
+ void (*fn)(),
+ /*@out@*/ void *rvalue,
+ /*@dependent@*/ ffi_raw *fake_avalue)
+{
+ extended_cif ecif;
+ void **avalue = (void **)fake_avalue;
+
+ 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) && (cif->rtype->size > 8))
+ {
+ /*@-sysunrecog@*/
+ ecif.rvalue = alloca(cif->rtype->size);
+ /*@=sysunrecog@*/
+ }
+ else
+ ecif.rvalue = rvalue;
+
+
+ switch (cif->abi)
+ {
+ case FFI_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#ifdef X86_WIN32
+ case FFI_STDCALL:
+ /*@-usedef@*/
+ ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+#endif /* X86_WIN32 */
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+#endif
+
+#endif /* __x86_64__ */
+
+#endif /* __i386__ */
diff --git a/libffi/src/x86/ffitarget.h b/libffi/src/x86/ffitarget.h
new file mode 100644
index 0000000..9500f40
--- /dev/null
+++ b/libffi/src/x86/ffitarget.h
@@ -0,0 +1,81 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for x86 and x86-64.
+
+ 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 ----------------------------------- */
+
+#if defined (X86_64) && defined (__i386__)
+#undef X86_64
+#define X86
+#endif
+
+/* ---- Generic type definitions ----------------------------------------- */
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+
+ /* ---- Intel x86 Win32 ---------- */
+#ifdef X86_WIN32
+ FFI_SYSV,
+ FFI_STDCALL,
+ /* TODO: Add fastcall support for the sake of completeness */
+ FFI_DEFAULT_ABI = FFI_SYSV,
+#endif
+
+ /* ---- Intel x86 and AMD x86-64 - */
+#if !defined(X86_WIN32) && (defined(__i386__) || defined(__x86_64__))
+ FFI_SYSV,
+ FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */
+#ifdef __i386__
+ FFI_DEFAULT_ABI = FFI_SYSV,
+#else
+ FFI_DEFAULT_ABI = FFI_UNIX64,
+#endif
+#endif
+
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+
+#ifdef X86_64
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_NATIVE_RAW_API 0
+#else
+#define FFI_TRAMPOLINE_SIZE 10
+#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
+#endif
+
+#endif
+
diff --git a/libffi/src/x86/sysv.S b/libffi/src/x86/sysv.S
new file mode 100644
index 0000000..53a4c2b
--- /dev/null
+++ b/libffi/src/x86/sysv.S
@@ -0,0 +1,184 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 1996, 1998, 2001, 2002, 2003 Red Hat, Inc.
+
+ X86 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.
+ ----------------------------------------------------------------------- */
+
+#ifndef __x86_64__
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+.text
+
+.globl ffi_prep_args
+
+ .align 4
+.globl ffi_call_SYSV
+ .type ffi_call_SYSV,@function
+
+ffi_call_SYSV:
+.LFB1:
+ pushl %ebp
+.LCFI0:
+ movl %esp,%ebp
+.LCFI1:
+ /* Make room for all of the new args. */
+ movl 16(%ebp),%ecx
+ subl %ecx,%esp
+
+ movl %esp,%eax
+
+ /* Place all of the ffi_prep_args in position */
+ pushl 12(%ebp)
+ pushl %eax
+ call *8(%ebp)
+
+ /* Return stack to previous state and call the function */
+ addl $8,%esp
+
+ call *28(%ebp)
+
+ /* Remove the space we pushed for the args */
+ movl 16(%ebp),%ecx
+ addl %ecx,%esp
+
+ /* Load %ecx with the return type code */
+ movl 20(%ebp),%ecx
+
+ /* If the return value pointer is NULL, assume no return value. */
+ cmpl $0,24(%ebp)
+ jne retint
+
+ /* Even if there is no space for the return value, we are
+ obliged to handle floating-point values. */
+ cmpl $FFI_TYPE_FLOAT,%ecx
+ jne noretval
+ fstp %st(0)
+
+ jmp epilogue
+
+retint:
+ cmpl $FFI_TYPE_INT,%ecx
+ jne retfloat
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ movl %eax,0(%ecx)
+ jmp epilogue
+
+retfloat:
+ cmpl $FFI_TYPE_FLOAT,%ecx
+ jne retdouble
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ fstps (%ecx)
+ jmp epilogue
+
+retdouble:
+ cmpl $FFI_TYPE_DOUBLE,%ecx
+ jne retlongdouble
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ fstpl (%ecx)
+ jmp epilogue
+
+retlongdouble:
+ cmpl $FFI_TYPE_LONGDOUBLE,%ecx
+ jne retint64
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ fstpt (%ecx)
+ jmp epilogue
+
+retint64:
+ cmpl $FFI_TYPE_SINT64,%ecx
+ jne retstruct
+ /* Load %ecx with the pointer to storage for the return value */
+ movl 24(%ebp),%ecx
+ movl %eax,0(%ecx)
+ movl %edx,4(%ecx)
+
+retstruct:
+ /* Nothing to do! */
+
+noretval:
+epilogue:
+ movl %ebp,%esp
+ popl %ebp
+ ret
+.LFE1:
+.ffi_call_SYSV_end:
+ .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
+
+ .section .eh_frame,EH_FRAME_FLAGS,@progbits
+.Lframe1:
+ .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */
+.LSCIE1:
+ .long 0x0 /* CIE Identifier Tag */
+ .byte 0x1 /* CIE Version */
+#ifdef __PIC__
+ .ascii "zR\0" /* CIE Augmentation */
+#else
+ .ascii "\0" /* CIE Augmentation */
+#endif
+ .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
+ .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
+ .byte 0x8 /* CIE RA Column */
+#ifdef __PIC__
+ .byte 0x1 /* .uleb128 0x1; Augmentation size */
+ .byte 0x1b /* FDE Encoding (pcrel sdata4) */
+#endif
+ .byte 0xc /* DW_CFA_def_cfa */
+ .byte 0x4 /* .uleb128 0x4 */
+ .byte 0x4 /* .uleb128 0x4 */
+ .byte 0x88 /* DW_CFA_offset, column 0x8 */
+ .byte 0x1 /* .uleb128 0x1 */
+ .align 4
+.LECIE1:
+.LSFDE1:
+ .long .LEFDE1-.LASFDE1 /* FDE Length */
+.LASFDE1:
+ .long .LASFDE1-.Lframe1 /* FDE CIE offset */
+#ifdef __PIC__
+ .long .LFB1-. /* FDE initial location */
+#else
+ .long .LFB1 /* FDE initial location */
+#endif
+ .long .LFE1-.LFB1 /* FDE address range */
+#ifdef __PIC__
+ .byte 0x0 /* .uleb128 0x0; Augmentation size */
+#endif
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .long .LCFI0-.LFB1
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x8 /* .uleb128 0x8 */
+ .byte 0x85 /* DW_CFA_offset, column 0x5 */
+ .byte 0x2 /* .uleb128 0x2 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .long .LCFI1-.LCFI0
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0x5 /* .uleb128 0x5 */
+ .align 4
+.LEFDE1:
+
+#endif /* ifndef __x86_64__ */
diff --git a/libffi/src/x86/unix64.S b/libffi/src/x86/unix64.S
new file mode 100644
index 0000000..310fed7
--- /dev/null
+++ b/libffi/src/x86/unix64.S
@@ -0,0 +1,303 @@
+/* -----------------------------------------------------------------------
+ unix64.S - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
+
+ x86-64 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.
+ ----------------------------------------------------------------------- */
+
+#ifdef __x86_64__
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+ .section .rodata
+.LC0:
+ .string "asm in progress %lld\n"
+.LC1:
+ .string "asm in progress\n"
+.text
+ .align 2
+.globl ffi_call_UNIX64
+ .type ffi_call_UNIX64,@function
+
+ffi_call_UNIX64:
+.LFB1:
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ /* Save all arguments */
+ subq $48, %rsp
+.LCFI2:
+ movq %rdi, -8(%rbp) /* ffi_prep_args */
+ movq %rsi, -16(%rbp) /* ffi_fill_return_value */
+ movq %rdx, -24(%rbp) /* ecif */
+ movq %rcx, -32(%rbp) /* cif->bytes */
+ movq %r8, -40(%rbp) /* ecif.rvalue */
+ movq %r9, -48(%rbp) /* fn */
+
+ /* Make room for all of the new args and the register args */
+ addl $176, %ecx
+.LCFI3:
+ subq %rcx, %rsp
+.LCFI4:
+ /* Setup the call to ffi_prep_args. */
+ movq %rdi, %rax /* &ffi_prep_args */
+ movq %rsp, %rdi /* stackLayout */
+ movq %rdx, %rsi /* ecif */
+ call *%rax /* ffi_prep_args(stackLayout, ecif);*/
+
+ /* ffi_prep_args have put all the register contents into the */
+ /* stackLayout struct. Now put the register values in place. */
+ movq (%rsp), %rdi
+ movq 8(%rsp), %rsi
+ movq 16(%rsp), %rdx
+ movq 24(%rsp), %rcx
+ movq 32(%rsp), %r8
+ movq 40(%rsp), %r9
+ movaps 48(%rsp), %xmm0
+ movaps 64(%rsp), %xmm1
+ movaps 80(%rsp), %xmm2
+ movaps 96(%rsp), %xmm3
+ movaps 112(%rsp), %xmm4
+ movaps 128(%rsp), %xmm5
+ movaps 144(%rsp), %xmm6
+ movaps 160(%rsp), %xmm7
+
+ /* Remove space for stackLayout so stack arguments are placed
+ correctly for the call. */
+.LCFI5:
+ addq $176, %rsp
+.LCFI6:
+ /* Call the user function. */
+ call *-48(%rbp)
+
+ /* Make stack space for the return_value struct. */
+ subq $64, %rsp
+
+ /* Fill in all potential return values to this struct. */
+ movq %rax, (%rsp)
+ movq %rdx, 8(%rsp)
+ movaps %xmm0, 16(%rsp)
+ movaps %xmm1, 32(%rsp)
+ fstpt 48(%rsp)
+
+ /* Now call ffi_fill_return_value. */
+ movq %rsp, %rdi /* struct return_value */
+ movq -24(%rbp), %rsi /* ecif */
+ movq -16(%rbp), %rax /* &ffi_fill_return_value */
+ call *%rax /* call it */
+
+ /* And the work is done. */
+ leave
+ ret
+.LFE1:
+.ffi_call_UNIX64_end:
+ .size ffi_call_UNIX64,.ffi_call_UNIX64_end-ffi_call_UNIX64
+
+.text
+ .align 2
+.globl float2sse
+ .type float2sse,@function
+float2sse:
+ /* Save the contents of this sse-float in a pointer. */
+ movaps %xmm0, (%rdi)
+ ret
+
+ .align 2
+.globl floatfloat2sse
+ .type floatfloat2sse,@function
+floatfloat2sse:
+ /* Save the contents of these two sse-floats in a pointer. */
+ movq (%rdi), %xmm0
+ movaps %xmm0, (%rsi)
+ ret
+
+ .align 2
+.globl double2sse
+ .type double2sse,@function
+double2sse:
+ /* Save the contents of this sse-double in a pointer. */
+ movaps %xmm0, (%rdi)
+ ret
+
+ .align 2
+.globl sse2float
+ .type sse2float,@function
+sse2float:
+ /* Save the contents of this sse-float in a pointer. */
+ movaps (%rdi), %xmm0
+ ret
+
+ .align 2
+.globl sse2double
+ .type sse2double,@function
+sse2double:
+ /* Save the contents of this pointer in a sse-double. */
+ movaps (%rdi), %xmm0
+ ret
+
+ .align 2
+.globl sse2floatfloat
+ .type sse2floatfloat,@function
+sse2floatfloat:
+ /* Save the contents of this pointer in two sse-floats. */
+ movaps (%rdi), %xmm0
+ movq %xmm0, (%rsi)
+ ret
+
+ .align 2
+.globl ffi_closure_UNIX64
+ .type ffi_closure_UNIX64,@function
+
+ffi_closure_UNIX64:
+.LFB2:
+ pushq %rbp
+.LCFI10:
+ movq %rsp, %rbp
+.LCFI11:
+ subq $240, %rsp
+.LCFI12:
+ movq %rdi, -176(%rbp)
+ movq %rsi, -168(%rbp)
+ movq %rdx, -160(%rbp)
+ movq %rcx, -152(%rbp)
+ movq %r8, -144(%rbp)
+ movq %r9, -136(%rbp)
+ /* FIXME: We can avoid all this stashing of XMM registers by
+ (in ffi_prep_closure) computing the number of
+ floating-point args and moving it into %rax before calling
+ this function. Once this is done, uncomment the next few
+ lines and only the essential XMM registers will be written
+ to memory. This is a significant saving. */
+/* movzbl %al, %eax */
+/* movq %rax, %rdx */
+/* leaq 0(,%rdx,4), %rax */
+/* leaq 2f(%rip), %rdx */
+/* subq %rax, %rdx */
+ leaq -1(%rbp), %rax
+/* jmp *%rdx */
+ movaps %xmm7, -15(%rax)
+ movaps %xmm6, -31(%rax)
+ movaps %xmm5, -47(%rax)
+ movaps %xmm4, -63(%rax)
+ movaps %xmm3, -79(%rax)
+ movaps %xmm2, -95(%rax)
+ movaps %xmm1, -111(%rax)
+ movaps %xmm0, -127(%rax)
+2:
+ movl %edi, -180(%rbp)
+ movl $0, -224(%rbp)
+ movl $48, -220(%rbp)
+ leaq 16(%rbp), %rax
+ movq %rax, -216(%rbp)
+ leaq -176(%rbp), %rdx
+ movq %rdx, -208(%rbp)
+ leaq -224(%rbp), %rsi
+ movq %r10, %rdi
+ movq %rsp, %rdx
+ call ffi_closure_UNIX64_inner@PLT
+
+ cmpl $FFI_TYPE_FLOAT, %eax
+ je 1f
+ cmpl $FFI_TYPE_DOUBLE, %eax
+ je 2f
+ cmpl $FFI_TYPE_LONGDOUBLE, %eax
+ je 3f
+ cmpl $FFI_TYPE_STRUCT, %eax
+ je 4f
+ popq %rax
+ leave
+ ret
+1:
+2:
+3:
+ movaps -240(%rbp), %xmm0
+ leave
+ ret
+4:
+ leave
+ ret
+.LFE2:
+
+ .section .eh_frame,EH_FRAME_FLAGS,@progbits
+.Lframe0:
+ .long .LECIE1-.LSCIE1
+.LSCIE1:
+ .long 0x0
+ .byte 0x1
+ .string "zR"
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .uleb128 0x1
+ .byte 0x1b
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE1:
+.LSFDE1:
+ .long .LEFDE1-.LASFDE1
+.LASFDE1:
+ .long .LASFDE1-.Lframe0
+
+ .long .LFB1-.
+ .long .LFE1-.LFB1
+ .uleb128 0x0
+ .byte 0x4 # DW_CFA_advance_loc4
+ .long .LCFI0-.LFB1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x10
+ .byte 0x86 # DW_CFA_offset: r6 at cfa-16
+ .uleb128 0x2
+ .byte 0x4 # DW_CFA_advance_loc4
+ .long .LCFI1-.LCFI0
+ .byte 0x86 # DW_CFA_offset: r6 at cfa-16
+ .uleb128 0x2
+ .byte 0xd # DW_CFA_def_cfa_reg: r6
+ .uleb128 0x6
+ .align 8
+.LEFDE1:
+.LSFDE3:
+ .long .LEFDE3-.LASFDE3 # FDE Length
+.LASFDE3:
+ .long .LASFDE3-.Lframe0 # FDE CIE offset
+
+ .long .LFB2-. # FDE initial location
+ .long .LFE2-.LFB2 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .long .LCFI10-.LFB2
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x10
+ .byte 0x86 # DW_CFA_offset, column 0x6
+ .uleb128 0x2
+ .byte 0x4 # DW_CFA_advance_loc4
+ .long .LCFI11-.LCFI10
+ .byte 0xd # DW_CFA_def_cfa_register
+ .uleb128 0x6
+ .align 8
+.LEFDE3:
+
+#endif /* __x86_64__ */
diff --git a/libffi/src/x86/win32.S b/libffi/src/x86/win32.S
new file mode 100644
index 0000000..bc2812c
--- /dev/null
+++ b/libffi/src/x86/win32.S
@@ -0,0 +1,259 @@
+/* -----------------------------------------------------------------------
+ win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc.
+ Copyright (c) 2001 John Beniton
+ Copyright (c) 2002 Ranjit Mathew
+
+
+ X86 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
+
+.globl ffi_prep_args
+
+ # This assumes we are using gas.
+ .balign 16
+.globl _ffi_call_SYSV
+
+_ffi_call_SYSV:
+ pushl %ebp
+ movl %esp,%ebp
+
+ # Make room for all of the new args.
+ movl 16(%ebp),%ecx
+ subl %ecx,%esp
+
+ movl %esp,%eax
+
+ # Place all of the ffi_prep_args in position
+ pushl 12(%ebp)
+ pushl %eax
+ call *8(%ebp)
+
+ # Return stack to previous state and call the function
+ addl $8,%esp
+
+ # FIXME: Align the stack to a 128-bit boundary to avoid
+ # potential performance hits.
+
+ call *28(%ebp)
+
+ # Remove the space we pushed for the args
+ movl 16(%ebp),%ecx
+ addl %ecx,%esp
+
+ # Load %ecx with the return type code
+ movl 20(%ebp),%ecx
+
+ # If the return value pointer is NULL, assume no return value.
+ cmpl $0,24(%ebp)
+ jne retint
+
+ # Even if there is no space for the return value, we are
+ # obliged to handle floating-point values.
+ cmpl $FFI_TYPE_FLOAT,%ecx
+ jne noretval
+ fstp %st(0)
+
+ jmp epilogue
+
+retint:
+ cmpl $FFI_TYPE_INT,%ecx
+ jne retfloat
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ movl %eax,0(%ecx)
+ jmp epilogue
+
+retfloat:
+ cmpl $FFI_TYPE_FLOAT,%ecx
+ jne retdouble
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ fstps (%ecx)
+ jmp epilogue
+
+retdouble:
+ cmpl $FFI_TYPE_DOUBLE,%ecx
+ jne retlongdouble
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ fstpl (%ecx)
+ jmp epilogue
+
+retlongdouble:
+ cmpl $FFI_TYPE_LONGDOUBLE,%ecx
+ jne retint64
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ fstpt (%ecx)
+ jmp epilogue
+
+retint64:
+ cmpl $FFI_TYPE_SINT64,%ecx
+ jne retstruct1b
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ movl %eax,0(%ecx)
+ movl %edx,4(%ecx)
+
+retstruct1b:
+ cmpl $FFI_TYPE_SINT8,%ecx
+ jne retstruct2b
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ movb %al,0(%ecx)
+ jmp epilogue
+
+retstruct2b:
+ cmpl $FFI_TYPE_SINT16,%ecx
+ jne retstruct
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ movw %ax,0(%ecx)
+ jmp epilogue
+
+retstruct:
+ # Nothing to do!
+
+noretval:
+epilogue:
+ movl %ebp,%esp
+ popl %ebp
+ ret
+
+.ffi_call_SYSV_end:
+
+ # This assumes we are using gas.
+ .balign 16
+.globl _ffi_call_STDCALL
+
+_ffi_call_STDCALL:
+ pushl %ebp
+ movl %esp,%ebp
+
+ # Make room for all of the new args.
+ movl 16(%ebp),%ecx
+ subl %ecx,%esp
+
+ movl %esp,%eax
+
+ # Place all of the ffi_prep_args in position
+ pushl 12(%ebp)
+ pushl %eax
+ call *8(%ebp)
+
+ # Return stack to previous state and call the function
+ addl $8,%esp
+
+ # FIXME: Align the stack to a 128-bit boundary to avoid
+ # potential performance hits.
+
+ call *28(%ebp)
+
+ # stdcall functions pop arguments off the stack themselves
+
+ # Load %ecx with the return type code
+ movl 20(%ebp),%ecx
+
+ # If the return value pointer is NULL, assume no return value.
+ cmpl $0,24(%ebp)
+ jne sc_retint
+
+ # Even if there is no space for the return value, we are
+ # obliged to handle floating-point values.
+ cmpl $FFI_TYPE_FLOAT,%ecx
+ jne sc_noretval
+ fstp %st(0)
+
+ jmp sc_epilogue
+
+sc_retint:
+ cmpl $FFI_TYPE_INT,%ecx
+ jne sc_retfloat
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ movl %eax,0(%ecx)
+ jmp sc_epilogue
+
+sc_retfloat:
+ cmpl $FFI_TYPE_FLOAT,%ecx
+ jne sc_retdouble
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ fstps (%ecx)
+ jmp sc_epilogue
+
+sc_retdouble:
+ cmpl $FFI_TYPE_DOUBLE,%ecx
+ jne sc_retlongdouble
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ fstpl (%ecx)
+ jmp sc_epilogue
+
+sc_retlongdouble:
+ cmpl $FFI_TYPE_LONGDOUBLE,%ecx
+ jne sc_retint64
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ fstpt (%ecx)
+ jmp sc_epilogue
+
+sc_retint64:
+ cmpl $FFI_TYPE_SINT64,%ecx
+ jne sc_retstruct1b
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ movl %eax,0(%ecx)
+ movl %edx,4(%ecx)
+
+sc_retstruct1b:
+ cmpl $FFI_TYPE_SINT8,%ecx
+ jne sc_retstruct2b
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ movb %al,0(%ecx)
+ jmp sc_epilogue
+
+sc_retstruct2b:
+ cmpl $FFI_TYPE_SINT16,%ecx
+ jne sc_retstruct
+ # Load %ecx with the pointer to storage for the return value
+ movl 24(%ebp),%ecx
+ movw %ax,0(%ecx)
+ jmp sc_epilogue
+
+sc_retstruct:
+ # Nothing to do!
+
+sc_noretval:
+sc_epilogue:
+ movl %ebp,%esp
+ popl %ebp
+ ret
+
+.ffi_call_STDCALL_end: