summaryrefslogtreecommitdiff
path: root/libffi-3.0.4/src/powerpc
diff options
context:
space:
mode:
authorMatthias Benkard <code@mail.matthias.benkard.de>2008-03-03 21:39:37 +0100
committerMatthias Benkard <code@mail.matthias.benkard.de>2008-03-03 21:39:37 +0100
commitcd11ae061b002913740483529e31b3f6d3da753d (patch)
treea6d84df9a4a8ed53476aa079a7202fdec69f4d98 /libffi-3.0.4/src/powerpc
parentb2342735e543f8fec2f6914d5e628391dd0ffc46 (diff)
Update libffi to 3.0.4.
darcs-hash:d0cdf89441c98da668f268b1af91e536dc3ed76e
Diffstat (limited to 'libffi-3.0.4/src/powerpc')
-rw-r--r--libffi-3.0.4/src/powerpc/aix.S225
-rw-r--r--libffi-3.0.4/src/powerpc/aix_closure.S247
-rw-r--r--libffi-3.0.4/src/powerpc/asm.h125
-rw-r--r--libffi-3.0.4/src/powerpc/darwin.S245
-rw-r--r--libffi-3.0.4/src/powerpc/darwin_closure.S317
-rw-r--r--libffi-3.0.4/src/powerpc/ffi.c1428
-rw-r--r--libffi-3.0.4/src/powerpc/ffi_darwin.c800
-rw-r--r--libffi-3.0.4/src/powerpc/ffitarget.h118
-rw-r--r--libffi-3.0.4/src/powerpc/linux64.S181
-rw-r--r--libffi-3.0.4/src/powerpc/linux64_closure.S206
-rw-r--r--libffi-3.0.4/src/powerpc/ppc_closure.S297
-rw-r--r--libffi-3.0.4/src/powerpc/sysv.S225
12 files changed, 4414 insertions, 0 deletions
diff --git a/libffi-3.0.4/src/powerpc/aix.S b/libffi-3.0.4/src/powerpc/aix.S
new file mode 100644
index 0000000..45502f7
--- /dev/null
+++ b/libffi-3.0.4/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-3.0.4/src/powerpc/aix_closure.S b/libffi-3.0.4/src/powerpc/aix_closure.S
new file mode 100644
index 0000000..7bf5c65
--- /dev/null
+++ b/libffi-3.0.4/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-3.0.4/src/powerpc/asm.h b/libffi-3.0.4/src/powerpc/asm.h
new file mode 100644
index 0000000..e86e6b0
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/asm.h
@@ -0,0 +1,125 @@
+/* -----------------------------------------------------------------------
+ asm.h - Copyright (c) 1998 Geoffrey Keating
+
+ 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 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-3.0.4/src/powerpc/darwin.S b/libffi-3.0.4/src/powerpc/darwin.S
new file mode 100644
index 0000000..d8a1df5
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/darwin.S
@@ -0,0 +1,245 @@
+/* -----------------------------------------------------------------------
+ darwin.S - Copyright (c) 2000 John Hornkvist
+ Copyright (c) 2004 Free Software Foundation, Inc.
+
+ 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.
+ ----------------------------------------------------------------------- */
+
+#if defined(__ppc64__)
+#define MODE_CHOICE(x, y) y
+#else
+#define MODE_CHOICE(x, y) x
+#endif
+
+#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */
+
+#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */
+
+#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 /* No floats to load. */
+ 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):
+ /* Do we have long double to store? */
+ bf 31,L(fd_return_value)
+ stfd f1,0(r30)
+ stfd f2,8(r30)
+ b L(done_return_value)
+
+L(fd_return_value):
+ /* Do we have double to store? */
+ bf 28,L(float_return_value)
+ stfd f1,0(r30)
+ b L(done_return_value)
+
+L(float_return_value):
+ /* We only have a float to store. */
+ 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 LOG2_GPR_BYTES
+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
+ .g_long LLFB0$non_lazy_ptr-. ; FDE initial location
+ .set L$set$3,LFE1-LFB0
+ .g_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 LOG2_GPR_BYTES
+LEFDE1:
+.data
+ .align LOG2_GPR_BYTES
+LLFB0$non_lazy_ptr:
+ .g_long LFB0
diff --git a/libffi-3.0.4/src/powerpc/darwin_closure.S b/libffi-3.0.4/src/powerpc/darwin_closure.S
new file mode 100644
index 0000000..7959838
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/darwin_closure.S
@@ -0,0 +1,317 @@
+/* -----------------------------------------------------------------------
+ darwin_closure.S - Copyright (c) 2002, 2003, 2004, 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
+
+#if defined(__ppc64__)
+#define MODE_CHOICE(x, y) y
+#else
+#define MODE_CHOICE(x, y) x
+#endif
+
+#define lgu MODE_CHOICE(lwzu, ldu)
+
+#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */
+
+#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */
+
+ .file "darwin_closure.S"
+.text
+ .align LOG2_GPR_BYTES
+.globl _ffi_closure_ASM
+
+.text
+ .align LOG2_GPR_BYTES
+_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)
+ 16 Bytes (result)
+ 176 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)
+ lfd f2,8(r5)
+ b Lfinish
+ 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+live_support
+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 LOG2_GPR_BYTES
+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
+ .g_long LLFB1$non_lazy_ptr-. ; FDE initial location
+ .set L$set$3,LFE1-LFB1
+ .g_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 LOG2_GPR_BYTES
+LEFDE1:
+.data
+ .align LOG2_GPR_BYTES
+LDFCM0:
+.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
+ .align LOG2_GPR_BYTES
+Lffi_closure_helper_DARWIN$stub:
+#if 1
+ .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
+ lgu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN)(r11)
+ mtctr r12
+ bctr
+.lazy_symbol_pointer
+L_ffi_closure_helper_DARWIN$lazy_ptr:
+ .indirect_symbol _ffi_closure_helper_DARWIN
+ .g_long dyld_stub_binding_helper
+#endif
+.data
+ .align LOG2_GPR_BYTES
+LLFB1$non_lazy_ptr:
+ .g_long LFB1
diff --git a/libffi-3.0.4/src/powerpc/ffi.c b/libffi-3.0.4/src/powerpc/ffi.c
new file mode 100644
index 0000000..e6b869f
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/ffi.c
@@ -0,0 +1,1428 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1998 Geoffrey Keating
+ Copyright (C) 2007 Free Software Foundation, Inc
+
+ PowerPC 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.
+ ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+extern void ffi_closure_SYSV (void);
+extern void FFI_HIDDEN ffi_closure_LINUX64 (void);
+
+enum {
+ /* The assembly depends on these exact flags. */
+ FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */
+ FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */
+ FLAG_RETURNS_FP = 1 << (31-29),
+ FLAG_RETURNS_64BITS = 1 << (31-28),
+
+ FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */
+
+ 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. */
+unsigned int NUM_GPR_ARG_REGISTERS = 8;
+#ifndef __NO_FPRS__
+unsigned int NUM_FPR_ARG_REGISTERS = 8;
+#else
+unsigned int NUM_FPR_ARG_REGISTERS = 0;
+#endif
+
+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
+
+*/
+
+void
+ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
+{
+ const unsigned bytes = ecif->cif->bytes;
+ const unsigned flags = ecif->cif->flags;
+
+ typedef union {
+ char *c;
+ unsigned *u;
+ long long *ll;
+ float *f;
+ double *d;
+ } valp;
+
+ /* 'stacktop' points at the previous backchain pointer. */
+ valp stacktop;
+
+ /* 'gpr_base' points at the space for gpr3, and grows upwards as
+ we use GPR registers. */
+ valp gpr_base;
+ int intarg_count;
+
+ /* 'fpr_base' points at the space for fpr1, and grows upwards as
+ we use FPR registers. */
+ valp fpr_base;
+ int fparg_count;
+
+ /* 'copy_space' grows down as we put structures in it. It should
+ stay 16-byte aligned. */
+ valp copy_space;
+
+ /* 'next_arg' grows up as we put parameters in it. */
+ valp next_arg;
+
+ int i, ii MAYBE_UNUSED;
+ ffi_type **ptr;
+ double double_tmp;
+ union {
+ void **v;
+ char **c;
+ signed char **sc;
+ unsigned char **uc;
+ signed short **ss;
+ unsigned short **us;
+ unsigned int **ui;
+ long long **ll;
+ float **f;
+ double **d;
+ } p_argv;
+ size_t struct_copy_size;
+ unsigned gprvalue;
+
+ if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
+ NUM_FPR_ARG_REGISTERS = 0;
+
+ stacktop.c = (char *) stack + bytes;
+ gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
+ intarg_count = 0;
+ fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS;
+ fparg_count = 0;
+ copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
+ next_arg.u = stack + 2;
+
+ /* Check that everything starts aligned properly. */
+ FFI_ASSERT (((unsigned) (char *) stack & 0xF) == 0);
+ FFI_ASSERT (((unsigned) copy_space.c & 0xF) == 0);
+ FFI_ASSERT (((unsigned) stacktop.c & 0xF) == 0);
+ FFI_ASSERT ((bytes & 0xF) == 0);
+ FFI_ASSERT (copy_space.c >= next_arg.c);
+
+ /* Deal with return values that are actually pass-by-reference. */
+ if (flags & FLAG_RETVAL_REFERENCE)
+ {
+ *gpr_base.u++ = (unsigned long) (char *) ecif->rvalue;
+ intarg_count++;
+ }
+
+ /* Now for the arguments. */
+ p_argv.v = ecif->avalue;
+ for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
+ i > 0;
+ i--, ptr++, p_argv.v++)
+ {
+ switch ((*ptr)->type)
+ {
+ case FFI_TYPE_FLOAT:
+ /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
+ if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
+ goto soft_float_prep;
+ double_tmp = **p_argv.f;
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ {
+ *next_arg.f = (float) double_tmp;
+ next_arg.u += 1;
+ }
+ else
+ *fpr_base.d++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
+ if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
+ goto soft_double_prep;
+ double_tmp = **p_argv.d;
+
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ {
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS
+ && intarg_count % 2 != 0)
+ {
+ intarg_count++;
+ next_arg.u++;
+ }
+ *next_arg.d = double_tmp;
+ next_arg.u += 2;
+ }
+ else
+ *fpr_base.d++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
+ break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if ((ecif->cif->abi != FFI_LINUX)
+ && (ecif->cif->abi != FFI_LINUX_SOFT_FLOAT))
+ goto do_struct;
+ /* The soft float ABI for long doubles works like this,
+ a long double is passed in four consecutive gprs if available.
+ A maximum of 2 long doubles can be passed in gprs.
+ If we do not have 4 gprs left, the long double is passed on the
+ stack, 4-byte aligned. */
+ if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
+ {
+ unsigned int int_tmp = (*p_argv.ui)[0];
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3)
+ {
+ if (intarg_count < NUM_GPR_ARG_REGISTERS)
+ intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
+ *next_arg.u = int_tmp;
+ next_arg.u++;
+ for (ii = 1; ii < 4; ii++)
+ {
+ int_tmp = (*p_argv.ui)[ii];
+ *next_arg.u = int_tmp;
+ next_arg.u++;
+ }
+ }
+ else
+ {
+ *gpr_base.u++ = int_tmp;
+ for (ii = 1; ii < 4; ii++)
+ {
+ int_tmp = (*p_argv.ui)[ii];
+ *gpr_base.u++ = int_tmp;
+ }
+ }
+ intarg_count +=4;
+ }
+ else
+ {
+ double_tmp = (*p_argv.d)[0];
+
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
+ {
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS
+ && intarg_count % 2 != 0)
+ {
+ intarg_count++;
+ next_arg.u++;
+ }
+ *next_arg.d = double_tmp;
+ next_arg.u += 2;
+ double_tmp = (*p_argv.d)[1];
+ *next_arg.d = double_tmp;
+ next_arg.u += 2;
+ }
+ else
+ {
+ *fpr_base.d++ = double_tmp;
+ double_tmp = (*p_argv.d)[1];
+ *fpr_base.d++ = double_tmp;
+ }
+
+ fparg_count += 2;
+ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
+ }
+ break;
+#endif
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ soft_double_prep:
+ 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.u++;
+ }
+ *next_arg.ll = **p_argv.ll;
+ next_arg.u += 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.u++;
+ }
+ *gpr_base.ll++ = **p_argv.ll;
+ }
+ intarg_count += 2;
+ break;
+
+ case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ do_struct:
+#endif
+ struct_copy_size = ((*ptr)->size + 15) & ~0xF;
+ copy_space.c -= struct_copy_size;
+ memcpy (copy_space.c, *p_argv.c, (*ptr)->size);
+
+ gprvalue = (unsigned long) copy_space.c;
+
+ FFI_ASSERT (copy_space.c > next_arg.c);
+ FFI_ASSERT (flags & FLAG_ARG_NEEDS_COPY);
+ goto putgpr;
+
+ case FFI_TYPE_UINT8:
+ gprvalue = **p_argv.uc;
+ goto putgpr;
+ case FFI_TYPE_SINT8:
+ gprvalue = **p_argv.sc;
+ goto putgpr;
+ case FFI_TYPE_UINT16:
+ gprvalue = **p_argv.us;
+ goto putgpr;
+ case FFI_TYPE_SINT16:
+ gprvalue = **p_argv.ss;
+ goto putgpr;
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_POINTER:
+ soft_float_prep:
+
+ gprvalue = **p_argv.ui;
+
+ putgpr:
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS)
+ *next_arg.u++ = gprvalue;
+ else
+ *gpr_base.u++ = gprvalue;
+ intarg_count++;
+ break;
+ }
+ }
+
+ /* Check that we didn't overrun the stack... */
+ FFI_ASSERT (copy_space.c >= next_arg.c);
+ FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS);
+ FFI_ASSERT (fpr_base.u
+ <= stacktop.u - 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
+
+*/
+
+void FFI_HIDDEN
+ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
+{
+ const unsigned long bytes = ecif->cif->bytes;
+ const unsigned long flags = ecif->cif->flags;
+
+ typedef union {
+ char *c;
+ unsigned long *ul;
+ float *f;
+ double *d;
+ } valp;
+
+ /* 'stacktop' points at the previous backchain pointer. */
+ valp stacktop;
+
+ /* 'next_arg' points at the space for gpr3, and grows upwards as
+ we use GPR registers, then continues at rest. */
+ valp gpr_base;
+ valp gpr_end;
+ valp rest;
+ valp next_arg;
+
+ /* 'fpr_base' points at the space for fpr3, and grows upwards as
+ we use FPR registers. */
+ valp fpr_base;
+ int fparg_count;
+
+ int i, words;
+ ffi_type **ptr;
+ double double_tmp;
+ union {
+ void **v;
+ char **c;
+ signed char **sc;
+ unsigned char **uc;
+ signed short **ss;
+ unsigned short **us;
+ signed int **si;
+ unsigned int **ui;
+ unsigned long **ul;
+ float **f;
+ double **d;
+ } p_argv;
+ unsigned long gprvalue;
+
+ stacktop.c = (char *) stack + bytes;
+ gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
+ gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
+ rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
+ fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
+ fparg_count = 0;
+ next_arg.ul = gpr_base.ul;
+
+ /* Check that everything starts aligned properly. */
+ FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
+ FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
+ FFI_ASSERT ((bytes & 0xF) == 0);
+
+ /* Deal with return values that are actually pass-by-reference. */
+ if (flags & FLAG_RETVAL_REFERENCE)
+ *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue;
+
+ /* Now for the arguments. */
+ p_argv.v = ecif->avalue;
+ for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
+ i > 0;
+ i--, ptr++, p_argv.v++)
+ {
+ switch ((*ptr)->type)
+ {
+ case FFI_TYPE_FLOAT:
+ double_tmp = **p_argv.f;
+ *next_arg.f = (float) double_tmp;
+ if (++next_arg.ul == gpr_end.ul)
+ next_arg.ul = rest.ul;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base.d++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ double_tmp = **p_argv.d;
+ *next_arg.d = double_tmp;
+ if (++next_arg.ul == gpr_end.ul)
+ next_arg.ul = rest.ul;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base.d++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
+ break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ double_tmp = (*p_argv.d)[0];
+ *next_arg.d = double_tmp;
+ if (++next_arg.ul == gpr_end.ul)
+ next_arg.ul = rest.ul;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base.d++ = double_tmp;
+ fparg_count++;
+ double_tmp = (*p_argv.d)[1];
+ *next_arg.d = double_tmp;
+ if (++next_arg.ul == gpr_end.ul)
+ next_arg.ul = rest.ul;
+ if (fparg_count < NUM_FPR_ARG_REGISTERS64)
+ *fpr_base.d++ = double_tmp;
+ fparg_count++;
+ FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
+ FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
+ break;
+#endif
+
+ case FFI_TYPE_STRUCT:
+ words = ((*ptr)->size + 7) / 8;
+ if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
+ {
+ size_t first = gpr_end.c - next_arg.c;
+ memcpy (next_arg.c, *p_argv.c, first);
+ memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
+ next_arg.c = rest.c + words * 8 - first;
+ }
+ else
+ {
+ char *where = next_arg.c;
+
+ /* Structures with size less than eight bytes are passed
+ left-padded. */
+ if ((*ptr)->size < 8)
+ where += 8 - (*ptr)->size;
+
+ memcpy (where, *p_argv.c, (*ptr)->size);
+ next_arg.ul += words;
+ if (next_arg.ul == gpr_end.ul)
+ next_arg.ul = rest.ul;
+ }
+ break;
+
+ case FFI_TYPE_UINT8:
+ gprvalue = **p_argv.uc;
+ goto putgpr;
+ case FFI_TYPE_SINT8:
+ gprvalue = **p_argv.sc;
+ goto putgpr;
+ case FFI_TYPE_UINT16:
+ gprvalue = **p_argv.us;
+ goto putgpr;
+ case FFI_TYPE_SINT16:
+ gprvalue = **p_argv.ss;
+ goto putgpr;
+ case FFI_TYPE_UINT32:
+ gprvalue = **p_argv.ui;
+ goto putgpr;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ gprvalue = **p_argv.si;
+ goto putgpr;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_POINTER:
+ gprvalue = **p_argv.ul;
+ putgpr:
+ *next_arg.ul++ = gprvalue;
+ if (next_arg.ul == gpr_end.ul)
+ next_arg.ul = rest.ul;
+ break;
+ }
+ }
+
+ FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS
+ || (next_arg.ul >= gpr_base.ul
+ && next_arg.ul <= gpr_base.ul + 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;
+ unsigned size = cif->rtype->size;
+
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+ NUM_FPR_ARG_REGISTERS = 0;
+
+ 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);
+ }
+
+ /* 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 are allocated space and a pointer is passed as
+ the first argument.
+ - long doubles (if not equivalent to double) are returned in
+ fpr1,fpr2 for Linux and as for large structs for SysV.
+ For LINUX64:
+ - integer values in gpr3;
+ - Structures/Unions by reference;
+ - Single/double FP values in fpr1, long double in fpr1,fpr2.
+ - soft-float float/doubles are treated as UINT32/UINT64 respectivley.
+ - soft-float long doubles are returned in gpr3-gpr6. */
+ switch (type)
+ {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64
+ && cif->abi != FFI_LINUX_SOFT_FLOAT)
+ goto byref;
+ flags |= FLAG_RETURNS_128BITS;
+ /* Fall through. */
+#endif
+ case FFI_TYPE_DOUBLE:
+ flags |= FLAG_RETURNS_64BITS;
+ /* Fall through. */
+ case FFI_TYPE_FLOAT:
+ /* With FFI_LINUX_SOFT_FLOAT no fp registers are used. */
+ if (cif->abi != FFI_LINUX_SOFT_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_SYSV)
+ {
+ /* The final SYSV ABI says that structures smaller or equal 8 bytes
+ are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them
+ in memory. */
+
+ /* Treat structs with size <= 8 bytes. */
+ if (size <= 8)
+ {
+ flags |= FLAG_RETURNS_SMST;
+ /* These structs are returned in r3. We pack the type and the
+ precalculated shift value (needed in the sysv.S) into flags.
+ The same applies for the structs returned in r3/r4. */
+ if (size <= 4)
+ {
+ flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 1);
+ flags |= 8 * (4 - size) << 4;
+ break;
+ }
+ /* These structs are returned in r3 and r4. See above. */
+ if (size <= 8)
+ {
+ flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 2);
+ flags |= 8 * (8 - size) << 4;
+ break;
+ }
+ }
+ }
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ byref:
+#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:
+ /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+ goto soft_float_cif;
+ fparg_count++;
+ /* floating singles are not 8-aligned on stack */
+ break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
+ goto do_struct;
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+ {
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
+ || intarg_count < NUM_GPR_ARG_REGISTERS)
+ /* A long double in FFI_LINUX_SOFT_FLOAT can use only
+ a set of four consecutive gprs. If we have not enough,
+ we have to adjust the intarg_count value. */
+ intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
+ intarg_count += 4;
+ break;
+ }
+ else
+ fparg_count++;
+ /* Fall thru */
+#endif
+ case FFI_TYPE_DOUBLE:
+ /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+ goto soft_double_cif;
+ 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 >= NUM_GPR_ARG_REGISTERS
+ && intarg_count % 2 != 0)
+ intarg_count++;
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ soft_double_cif:
+ /* '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.
+
+ Also, only certain register pairs can be used for
+ passing long long int -- specifically (r3,r4), (r5,r6),
+ (r7,r8), (r9,r10).
+ */
+ if (intarg_count == NUM_GPR_ARG_REGISTERS-1
+ || intarg_count % 2 != 0)
+ intarg_count++;
+ intarg_count += 2;
+ break;
+
+ case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ do_struct:
+#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:
+ soft_float_cif:
+ /* 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:
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+ intarg_count += 4;
+ else
+ {
+ 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;
+}
+
+extern void ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *,
+ void (*fn)());
+extern void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long,
+ unsigned long, unsigned long *,
+ 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))
+ {
+ ecif.rvalue = alloca(cif->rtype->size);
+ }
+ else
+ ecif.rvalue = rvalue;
+
+
+ switch (cif->abi)
+ {
+#ifndef POWERPC64
+ case FFI_SYSV:
+ case FFI_GCC_SYSV:
+ case FFI_LINUX:
+ case FFI_LINUX_SOFT_FLOAT:
+ ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
+ break;
+#else
+ case FFI_LINUX64:
+ ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn);
+ break;
+#endif
+ default:
+ FFI_ASSERT (0);
+ break;
+ }
+}
+
+
+#ifndef POWERPC64
+#define MIN_CACHE_LINE_SIZE 8
+
+static void
+flush_icache (char *wraddr, char *xaddr, int size)
+{
+ int i;
+ for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
+ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
+ : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
+ __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
+ : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
+ : "memory");
+}
+#endif
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure *closure,
+ ffi_cif *cif,
+ void (*fun) (ffi_cif *, void *, void **, void *),
+ void *user_data,
+ void *codeloc)
+{
+#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] = codeloc;
+#else
+ unsigned int *tramp;
+
+ FFI_ASSERT (cif->abi == FFI_GCC_SYSV || cif->abi == FFI_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] = codeloc; /* context */
+
+ /* Flush the icache. */
+ flush_icache ((char *)tramp, (char *)codeloc, 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;
+ unsigned size;
+
+ cif = closure->cif;
+ avalue = alloca (cif->nargs * sizeof (void *));
+ size = cif->rtype->size;
+
+ nf = 0;
+ ng = 0;
+
+ /* Copy the caller's structure return value address so that the closure
+ returns the data directly to the caller.
+ For FFI_SYSV the result is passed in r3/r4 if the struct size is less
+ or equal 8 bytes. */
+
+ if ((cif->rtype->type == FFI_TYPE_STRUCT
+ && !((cif->abi == FFI_SYSV) && (size <= 8)))
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ || (cif->rtype->type == FFI_TYPE_LONGDOUBLE
+ && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
+#endif
+ )
+ {
+ 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:
+ soft_float_closure:
+ /* 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:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ do_struct:
+#endif
+ /* 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:
+ soft_double_closure:
+ /* 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:
+ /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+ goto soft_float_closure;
+ /* 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;
+ pst += 1;
+ }
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+ goto soft_double_closure;
+ /* 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;
+ pst += 2;
+ }
+ break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
+ goto do_struct;
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+ { /* Test if for the whole long double, 4 gprs are available.
+ otherwise the stuff ends up on the stack. */
+ if (ng < 5)
+ {
+ avalue[i] = pgr;
+ pgr += 4;
+ ng += 4;
+ }
+ else
+ {
+ avalue[i] = pst;
+ pst += 4;
+ }
+ break;
+ }
+ if (nf < 7)
+ {
+ avalue[i] = pfr;
+ pfr += 2;
+ nf += 2;
+ }
+ else
+ {
+ if (((long) pst) & 4)
+ pst++;
+ avalue[i] = pst;
+ pst += 4;
+ nf = 8;
+ }
+ break;
+#endif
+
+ default:
+ FFI_ASSERT (0);
+ }
+
+ i++;
+ }
+
+
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_SYSV how to perform return type promotions.
+ Because the FFI_SYSV ABI returns the structures <= 8 bytes in r3/r4
+ we have to tell ffi_closure_SYSV how to treat them. */
+ if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
+ && size <= 8)
+ return FFI_SYSV_TYPE_SMALL_STRUCT + size;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
+ && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
+ return FFI_TYPE_STRUCT;
+#endif
+ /* With FFI_LINUX_SOFT_FLOAT floats and doubles are handled like UINT32
+ respectivley UINT64. */
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT)
+ {
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_FLOAT:
+ return FFI_TYPE_UINT32;
+ break;
+ case FFI_TYPE_DOUBLE:
+ return FFI_TYPE_UINT64;
+ break;
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ return FFI_TYPE_UINT128;
+ break;
+#endif
+ default:
+ return cif->rtype->type;
+ }
+ }
+ else
+ {
+ return cif->rtype->type;
+ }
+}
+
+int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,
+ unsigned long *, ffi_dblfl *);
+
+int FFI_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-3.0.4/src/powerpc/ffi_darwin.c b/libffi-3.0.4/src/powerpc/ffi_darwin.c
new file mode 100644
index 0000000..6d1b73e
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/ffi_darwin.c
@@ -0,0 +1,800 @@
+/* -----------------------------------------------------------------------
+ ffi_darwin.c
+
+ Copyright (C) 1998 Geoffrey Keating
+ Copyright (C) 2001 John Hornkvist
+ Copyright (C) 2002, 2006, 2007 Free Software Foundation, Inc.
+
+ FFI support for Darwin and AIX.
+
+ 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_RETURNS_128BITS = 1 << (31-31),
+
+ 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
+
+ */
+
+void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
+{
+ 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));
+
+ /* '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 positions. */
+
+ 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;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+
+ case FFI_TYPE_LONGDOUBLE:
+ double_tmp = ((double *)*p_argv)[0];
+ if (fparg_count >= NUM_FPR_ARG_REGISTERS)
+ *(double *)next_arg = double_tmp;
+ else
+ *fpr_base++ = double_tmp;
+ next_arg += 2;
+ fparg_count++;
+ double_tmp = ((double *)*p_argv)[1];
+ 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;
+#endif
+ 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:
+ 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);
+}
+
+/* Adjust the size of S to be correct for Darwin.
+ On Darwin, the first field of a structure has natural alignment. */
+
+static void
+darwin_adjust_aggregate_sizes (ffi_type *s)
+{
+ int i;
+
+ if (s->type != FFI_TYPE_STRUCT)
+ return;
+
+ s->size = 0;
+ for (i = 0; s->elements[i] != NULL; i++)
+ {
+ ffi_type *p;
+ int align;
+
+ p = s->elements[i];
+ darwin_adjust_aggregate_sizes (p);
+ if (i == 0
+ && (p->type == FFI_TYPE_UINT64
+ || p->type == FFI_TYPE_SINT64
+ || p->type == FFI_TYPE_DOUBLE
+ || p->alignment == 8))
+ align = 8;
+ else if (p->alignment == 16 || p->alignment < 4)
+ align = p->alignment;
+ else
+ align = 4;
+ s->size = ALIGN(s->size, align) + p->size;
+ }
+
+ s->size = ALIGN(s->size, s->alignment);
+
+ if (s->elements[0]->type == FFI_TYPE_UINT64
+ || s->elements[0]->type == FFI_TYPE_SINT64
+ || s->elements[0]->type == FFI_TYPE_DOUBLE
+ || s->elements[0]->alignment == 8)
+ s->alignment = s->alignment > 8 ? s->alignment : 8;
+ /* Do not add additional tail padding. */
+}
+
+/* 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.
+ All the calculation of structure sizes will also be wrong.
+ Redo the calculation for DARWIN. */
+
+ if (cif->abi == FFI_DARWIN)
+ {
+ darwin_adjust_aggregate_sizes (cif->rtype);
+ for (i = 0; i < cif->nargs; i++)
+ darwin_adjust_aggregate_sizes (cif->arg_types[i]);
+ }
+
+ /* 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:
+ flags |= FLAG_RETURNS_128BITS;
+ flags |= FLAG_RETURNS_FP;
+ break;
+#endif
+
+ 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 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;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+
+ case FFI_TYPE_LONGDOUBLE:
+ fparg_count += 2;
+ /* 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++;
+ intarg_count +=2;
+ break;
+#endif
+
+ 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:
+ 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;
+}
+
+extern void ffi_call_AIX(extended_cif *, unsigned, unsigned, unsigned *,
+ void (*fn)(), void (*fn2)());
+extern void ffi_call_DARWIN(extended_cif *, unsigned, unsigned, unsigned *,
+ void (*fn)(), void (*fn2)());
+
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+{
+ extended_cif ecif;
+
+ ecif.cif = cif;
+ ecif.avalue = avalue;
+
+ /* If the return value is a struct and we don't have a return
+ value address then we need to make one. */
+
+ if ((rvalue == NULL) &&
+ (cif->rtype->type == FFI_TYPE_STRUCT))
+ {
+ ecif.rvalue = alloca(cif->rtype->size);
+ }
+ else
+ ecif.rvalue = rvalue;
+
+ switch (cif->abi)
+ {
+ case FFI_AIX:
+ ffi_call_AIX(&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn,
+ ffi_prep_args);
+ break;
+ case FFI_DARWIN:
+ ffi_call_DARWIN(&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn,
+ ffi_prep_args);
+ 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_loc (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ void *codeloc)
+{
+ 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) codeloc; /* context */
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ /* Flush the icache. Only necessary on Darwin. */
+ flush_range(codeloc, 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 = codeloc;
+ 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\n"
+ "\tsync\n"
+ "\ticbi 0,%0\n"
+ "\tsync\n"
+ "\tisync"
+ : : "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. */
+
+ typedef double ldbits[2];
+
+ union ldu
+ {
+ ldbits lb;
+ long double ld;
+ };
+
+ 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;
+ union ldu temp_ld;
+
+ 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;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+
+ case FFI_TYPE_LONGDOUBLE:
+ /* A long double value consumes four GPRs and two FPRs.
+ There are 13 64bit floating point registers. */
+ if (nf < NUM_FPR_ARG_REGISTERS - 1)
+ {
+ avalue[i] = pfr;
+ pfr += 2;
+ }
+ /* Here we have the situation where one part of the long double
+ is stored in fpr13 and the other part is already on the stack.
+ We use a union to pass the long double to avalue[i]. */
+ else if (nf == NUM_FPR_ARG_REGISTERS - 1)
+ {
+ memcpy (&temp_ld.lb[0], pfr, sizeof(ldbits));
+ memcpy (&temp_ld.lb[1], pgr + 2, sizeof(ldbits));
+ avalue[i] = &temp_ld.ld;
+ }
+ else
+ {
+ avalue[i] = pgr;
+ }
+ nf += 2;
+ ng += 4;
+ pgr += 4;
+ break;
+#endif
+ 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;
+}
diff --git a/libffi-3.0.4/src/powerpc/ffitarget.h b/libffi-3.0.4/src/powerpc/ffitarget.h
new file mode 100644
index 0000000..f499ac3
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/ffitarget.h
@@ -0,0 +1,118 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Copyright (C) 2007 Free Software Foundation, 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 THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+ ----------------------------------------------------------------------- */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+/* ---- 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,
+ FFI_LINUX,
+ FFI_LINUX_SOFT_FLOAT,
+# ifdef POWERPC64
+ FFI_DEFAULT_ABI = FFI_LINUX64,
+# else
+# if (!defined(__NO_FPRS__) && (__LDBL_MANT_DIG__ == 106))
+ FFI_DEFAULT_ABI = FFI_LINUX,
+# else
+# ifdef __NO_FPRS__
+ FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT,
+# else
+ FFI_DEFAULT_ABI = FFI_GCC_SYSV,
+# endif
+# endif
+# 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
+
+#ifdef POWERPC_FREEBSD
+ FFI_SYSV,
+ FFI_GCC_SYSV,
+ FFI_LINUX64,
+ FFI_DEFAULT_ABI = FFI_SYSV,
+#endif
+
+ FFI_LAST_ABI
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_NATIVE_RAW_API 0
+
+/* For additional types like the below, take care about the order in
+ ppc_closures.S. They must follow after the FFI_TYPE_LAST. */
+
+/* Needed for soft-float long-double-128 support. */
+#define FFI_TYPE_UINT128 (FFI_TYPE_LAST + 1)
+
+/* Needed for FFI_SYSV small structure returns. */
+#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2)
+
+#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-3.0.4/src/powerpc/linux64.S b/libffi-3.0.4/src/powerpc/linux64.S
new file mode 100644
index 0000000..2cfebbf
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/linux64.S
@@ -0,0 +1,181 @@
+/* -----------------------------------------------------------------------
+ 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. */
+.LCFI0:
+ stdux %r1, %r1, %r4
+ 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
+
+ /* This must follow the call immediately, the unwinder
+ uses this to find out if r2 has been saved or not. */
+ ld %r2, 40(%r1)
+
+ /* 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. */
+ 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)
+ mtcrf 0x02, %r31 /* cr6 */
+ bf 27, .Ldone_return_value
+ stfd %f2, 8(%r30)
+ 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-3.0.4/src/powerpc/linux64_closure.S b/libffi-3.0.4/src/powerpc/linux64_closure.S
new file mode 100644
index 0000000..b19bc71
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/linux64_closure.S
@@ -0,0 +1,206 @@
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+ .file "linux64_closure.S"
+
+#ifdef __powerpc64__
+ FFI_HIDDEN (ffi_closure_LINUX64)
+ FFI_HIDDEN (.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-3.0.4/src/powerpc/ppc_closure.S b/libffi-3.0.4/src/powerpc/ppc_closure.S
new file mode 100644
index 0000000..c9f5742
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/ppc_closure.S
@@ -0,0 +1,297 @@
+#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)
+
+#ifndef __NO_FPRS__
+ # 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)
+#endif
+
+ # 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 ffi_closure_helper_SYSV@local
+.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
+ slwi %r3,%r3,4 # now multiply return type by 16
+ addi %r4, %r4, .Lret_type0 - .Lret
+ lwz %r0,148(%r1)
+ 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
+# case FFI_TYPE_VOID
+.Lret_type0:
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+ nop
+
+# case FFI_TYPE_INT
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+.Lfinish:
+ addi %r1,%r1,144
+ blr
+
+# case FFI_TYPE_FLOAT
+ lfs %f1,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_TYPE_DOUBLE
+ lfd %f1,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_TYPE_LONGDOUBLE
+ lfd %f1,112+0(%r1)
+ lfd %f2,112+8(%r1)
+ mtlr %r0
+ b .Lfinish
+
+# case FFI_TYPE_UINT8
+ lbz %r3,112+3(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_TYPE_SINT8
+ lbz %r3,112+3(%r1)
+ extsb %r3,%r3
+ mtlr %r0
+ b .Lfinish
+
+# case FFI_TYPE_UINT16
+ lhz %r3,112+2(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_TYPE_SINT16
+ lha %r3,112+2(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_TYPE_UINT32
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_TYPE_SINT32
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_TYPE_UINT64
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ mtlr %r0
+ b .Lfinish
+
+# case FFI_TYPE_SINT64
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ mtlr %r0
+ b .Lfinish
+
+# case FFI_TYPE_STRUCT
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+ nop
+
+# case FFI_TYPE_POINTER
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_TYPE_UINT128
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ lwz %r5,112+8(%r1)
+ bl .Luint128
+
+# The return types below are only used when the ABI type is FFI_SYSV.
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
+ lbz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
+ lhz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
+ lwz %r3,112+0(%r1)
+ srwi %r3,%r3,8
+ mtlr %r0
+ b .Lfinish
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
+ lwz %r3,112+0(%r1)
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ li %r5,24
+ b .Lstruct567
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ li %r5,16
+ b .Lstruct567
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ li %r5,8
+ b .Lstruct567
+
+# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
+ lwz %r3,112+0(%r1)
+ lwz %r4,112+4(%r1)
+ mtlr %r0
+ b .Lfinish
+
+.Lstruct567:
+ subfic %r6,%r5,32
+ srw %r4,%r4,%r5
+ slw %r6,%r3,%r6
+ srw %r3,%r3,%r5
+ or %r4,%r6,%r4
+ mtlr %r0
+ addi %r1,%r1,144
+ blr
+
+.Luint128:
+ lwz %r6,112+12(%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 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x41
+ .sleb128 -1
+ .align 2
+.LEFDE1:
+
+#endif
diff --git a/libffi-3.0.4/src/powerpc/sysv.S b/libffi-3.0.4/src/powerpc/sysv.S
new file mode 100644
index 0000000..2136714
--- /dev/null
+++ b/libffi-3.0.4/src/powerpc/sysv.S
@@ -0,0 +1,225 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 1998 Geoffrey Keating
+ Copyright (C) 2007 Free Software Foundation, Inc
+
+ 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>
+#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 ffi_prep_args_SYSV@local
+
+ /* 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 /* cr7 */
+ bt- 31,L(small_struct_return_value)
+ 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)
+ mtcrf 0x02,%r31 /* cr6 */
+ bf 27,L(done_return_value)
+ stw %r5,8(%r30)
+ stw %r6,12(%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)
+ mtcrf 0x02,%r31 /* cr6 */
+ bf 27,L(done_return_value)
+ stfd %f2,8(%r30)
+ b L(done_return_value)
+L(float_return_value):
+ stfs %f1,0(%r30)
+ b L(done_return_value)
+
+L(small_struct_return_value):
+ mtcrf 0x10,%r31 /* cr3 */
+ bt- 15,L(smst_one_register)
+ mtcrf 0x08,%r31 /* cr4 */
+ bt- 16,L(smst_two_register)
+ b L(done_return_value)
+
+L(smst_one_register):
+ rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */
+ slw %r3,%r3,%r5
+ stw %r3,0(%r30)
+ b L(done_return_value)
+L(smst_two_register):
+ rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */
+ cmpwi %r5,0
+ subfic %r9,%r5,32
+ slw %r29,%r3,%r5
+ srw %r9,%r4,%r9
+ beq- L(smst_8byte)
+ or %r3,%r9,%r29
+ slw %r4,%r4,%r5
+L(smst_8byte):
+ stw %r3,0(%r30)
+ stw %r4,4(%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 0x11 /* DW_CFA_offset_extended_sf */
+ .uleb128 0x41
+ .sleb128 -1
+ .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