diff options
author | Mikhail Borisov <borisov.mikhail@gmail.com> | 2022-02-10 16:45:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:39 +0300 |
commit | a6a92afe03e02795227d2641b49819b687f088f8 (patch) | |
tree | f6984a1d27d5a7ec88a6fdd6e20cd5b7693b6ece /contrib/restricted/libffi/src/powerpc | |
parent | c6dc8b8bd530985bc4cce0137e9a5de32f1087cb (diff) | |
download | ydb-a6a92afe03e02795227d2641b49819b687f088f8.tar.gz |
Restoring authorship annotation for Mikhail Borisov <borisov.mikhail@gmail.com>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/libffi/src/powerpc')
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/aix.S | 1132 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/aix_closure.S | 1388 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/asm.h | 250 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/darwin.S | 756 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/darwin_closure.S | 1142 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/ffi.c | 350 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/ffi_darwin.c | 2870 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/ffi_linux64.c | 2306 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/ffi_powerpc.h | 210 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/ffi_sysv.c | 1846 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/ffitarget.h | 408 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/linux64.S | 566 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/linux64_closure.S | 1104 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/ppc_closure.S | 794 | ||||
-rw-r--r-- | contrib/restricted/libffi/src/powerpc/sysv.S | 350 |
15 files changed, 7736 insertions, 7736 deletions
diff --git a/contrib/restricted/libffi/src/powerpc/aix.S b/contrib/restricted/libffi/src/powerpc/aix.S index 7ba541595f..60544b489d 100644 --- a/contrib/restricted/libffi/src/powerpc/aix.S +++ b/contrib/restricted/libffi/src/powerpc/aix.S @@ -1,566 +1,566 @@ -/* ----------------------------------------------------------------------- - aix.S - Copyright (c) 2002, 2009 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 - - .extern .ffi_prep_args - -#define LIBFFI_ASM -#include <fficonfig.h> -#include <ffi.h> -#define JUMPTARGET(name) name -#define L(x) x - .file "aix.S" - .toc - - /* void ffi_call_AIX(extended_cif *ecif, unsigned long bytes, - * unsigned int flags, unsigned int *rvalue, - * void (*fn)(), - * void (*prep_args)(extended_cif*, unsigned *const)); - * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args - */ - -.csect .text[PR] - .align 2 - .globl ffi_call_AIX - .globl .ffi_call_AIX -.csect ffi_call_AIX[DS] -ffi_call_AIX: -#ifdef __64BIT__ - .llong .ffi_call_AIX, TOC[tc0], 0 - .csect .text[PR] -.ffi_call_AIX: - .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0 - .bf __LINE__ - .line 1 -LFB..0: - /* Save registers we use. */ - mflr r0 - - std r28,-32(r1) - std r29,-24(r1) - std r30,-16(r1) - std r31, -8(r1) - - std r0, 16(r1) -LCFI..0: - mr r28, r1 /* our AP. */ - stdux r1, r1, r4 -LCFI..1: - - /* Save arguments over call... */ - mr r31, r5 /* flags, */ - mr r30, r6 /* rvalue, */ - mr r29, r7 /* function address. */ - std r2, 40(r1) - - /* Call ffi_prep_args. */ - mr r4, r1 - bl .ffi_prep_args - nop - - /* Now do the call. */ - ld r0, 0(r29) - ld r2, 8(r29) - ld r11, 16(r29) - /* Set up cr1 with bits 4-7 of the flags. */ - mtcrf 0x40, r31 - mtctr r0 - /* Load all those argument registers. */ - /* We have set up a nice stack frame, just load it into registers. */ - ld r3, 40+(1*8)(r1) - ld r4, 40+(2*8)(r1) - ld r5, 40+(3*8)(r1) - ld r6, 40+(4*8)(r1) - nop - ld r7, 40+(5*8)(r1) - ld r8, 40+(6*8)(r1) - ld r9, 40+(7*8)(r1) - ld r10,40+(8*8)(r1) - -L1: - /* Load all the FP registers. */ - bf 6,L2 /* 2f + 0x18 */ - lfd f1,-32-(13*8)(r28) - lfd f2,-32-(12*8)(r28) - lfd f3,-32-(11*8)(r28) - lfd f4,-32-(10*8)(r28) - nop - lfd f5,-32-(9*8)(r28) - lfd f6,-32-(8*8)(r28) - lfd f7,-32-(7*8)(r28) - lfd f8,-32-(6*8)(r28) - nop - lfd f9,-32-(5*8)(r28) - lfd f10,-32-(4*8)(r28) - lfd f11,-32-(3*8)(r28) - lfd f12,-32-(2*8)(r28) - nop - lfd f13,-32-(1*8)(r28) - -L2: - /* Make the call. */ - bctrl - ld r2, 40(r1) - - /* Now, deal with the return value. */ - mtcrf 0x01, r31 - - bt 30, L(done_return_value) - bt 29, L(fp_return_value) - std r3, 0(r30) - - /* Fall through... */ - -L(done_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 - -L(fp_return_value): - bf 28, L(float_return_value) - stfd f1, 0(r30) - bf 31, 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) -LFE..0: -#else /* ! __64BIT__ */ - - .long .ffi_call_AIX, TOC[tc0], 0 - .csect .text[PR] -.ffi_call_AIX: - .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0 - .bf __LINE__ - .line 1 -LFB..0: - /* Save registers we use. */ - mflr r0 - - stw r28,-16(r1) - stw r29,-12(r1) - stw r30, -8(r1) - stw r31, -4(r1) - - stw r0, 8(r1) -LCFI..0: - mr r28, r1 /* out AP. */ - stwux r1, r1, r4 -LCFI..1: - - /* Save arguments over call... */ - mr r31, r5 /* flags, */ - mr r30, r6 /* rvalue, */ - mr r29, r7 /* function address, */ - stw r2, 20(r1) - - /* Call ffi_prep_args. */ - mr r4, r1 - bl .ffi_prep_args - nop - - /* Now do the call. */ - lwz r0, 0(r29) - lwz r2, 4(r29) - lwz r11, 8(r29) - /* Set up cr1 with bits 4-7 of the flags. */ - mtcrf 0x40, r31 - mtctr r0 - /* 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. */ - mr r1, r28 - lwz r0, 8(r28) - lwz r28,-16(r1) - mtlr r0 - lwz r29,-12(r1) - lwz r30, -8(r1) - lwz r31, -4(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) -LFE..0: -#endif - .ef __LINE__ - .long 0 - .byte 0,0,0,1,128,4,0,0 -/* END(ffi_call_AIX) */ - - /* void ffi_call_go_AIX(extended_cif *ecif, unsigned long bytes, - * unsigned int flags, unsigned int *rvalue, - * void (*fn)(), - * void (*prep_args)(extended_cif*, unsigned *const), - * void *closure); - * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args, r9=closure - */ - -.csect .text[PR] - .align 2 - .globl ffi_call_go_AIX - .globl .ffi_call_go_AIX -.csect ffi_call_go_AIX[DS] -ffi_call_go_AIX: -#ifdef __64BIT__ - .llong .ffi_call_go_AIX, TOC[tc0], 0 - .csect .text[PR] -.ffi_call_go_AIX: - .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1 - .bf __LINE__ - .line 1 -LFB..1: - /* Save registers we use. */ - mflr r0 - - std r28,-32(r1) - std r29,-24(r1) - std r30,-16(r1) - std r31, -8(r1) - - std r9, 8(r1) /* closure, saved in cr field. */ - std r0, 16(r1) -LCFI..2: - mr r28, r1 /* our AP. */ - stdux r1, r1, r4 -LCFI..3: - - /* Save arguments over call... */ - mr r31, r5 /* flags, */ - mr r30, r6 /* rvalue, */ - mr r29, r7 /* function address, */ - std r2, 40(r1) - - /* Call ffi_prep_args. */ - mr r4, r1 - bl .ffi_prep_args - nop - - /* Now do the call. */ - ld r0, 0(r29) - ld r2, 8(r29) - ld r11, 8(r28) /* closure */ - /* Set up cr1 with bits 4-7 of the flags. */ - mtcrf 0x40, r31 - mtctr r0 - /* Load all those argument registers. */ - /* We have set up a nice stack frame, just load it into registers. */ - ld r3, 40+(1*8)(r1) - ld r4, 40+(2*8)(r1) - ld r5, 40+(3*8)(r1) - ld r6, 40+(4*8)(r1) - nop - ld r7, 40+(5*8)(r1) - ld r8, 40+(6*8)(r1) - ld r9, 40+(7*8)(r1) - ld r10,40+(8*8)(r1) - - b L1 -LFE..1: -#else /* ! __64BIT__ */ - - .long .ffi_call_go_AIX, TOC[tc0], 0 - .csect .text[PR] -.ffi_call_go_AIX: - .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1 - .bf __LINE__ - .line 1 - /* Save registers we use. */ -LFB..1: - mflr r0 - - stw r28,-16(r1) - stw r29,-12(r1) - stw r30, -8(r1) - stw r31, -4(r1) - - stw r9, 4(r1) /* closure, saved in cr field. */ - stw r0, 8(r1) -LCFI..2: - mr r28, r1 /* out AP. */ - stwux r1, r1, r4 -LCFI..3: - - /* Save arguments over call... */ - mr r31, r5 /* flags, */ - mr r30, r6 /* rvalue, */ - mr r29, r7 /* function address, */ - stw r2, 20(r1) - - /* Call ffi_prep_args. */ - mr r4, r1 - bl .ffi_prep_args - nop - - /* Now do the call. */ - lwz r0, 0(r29) - lwz r2, 4(r29) - lwz r11, 4(r28) /* closure */ - /* Set up cr1 with bits 4-7 of the flags. */ - mtcrf 0x40, r31 - mtctr r0 - /* 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) - - b L1 -LFE..1: -#endif - .ef __LINE__ - .long 0 - .byte 0,0,0,1,128,4,0,0 -/* END(ffi_call_go_AIX) */ - -.csect .text[PR] - .align 2 - .globl ffi_call_DARWIN - .globl .ffi_call_DARWIN -.csect ffi_call_DARWIN[DS] -ffi_call_DARWIN: -#ifdef __64BIT__ - .llong .ffi_call_DARWIN, TOC[tc0], 0 -#else - .long .ffi_call_DARWIN, TOC[tc0], 0 -#endif - .csect .text[PR] -.ffi_call_DARWIN: - blr - .long 0 - .byte 0,0,0,0,0,0,0,0 -/* END(ffi_call_DARWIN) */ - -/* EH frame stuff. */ - -#define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */ -#ifdef __64BIT__ -#define PTRSIZE 8 -#define LOG2_PTRSIZE 3 -#define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */ -#define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */ -#else -#define PTRSIZE 4 -#define LOG2_PTRSIZE 2 -#define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */ -#define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */ -#endif - .csect _unwind.ro_[RO],4 - .align LOG2_PTRSIZE - .globl _GLOBAL__F_libffi_src_powerpc_aix -_GLOBAL__F_libffi_src_powerpc_aix: -Lframe..1: - .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */ -LSCIE..1: - .vbyte 4,0 /* CIE Identifier Tag */ - .byte 0x3 /* CIE Version */ - .byte "zR" /* CIE Augmentation */ - .byte 0 - .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ - .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */ - .byte 0x41 /* CIE RA Column */ - .byte 0x1 /* uleb128 0x1; Augmentation size */ - .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */ - .byte 0xc /* DW_CFA_def_cfa */ - .byte 0x1 /* uleb128 0x1; Register r1 */ - .byte 0 /* uleb128 0x0; Offset 0 */ - .align LOG2_PTRSIZE -LECIE..1: -LSFDE..1: - .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */ -LASFDE..1: - .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */ - .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */ - .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */ - .byte 0 /* uleb128 0x0; Augmentation size */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .vbyte 4,LCFI..0-LFB..0 - .byte 0x11 /* DW_CFA_def_offset_extended_sf */ - .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ - .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ - .byte 0x9f /* DW_CFA_offset Register r31 */ - .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */ - .byte 0x9e /* DW_CFA_offset Register r30 */ - .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */ - .byte 0x9d /* DW_CFA_offset Register r29 */ - .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */ - .byte 0x9c /* DW_CFA_offset Register r28 */ - .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .vbyte 4,LCFI..1-LCFI..0 - .byte 0xd /* DW_CFA_def_cfa_register */ - .byte 0x1c /* uleb128 28; Register r28 */ - .align LOG2_PTRSIZE -LEFDE..1: -LSFDE..2: - .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */ -LASFDE..2: - .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */ - .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */ - .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */ - .byte 0 /* uleb128 0x0; Augmentation size */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .vbyte 4,LCFI..2-LFB..1 - .byte 0x11 /* DW_CFA_def_offset_extended_sf */ - .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ - .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ - .byte 0x9f /* DW_CFA_offset Register r31 */ - .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */ - .byte 0x9e /* DW_CFA_offset Register r30 */ - .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */ - .byte 0x9d /* DW_CFA_offset Register r29 */ - .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */ - .byte 0x9c /* DW_CFA_offset Register r28 */ - .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .vbyte 4,LCFI..3-LCFI..2 - .byte 0xd /* DW_CFA_def_cfa_register */ - .byte 0x1c /* uleb128 28; Register r28 */ - .align LOG2_PTRSIZE -LEFDE..2: - .vbyte 4,0 /* End of FDEs */ - - .csect .text[PR] - .ref _GLOBAL__F_libffi_src_powerpc_aix /* Prevents garbage collection by AIX linker */ - +/* ----------------------------------------------------------------------- + aix.S - Copyright (c) 2002, 2009 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 + + .extern .ffi_prep_args + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#define JUMPTARGET(name) name +#define L(x) x + .file "aix.S" + .toc + + /* void ffi_call_AIX(extended_cif *ecif, unsigned long bytes, + * unsigned int flags, unsigned int *rvalue, + * void (*fn)(), + * void (*prep_args)(extended_cif*, unsigned *const)); + * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args + */ + +.csect .text[PR] + .align 2 + .globl ffi_call_AIX + .globl .ffi_call_AIX +.csect ffi_call_AIX[DS] +ffi_call_AIX: +#ifdef __64BIT__ + .llong .ffi_call_AIX, TOC[tc0], 0 + .csect .text[PR] +.ffi_call_AIX: + .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0 + .bf __LINE__ + .line 1 +LFB..0: + /* Save registers we use. */ + mflr r0 + + std r28,-32(r1) + std r29,-24(r1) + std r30,-16(r1) + std r31, -8(r1) + + std r0, 16(r1) +LCFI..0: + mr r28, r1 /* our AP. */ + stdux r1, r1, r4 +LCFI..1: + + /* Save arguments over call... */ + mr r31, r5 /* flags, */ + mr r30, r6 /* rvalue, */ + mr r29, r7 /* function address. */ + std r2, 40(r1) + + /* Call ffi_prep_args. */ + mr r4, r1 + bl .ffi_prep_args + nop + + /* Now do the call. */ + ld r0, 0(r29) + ld r2, 8(r29) + ld r11, 16(r29) + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40, r31 + mtctr r0 + /* Load all those argument registers. */ + /* We have set up a nice stack frame, just load it into registers. */ + ld r3, 40+(1*8)(r1) + ld r4, 40+(2*8)(r1) + ld r5, 40+(3*8)(r1) + ld r6, 40+(4*8)(r1) + nop + ld r7, 40+(5*8)(r1) + ld r8, 40+(6*8)(r1) + ld r9, 40+(7*8)(r1) + ld r10,40+(8*8)(r1) + +L1: + /* Load all the FP registers. */ + bf 6,L2 /* 2f + 0x18 */ + lfd f1,-32-(13*8)(r28) + lfd f2,-32-(12*8)(r28) + lfd f3,-32-(11*8)(r28) + lfd f4,-32-(10*8)(r28) + nop + lfd f5,-32-(9*8)(r28) + lfd f6,-32-(8*8)(r28) + lfd f7,-32-(7*8)(r28) + lfd f8,-32-(6*8)(r28) + nop + lfd f9,-32-(5*8)(r28) + lfd f10,-32-(4*8)(r28) + lfd f11,-32-(3*8)(r28) + lfd f12,-32-(2*8)(r28) + nop + lfd f13,-32-(1*8)(r28) + +L2: + /* Make the call. */ + bctrl + ld r2, 40(r1) + + /* Now, deal with the return value. */ + mtcrf 0x01, r31 + + bt 30, L(done_return_value) + bt 29, L(fp_return_value) + std r3, 0(r30) + + /* Fall through... */ + +L(done_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 + +L(fp_return_value): + bf 28, L(float_return_value) + stfd f1, 0(r30) + bf 31, 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) +LFE..0: +#else /* ! __64BIT__ */ + + .long .ffi_call_AIX, TOC[tc0], 0 + .csect .text[PR] +.ffi_call_AIX: + .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0 + .bf __LINE__ + .line 1 +LFB..0: + /* Save registers we use. */ + mflr r0 + + stw r28,-16(r1) + stw r29,-12(r1) + stw r30, -8(r1) + stw r31, -4(r1) + + stw r0, 8(r1) +LCFI..0: + mr r28, r1 /* out AP. */ + stwux r1, r1, r4 +LCFI..1: + + /* Save arguments over call... */ + mr r31, r5 /* flags, */ + mr r30, r6 /* rvalue, */ + mr r29, r7 /* function address, */ + stw r2, 20(r1) + + /* Call ffi_prep_args. */ + mr r4, r1 + bl .ffi_prep_args + nop + + /* Now do the call. */ + lwz r0, 0(r29) + lwz r2, 4(r29) + lwz r11, 8(r29) + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40, r31 + mtctr r0 + /* 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. */ + mr r1, r28 + lwz r0, 8(r28) + lwz r28,-16(r1) + mtlr r0 + lwz r29,-12(r1) + lwz r30, -8(r1) + lwz r31, -4(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) +LFE..0: +#endif + .ef __LINE__ + .long 0 + .byte 0,0,0,1,128,4,0,0 +/* END(ffi_call_AIX) */ + + /* void ffi_call_go_AIX(extended_cif *ecif, unsigned long bytes, + * unsigned int flags, unsigned int *rvalue, + * void (*fn)(), + * void (*prep_args)(extended_cif*, unsigned *const), + * void *closure); + * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args, r9=closure + */ + +.csect .text[PR] + .align 2 + .globl ffi_call_go_AIX + .globl .ffi_call_go_AIX +.csect ffi_call_go_AIX[DS] +ffi_call_go_AIX: +#ifdef __64BIT__ + .llong .ffi_call_go_AIX, TOC[tc0], 0 + .csect .text[PR] +.ffi_call_go_AIX: + .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1 + .bf __LINE__ + .line 1 +LFB..1: + /* Save registers we use. */ + mflr r0 + + std r28,-32(r1) + std r29,-24(r1) + std r30,-16(r1) + std r31, -8(r1) + + std r9, 8(r1) /* closure, saved in cr field. */ + std r0, 16(r1) +LCFI..2: + mr r28, r1 /* our AP. */ + stdux r1, r1, r4 +LCFI..3: + + /* Save arguments over call... */ + mr r31, r5 /* flags, */ + mr r30, r6 /* rvalue, */ + mr r29, r7 /* function address, */ + std r2, 40(r1) + + /* Call ffi_prep_args. */ + mr r4, r1 + bl .ffi_prep_args + nop + + /* Now do the call. */ + ld r0, 0(r29) + ld r2, 8(r29) + ld r11, 8(r28) /* closure */ + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40, r31 + mtctr r0 + /* Load all those argument registers. */ + /* We have set up a nice stack frame, just load it into registers. */ + ld r3, 40+(1*8)(r1) + ld r4, 40+(2*8)(r1) + ld r5, 40+(3*8)(r1) + ld r6, 40+(4*8)(r1) + nop + ld r7, 40+(5*8)(r1) + ld r8, 40+(6*8)(r1) + ld r9, 40+(7*8)(r1) + ld r10,40+(8*8)(r1) + + b L1 +LFE..1: +#else /* ! __64BIT__ */ + + .long .ffi_call_go_AIX, TOC[tc0], 0 + .csect .text[PR] +.ffi_call_go_AIX: + .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1 + .bf __LINE__ + .line 1 + /* Save registers we use. */ +LFB..1: + mflr r0 + + stw r28,-16(r1) + stw r29,-12(r1) + stw r30, -8(r1) + stw r31, -4(r1) + + stw r9, 4(r1) /* closure, saved in cr field. */ + stw r0, 8(r1) +LCFI..2: + mr r28, r1 /* out AP. */ + stwux r1, r1, r4 +LCFI..3: + + /* Save arguments over call... */ + mr r31, r5 /* flags, */ + mr r30, r6 /* rvalue, */ + mr r29, r7 /* function address, */ + stw r2, 20(r1) + + /* Call ffi_prep_args. */ + mr r4, r1 + bl .ffi_prep_args + nop + + /* Now do the call. */ + lwz r0, 0(r29) + lwz r2, 4(r29) + lwz r11, 4(r28) /* closure */ + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40, r31 + mtctr r0 + /* 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) + + b L1 +LFE..1: +#endif + .ef __LINE__ + .long 0 + .byte 0,0,0,1,128,4,0,0 +/* END(ffi_call_go_AIX) */ + +.csect .text[PR] + .align 2 + .globl ffi_call_DARWIN + .globl .ffi_call_DARWIN +.csect ffi_call_DARWIN[DS] +ffi_call_DARWIN: +#ifdef __64BIT__ + .llong .ffi_call_DARWIN, TOC[tc0], 0 +#else + .long .ffi_call_DARWIN, TOC[tc0], 0 +#endif + .csect .text[PR] +.ffi_call_DARWIN: + blr + .long 0 + .byte 0,0,0,0,0,0,0,0 +/* END(ffi_call_DARWIN) */ + +/* EH frame stuff. */ + +#define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */ +#ifdef __64BIT__ +#define PTRSIZE 8 +#define LOG2_PTRSIZE 3 +#define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */ +#define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */ +#else +#define PTRSIZE 4 +#define LOG2_PTRSIZE 2 +#define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */ +#define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */ +#endif + .csect _unwind.ro_[RO],4 + .align LOG2_PTRSIZE + .globl _GLOBAL__F_libffi_src_powerpc_aix +_GLOBAL__F_libffi_src_powerpc_aix: +Lframe..1: + .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */ +LSCIE..1: + .vbyte 4,0 /* CIE Identifier Tag */ + .byte 0x3 /* CIE Version */ + .byte "zR" /* CIE Augmentation */ + .byte 0 + .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ + .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */ + .byte 0x41 /* CIE RA Column */ + .byte 0x1 /* uleb128 0x1; Augmentation size */ + .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */ + .byte 0xc /* DW_CFA_def_cfa */ + .byte 0x1 /* uleb128 0x1; Register r1 */ + .byte 0 /* uleb128 0x0; Offset 0 */ + .align LOG2_PTRSIZE +LECIE..1: +LSFDE..1: + .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */ +LASFDE..1: + .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */ + .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */ + .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */ + .byte 0 /* uleb128 0x0; Augmentation size */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .vbyte 4,LCFI..0-LFB..0 + .byte 0x11 /* DW_CFA_def_offset_extended_sf */ + .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ + .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ + .byte 0x9f /* DW_CFA_offset Register r31 */ + .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */ + .byte 0x9e /* DW_CFA_offset Register r30 */ + .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */ + .byte 0x9d /* DW_CFA_offset Register r29 */ + .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */ + .byte 0x9c /* DW_CFA_offset Register r28 */ + .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .vbyte 4,LCFI..1-LCFI..0 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x1c /* uleb128 28; Register r28 */ + .align LOG2_PTRSIZE +LEFDE..1: +LSFDE..2: + .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */ +LASFDE..2: + .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */ + .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */ + .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */ + .byte 0 /* uleb128 0x0; Augmentation size */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .vbyte 4,LCFI..2-LFB..1 + .byte 0x11 /* DW_CFA_def_offset_extended_sf */ + .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ + .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ + .byte 0x9f /* DW_CFA_offset Register r31 */ + .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */ + .byte 0x9e /* DW_CFA_offset Register r30 */ + .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */ + .byte 0x9d /* DW_CFA_offset Register r29 */ + .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */ + .byte 0x9c /* DW_CFA_offset Register r28 */ + .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .vbyte 4,LCFI..3-LCFI..2 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x1c /* uleb128 28; Register r28 */ + .align LOG2_PTRSIZE +LEFDE..2: + .vbyte 4,0 /* End of FDEs */ + + .csect .text[PR] + .ref _GLOBAL__F_libffi_src_powerpc_aix /* Prevents garbage collection by AIX linker */ + diff --git a/contrib/restricted/libffi/src/powerpc/aix_closure.S b/contrib/restricted/libffi/src/powerpc/aix_closure.S index 132c785edd..be836056e6 100644 --- a/contrib/restricted/libffi/src/powerpc/aix_closure.S +++ b/contrib/restricted/libffi/src/powerpc/aix_closure.S @@ -1,694 +1,694 @@ -/* ----------------------------------------------------------------------- - aix_closure.S - Copyright (c) 2002, 2003, 2009 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 - - .extern .ffi_closure_helper_DARWIN - .extern .ffi_go_closure_helper_DARWIN - -#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: -#ifdef __64BIT__ - .llong .ffi_closure_ASM, TOC[tc0], 0 - .csect .text[PR] -.ffi_closure_ASM: - .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0 - .bf __LINE__ - .line 1 -LFB..0: -/* 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 */ - std r3, 48+(0*8)(r1) - std r4, 48+(1*8)(r1) - std r5, 48+(2*8)(r1) - std r6, 48+(3*8)(r1) - mflr r0 - - std r7, 48+(4*8)(r1) - std r8, 48+(5*8)(r1) - std r9, 48+(6*8)(r1) - std r10, 48+(7*8)(r1) - std r0, 16(r1) /* save the return address */ -LCFI..0: - /* 48 Bytes (Linkage Area) */ - /* 64 Bytes (params) */ - /* 16 Bytes (result) */ - /* 104 Bytes (13*8 from FPR) */ - /* 8 Bytes (alignment) */ - /* 240 Bytes */ - - stdu r1, -240(r1) /* skip over caller save area - keep stack aligned to 16 */ -LCFI..1: - - /* next save fpr 1 to fpr 13 (aligned to 8) */ - 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 saved gpr registers */ - addi r5, r1, 288 - - /* now load up the pointer to the saved fpr registers */ - addi r6, r1, 128 - - /* make the call */ - bl .ffi_closure_helper_DARWIN - nop - -.Ldoneclosure: - - /* 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 */ - lhz r3, 10(r3) /* load type from return type */ - ld r4, LC..60(2) /* get address of jump table */ - sldi r3, r3, 4 /* now multiply return type by 16 */ - ld r0, 240+16(r1) /* load return address */ - add r3, r3, r4 /* add contents of table to table address */ - mtctr r3 - bctr /* jump to it */ - -/* Each fragment must be exactly 16 bytes long (4 instructions). - Align to 16 byte boundary for cache and dispatch efficiency. */ - .align 4 - -L..60: -/* 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 L..finish - -/* 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) - mtlr r0 - extsb r3, r3 - b L..finish - -/* case FFI_TYPE_UINT16 */ - lhz r3, 112+6(r1) - mtlr r0 -L..finish: - 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 -LFE..0: - -#else /* ! __64BIT__ */ - - .long .ffi_closure_ASM, TOC[tc0], 0 - .csect .text[PR] -.ffi_closure_ASM: - .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0 - .bf __LINE__ - .line 1 -LFB..0: -/* 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, 24+(0*4)(r1) - stw r4, 24+(1*4)(r1) - stw r5, 24+(2*4)(r1) - stw r6, 24+(3*4)(r1) - mflr r0 - - stw r7, 24+(4*4)(r1) - stw r8, 24+(5*4)(r1) - stw r9, 24+(6*4)(r1) - stw r10, 24+(7*4)(r1) - stw r0, 8(r1) -LCFI..0: - /* 24 Bytes (Linkage Area) */ - /* 32 Bytes (params) */ - /* 16 Bytes (result) */ - /* 104 Bytes (13*8 from FPR) */ - /* 176 Bytes */ - - stwu r1, -176(r1) /* skip over caller save area - keep stack aligned to 16 */ -LCFI..1: - - /* next save fpr 1 to fpr 13 (aligned to 8) */ - stfd f1, 72+(0*8)(r1) - stfd f2, 72+(1*8)(r1) - stfd f3, 72+(2*8)(r1) - stfd f4, 72+(3*8)(r1) - stfd f5, 72+(4*8)(r1) - stfd f6, 72+(5*8)(r1) - stfd f7, 72+(6*8)(r1) - stfd f8, 72+(7*8)(r1) - stfd f9, 72+(8*8)(r1) - stfd f10, 72+(9*8)(r1) - stfd f11, 72+(10*8)(r1) - stfd f12, 72+(11*8)(r1) - stfd f13, 72+(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, 56 - - /* 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, 72 - - /* make the call */ - bl .ffi_closure_helper_DARWIN - nop - -.Ldoneclosure: - - /* 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 */ - lhz r3, 6(r3) /* load type from return type */ - lwz r4, LC..60(2) /* get address of jump table */ - slwi r3, r3, 4 /* now multiply return type by 16 */ - lwz r0, 176+8(r1) /* load return address */ - add r3, r3, r4 /* add contents of table to table address */ - mtctr r3 - bctr /* jump to it */ - -/* Each fragment must be exactly 16 bytes long (4 instructions). - Align to 16 byte boundary for cache and dispatch efficiency. */ - .align 4 - -L..60: -/* case FFI_TYPE_VOID */ - mtlr r0 - addi r1, r1, 176 - blr - nop - -/* case FFI_TYPE_INT */ - lwz r3, 56+0(r1) - mtlr r0 - addi r1, r1, 176 - blr - -/* case FFI_TYPE_FLOAT */ - lfs f1, 56+0(r1) - mtlr r0 - addi r1, r1, 176 - blr - -/* case FFI_TYPE_DOUBLE */ - lfd f1, 56+0(r1) - mtlr r0 - addi r1, r1, 176 - blr - -/* case FFI_TYPE_LONGDOUBLE */ - lfd f1, 56+0(r1) - mtlr r0 - lfd f2, 56+8(r1) - b L..finish - -/* case FFI_TYPE_UINT8 */ - lbz r3, 56+3(r1) - mtlr r0 - addi r1, r1, 176 - blr - -/* case FFI_TYPE_SINT8 */ - lbz r3, 56+3(r1) - mtlr r0 - extsb r3, r3 - b L..finish - -/* case FFI_TYPE_UINT16 */ - lhz r3, 56+2(r1) - mtlr r0 - addi r1, r1, 176 - blr - -/* case FFI_TYPE_SINT16 */ - lha r3, 56+2(r1) - mtlr r0 - addi r1, r1, 176 - blr - -/* case FFI_TYPE_UINT32 */ - lwz r3, 56+0(r1) - mtlr r0 - addi r1, r1, 176 - blr - -/* case FFI_TYPE_SINT32 */ - lwz r3, 56+0(r1) - mtlr r0 - addi r1, r1, 176 - blr - -/* case FFI_TYPE_UINT64 */ - lwz r3, 56+0(r1) - mtlr r0 - lwz r4, 56+4(r1) - b L..finish - -/* case FFI_TYPE_SINT64 */ - lwz r3, 56+0(r1) - mtlr r0 - lwz r4, 56+4(r1) - b L..finish - -/* case FFI_TYPE_STRUCT */ - mtlr r0 - addi r1, r1, 176 - blr - nop - -/* case FFI_TYPE_POINTER */ - lwz r3, 56+0(r1) - mtlr r0 -L..finish: - addi r1, r1, 176 - blr -LFE..0: -#endif - .ef __LINE__ -/* END(ffi_closure_ASM) */ - - -.csect .text[PR] - .align 2 - .globl ffi_go_closure_ASM - .globl .ffi_go_closure_ASM -.csect ffi_go_closure_ASM[DS] -ffi_go_closure_ASM: -#ifdef __64BIT__ - .llong .ffi_go_closure_ASM, TOC[tc0], 0 - .csect .text[PR] -.ffi_go_closure_ASM: - .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1 - .bf __LINE__ - .line 1 -LFB..1: -/* 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 */ - std r3, 48+(0*8)(r1) - std r4, 48+(1*8)(r1) - std r5, 48+(2*8)(r1) - std r6, 48+(3*8)(r1) - mflr r0 - - std r7, 48+(4*8)(r1) - std r8, 48+(5*8)(r1) - std r9, 48+(6*8)(r1) - std r10, 48+(7*8)(r1) - std r0, 16(r1) /* save the return address */ -LCFI..2: - /* 48 Bytes (Linkage Area) */ - /* 64 Bytes (params) */ - /* 16 Bytes (result) */ - /* 104 Bytes (13*8 from FPR) */ - /* 8 Bytes (alignment) */ - /* 240 Bytes */ - - stdu r1, -240(r1) /* skip over caller save area - keep stack aligned to 16 */ -LCFI..3: - - /* next save fpr 1 to fpr 13 (aligned to 8) */ - 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 */ - mr r3, r11 /* go closure */ - - /* 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, 288 - - /* now load up the pointer to the saved fpr registers */ - addi r6, r1, 128 - - /* make the call */ - bl .ffi_go_closure_helper_DARWIN - nop - - b .Ldoneclosure -LFE..1: - -#else /* ! __64BIT__ */ - - .long .ffi_go_closure_ASM, TOC[tc0], 0 - .csect .text[PR] -.ffi_go_closure_ASM: - .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1 - .bf __LINE__ - .line 1 -LFB..1: -/* 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, 24+(0*4)(r1) - stw r4, 24+(1*4)(r1) - stw r5, 24+(2*4)(r1) - stw r6, 24+(3*4)(r1) - mflr r0 - - stw r7, 24+(4*4)(r1) - stw r8, 24+(5*4)(r1) - stw r9, 24+(6*4)(r1) - stw r10, 24+(7*4)(r1) - stw r0, 8(r1) -LCFI..2: - /* 24 Bytes (Linkage Area) */ - /* 32 Bytes (params) */ - /* 16 Bytes (result) */ - /* 104 Bytes (13*8 from FPR) */ - /* 176 Bytes */ - - stwu r1, -176(r1) /* skip over caller save area - keep stack aligned to 16 */ -LCFI..3: - - /* next save fpr 1 to fpr 13 (aligned to 8) */ - stfd f1, 72+(0*8)(r1) - stfd f2, 72+(1*8)(r1) - stfd f3, 72+(2*8)(r1) - stfd f4, 72+(3*8)(r1) - stfd f5, 72+(4*8)(r1) - stfd f6, 72+(5*8)(r1) - stfd f7, 72+(6*8)(r1) - stfd f8, 72+(7*8)(r1) - stfd f9, 72+(8*8)(r1) - stfd f10, 72+(9*8)(r1) - stfd f11, 72+(10*8)(r1) - stfd f12, 72+(11*8)(r1) - stfd f13, 72+(12*8)(r1) - - /* set up registers for the routine that actually does the work */ - mr r3, 11 /* go closure */ - - /* now load up the pointer to the result storage */ - addi r4, r1, 56 - - /* 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, 72 - - /* make the call */ - bl .ffi_go_closure_helper_DARWIN - nop - - b .Ldoneclosure -LFE..1: -#endif - .ef __LINE__ -/* END(ffi_go_closure_ASM) */ - -/* EH frame stuff. */ - -#define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */ -#ifdef __64BIT__ -#define PTRSIZE 8 -#define LOG2_PTRSIZE 3 -#define CFA_OFFSET 0xf0,0x01 /* LEB128 240 */ -#define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */ -#define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */ -#else -#define PTRSIZE 4 -#define LOG2_PTRSIZE 2 -#define CFA_OFFSET 0xb0,0x01 /* LEB128 176 */ -#define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */ -#define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */ -#endif - - .csect _unwind.ro_[RO],4 - .align LOG2_PTRSIZE - .globl _GLOBAL__F_libffi_src_powerpc_aix_closure -_GLOBAL__F_libffi_src_powerpc_aix_closure: -Lframe..1: - .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */ -LSCIE..1: - .vbyte 4,0 /* CIE Identifier Tag */ - .byte 0x3 /* CIE Version */ - .byte "zR" /* CIE Augmentation */ - .byte 0 - .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ - .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */ - .byte LR_REGNO /* CIE RA Column */ - .byte 0x1 /* uleb128 0x1; Augmentation size */ - .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */ - .byte 0xc /* DW_CFA_def_cfa */ - .byte 0x1 /* uleb128 0x1; Register r1 */ - .byte 0 /* uleb128 0x0; Offset 0 */ - .align LOG2_PTRSIZE -LECIE..1: -LSFDE..1: - .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */ -LASFDE..1: - .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */ - .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */ - .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */ - .byte 0 /* uleb128 0x0; Augmentation size */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .vbyte 4,LCFI..1-LCFI..0 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .byte CFA_OFFSET /* uleb128 176/240 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .vbyte 4,LCFI..0-LFB..0 - .byte 0x11 /* DW_CFA_offset_extended_sf */ - .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ - .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ - .align LOG2_PTRSIZE -LEFDE..1: -LSFDE..2: - .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */ -LASFDE..2: - .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */ - .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */ - .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */ - .byte 0 /* uleb128 0x0; Augmentation size */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .vbyte 4,LCFI..3-LCFI..2 - .byte 0xe /* DW_CFA_def_cfa_offset */ - .byte CFA_OFFSET /* uleb128 176/240 */ - .byte 0x4 /* DW_CFA_advance_loc4 */ - .vbyte 4,LCFI..2-LFB..1 - .byte 0x11 /* DW_CFA_offset_extended_sf */ - .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ - .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ - .align LOG2_PTRSIZE -LEFDE..2: - .vbyte 4,0 /* End of FDEs */ - - .csect .text[PR] - .ref _GLOBAL__F_libffi_src_powerpc_aix_closure /* Prevents garbage collection by AIX linker */ - +/* ----------------------------------------------------------------------- + aix_closure.S - Copyright (c) 2002, 2003, 2009 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 + + .extern .ffi_closure_helper_DARWIN + .extern .ffi_go_closure_helper_DARWIN + +#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: +#ifdef __64BIT__ + .llong .ffi_closure_ASM, TOC[tc0], 0 + .csect .text[PR] +.ffi_closure_ASM: + .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0 + .bf __LINE__ + .line 1 +LFB..0: +/* 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 */ + std r3, 48+(0*8)(r1) + std r4, 48+(1*8)(r1) + std r5, 48+(2*8)(r1) + std r6, 48+(3*8)(r1) + mflr r0 + + std r7, 48+(4*8)(r1) + std r8, 48+(5*8)(r1) + std r9, 48+(6*8)(r1) + std r10, 48+(7*8)(r1) + std r0, 16(r1) /* save the return address */ +LCFI..0: + /* 48 Bytes (Linkage Area) */ + /* 64 Bytes (params) */ + /* 16 Bytes (result) */ + /* 104 Bytes (13*8 from FPR) */ + /* 8 Bytes (alignment) */ + /* 240 Bytes */ + + stdu r1, -240(r1) /* skip over caller save area + keep stack aligned to 16 */ +LCFI..1: + + /* next save fpr 1 to fpr 13 (aligned to 8) */ + 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 saved gpr registers */ + addi r5, r1, 288 + + /* now load up the pointer to the saved fpr registers */ + addi r6, r1, 128 + + /* make the call */ + bl .ffi_closure_helper_DARWIN + nop + +.Ldoneclosure: + + /* 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 */ + lhz r3, 10(r3) /* load type from return type */ + ld r4, LC..60(2) /* get address of jump table */ + sldi r3, r3, 4 /* now multiply return type by 16 */ + ld r0, 240+16(r1) /* load return address */ + add r3, r3, r4 /* add contents of table to table address */ + mtctr r3 + bctr /* jump to it */ + +/* Each fragment must be exactly 16 bytes long (4 instructions). + Align to 16 byte boundary for cache and dispatch efficiency. */ + .align 4 + +L..60: +/* 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 L..finish + +/* 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) + mtlr r0 + extsb r3, r3 + b L..finish + +/* case FFI_TYPE_UINT16 */ + lhz r3, 112+6(r1) + mtlr r0 +L..finish: + 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 +LFE..0: + +#else /* ! __64BIT__ */ + + .long .ffi_closure_ASM, TOC[tc0], 0 + .csect .text[PR] +.ffi_closure_ASM: + .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0 + .bf __LINE__ + .line 1 +LFB..0: +/* 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, 24+(0*4)(r1) + stw r4, 24+(1*4)(r1) + stw r5, 24+(2*4)(r1) + stw r6, 24+(3*4)(r1) + mflr r0 + + stw r7, 24+(4*4)(r1) + stw r8, 24+(5*4)(r1) + stw r9, 24+(6*4)(r1) + stw r10, 24+(7*4)(r1) + stw r0, 8(r1) +LCFI..0: + /* 24 Bytes (Linkage Area) */ + /* 32 Bytes (params) */ + /* 16 Bytes (result) */ + /* 104 Bytes (13*8 from FPR) */ + /* 176 Bytes */ + + stwu r1, -176(r1) /* skip over caller save area + keep stack aligned to 16 */ +LCFI..1: + + /* next save fpr 1 to fpr 13 (aligned to 8) */ + stfd f1, 72+(0*8)(r1) + stfd f2, 72+(1*8)(r1) + stfd f3, 72+(2*8)(r1) + stfd f4, 72+(3*8)(r1) + stfd f5, 72+(4*8)(r1) + stfd f6, 72+(5*8)(r1) + stfd f7, 72+(6*8)(r1) + stfd f8, 72+(7*8)(r1) + stfd f9, 72+(8*8)(r1) + stfd f10, 72+(9*8)(r1) + stfd f11, 72+(10*8)(r1) + stfd f12, 72+(11*8)(r1) + stfd f13, 72+(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, 56 + + /* 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, 72 + + /* make the call */ + bl .ffi_closure_helper_DARWIN + nop + +.Ldoneclosure: + + /* 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 */ + lhz r3, 6(r3) /* load type from return type */ + lwz r4, LC..60(2) /* get address of jump table */ + slwi r3, r3, 4 /* now multiply return type by 16 */ + lwz r0, 176+8(r1) /* load return address */ + add r3, r3, r4 /* add contents of table to table address */ + mtctr r3 + bctr /* jump to it */ + +/* Each fragment must be exactly 16 bytes long (4 instructions). + Align to 16 byte boundary for cache and dispatch efficiency. */ + .align 4 + +L..60: +/* case FFI_TYPE_VOID */ + mtlr r0 + addi r1, r1, 176 + blr + nop + +/* case FFI_TYPE_INT */ + lwz r3, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_FLOAT */ + lfs f1, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_DOUBLE */ + lfd f1, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_LONGDOUBLE */ + lfd f1, 56+0(r1) + mtlr r0 + lfd f2, 56+8(r1) + b L..finish + +/* case FFI_TYPE_UINT8 */ + lbz r3, 56+3(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_SINT8 */ + lbz r3, 56+3(r1) + mtlr r0 + extsb r3, r3 + b L..finish + +/* case FFI_TYPE_UINT16 */ + lhz r3, 56+2(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_SINT16 */ + lha r3, 56+2(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_UINT32 */ + lwz r3, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_SINT32 */ + lwz r3, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_UINT64 */ + lwz r3, 56+0(r1) + mtlr r0 + lwz r4, 56+4(r1) + b L..finish + +/* case FFI_TYPE_SINT64 */ + lwz r3, 56+0(r1) + mtlr r0 + lwz r4, 56+4(r1) + b L..finish + +/* case FFI_TYPE_STRUCT */ + mtlr r0 + addi r1, r1, 176 + blr + nop + +/* case FFI_TYPE_POINTER */ + lwz r3, 56+0(r1) + mtlr r0 +L..finish: + addi r1, r1, 176 + blr +LFE..0: +#endif + .ef __LINE__ +/* END(ffi_closure_ASM) */ + + +.csect .text[PR] + .align 2 + .globl ffi_go_closure_ASM + .globl .ffi_go_closure_ASM +.csect ffi_go_closure_ASM[DS] +ffi_go_closure_ASM: +#ifdef __64BIT__ + .llong .ffi_go_closure_ASM, TOC[tc0], 0 + .csect .text[PR] +.ffi_go_closure_ASM: + .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1 + .bf __LINE__ + .line 1 +LFB..1: +/* 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 */ + std r3, 48+(0*8)(r1) + std r4, 48+(1*8)(r1) + std r5, 48+(2*8)(r1) + std r6, 48+(3*8)(r1) + mflr r0 + + std r7, 48+(4*8)(r1) + std r8, 48+(5*8)(r1) + std r9, 48+(6*8)(r1) + std r10, 48+(7*8)(r1) + std r0, 16(r1) /* save the return address */ +LCFI..2: + /* 48 Bytes (Linkage Area) */ + /* 64 Bytes (params) */ + /* 16 Bytes (result) */ + /* 104 Bytes (13*8 from FPR) */ + /* 8 Bytes (alignment) */ + /* 240 Bytes */ + + stdu r1, -240(r1) /* skip over caller save area + keep stack aligned to 16 */ +LCFI..3: + + /* next save fpr 1 to fpr 13 (aligned to 8) */ + 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 */ + mr r3, r11 /* go closure */ + + /* 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, 288 + + /* now load up the pointer to the saved fpr registers */ + addi r6, r1, 128 + + /* make the call */ + bl .ffi_go_closure_helper_DARWIN + nop + + b .Ldoneclosure +LFE..1: + +#else /* ! __64BIT__ */ + + .long .ffi_go_closure_ASM, TOC[tc0], 0 + .csect .text[PR] +.ffi_go_closure_ASM: + .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1 + .bf __LINE__ + .line 1 +LFB..1: +/* 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, 24+(0*4)(r1) + stw r4, 24+(1*4)(r1) + stw r5, 24+(2*4)(r1) + stw r6, 24+(3*4)(r1) + mflr r0 + + stw r7, 24+(4*4)(r1) + stw r8, 24+(5*4)(r1) + stw r9, 24+(6*4)(r1) + stw r10, 24+(7*4)(r1) + stw r0, 8(r1) +LCFI..2: + /* 24 Bytes (Linkage Area) */ + /* 32 Bytes (params) */ + /* 16 Bytes (result) */ + /* 104 Bytes (13*8 from FPR) */ + /* 176 Bytes */ + + stwu r1, -176(r1) /* skip over caller save area + keep stack aligned to 16 */ +LCFI..3: + + /* next save fpr 1 to fpr 13 (aligned to 8) */ + stfd f1, 72+(0*8)(r1) + stfd f2, 72+(1*8)(r1) + stfd f3, 72+(2*8)(r1) + stfd f4, 72+(3*8)(r1) + stfd f5, 72+(4*8)(r1) + stfd f6, 72+(5*8)(r1) + stfd f7, 72+(6*8)(r1) + stfd f8, 72+(7*8)(r1) + stfd f9, 72+(8*8)(r1) + stfd f10, 72+(9*8)(r1) + stfd f11, 72+(10*8)(r1) + stfd f12, 72+(11*8)(r1) + stfd f13, 72+(12*8)(r1) + + /* set up registers for the routine that actually does the work */ + mr r3, 11 /* go closure */ + + /* now load up the pointer to the result storage */ + addi r4, r1, 56 + + /* 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, 72 + + /* make the call */ + bl .ffi_go_closure_helper_DARWIN + nop + + b .Ldoneclosure +LFE..1: +#endif + .ef __LINE__ +/* END(ffi_go_closure_ASM) */ + +/* EH frame stuff. */ + +#define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */ +#ifdef __64BIT__ +#define PTRSIZE 8 +#define LOG2_PTRSIZE 3 +#define CFA_OFFSET 0xf0,0x01 /* LEB128 240 */ +#define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */ +#define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */ +#else +#define PTRSIZE 4 +#define LOG2_PTRSIZE 2 +#define CFA_OFFSET 0xb0,0x01 /* LEB128 176 */ +#define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */ +#define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */ +#endif + + .csect _unwind.ro_[RO],4 + .align LOG2_PTRSIZE + .globl _GLOBAL__F_libffi_src_powerpc_aix_closure +_GLOBAL__F_libffi_src_powerpc_aix_closure: +Lframe..1: + .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */ +LSCIE..1: + .vbyte 4,0 /* CIE Identifier Tag */ + .byte 0x3 /* CIE Version */ + .byte "zR" /* CIE Augmentation */ + .byte 0 + .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ + .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */ + .byte LR_REGNO /* CIE RA Column */ + .byte 0x1 /* uleb128 0x1; Augmentation size */ + .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */ + .byte 0xc /* DW_CFA_def_cfa */ + .byte 0x1 /* uleb128 0x1; Register r1 */ + .byte 0 /* uleb128 0x0; Offset 0 */ + .align LOG2_PTRSIZE +LECIE..1: +LSFDE..1: + .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */ +LASFDE..1: + .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */ + .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */ + .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */ + .byte 0 /* uleb128 0x0; Augmentation size */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .vbyte 4,LCFI..1-LCFI..0 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte CFA_OFFSET /* uleb128 176/240 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .vbyte 4,LCFI..0-LFB..0 + .byte 0x11 /* DW_CFA_offset_extended_sf */ + .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ + .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ + .align LOG2_PTRSIZE +LEFDE..1: +LSFDE..2: + .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */ +LASFDE..2: + .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */ + .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */ + .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */ + .byte 0 /* uleb128 0x0; Augmentation size */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .vbyte 4,LCFI..3-LCFI..2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte CFA_OFFSET /* uleb128 176/240 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .vbyte 4,LCFI..2-LFB..1 + .byte 0x11 /* DW_CFA_offset_extended_sf */ + .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */ + .byte 0x7e /* leb128 -2; Offset -2 (8/16) */ + .align LOG2_PTRSIZE +LEFDE..2: + .vbyte 4,0 /* End of FDEs */ + + .csect .text[PR] + .ref _GLOBAL__F_libffi_src_powerpc_aix_closure /* Prevents garbage collection by AIX linker */ + diff --git a/contrib/restricted/libffi/src/powerpc/asm.h b/contrib/restricted/libffi/src/powerpc/asm.h index 27b22f670a..4f8a4b4c6b 100644 --- a/contrib/restricted/libffi/src/powerpc/asm.h +++ b/contrib/restricted/libffi/src/powerpc/asm.h @@ -1,125 +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 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 EFFI_ALIGN(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 EFFI_ALIGN(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 +/* ----------------------------------------------------------------------- + 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 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 EFFI_ALIGN(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 EFFI_ALIGN(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/contrib/restricted/libffi/src/powerpc/darwin.S b/contrib/restricted/libffi/src/powerpc/darwin.S index 066eb82efe..5012ffba65 100644 --- a/contrib/restricted/libffi/src/powerpc/darwin.S +++ b/contrib/restricted/libffi/src/powerpc/darwin.S @@ -1,378 +1,378 @@ -/* ----------------------------------------------------------------------- - darwin.S - Copyright (c) 2000 John Hornkvist - Copyright (c) 2004, 2010 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 -#if defined(__ppc64__) -#define MODE_CHOICE(x, y) y -#else -#define MODE_CHOICE(x, y) x -#endif - -#define machine_choice MODE_CHOICE(ppc7400,ppc64) - -; Define some pseudo-opcodes for size-independent load & store of GPRs ... -#define lgu MODE_CHOICE(lwzu, ldu) -#define lg MODE_CHOICE(lwz,ld) -#define sg MODE_CHOICE(stw,std) -#define sgu MODE_CHOICE(stwu,stdu) -#define sgux MODE_CHOICE(stwux,stdux) - -; ... and the size of GPRs and their storage indicator. -#define GPR_BYTES MODE_CHOICE(4,8) -#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ -#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ - -; From the ABI doc: "Mac OS X ABI Function Call Guide" Version 2009-02-04. -#define LINKAGE_SIZE MODE_CHOICE(24,48) -#define PARAM_AREA MODE_CHOICE(32,64) -#define SAVED_LR_OFFSET MODE_CHOICE(8,16) /* save position for lr */ - -/* If there is any FP stuff we make space for all of the regs. */ -#define SAVED_FPR_COUNT 13 -#define FPR_SIZE 8 -#define RESULT_BYTES 16 - -/* This should be kept in step with the same value in ffi_darwin.c. */ -#define ASM_NEEDS_REGISTERS 4 -#define SAVE_REGS_SIZE (ASM_NEEDS_REGISTERS * GPR_BYTES) - -#include <fficonfig.h> -#include <ffi.h> - -#define JUMPTARGET(name) name -#define L(x) x - - .text - .align 2 - .globl _ffi_prep_args - - .align 2 - .globl _ffi_call_DARWIN - - /* We arrive here with: - r3 = ptr to extended cif. - r4 = -bytes. - r5 = cif flags. - r6 = ptr to return value. - r7 = fn pointer (user func). - r8 = fn pointer (ffi_prep_args). - r9 = ffi_type* for the ret val. */ - -_ffi_call_DARWIN: -Lstartcode: - mr r12,r8 /* We only need r12 until the call, - so it does not have to be saved. */ -LFB1: - /* Save the old stack pointer as AP. */ - mr r8,r1 -LCFI0: - - /* Save the retval type in parents frame. */ - sg r9,(LINKAGE_SIZE+6*GPR_BYTES)(r8) - - /* Allocate the stack space we need. */ - sgux r1,r1,r4 - - /* Save registers we use. */ - mflr r9 - sg r9,SAVED_LR_OFFSET(r8) - - sg r28,-(4 * GPR_BYTES)(r8) - sg r29,-(3 * GPR_BYTES)(r8) - sg r30,-(2 * GPR_BYTES)(r8) - sg r31,-( GPR_BYTES)(r8) - -#if !defined(POWERPC_DARWIN) - /* The TOC slot is reserved in the Darwin ABI and r2 is volatile. */ - sg r2,(5 * GPR_BYTES)(r1) -#endif - -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. r3 = extended cif, r4 = stack ptr copy. */ - mr r4,r1 - li r9,0 - - mtctr r12 /* r12 holds address of _ffi_prep_args. */ - bctrl - -#if !defined(POWERPC_DARWIN) - /* The TOC slot is reserved in the Darwin ABI and r2 is volatile. */ - lg r2,(5 * GPR_BYTES)(r1) -#endif - /* 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. */ - lg r3, (LINKAGE_SIZE )(r1) - lg r4, (LINKAGE_SIZE + GPR_BYTES)(r1) - lg r5, (LINKAGE_SIZE + 2 * GPR_BYTES)(r1) - lg r6, (LINKAGE_SIZE + 3 * GPR_BYTES)(r1) - nop - lg r7, (LINKAGE_SIZE + 4 * GPR_BYTES)(r1) - lg r8, (LINKAGE_SIZE + 5 * GPR_BYTES)(r1) - lg r9, (LINKAGE_SIZE + 6 * GPR_BYTES)(r1) - lg r10,(LINKAGE_SIZE + 7 * GPR_BYTES)(r1) - -L1: - /* ... Load all the FP registers. */ - bf 6,L2 /* No floats to load. */ - lfd f1, -SAVE_REGS_SIZE-(13*FPR_SIZE)(r28) - lfd f2, -SAVE_REGS_SIZE-(12*FPR_SIZE)(r28) - lfd f3, -SAVE_REGS_SIZE-(11*FPR_SIZE)(r28) - lfd f4, -SAVE_REGS_SIZE-(10*FPR_SIZE)(r28) - nop - lfd f5, -SAVE_REGS_SIZE-( 9*FPR_SIZE)(r28) - lfd f6, -SAVE_REGS_SIZE-( 8*FPR_SIZE)(r28) - lfd f7, -SAVE_REGS_SIZE-( 7*FPR_SIZE)(r28) - lfd f8, -SAVE_REGS_SIZE-( 6*FPR_SIZE)(r28) - nop - lfd f9, -SAVE_REGS_SIZE-( 5*FPR_SIZE)(r28) - lfd f10,-SAVE_REGS_SIZE-( 4*FPR_SIZE)(r28) - lfd f11,-SAVE_REGS_SIZE-( 3*FPR_SIZE)(r28) - lfd f12,-SAVE_REGS_SIZE-( 2*FPR_SIZE)(r28) - nop - lfd f13,-SAVE_REGS_SIZE-( 1*FPR_SIZE)(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. */ - - /* m64 structure returns can occupy the same set of registers as - would be used to pass such a structure as arg0 - so take care - not to step on any possibly hot regs. */ - - /* Get the flags.. */ - mtcrf 0x03,r31 ; we need c6 & cr7 now. - ; FLAG_RETURNS_NOTHING also covers struct ret-by-ref. - bt 30,L(done_return_value) ; FLAG_RETURNS_NOTHING - bf 27,L(scalar_return_value) ; not FLAG_RETURNS_STRUCT - - /* OK, so we have a struct. */ -#if defined(__ppc64__) - bt 31,L(maybe_return_128) ; FLAG_RETURNS_128BITS, special case - - /* OK, we have to map the return back to a mem struct. - We are about to trample the parents param area, so recover the - return type. r29 is free, since the call is done. */ - lg r29,(LINKAGE_SIZE + 6 * GPR_BYTES)(r28) - - sg r3, (LINKAGE_SIZE )(r28) - sg r4, (LINKAGE_SIZE + GPR_BYTES)(r28) - sg r5, (LINKAGE_SIZE + 2 * GPR_BYTES)(r28) - sg r6, (LINKAGE_SIZE + 3 * GPR_BYTES)(r28) - nop - sg r7, (LINKAGE_SIZE + 4 * GPR_BYTES)(r28) - sg r8, (LINKAGE_SIZE + 5 * GPR_BYTES)(r28) - sg r9, (LINKAGE_SIZE + 6 * GPR_BYTES)(r28) - sg r10,(LINKAGE_SIZE + 7 * GPR_BYTES)(r28) - /* OK, so do the block move - we trust that memcpy will not trample - the fprs... */ - mr r3,r30 ; dest - addi r4,r28,LINKAGE_SIZE ; source - /* The size is a size_t, should be long. */ - lg r5,0(r29) - /* Figure out small structs */ - cmpi 0,r5,4 - bgt L3 ; 1, 2 and 4 bytes have special rules. - cmpi 0,r5,3 - beq L3 ; not 3 - addi r4,r4,8 - subf r4,r5,r4 -L3: - bl _memcpy - - /* ... do we need the FP registers? - recover the flags.. */ - mtcrf 0x03,r31 ; we need c6 & cr7 now. - bf 29,L(done_return_value) /* No floats in the struct. */ - stfd f1, -SAVE_REGS_SIZE-(13*FPR_SIZE)(r28) - stfd f2, -SAVE_REGS_SIZE-(12*FPR_SIZE)(r28) - stfd f3, -SAVE_REGS_SIZE-(11*FPR_SIZE)(r28) - stfd f4, -SAVE_REGS_SIZE-(10*FPR_SIZE)(r28) - nop - stfd f5, -SAVE_REGS_SIZE-( 9*FPR_SIZE)(r28) - stfd f6, -SAVE_REGS_SIZE-( 8*FPR_SIZE)(r28) - stfd f7, -SAVE_REGS_SIZE-( 7*FPR_SIZE)(r28) - stfd f8, -SAVE_REGS_SIZE-( 6*FPR_SIZE)(r28) - nop - stfd f9, -SAVE_REGS_SIZE-( 5*FPR_SIZE)(r28) - stfd f10,-SAVE_REGS_SIZE-( 4*FPR_SIZE)(r28) - stfd f11,-SAVE_REGS_SIZE-( 3*FPR_SIZE)(r28) - stfd f12,-SAVE_REGS_SIZE-( 2*FPR_SIZE)(r28) - nop - stfd f13,-SAVE_REGS_SIZE-( 1*FPR_SIZE)(r28) - - mr r3,r29 ; ffi_type * - mr r4,r30 ; dest - addi r5,r28,-SAVE_REGS_SIZE-(13*FPR_SIZE) ; fprs - xor r6,r6,r6 - sg r6,(LINKAGE_SIZE + 7 * GPR_BYTES)(r28) - addi r6,r28,(LINKAGE_SIZE + 7 * GPR_BYTES) ; point to a zeroed counter. - bl _darwin64_struct_floats_to_mem - - b L(done_return_value) -#else - stw r3,0(r30) ; m32 the only struct return in reg is 4 bytes. -#endif - b L(done_return_value) - -L(fp_return_value): - /* Do we have long double to store? */ - bf 31,L(fd_return_value) ; FLAG_RETURNS_128BITS - stfd f1,0(r30) - stfd f2,FPR_SIZE(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) - -L(scalar_return_value): - bt 29,L(fp_return_value) ; FLAG_RETURNS_FP - ; ffi_arg is defined as unsigned long. - sg r3,0(r30) ; Save the reg. - bf 28,L(done_return_value) ; not FLAG_RETURNS_64BITS - -#if defined(__ppc64__) -L(maybe_return_128): - std r3,0(r30) - bf 31,L(done_return_value) ; not FLAG_RETURNS_128BITS - std r4,8(r30) -#else - stw r4,4(r30) -#endif - - /* Fall through. */ - /* We want this at the end to simplify eh epilog computation. */ - -L(done_return_value): - /* Restore the registers we used and return. */ - lg r29,SAVED_LR_OFFSET(r28) - ; epilog - lg r31,-(1 * GPR_BYTES)(r28) - mtlr r29 - lg r30,-(2 * GPR_BYTES)(r28) - lg r29,-(3 * GPR_BYTES)(r28) - lg r28,-(4 * GPR_BYTES)(r28) - lg r1,0(r1) - blr -LFE1: - .align 1 -/* END(_ffi_call_DARWIN) */ - -/* Provide a null definition of _ffi_call_AIX. */ - .text - .globl _ffi_call_AIX - .align 2 -_ffi_call_AIX: - blr -/* END(_ffi_call_AIX) */ - -/* EH stuff. */ - -#define EH_DATA_ALIGN_FACT MODE_CHOICE(0x7c,0x78) - - .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 EH_DATA_ALIGN_FACT ; sleb128 -4; CIE Data Alignment Factor - .byte 0x41 ; CIE RA Column - .byte 0x1 ; uleb128 0x1; Augmentation size - .byte 0x10 ; FDE Encoding (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 Lstartcode-. ; FDE initial location - .set L$set$3,LFE1-Lstartcode - .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-Lstartcode - .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: - .align 1 - +/* ----------------------------------------------------------------------- + darwin.S - Copyright (c) 2000 John Hornkvist + Copyright (c) 2004, 2010 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 +#if defined(__ppc64__) +#define MODE_CHOICE(x, y) y +#else +#define MODE_CHOICE(x, y) x +#endif + +#define machine_choice MODE_CHOICE(ppc7400,ppc64) + +; Define some pseudo-opcodes for size-independent load & store of GPRs ... +#define lgu MODE_CHOICE(lwzu, ldu) +#define lg MODE_CHOICE(lwz,ld) +#define sg MODE_CHOICE(stw,std) +#define sgu MODE_CHOICE(stwu,stdu) +#define sgux MODE_CHOICE(stwux,stdux) + +; ... and the size of GPRs and their storage indicator. +#define GPR_BYTES MODE_CHOICE(4,8) +#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ +#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ + +; From the ABI doc: "Mac OS X ABI Function Call Guide" Version 2009-02-04. +#define LINKAGE_SIZE MODE_CHOICE(24,48) +#define PARAM_AREA MODE_CHOICE(32,64) +#define SAVED_LR_OFFSET MODE_CHOICE(8,16) /* save position for lr */ + +/* If there is any FP stuff we make space for all of the regs. */ +#define SAVED_FPR_COUNT 13 +#define FPR_SIZE 8 +#define RESULT_BYTES 16 + +/* This should be kept in step with the same value in ffi_darwin.c. */ +#define ASM_NEEDS_REGISTERS 4 +#define SAVE_REGS_SIZE (ASM_NEEDS_REGISTERS * GPR_BYTES) + +#include <fficonfig.h> +#include <ffi.h> + +#define JUMPTARGET(name) name +#define L(x) x + + .text + .align 2 + .globl _ffi_prep_args + + .align 2 + .globl _ffi_call_DARWIN + + /* We arrive here with: + r3 = ptr to extended cif. + r4 = -bytes. + r5 = cif flags. + r6 = ptr to return value. + r7 = fn pointer (user func). + r8 = fn pointer (ffi_prep_args). + r9 = ffi_type* for the ret val. */ + +_ffi_call_DARWIN: +Lstartcode: + mr r12,r8 /* We only need r12 until the call, + so it does not have to be saved. */ +LFB1: + /* Save the old stack pointer as AP. */ + mr r8,r1 +LCFI0: + + /* Save the retval type in parents frame. */ + sg r9,(LINKAGE_SIZE+6*GPR_BYTES)(r8) + + /* Allocate the stack space we need. */ + sgux r1,r1,r4 + + /* Save registers we use. */ + mflr r9 + sg r9,SAVED_LR_OFFSET(r8) + + sg r28,-(4 * GPR_BYTES)(r8) + sg r29,-(3 * GPR_BYTES)(r8) + sg r30,-(2 * GPR_BYTES)(r8) + sg r31,-( GPR_BYTES)(r8) + +#if !defined(POWERPC_DARWIN) + /* The TOC slot is reserved in the Darwin ABI and r2 is volatile. */ + sg r2,(5 * GPR_BYTES)(r1) +#endif + +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. r3 = extended cif, r4 = stack ptr copy. */ + mr r4,r1 + li r9,0 + + mtctr r12 /* r12 holds address of _ffi_prep_args. */ + bctrl + +#if !defined(POWERPC_DARWIN) + /* The TOC slot is reserved in the Darwin ABI and r2 is volatile. */ + lg r2,(5 * GPR_BYTES)(r1) +#endif + /* 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. */ + lg r3, (LINKAGE_SIZE )(r1) + lg r4, (LINKAGE_SIZE + GPR_BYTES)(r1) + lg r5, (LINKAGE_SIZE + 2 * GPR_BYTES)(r1) + lg r6, (LINKAGE_SIZE + 3 * GPR_BYTES)(r1) + nop + lg r7, (LINKAGE_SIZE + 4 * GPR_BYTES)(r1) + lg r8, (LINKAGE_SIZE + 5 * GPR_BYTES)(r1) + lg r9, (LINKAGE_SIZE + 6 * GPR_BYTES)(r1) + lg r10,(LINKAGE_SIZE + 7 * GPR_BYTES)(r1) + +L1: + /* ... Load all the FP registers. */ + bf 6,L2 /* No floats to load. */ + lfd f1, -SAVE_REGS_SIZE-(13*FPR_SIZE)(r28) + lfd f2, -SAVE_REGS_SIZE-(12*FPR_SIZE)(r28) + lfd f3, -SAVE_REGS_SIZE-(11*FPR_SIZE)(r28) + lfd f4, -SAVE_REGS_SIZE-(10*FPR_SIZE)(r28) + nop + lfd f5, -SAVE_REGS_SIZE-( 9*FPR_SIZE)(r28) + lfd f6, -SAVE_REGS_SIZE-( 8*FPR_SIZE)(r28) + lfd f7, -SAVE_REGS_SIZE-( 7*FPR_SIZE)(r28) + lfd f8, -SAVE_REGS_SIZE-( 6*FPR_SIZE)(r28) + nop + lfd f9, -SAVE_REGS_SIZE-( 5*FPR_SIZE)(r28) + lfd f10,-SAVE_REGS_SIZE-( 4*FPR_SIZE)(r28) + lfd f11,-SAVE_REGS_SIZE-( 3*FPR_SIZE)(r28) + lfd f12,-SAVE_REGS_SIZE-( 2*FPR_SIZE)(r28) + nop + lfd f13,-SAVE_REGS_SIZE-( 1*FPR_SIZE)(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. */ + + /* m64 structure returns can occupy the same set of registers as + would be used to pass such a structure as arg0 - so take care + not to step on any possibly hot regs. */ + + /* Get the flags.. */ + mtcrf 0x03,r31 ; we need c6 & cr7 now. + ; FLAG_RETURNS_NOTHING also covers struct ret-by-ref. + bt 30,L(done_return_value) ; FLAG_RETURNS_NOTHING + bf 27,L(scalar_return_value) ; not FLAG_RETURNS_STRUCT + + /* OK, so we have a struct. */ +#if defined(__ppc64__) + bt 31,L(maybe_return_128) ; FLAG_RETURNS_128BITS, special case + + /* OK, we have to map the return back to a mem struct. + We are about to trample the parents param area, so recover the + return type. r29 is free, since the call is done. */ + lg r29,(LINKAGE_SIZE + 6 * GPR_BYTES)(r28) + + sg r3, (LINKAGE_SIZE )(r28) + sg r4, (LINKAGE_SIZE + GPR_BYTES)(r28) + sg r5, (LINKAGE_SIZE + 2 * GPR_BYTES)(r28) + sg r6, (LINKAGE_SIZE + 3 * GPR_BYTES)(r28) + nop + sg r7, (LINKAGE_SIZE + 4 * GPR_BYTES)(r28) + sg r8, (LINKAGE_SIZE + 5 * GPR_BYTES)(r28) + sg r9, (LINKAGE_SIZE + 6 * GPR_BYTES)(r28) + sg r10,(LINKAGE_SIZE + 7 * GPR_BYTES)(r28) + /* OK, so do the block move - we trust that memcpy will not trample + the fprs... */ + mr r3,r30 ; dest + addi r4,r28,LINKAGE_SIZE ; source + /* The size is a size_t, should be long. */ + lg r5,0(r29) + /* Figure out small structs */ + cmpi 0,r5,4 + bgt L3 ; 1, 2 and 4 bytes have special rules. + cmpi 0,r5,3 + beq L3 ; not 3 + addi r4,r4,8 + subf r4,r5,r4 +L3: + bl _memcpy + + /* ... do we need the FP registers? - recover the flags.. */ + mtcrf 0x03,r31 ; we need c6 & cr7 now. + bf 29,L(done_return_value) /* No floats in the struct. */ + stfd f1, -SAVE_REGS_SIZE-(13*FPR_SIZE)(r28) + stfd f2, -SAVE_REGS_SIZE-(12*FPR_SIZE)(r28) + stfd f3, -SAVE_REGS_SIZE-(11*FPR_SIZE)(r28) + stfd f4, -SAVE_REGS_SIZE-(10*FPR_SIZE)(r28) + nop + stfd f5, -SAVE_REGS_SIZE-( 9*FPR_SIZE)(r28) + stfd f6, -SAVE_REGS_SIZE-( 8*FPR_SIZE)(r28) + stfd f7, -SAVE_REGS_SIZE-( 7*FPR_SIZE)(r28) + stfd f8, -SAVE_REGS_SIZE-( 6*FPR_SIZE)(r28) + nop + stfd f9, -SAVE_REGS_SIZE-( 5*FPR_SIZE)(r28) + stfd f10,-SAVE_REGS_SIZE-( 4*FPR_SIZE)(r28) + stfd f11,-SAVE_REGS_SIZE-( 3*FPR_SIZE)(r28) + stfd f12,-SAVE_REGS_SIZE-( 2*FPR_SIZE)(r28) + nop + stfd f13,-SAVE_REGS_SIZE-( 1*FPR_SIZE)(r28) + + mr r3,r29 ; ffi_type * + mr r4,r30 ; dest + addi r5,r28,-SAVE_REGS_SIZE-(13*FPR_SIZE) ; fprs + xor r6,r6,r6 + sg r6,(LINKAGE_SIZE + 7 * GPR_BYTES)(r28) + addi r6,r28,(LINKAGE_SIZE + 7 * GPR_BYTES) ; point to a zeroed counter. + bl _darwin64_struct_floats_to_mem + + b L(done_return_value) +#else + stw r3,0(r30) ; m32 the only struct return in reg is 4 bytes. +#endif + b L(done_return_value) + +L(fp_return_value): + /* Do we have long double to store? */ + bf 31,L(fd_return_value) ; FLAG_RETURNS_128BITS + stfd f1,0(r30) + stfd f2,FPR_SIZE(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) + +L(scalar_return_value): + bt 29,L(fp_return_value) ; FLAG_RETURNS_FP + ; ffi_arg is defined as unsigned long. + sg r3,0(r30) ; Save the reg. + bf 28,L(done_return_value) ; not FLAG_RETURNS_64BITS + +#if defined(__ppc64__) +L(maybe_return_128): + std r3,0(r30) + bf 31,L(done_return_value) ; not FLAG_RETURNS_128BITS + std r4,8(r30) +#else + stw r4,4(r30) +#endif + + /* Fall through. */ + /* We want this at the end to simplify eh epilog computation. */ + +L(done_return_value): + /* Restore the registers we used and return. */ + lg r29,SAVED_LR_OFFSET(r28) + ; epilog + lg r31,-(1 * GPR_BYTES)(r28) + mtlr r29 + lg r30,-(2 * GPR_BYTES)(r28) + lg r29,-(3 * GPR_BYTES)(r28) + lg r28,-(4 * GPR_BYTES)(r28) + lg r1,0(r1) + blr +LFE1: + .align 1 +/* END(_ffi_call_DARWIN) */ + +/* Provide a null definition of _ffi_call_AIX. */ + .text + .globl _ffi_call_AIX + .align 2 +_ffi_call_AIX: + blr +/* END(_ffi_call_AIX) */ + +/* EH stuff. */ + +#define EH_DATA_ALIGN_FACT MODE_CHOICE(0x7c,0x78) + + .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 EH_DATA_ALIGN_FACT ; sleb128 -4; CIE Data Alignment Factor + .byte 0x41 ; CIE RA Column + .byte 0x1 ; uleb128 0x1; Augmentation size + .byte 0x10 ; FDE Encoding (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 Lstartcode-. ; FDE initial location + .set L$set$3,LFE1-Lstartcode + .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-Lstartcode + .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: + .align 1 + diff --git a/contrib/restricted/libffi/src/powerpc/darwin_closure.S b/contrib/restricted/libffi/src/powerpc/darwin_closure.S index 3121e6ac26..0e111edd35 100644 --- a/contrib/restricted/libffi/src/powerpc/darwin_closure.S +++ b/contrib/restricted/libffi/src/powerpc/darwin_closure.S @@ -1,571 +1,571 @@ -/* ----------------------------------------------------------------------- - darwin_closure.S - Copyright (c) 2002, 2003, 2004, 2010, - 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 machine_choice MODE_CHOICE(ppc7400,ppc64) - -; Define some pseudo-opcodes for size-independent load & store of GPRs ... -#define lgu MODE_CHOICE(lwzu, ldu) -#define lg MODE_CHOICE(lwz,ld) -#define sg MODE_CHOICE(stw,std) -#define sgu MODE_CHOICE(stwu,stdu) - -; ... and the size of GPRs and their storage indicator. -#define GPR_BYTES MODE_CHOICE(4,8) -#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ -#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ - -; From the ABI doc: "Mac OS X ABI Function Call Guide" Version 2009-02-04. -#define LINKAGE_SIZE MODE_CHOICE(24,48) -#define PARAM_AREA MODE_CHOICE(32,64) - -#define SAVED_CR_OFFSET MODE_CHOICE(4,8) /* save position for CR */ -#define SAVED_LR_OFFSET MODE_CHOICE(8,16) /* save position for lr */ - -/* WARNING: if ffi_type is changed... here be monsters. - Offsets of items within the result type. */ -#define FFI_TYPE_TYPE MODE_CHOICE(6,10) -#define FFI_TYPE_ELEM MODE_CHOICE(8,16) - -#define SAVED_FPR_COUNT 13 -#define FPR_SIZE 8 -/* biggest m64 struct ret is 8GPRS + 13FPRS = 168 bytes - rounded to 16bytes = 176. */ -#define RESULT_BYTES MODE_CHOICE(16,176) - -; The whole stack frame **MUST** be 16byte-aligned. -#define SAVE_SIZE (((LINKAGE_SIZE+PARAM_AREA+SAVED_FPR_COUNT*FPR_SIZE+RESULT_BYTES)+15) & -16LL) -#define PAD_SIZE (SAVE_SIZE-(LINKAGE_SIZE+PARAM_AREA+SAVED_FPR_COUNT*FPR_SIZE+RESULT_BYTES)) - -#define PARENT_PARM_BASE (SAVE_SIZE+LINKAGE_SIZE) -#define FP_SAVE_BASE (LINKAGE_SIZE+PARAM_AREA) - -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 -; We no longer need the pic symbol stub for Darwin >= 9. -#define BLCLS_HELP _ffi_closure_helper_DARWIN -#define STRUCT_RETVALUE_P _darwin64_struct_ret_by_value_p -#define PASS_STR_FLOATS _darwin64_pass_struct_floats -#undef WANT_STUB -#else -#define BLCLS_HELP L_ffi_closure_helper_DARWIN$stub -#define STRUCT_RETVALUE_P L_darwin64_struct_ret_by_value_p$stub -#define PASS_STR_FLOATS L_darwin64_pass_struct_floats$stub -#define WANT_STUB -#endif - -/* m32/m64 - - The stack layout looks like this: - - | Additional params... | | Higher address - ~ ~ ~ - | Parameters (at least 8*4/8=32/64) | | NUM_GPR_ARG_REGISTERS - |--------------------------------------------| | - | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | - |--------------------------------------------| | - | Reserved 2*4/8 | | - |--------------------------------------------| | - | Space for callee`s LR 4/8 | | - |--------------------------------------------| | - | Saved CR [low word for m64] 4/8 | | - |--------------------------------------------| | - | Current backchain pointer 4/8 |-/ Parent`s frame. - |--------------------------------------------| <+ <<< on entry to - | Result Bytes 16/176 | | - |--------------------------------------------| | - ~ padding to 16-byte alignment ~ ~ - |--------------------------------------------| | - | NUM_FPR_ARG_REGISTERS slots | | - | here fp13 .. fp1 13*8 | | - |--------------------------------------------| | - | R3..R10 8*4/8=32/64 | | NUM_GPR_ARG_REGISTERS - |--------------------------------------------| | - | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | - |--------------------------------------------| | stack | - | Reserved [compiler,binder] 2*4/8 | | grows | - |--------------------------------------------| | down V - | Space for callees LR 4/8 | | - |--------------------------------------------| | lower addresses - | Saved CR [low word for m64] 4/8 | | - |--------------------------------------------| | stack pointer here - | Current backchain pointer 4/8 |-/ during - |--------------------------------------------| <<< call. - -*/ - - .file "darwin_closure.S" - - .machine machine_choice - - .text - .globl _ffi_closure_ASM - .align LOG2_GPR_BYTES -_ffi_closure_ASM: -LFB1: -Lstartcode: - mflr r0 /* extract return address */ - sg r0,SAVED_LR_OFFSET(r1) /* save the return address */ -LCFI0: - sgu r1,-SAVE_SIZE(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) */ - - /* Put gpr 3 to gpr 10 in the parents outgoing area... - ... the remainder of any params that overflowed the regs will - follow here. */ - sg r3, (PARENT_PARM_BASE )(r1) - sg r4, (PARENT_PARM_BASE + GPR_BYTES )(r1) - sg r5, (PARENT_PARM_BASE + GPR_BYTES * 2)(r1) - sg r6, (PARENT_PARM_BASE + GPR_BYTES * 3)(r1) - sg r7, (PARENT_PARM_BASE + GPR_BYTES * 4)(r1) - sg r8, (PARENT_PARM_BASE + GPR_BYTES * 5)(r1) - sg r9, (PARENT_PARM_BASE + GPR_BYTES * 6)(r1) - sg r10,(PARENT_PARM_BASE + GPR_BYTES * 7)(r1) - - /* We save fpr 1 to fpr 14 in our own save frame. */ - stfd f1, (FP_SAVE_BASE )(r1) - stfd f2, (FP_SAVE_BASE + FPR_SIZE )(r1) - stfd f3, (FP_SAVE_BASE + FPR_SIZE * 2 )(r1) - stfd f4, (FP_SAVE_BASE + FPR_SIZE * 3 )(r1) - stfd f5, (FP_SAVE_BASE + FPR_SIZE * 4 )(r1) - stfd f6, (FP_SAVE_BASE + FPR_SIZE * 5 )(r1) - stfd f7, (FP_SAVE_BASE + FPR_SIZE * 6 )(r1) - stfd f8, (FP_SAVE_BASE + FPR_SIZE * 7 )(r1) - stfd f9, (FP_SAVE_BASE + FPR_SIZE * 8 )(r1) - stfd f10,(FP_SAVE_BASE + FPR_SIZE * 9 )(r1) - stfd f11,(FP_SAVE_BASE + FPR_SIZE * 10)(r1) - stfd f12,(FP_SAVE_BASE + FPR_SIZE * 11)(r1) - stfd f13,(FP_SAVE_BASE + FPR_SIZE * 12)(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,(SAVE_SIZE-RESULT_BYTES) - - /* Now load up the pointer to the saved gpr registers. */ - addi r5,r1,PARENT_PARM_BASE - - /* Now load up the pointer to the saved fpr registers. */ - addi r6,r1,FP_SAVE_BASE - - /* Make the call. */ - bl BLCLS_HELP - - /* r3 contains the rtype pointer... save it since we will need - it later. */ - sg r3,LINKAGE_SIZE(r1) ; ffi_type * result_type - lg r0,0(r3) ; size => r0 - lhz r3,FFI_TYPE_TYPE(r3) ; type => r3 - - /* The helper will have intercepted structure returns and inserted - the caller`s destination address for structs returned by ref. */ - - /* r3 contains the return type so use it to look up in a table - so we know how to deal with each type. */ - - addi r5,r1,(SAVE_SIZE-RESULT_BYTES) /* Otherwise, our return is here. */ - 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: - lg 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: -#if defined(__ppc64__) - lbz r3,7(r5) -#else - lbz r3,3(r5) -#endif - b Lfinish - nop - nop - -/* case FFI_TYPE_SINT8 */ -Lret_type6: -#if defined(__ppc64__) - lbz r3,7(r5) -#else - lbz r3,3(r5) -#endif - extsb r3,r3 - b Lfinish - nop - -/* case FFI_TYPE_UINT16 */ -Lret_type7: -#if defined(__ppc64__) - lhz r3,6(r5) -#else - lhz r3,2(r5) -#endif - b Lfinish - nop - nop - -/* case FFI_TYPE_SINT16 */ -Lret_type8: -#if defined(__ppc64__) - lha r3,6(r5) -#else - lha r3,2(r5) -#endif - b Lfinish - nop - nop - -/* case FFI_TYPE_UINT32 */ -Lret_type9: -#if defined(__ppc64__) - lwz r3,4(r5) -#else - lwz r3,0(r5) -#endif - b Lfinish - nop - nop - -/* case FFI_TYPE_SINT32 */ -Lret_type10: -#if defined(__ppc64__) - lwz r3,4(r5) -#else - lwz r3,0(r5) -#endif - b Lfinish - nop - nop - -/* case FFI_TYPE_UINT64 */ -Lret_type11: -#if defined(__ppc64__) - lg r3,0(r5) - b Lfinish - nop -#else - lwz r3,0(r5) - lwz r4,4(r5) - b Lfinish -#endif - nop - -/* case FFI_TYPE_SINT64 */ -Lret_type12: -#if defined(__ppc64__) - lg r3,0(r5) - b Lfinish - nop -#else - lwz r3,0(r5) - lwz r4,4(r5) - b Lfinish -#endif - nop - -/* case FFI_TYPE_STRUCT */ -Lret_type13: -#if defined(__ppc64__) - lg r3,0(r5) ; we need at least this... - cmpi 0,r0,4 - bgt Lstructend ; not a special small case - b Lsmallstruct ; see if we need more. -#else - cmpwi 0,r0,4 - bgt Lfinish ; not by value - lg r3,0(r5) - b Lfinish -#endif -/* case FFI_TYPE_POINTER */ -Lret_type14: - lg r3,0(r5) - b Lfinish - nop - nop - -#if defined(__ppc64__) -Lsmallstruct: - beq Lfour ; continuation of Lret13. - cmpi 0,r0,3 - beq Lfinish ; don`t adjust this - can`t be any floats here... - srdi r3,r3,48 - cmpi 0,r0,2 - beq Lfinish ; .. or here .. - srdi r3,r3,8 - b Lfinish ; .. or here. - -Lfour: - lg r6,LINKAGE_SIZE(r1) ; get the result type - lg r6,FFI_TYPE_ELEM(r6) ; elements array pointer - lg r6,0(r6) ; first element - lhz r0,FFI_TYPE_TYPE(r6) ; OK go the type - cmpi 0,r0,2 ; FFI_TYPE_FLOAT - bne Lfourint - lfs f1,0(r5) ; just one float in the struct. - b Lfinish - -Lfourint: - srdi r3,r3,32 ; four bytes. - b Lfinish - -Lstructend: - lg r3,LINKAGE_SIZE(r1) ; get the result type - bl STRUCT_RETVALUE_P - cmpi 0,r3,0 - beq Lfinish ; nope. - /* Recover a pointer to the results. */ - addi r11,r1,(SAVE_SIZE-RESULT_BYTES) - lg r3,0(r11) ; we need at least this... - lg r4,8(r11) - cmpi 0,r0,16 - beq Lfinish ; special case 16 bytes we don't consider floats. - - /* OK, frustratingly, the process of saving the struct to mem might have - messed with the FPRs, so we have to re-load them :(. - We`ll use our FPRs space again - calling: - void darwin64_pass_struct_floats (ffi_type *s, char *src, - unsigned *nfpr, double **fprs) - We`ll temporarily pinch the first two slots of the param area for local - vars used by the routine. */ - xor r6,r6,r6 - addi r5,r1,PARENT_PARM_BASE ; some space - sg r6,0(r5) ; *nfpr zeroed. - addi r6,r5,8 ; **fprs - addi r3,r1,FP_SAVE_BASE ; pointer to FPRs space - sg r3,0(r6) - mr r4,r11 ; the struct is here... - lg r3,LINKAGE_SIZE(r1) ; ffi_type * result_type. - bl PASS_STR_FLOATS ; get struct floats into FPR save space. - /* See if we used any floats */ - lwz r0,(SAVE_SIZE-RESULT_BYTES)(r1) - cmpi 0,r0,0 - beq Lstructints ; nope. - /* OK load `em up... */ - lfd f1, (FP_SAVE_BASE )(r1) - lfd f2, (FP_SAVE_BASE + FPR_SIZE )(r1) - lfd f3, (FP_SAVE_BASE + FPR_SIZE * 2 )(r1) - lfd f4, (FP_SAVE_BASE + FPR_SIZE * 3 )(r1) - lfd f5, (FP_SAVE_BASE + FPR_SIZE * 4 )(r1) - lfd f6, (FP_SAVE_BASE + FPR_SIZE * 5 )(r1) - lfd f7, (FP_SAVE_BASE + FPR_SIZE * 6 )(r1) - lfd f8, (FP_SAVE_BASE + FPR_SIZE * 7 )(r1) - lfd f9, (FP_SAVE_BASE + FPR_SIZE * 8 )(r1) - lfd f10,(FP_SAVE_BASE + FPR_SIZE * 9 )(r1) - lfd f11,(FP_SAVE_BASE + FPR_SIZE * 10)(r1) - lfd f12,(FP_SAVE_BASE + FPR_SIZE * 11)(r1) - lfd f13,(FP_SAVE_BASE + FPR_SIZE * 12)(r1) - - /* point back at our saved struct. */ -Lstructints: - addi r11,r1,(SAVE_SIZE-RESULT_BYTES) - lg r3,0(r11) ; we end up picking the - lg r4,8(r11) ; first two again. - lg r5,16(r11) - lg r6,24(r11) - lg r7,32(r11) - lg r8,40(r11) - lg r9,48(r11) - lg r10,56(r11) -#endif - -/* case done */ -Lfinish: - addi r1,r1,SAVE_SIZE /* Restore stack pointer. */ - lg r0,SAVED_LR_OFFSET(r1) /* Get return address. */ - mtlr r0 /* Reset link register. */ - blr -Lendcode: - .align 1 - -/* END(ffi_closure_ASM) */ - -/* EH frame stuff. */ -#define EH_DATA_ALIGN_FACT MODE_CHOICE(0x7c,0x78) -/* 176, 400 */ -#define EH_FRAME_OFFSETA MODE_CHOICE(176,0x90) -#define EH_FRAME_OFFSETB MODE_CHOICE(1,3) - - .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 EH_DATA_ALIGN_FACT ; sleb128 -4; CIE Data Alignment Factor - .byte 0x41 ; CIE RA Column - .byte 0x1 ; uleb128 0x1; Augmentation size - .byte 0x10 ; FDE Encoding (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 Lstartcode-. ; FDE initial location - .set L$set$2,LFE1-Lstartcode - .g_long L$set$2 ; 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 EH_FRAME_OFFSETA,EH_FRAME_OFFSETB ; uleb128 176,1/190,3 - .byte 0x4 ; DW_CFA_advance_loc4 - .set L$set$4,LCFI0-Lstartcode - .long L$set$4 - .byte 0x11 ; DW_CFA_offset_extended_sf - .byte 0x41 ; uleb128 0x41 - .byte 0x7e ; sleb128 -2 - .align LOG2_GPR_BYTES -LEFDE1: - .align 1 - -#ifdef WANT_STUB - .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 - .align 5 -L_ffi_closure_helper_DARWIN$stub: - .indirect_symbol _ffi_closure_helper_DARWIN - mflr r0 - bcl 20,31,"L1$spb" -"L1$spb": - mflr r11 - addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L1$spb") - mtlr r0 - lwzu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L1$spb")(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 - -#if defined(__ppc64__) - .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 - .align 5 -L_darwin64_struct_ret_by_value_p$stub: - .indirect_symbol _darwin64_struct_ret_by_value_p - mflr r0 - bcl 20,31,"L2$spb" -"L2$spb": - mflr r11 - addis r11,r11,ha16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L2$spb") - mtlr r0 - lwzu r12,lo16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L2$spb")(r11) - mtctr r12 - bctr - .lazy_symbol_pointer -L_darwin64_struct_ret_by_value_p$lazy_ptr: - .indirect_symbol _darwin64_struct_ret_by_value_p - .g_long dyld_stub_binding_helper - - .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 - .align 5 -L_darwin64_pass_struct_floats$stub: - .indirect_symbol _darwin64_pass_struct_floats - mflr r0 - bcl 20,31,"L3$spb" -"L3$spb": - mflr r11 - addis r11,r11,ha16(L_darwin64_pass_struct_floats$lazy_ptr-"L3$spb") - mtlr r0 - lwzu r12,lo16(L_darwin64_pass_struct_floats$lazy_ptr-"L3$spb")(r11) - mtctr r12 - bctr - .lazy_symbol_pointer -L_darwin64_pass_struct_floats$lazy_ptr: - .indirect_symbol _darwin64_pass_struct_floats - .g_long dyld_stub_binding_helper -# endif -#endif +/* ----------------------------------------------------------------------- + darwin_closure.S - Copyright (c) 2002, 2003, 2004, 2010, + 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 machine_choice MODE_CHOICE(ppc7400,ppc64) + +; Define some pseudo-opcodes for size-independent load & store of GPRs ... +#define lgu MODE_CHOICE(lwzu, ldu) +#define lg MODE_CHOICE(lwz,ld) +#define sg MODE_CHOICE(stw,std) +#define sgu MODE_CHOICE(stwu,stdu) + +; ... and the size of GPRs and their storage indicator. +#define GPR_BYTES MODE_CHOICE(4,8) +#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ +#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ + +; From the ABI doc: "Mac OS X ABI Function Call Guide" Version 2009-02-04. +#define LINKAGE_SIZE MODE_CHOICE(24,48) +#define PARAM_AREA MODE_CHOICE(32,64) + +#define SAVED_CR_OFFSET MODE_CHOICE(4,8) /* save position for CR */ +#define SAVED_LR_OFFSET MODE_CHOICE(8,16) /* save position for lr */ + +/* WARNING: if ffi_type is changed... here be monsters. + Offsets of items within the result type. */ +#define FFI_TYPE_TYPE MODE_CHOICE(6,10) +#define FFI_TYPE_ELEM MODE_CHOICE(8,16) + +#define SAVED_FPR_COUNT 13 +#define FPR_SIZE 8 +/* biggest m64 struct ret is 8GPRS + 13FPRS = 168 bytes - rounded to 16bytes = 176. */ +#define RESULT_BYTES MODE_CHOICE(16,176) + +; The whole stack frame **MUST** be 16byte-aligned. +#define SAVE_SIZE (((LINKAGE_SIZE+PARAM_AREA+SAVED_FPR_COUNT*FPR_SIZE+RESULT_BYTES)+15) & -16LL) +#define PAD_SIZE (SAVE_SIZE-(LINKAGE_SIZE+PARAM_AREA+SAVED_FPR_COUNT*FPR_SIZE+RESULT_BYTES)) + +#define PARENT_PARM_BASE (SAVE_SIZE+LINKAGE_SIZE) +#define FP_SAVE_BASE (LINKAGE_SIZE+PARAM_AREA) + +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 +; We no longer need the pic symbol stub for Darwin >= 9. +#define BLCLS_HELP _ffi_closure_helper_DARWIN +#define STRUCT_RETVALUE_P _darwin64_struct_ret_by_value_p +#define PASS_STR_FLOATS _darwin64_pass_struct_floats +#undef WANT_STUB +#else +#define BLCLS_HELP L_ffi_closure_helper_DARWIN$stub +#define STRUCT_RETVALUE_P L_darwin64_struct_ret_by_value_p$stub +#define PASS_STR_FLOATS L_darwin64_pass_struct_floats$stub +#define WANT_STUB +#endif + +/* m32/m64 + + The stack layout looks like this: + + | Additional params... | | Higher address + ~ ~ ~ + | Parameters (at least 8*4/8=32/64) | | NUM_GPR_ARG_REGISTERS + |--------------------------------------------| | + | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | + |--------------------------------------------| | + | Reserved 2*4/8 | | + |--------------------------------------------| | + | Space for callee`s LR 4/8 | | + |--------------------------------------------| | + | Saved CR [low word for m64] 4/8 | | + |--------------------------------------------| | + | Current backchain pointer 4/8 |-/ Parent`s frame. + |--------------------------------------------| <+ <<< on entry to + | Result Bytes 16/176 | | + |--------------------------------------------| | + ~ padding to 16-byte alignment ~ ~ + |--------------------------------------------| | + | NUM_FPR_ARG_REGISTERS slots | | + | here fp13 .. fp1 13*8 | | + |--------------------------------------------| | + | R3..R10 8*4/8=32/64 | | NUM_GPR_ARG_REGISTERS + |--------------------------------------------| | + | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | + |--------------------------------------------| | stack | + | Reserved [compiler,binder] 2*4/8 | | grows | + |--------------------------------------------| | down V + | Space for callees LR 4/8 | | + |--------------------------------------------| | lower addresses + | Saved CR [low word for m64] 4/8 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 4/8 |-/ during + |--------------------------------------------| <<< call. + +*/ + + .file "darwin_closure.S" + + .machine machine_choice + + .text + .globl _ffi_closure_ASM + .align LOG2_GPR_BYTES +_ffi_closure_ASM: +LFB1: +Lstartcode: + mflr r0 /* extract return address */ + sg r0,SAVED_LR_OFFSET(r1) /* save the return address */ +LCFI0: + sgu r1,-SAVE_SIZE(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) */ + + /* Put gpr 3 to gpr 10 in the parents outgoing area... + ... the remainder of any params that overflowed the regs will + follow here. */ + sg r3, (PARENT_PARM_BASE )(r1) + sg r4, (PARENT_PARM_BASE + GPR_BYTES )(r1) + sg r5, (PARENT_PARM_BASE + GPR_BYTES * 2)(r1) + sg r6, (PARENT_PARM_BASE + GPR_BYTES * 3)(r1) + sg r7, (PARENT_PARM_BASE + GPR_BYTES * 4)(r1) + sg r8, (PARENT_PARM_BASE + GPR_BYTES * 5)(r1) + sg r9, (PARENT_PARM_BASE + GPR_BYTES * 6)(r1) + sg r10,(PARENT_PARM_BASE + GPR_BYTES * 7)(r1) + + /* We save fpr 1 to fpr 14 in our own save frame. */ + stfd f1, (FP_SAVE_BASE )(r1) + stfd f2, (FP_SAVE_BASE + FPR_SIZE )(r1) + stfd f3, (FP_SAVE_BASE + FPR_SIZE * 2 )(r1) + stfd f4, (FP_SAVE_BASE + FPR_SIZE * 3 )(r1) + stfd f5, (FP_SAVE_BASE + FPR_SIZE * 4 )(r1) + stfd f6, (FP_SAVE_BASE + FPR_SIZE * 5 )(r1) + stfd f7, (FP_SAVE_BASE + FPR_SIZE * 6 )(r1) + stfd f8, (FP_SAVE_BASE + FPR_SIZE * 7 )(r1) + stfd f9, (FP_SAVE_BASE + FPR_SIZE * 8 )(r1) + stfd f10,(FP_SAVE_BASE + FPR_SIZE * 9 )(r1) + stfd f11,(FP_SAVE_BASE + FPR_SIZE * 10)(r1) + stfd f12,(FP_SAVE_BASE + FPR_SIZE * 11)(r1) + stfd f13,(FP_SAVE_BASE + FPR_SIZE * 12)(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,(SAVE_SIZE-RESULT_BYTES) + + /* Now load up the pointer to the saved gpr registers. */ + addi r5,r1,PARENT_PARM_BASE + + /* Now load up the pointer to the saved fpr registers. */ + addi r6,r1,FP_SAVE_BASE + + /* Make the call. */ + bl BLCLS_HELP + + /* r3 contains the rtype pointer... save it since we will need + it later. */ + sg r3,LINKAGE_SIZE(r1) ; ffi_type * result_type + lg r0,0(r3) ; size => r0 + lhz r3,FFI_TYPE_TYPE(r3) ; type => r3 + + /* The helper will have intercepted structure returns and inserted + the caller`s destination address for structs returned by ref. */ + + /* r3 contains the return type so use it to look up in a table + so we know how to deal with each type. */ + + addi r5,r1,(SAVE_SIZE-RESULT_BYTES) /* Otherwise, our return is here. */ + 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: + lg 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: +#if defined(__ppc64__) + lbz r3,7(r5) +#else + lbz r3,3(r5) +#endif + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT8 */ +Lret_type6: +#if defined(__ppc64__) + lbz r3,7(r5) +#else + lbz r3,3(r5) +#endif + extsb r3,r3 + b Lfinish + nop + +/* case FFI_TYPE_UINT16 */ +Lret_type7: +#if defined(__ppc64__) + lhz r3,6(r5) +#else + lhz r3,2(r5) +#endif + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT16 */ +Lret_type8: +#if defined(__ppc64__) + lha r3,6(r5) +#else + lha r3,2(r5) +#endif + b Lfinish + nop + nop + +/* case FFI_TYPE_UINT32 */ +Lret_type9: +#if defined(__ppc64__) + lwz r3,4(r5) +#else + lwz r3,0(r5) +#endif + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT32 */ +Lret_type10: +#if defined(__ppc64__) + lwz r3,4(r5) +#else + lwz r3,0(r5) +#endif + b Lfinish + nop + nop + +/* case FFI_TYPE_UINT64 */ +Lret_type11: +#if defined(__ppc64__) + lg r3,0(r5) + b Lfinish + nop +#else + lwz r3,0(r5) + lwz r4,4(r5) + b Lfinish +#endif + nop + +/* case FFI_TYPE_SINT64 */ +Lret_type12: +#if defined(__ppc64__) + lg r3,0(r5) + b Lfinish + nop +#else + lwz r3,0(r5) + lwz r4,4(r5) + b Lfinish +#endif + nop + +/* case FFI_TYPE_STRUCT */ +Lret_type13: +#if defined(__ppc64__) + lg r3,0(r5) ; we need at least this... + cmpi 0,r0,4 + bgt Lstructend ; not a special small case + b Lsmallstruct ; see if we need more. +#else + cmpwi 0,r0,4 + bgt Lfinish ; not by value + lg r3,0(r5) + b Lfinish +#endif +/* case FFI_TYPE_POINTER */ +Lret_type14: + lg r3,0(r5) + b Lfinish + nop + nop + +#if defined(__ppc64__) +Lsmallstruct: + beq Lfour ; continuation of Lret13. + cmpi 0,r0,3 + beq Lfinish ; don`t adjust this - can`t be any floats here... + srdi r3,r3,48 + cmpi 0,r0,2 + beq Lfinish ; .. or here .. + srdi r3,r3,8 + b Lfinish ; .. or here. + +Lfour: + lg r6,LINKAGE_SIZE(r1) ; get the result type + lg r6,FFI_TYPE_ELEM(r6) ; elements array pointer + lg r6,0(r6) ; first element + lhz r0,FFI_TYPE_TYPE(r6) ; OK go the type + cmpi 0,r0,2 ; FFI_TYPE_FLOAT + bne Lfourint + lfs f1,0(r5) ; just one float in the struct. + b Lfinish + +Lfourint: + srdi r3,r3,32 ; four bytes. + b Lfinish + +Lstructend: + lg r3,LINKAGE_SIZE(r1) ; get the result type + bl STRUCT_RETVALUE_P + cmpi 0,r3,0 + beq Lfinish ; nope. + /* Recover a pointer to the results. */ + addi r11,r1,(SAVE_SIZE-RESULT_BYTES) + lg r3,0(r11) ; we need at least this... + lg r4,8(r11) + cmpi 0,r0,16 + beq Lfinish ; special case 16 bytes we don't consider floats. + + /* OK, frustratingly, the process of saving the struct to mem might have + messed with the FPRs, so we have to re-load them :(. + We`ll use our FPRs space again - calling: + void darwin64_pass_struct_floats (ffi_type *s, char *src, + unsigned *nfpr, double **fprs) + We`ll temporarily pinch the first two slots of the param area for local + vars used by the routine. */ + xor r6,r6,r6 + addi r5,r1,PARENT_PARM_BASE ; some space + sg r6,0(r5) ; *nfpr zeroed. + addi r6,r5,8 ; **fprs + addi r3,r1,FP_SAVE_BASE ; pointer to FPRs space + sg r3,0(r6) + mr r4,r11 ; the struct is here... + lg r3,LINKAGE_SIZE(r1) ; ffi_type * result_type. + bl PASS_STR_FLOATS ; get struct floats into FPR save space. + /* See if we used any floats */ + lwz r0,(SAVE_SIZE-RESULT_BYTES)(r1) + cmpi 0,r0,0 + beq Lstructints ; nope. + /* OK load `em up... */ + lfd f1, (FP_SAVE_BASE )(r1) + lfd f2, (FP_SAVE_BASE + FPR_SIZE )(r1) + lfd f3, (FP_SAVE_BASE + FPR_SIZE * 2 )(r1) + lfd f4, (FP_SAVE_BASE + FPR_SIZE * 3 )(r1) + lfd f5, (FP_SAVE_BASE + FPR_SIZE * 4 )(r1) + lfd f6, (FP_SAVE_BASE + FPR_SIZE * 5 )(r1) + lfd f7, (FP_SAVE_BASE + FPR_SIZE * 6 )(r1) + lfd f8, (FP_SAVE_BASE + FPR_SIZE * 7 )(r1) + lfd f9, (FP_SAVE_BASE + FPR_SIZE * 8 )(r1) + lfd f10,(FP_SAVE_BASE + FPR_SIZE * 9 )(r1) + lfd f11,(FP_SAVE_BASE + FPR_SIZE * 10)(r1) + lfd f12,(FP_SAVE_BASE + FPR_SIZE * 11)(r1) + lfd f13,(FP_SAVE_BASE + FPR_SIZE * 12)(r1) + + /* point back at our saved struct. */ +Lstructints: + addi r11,r1,(SAVE_SIZE-RESULT_BYTES) + lg r3,0(r11) ; we end up picking the + lg r4,8(r11) ; first two again. + lg r5,16(r11) + lg r6,24(r11) + lg r7,32(r11) + lg r8,40(r11) + lg r9,48(r11) + lg r10,56(r11) +#endif + +/* case done */ +Lfinish: + addi r1,r1,SAVE_SIZE /* Restore stack pointer. */ + lg r0,SAVED_LR_OFFSET(r1) /* Get return address. */ + mtlr r0 /* Reset link register. */ + blr +Lendcode: + .align 1 + +/* END(ffi_closure_ASM) */ + +/* EH frame stuff. */ +#define EH_DATA_ALIGN_FACT MODE_CHOICE(0x7c,0x78) +/* 176, 400 */ +#define EH_FRAME_OFFSETA MODE_CHOICE(176,0x90) +#define EH_FRAME_OFFSETB MODE_CHOICE(1,3) + + .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 EH_DATA_ALIGN_FACT ; sleb128 -4; CIE Data Alignment Factor + .byte 0x41 ; CIE RA Column + .byte 0x1 ; uleb128 0x1; Augmentation size + .byte 0x10 ; FDE Encoding (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 Lstartcode-. ; FDE initial location + .set L$set$2,LFE1-Lstartcode + .g_long L$set$2 ; 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 EH_FRAME_OFFSETA,EH_FRAME_OFFSETB ; uleb128 176,1/190,3 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$4,LCFI0-Lstartcode + .long L$set$4 + .byte 0x11 ; DW_CFA_offset_extended_sf + .byte 0x41 ; uleb128 0x41 + .byte 0x7e ; sleb128 -2 + .align LOG2_GPR_BYTES +LEFDE1: + .align 1 + +#ifdef WANT_STUB + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 5 +L_ffi_closure_helper_DARWIN$stub: + .indirect_symbol _ffi_closure_helper_DARWIN + mflr r0 + bcl 20,31,"L1$spb" +"L1$spb": + mflr r11 + addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L1$spb") + mtlr r0 + lwzu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr-"L1$spb")(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 + +#if defined(__ppc64__) + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 5 +L_darwin64_struct_ret_by_value_p$stub: + .indirect_symbol _darwin64_struct_ret_by_value_p + mflr r0 + bcl 20,31,"L2$spb" +"L2$spb": + mflr r11 + addis r11,r11,ha16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L2$spb") + mtlr r0 + lwzu r12,lo16(L_darwin64_struct_ret_by_value_p$lazy_ptr-"L2$spb")(r11) + mtctr r12 + bctr + .lazy_symbol_pointer +L_darwin64_struct_ret_by_value_p$lazy_ptr: + .indirect_symbol _darwin64_struct_ret_by_value_p + .g_long dyld_stub_binding_helper + + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 5 +L_darwin64_pass_struct_floats$stub: + .indirect_symbol _darwin64_pass_struct_floats + mflr r0 + bcl 20,31,"L3$spb" +"L3$spb": + mflr r11 + addis r11,r11,ha16(L_darwin64_pass_struct_floats$lazy_ptr-"L3$spb") + mtlr r0 + lwzu r12,lo16(L_darwin64_pass_struct_floats$lazy_ptr-"L3$spb")(r11) + mtctr r12 + bctr + .lazy_symbol_pointer +L_darwin64_pass_struct_floats$lazy_ptr: + .indirect_symbol _darwin64_pass_struct_floats + .g_long dyld_stub_binding_helper +# endif +#endif diff --git a/contrib/restricted/libffi/src/powerpc/ffi.c b/contrib/restricted/libffi/src/powerpc/ffi.c index a19bcbbfc5..5d618cc0dd 100644 --- a/contrib/restricted/libffi/src/powerpc/ffi.c +++ b/contrib/restricted/libffi/src/powerpc/ffi.c @@ -1,175 +1,175 @@ -/* ----------------------------------------------------------------------- - ffi.c - Copyright (C) 2013 IBM - Copyright (C) 2011 Anthony Green - Copyright (C) 2011 Kyle Moffett - Copyright (C) 2008 Red Hat, Inc - Copyright (C) 2007, 2008 Free Software Foundation, Inc - Copyright (c) 1998 Geoffrey Keating - - 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 "ffi_powerpc.h" - -#if HAVE_LONG_DOUBLE_VARIANT -/* Adjust ffi_type_longdouble. */ -void FFI_HIDDEN -ffi_prep_types (ffi_abi abi) -{ -# if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE -# ifdef POWERPC64 - ffi_prep_types_linux64 (abi); -# else - ffi_prep_types_sysv (abi); -# endif -# endif -} -#endif - -/* Perform machine dependent cif processing */ -ffi_status FFI_HIDDEN -ffi_prep_cif_machdep (ffi_cif *cif) -{ -#ifdef POWERPC64 - return ffi_prep_cif_linux64 (cif); -#else - return ffi_prep_cif_sysv (cif); -#endif -} - -ffi_status FFI_HIDDEN -ffi_prep_cif_machdep_var (ffi_cif *cif, - unsigned int nfixedargs MAYBE_UNUSED, - unsigned int ntotalargs MAYBE_UNUSED) -{ -#ifdef POWERPC64 - return ffi_prep_cif_linux64_var (cif, nfixedargs, ntotalargs); -#else - return ffi_prep_cif_sysv (cif); -#endif -} - -static void -ffi_call_int (ffi_cif *cif, - void (*fn) (void), - void *rvalue, - void **avalue, - void *closure) -{ - /* The final SYSV ABI says that structures smaller or equal 8 bytes - are returned in r3/r4. A draft ABI used by linux instead returns - them in memory. - - We bounce-buffer SYSV small struct return values so that sysv.S - can write r3 and r4 to memory without worrying about struct size. - - For ELFv2 ABI, use a bounce buffer for homogeneous structs too, - for similar reasons. This bounce buffer must be aligned to 16 - bytes for use with homogeneous structs of vectors (float128). */ - float128 smst_buffer[8]; - extended_cif ecif; - - ecif.cif = cif; - ecif.avalue = avalue; - - ecif.rvalue = rvalue; - if ((cif->flags & FLAG_RETURNS_SMST) != 0) - ecif.rvalue = smst_buffer; - /* Ensure that we have a valid struct return value. - FIXME: Isn't this just papering over a user problem? */ - else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT) - ecif.rvalue = alloca (cif->rtype->size); - -#ifdef POWERPC64 - ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure, - -(long) cif->bytes); -#else - ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes); -#endif - - /* Check for a bounce-buffered return value */ - if (rvalue && ecif.rvalue == smst_buffer) - { - unsigned int rsize = cif->rtype->size; -#ifndef __LITTLE_ENDIAN__ - /* The SYSV ABI returns a structure of up to 4 bytes in size - left-padded in r3. */ -# ifndef POWERPC64 - if (rsize <= 4) - memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize); - else -# endif - /* The SYSV ABI returns a structure of up to 8 bytes in size - left-padded in r3/r4, and the ELFv2 ABI similarly returns a - structure of up to 8 bytes in size left-padded in r3. But - note that a structure of a single float is not paddded. */ - if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0) - memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize); - else -#endif - memcpy (rvalue, smst_buffer, rsize); - } -} - -void -ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) -{ - ffi_call_int (cif, fn, rvalue, avalue, NULL); -} - -void -ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, - void *closure) -{ - ffi_call_int (cif, fn, rvalue, avalue, closure); -} - -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 - return ffi_prep_closure_loc_linux64 (closure, cif, fun, user_data, codeloc); -#else - return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc); -#endif -} - -ffi_status -ffi_prep_go_closure (ffi_go_closure *closure, - ffi_cif *cif, - void (*fun) (ffi_cif *, void *, void **, void *)) -{ -#ifdef POWERPC64 - closure->tramp = ffi_go_closure_linux64; -#else - closure->tramp = ffi_go_closure_sysv; -#endif - closure->cif = cif; - closure->fun = fun; - return FFI_OK; -} +/* ----------------------------------------------------------------------- + ffi.c - Copyright (C) 2013 IBM + Copyright (C) 2011 Anthony Green + Copyright (C) 2011 Kyle Moffett + Copyright (C) 2008 Red Hat, Inc + Copyright (C) 2007, 2008 Free Software Foundation, Inc + Copyright (c) 1998 Geoffrey Keating + + 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 "ffi_powerpc.h" + +#if HAVE_LONG_DOUBLE_VARIANT +/* Adjust ffi_type_longdouble. */ +void FFI_HIDDEN +ffi_prep_types (ffi_abi abi) +{ +# if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +# ifdef POWERPC64 + ffi_prep_types_linux64 (abi); +# else + ffi_prep_types_sysv (abi); +# endif +# endif +} +#endif + +/* Perform machine dependent cif processing */ +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep (ffi_cif *cif) +{ +#ifdef POWERPC64 + return ffi_prep_cif_linux64 (cif); +#else + return ffi_prep_cif_sysv (cif); +#endif +} + +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep_var (ffi_cif *cif, + unsigned int nfixedargs MAYBE_UNUSED, + unsigned int ntotalargs MAYBE_UNUSED) +{ +#ifdef POWERPC64 + return ffi_prep_cif_linux64_var (cif, nfixedargs, ntotalargs); +#else + return ffi_prep_cif_sysv (cif); +#endif +} + +static void +ffi_call_int (ffi_cif *cif, + void (*fn) (void), + void *rvalue, + void **avalue, + void *closure) +{ + /* The final SYSV ABI says that structures smaller or equal 8 bytes + are returned in r3/r4. A draft ABI used by linux instead returns + them in memory. + + We bounce-buffer SYSV small struct return values so that sysv.S + can write r3 and r4 to memory without worrying about struct size. + + For ELFv2 ABI, use a bounce buffer for homogeneous structs too, + for similar reasons. This bounce buffer must be aligned to 16 + bytes for use with homogeneous structs of vectors (float128). */ + float128 smst_buffer[8]; + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + ecif.rvalue = rvalue; + if ((cif->flags & FLAG_RETURNS_SMST) != 0) + ecif.rvalue = smst_buffer; + /* Ensure that we have a valid struct return value. + FIXME: Isn't this just papering over a user problem? */ + else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT) + ecif.rvalue = alloca (cif->rtype->size); + +#ifdef POWERPC64 + ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure, + -(long) cif->bytes); +#else + ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes); +#endif + + /* Check for a bounce-buffered return value */ + if (rvalue && ecif.rvalue == smst_buffer) + { + unsigned int rsize = cif->rtype->size; +#ifndef __LITTLE_ENDIAN__ + /* The SYSV ABI returns a structure of up to 4 bytes in size + left-padded in r3. */ +# ifndef POWERPC64 + if (rsize <= 4) + memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize); + else +# endif + /* The SYSV ABI returns a structure of up to 8 bytes in size + left-padded in r3/r4, and the ELFv2 ABI similarly returns a + structure of up to 8 bytes in size left-padded in r3. But + note that a structure of a single float is not paddded. */ + if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0) + memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize); + else +#endif + memcpy (rvalue, smst_buffer, rsize); + } +} + +void +ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) +{ + ffi_call_int (cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, + void *closure) +{ + ffi_call_int (cif, fn, rvalue, avalue, closure); +} + +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 + return ffi_prep_closure_loc_linux64 (closure, cif, fun, user_data, codeloc); +#else + return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc); +#endif +} + +ffi_status +ffi_prep_go_closure (ffi_go_closure *closure, + ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *)) +{ +#ifdef POWERPC64 + closure->tramp = ffi_go_closure_linux64; +#else + closure->tramp = ffi_go_closure_sysv; +#endif + closure->cif = cif; + closure->fun = fun; + return FFI_OK; +} diff --git a/contrib/restricted/libffi/src/powerpc/ffi_darwin.c b/contrib/restricted/libffi/src/powerpc/ffi_darwin.c index 61a18c4911..f9f587a2eb 100644 --- a/contrib/restricted/libffi/src/powerpc/ffi_darwin.c +++ b/contrib/restricted/libffi/src/powerpc/ffi_darwin.c @@ -1,1440 +1,1440 @@ -/* ----------------------------------------------------------------------- - ffi_darwin.c - - Copyright (C) 1998 Geoffrey Keating - Copyright (C) 2001 John Hornkvist - Copyright (C) 2002, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. - - FFI support for Darwin and AIX. +/* ----------------------------------------------------------------------- + ffi_darwin.c + + Copyright (C) 1998 Geoffrey Keating + Copyright (C) 2001 John Hornkvist + Copyright (C) 2002, 2006, 2007, 2009, 2010 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); +extern void ffi_go_closure_ASM (void); + +enum { + /* The assembly depends on these exact flags. + For Darwin64 (when FLAG_RETURNS_STRUCT is set): + FLAG_RETURNS_FP indicates that the structure embeds FP data. + FLAG_RETURNS_128BITS signals a special struct size that is not + expanded for float content. */ + FLAG_RETURNS_128BITS = 1 << (31-31), /* These go in cr7 */ + FLAG_RETURNS_NOTHING = 1 << (31-30), + FLAG_RETURNS_FP = 1 << (31-29), + FLAG_RETURNS_64BITS = 1 << (31-28), + + FLAG_RETURNS_STRUCT = 1 << (31-27), /* This goes in 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 DARWIN ABI. */ +enum { + NUM_GPR_ARG_REGISTERS = 8, + NUM_FPR_ARG_REGISTERS = 13, + LINKAGE_AREA_GPRS = 6 +}; + +enum { ASM_NEEDS_REGISTERS = 4 }; /* r28-r31 */ + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments. + + m32/m64 + + The stack layout we want looks like this: + + | Return address from ffi_call_DARWIN | higher addresses + |--------------------------------------------| + | Previous backchain pointer 4/8 | stack pointer here + |--------------------------------------------|<+ <<< on entry to + | ASM_NEEDS_REGISTERS=r28-r31 4*(4/8) | | ffi_call_DARWIN + |--------------------------------------------| | + | When we have any FP activity... the | | + | FPRs occupy NUM_FPR_ARG_REGISTERS slots | | + | here fp13 .. fp1 from high to low addr. | | + ~ ~ ~ + | Parameters (at least 8*4/8=32/64) | | NUM_GPR_ARG_REGISTERS + |--------------------------------------------| | + | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | + |--------------------------------------------| | stack | + | Reserved 2*4/8 | | grows | + |--------------------------------------------| | down V + | Space for callee's LR 4/8 | | + |--------------------------------------------| | lower addresses + | Saved CR [low word for m64] 4/8 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 4/8 |-/ during + |--------------------------------------------| <<< ffi_call_DARWIN + + */ + +#if defined(POWERPC_DARWIN64) +static void +darwin64_pass_struct_by_value + (ffi_type *, char *, unsigned, unsigned *, double **, unsigned long **); +#endif + +/* This depends on GPR_SIZE = sizeof (unsigned long) */ + +void +ffi_prep_args (extended_cif *ecif, unsigned long *const stack) +{ + const unsigned bytes = ecif->cif->bytes; + const unsigned flags = ecif->cif->flags; + const unsigned nargs = ecif->cif->nargs; +#if !defined(POWERPC_DARWIN64) + const ffi_abi abi = ecif->cif->abi; +#endif + + /* 'stacktop' points at the previous backchain pointer. */ + unsigned long *const stacktop = stack + (bytes / sizeof(unsigned long)); + + /* '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 gp_count = 0, fparg_count = 0; + + /* 'next_arg' grows up as we put parameters in it. */ + unsigned long *next_arg = stack + LINKAGE_AREA_GPRS; /* 6 reserved positions. */ + + int i; + double double_tmp; + void **p_argv = ecif->avalue; + unsigned long gprvalue; + ffi_type** ptr = ecif->cif->arg_types; +#if !defined(POWERPC_DARWIN64) + char *dest_cpy; +#endif + 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 long) (char *) ecif->rvalue; + + /* Now for the arguments. */ + for (i = nargs; 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) + *fpr_base++ = double_tmp; +#if defined(POWERPC_DARWIN) + *(float *)next_arg = *(float *) *p_argv; +#else + *(double *)next_arg = double_tmp; +#endif + next_arg++; + gp_count++; + 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) + *fpr_base++ = double_tmp; + *(double *)next_arg = double_tmp; +#ifdef POWERPC64 + next_arg++; + gp_count++; +#else + next_arg += 2; + gp_count += 2; +#endif + fparg_count++; + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_LONGDOUBLE: +# if defined(POWERPC64) && !defined(POWERPC_DARWIN64) + /* ??? This will exceed the regs count when the value starts at fp13 + and it will not put the extra bit on the stack. */ + if (fparg_count < NUM_FPR_ARG_REGISTERS) + *(long double *) fpr_base++ = *(long double *) *p_argv; + else + *(long double *) next_arg = *(long double *) *p_argv; + next_arg += 2; + fparg_count += 2; +# else + double_tmp = ((double *) *p_argv)[0]; + if (fparg_count < NUM_FPR_ARG_REGISTERS) + *fpr_base++ = double_tmp; + *(double *) next_arg = double_tmp; +# if defined(POWERPC_DARWIN64) + next_arg++; + gp_count++; +# else + next_arg += 2; + gp_count += 2; +# endif + fparg_count++; + double_tmp = ((double *) *p_argv)[1]; + if (fparg_count < NUM_FPR_ARG_REGISTERS) + *fpr_base++ = double_tmp; + *(double *) next_arg = double_tmp; +# if defined(POWERPC_DARWIN64) + next_arg++; + gp_count++; +# else + next_arg += 2; + gp_count += 2; +# endif + fparg_count++; +# endif + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + break; +#endif + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef POWERPC64 + gprvalue = *(long long *) *p_argv; + goto putgpr; +#else + *(long long *) next_arg = *(long long *) *p_argv; + next_arg += 2; + gp_count += 2; +#endif + break; + case FFI_TYPE_POINTER: + gprvalue = *(unsigned long *) *p_argv; + goto putgpr; + case FFI_TYPE_UINT8: + gprvalue = *(unsigned char *) *p_argv; + goto putgpr; + case FFI_TYPE_SINT8: + gprvalue = *(signed char *) *p_argv; + goto putgpr; + case FFI_TYPE_UINT16: + gprvalue = *(unsigned short *) *p_argv; + goto putgpr; + case FFI_TYPE_SINT16: + gprvalue = *(signed short *) *p_argv; + goto putgpr; + + case FFI_TYPE_STRUCT: + size_al = (*ptr)->size; +#if defined(POWERPC_DARWIN64) + next_arg = (unsigned long *)FFI_ALIGN((char *)next_arg, (*ptr)->alignment); + darwin64_pass_struct_by_value (*ptr, (char *) *p_argv, + (unsigned) size_al, + (unsigned int *) &fparg_count, + &fpr_base, &next_arg); +#else + dest_cpy = (char *) next_arg; + + /* If the first member of the struct is a double, then include enough + padding in the struct size to align it to double-word. */ + if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = FFI_ALIGN((*ptr)->size, 8); + +# if defined(POWERPC64) + FFI_ASSERT (abi != FFI_DARWIN); + memcpy ((char *) dest_cpy, (char *) *p_argv, size_al); + next_arg += (size_al + 7) / 8; +# else + /* 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. */ + if (size_al < 3 && abi == FFI_DARWIN) + dest_cpy += 4 - size_al; + + memcpy((char *) dest_cpy, (char *) *p_argv, size_al); + next_arg += (size_al + 3) / 4; +# endif +#endif + break; + + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + gprvalue = *(signed int *) *p_argv; + goto putgpr; + + case FFI_TYPE_UINT32: + gprvalue = *(unsigned int *) *p_argv; + putgpr: + *next_arg++ = gprvalue; + gp_count++; + 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); */ +} + +#if defined(POWERPC_DARWIN64) + +/* See if we can put some of the struct into fprs. + This should not be called for structures of size 16 bytes, since these are not + broken out this way. */ +static void +darwin64_scan_struct_for_floats (ffi_type *s, unsigned *nfpr) +{ + int i; + + FFI_ASSERT (s->type == FFI_TYPE_STRUCT) + + for (i = 0; s->elements[i] != NULL; i++) + { + ffi_type *p = s->elements[i]; + switch (p->type) + { + case FFI_TYPE_STRUCT: + darwin64_scan_struct_for_floats (p, nfpr); + break; + case FFI_TYPE_LONGDOUBLE: + (*nfpr) += 2; + break; + case FFI_TYPE_DOUBLE: + case FFI_TYPE_FLOAT: + (*nfpr) += 1; + break; + default: + break; + } + } +} + +static int +darwin64_struct_size_exceeds_gprs_p (ffi_type *s, char *src, unsigned *nfpr) +{ + unsigned struct_offset=0, i; + + for (i = 0; s->elements[i] != NULL; i++) + { + char *item_base; + ffi_type *p = s->elements[i]; + /* Find the start of this item (0 for the first one). */ + if (i > 0) + struct_offset = FFI_ALIGN(struct_offset, p->alignment); + + item_base = src + struct_offset; + + switch (p->type) + { + case FFI_TYPE_STRUCT: + if (darwin64_struct_size_exceeds_gprs_p (p, item_base, nfpr)) + return 1; + break; + case FFI_TYPE_LONGDOUBLE: + if (*nfpr >= NUM_FPR_ARG_REGISTERS) + return 1; + (*nfpr) += 1; + item_base += 8; + /* FALL THROUGH */ + case FFI_TYPE_DOUBLE: + if (*nfpr >= NUM_FPR_ARG_REGISTERS) + return 1; + (*nfpr) += 1; + break; + case FFI_TYPE_FLOAT: + if (*nfpr >= NUM_FPR_ARG_REGISTERS) + return 1; + (*nfpr) += 1; + break; + default: + /* If we try and place any item, that is non-float, once we've + exceeded the 8 GPR mark, then we can't fit the struct. */ + if ((unsigned long)item_base >= 8*8) + return 1; + break; + } + /* now count the size of what we just used. */ + struct_offset += p->size; + } + return 0; +} + +/* Can this struct be returned by value? */ +int +darwin64_struct_ret_by_value_p (ffi_type *s) +{ + unsigned nfp = 0; + + FFI_ASSERT (s && s->type == FFI_TYPE_STRUCT); - 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); -extern void ffi_go_closure_ASM (void); - -enum { - /* The assembly depends on these exact flags. - For Darwin64 (when FLAG_RETURNS_STRUCT is set): - FLAG_RETURNS_FP indicates that the structure embeds FP data. - FLAG_RETURNS_128BITS signals a special struct size that is not - expanded for float content. */ - FLAG_RETURNS_128BITS = 1 << (31-31), /* These go in cr7 */ - FLAG_RETURNS_NOTHING = 1 << (31-30), - FLAG_RETURNS_FP = 1 << (31-29), - FLAG_RETURNS_64BITS = 1 << (31-28), - - FLAG_RETURNS_STRUCT = 1 << (31-27), /* This goes in 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 DARWIN ABI. */ -enum { - NUM_GPR_ARG_REGISTERS = 8, - NUM_FPR_ARG_REGISTERS = 13, - LINKAGE_AREA_GPRS = 6 -}; - -enum { ASM_NEEDS_REGISTERS = 4 }; /* r28-r31 */ - -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments. + /* The largest structure we can return is 8long + 13 doubles. */ + if (s->size > 168) + return 0; - m32/m64 - - The stack layout we want looks like this: - - | Return address from ffi_call_DARWIN | higher addresses - |--------------------------------------------| - | Previous backchain pointer 4/8 | stack pointer here - |--------------------------------------------|<+ <<< on entry to - | ASM_NEEDS_REGISTERS=r28-r31 4*(4/8) | | ffi_call_DARWIN - |--------------------------------------------| | - | When we have any FP activity... the | | - | FPRs occupy NUM_FPR_ARG_REGISTERS slots | | - | here fp13 .. fp1 from high to low addr. | | - ~ ~ ~ - | Parameters (at least 8*4/8=32/64) | | NUM_GPR_ARG_REGISTERS - |--------------------------------------------| | - | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | - |--------------------------------------------| | stack | - | Reserved 2*4/8 | | grows | - |--------------------------------------------| | down V - | Space for callee's LR 4/8 | | - |--------------------------------------------| | lower addresses - | Saved CR [low word for m64] 4/8 | | - |--------------------------------------------| | stack pointer here - | Current backchain pointer 4/8 |-/ during - |--------------------------------------------| <<< ffi_call_DARWIN - - */ - -#if defined(POWERPC_DARWIN64) -static void -darwin64_pass_struct_by_value - (ffi_type *, char *, unsigned, unsigned *, double **, unsigned long **); -#endif - -/* This depends on GPR_SIZE = sizeof (unsigned long) */ - -void -ffi_prep_args (extended_cif *ecif, unsigned long *const stack) -{ - const unsigned bytes = ecif->cif->bytes; - const unsigned flags = ecif->cif->flags; - const unsigned nargs = ecif->cif->nargs; -#if !defined(POWERPC_DARWIN64) - const ffi_abi abi = ecif->cif->abi; -#endif - - /* 'stacktop' points at the previous backchain pointer. */ - unsigned long *const stacktop = stack + (bytes / sizeof(unsigned long)); - - /* '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 gp_count = 0, fparg_count = 0; - - /* 'next_arg' grows up as we put parameters in it. */ - unsigned long *next_arg = stack + LINKAGE_AREA_GPRS; /* 6 reserved positions. */ - - int i; - double double_tmp; - void **p_argv = ecif->avalue; - unsigned long gprvalue; - ffi_type** ptr = ecif->cif->arg_types; + /* We can't pass more than 13 floats. */ + darwin64_scan_struct_for_floats (s, &nfp); + if (nfp > 13) + return 0; + + /* If there are not too many floats, and the struct is + small enough to accommodate in the GPRs, then it must be OK. */ + if (s->size <= 64) + return 1; + + /* Well, we have to look harder. */ + nfp = 0; + if (darwin64_struct_size_exceeds_gprs_p (s, NULL, &nfp)) + return 0; + + return 1; +} + +void +darwin64_pass_struct_floats (ffi_type *s, char *src, + unsigned *nfpr, double **fprs) +{ + int i; + double *fpr_base = *fprs; + unsigned struct_offset = 0; + + /* We don't assume anything about the alignment of the source. */ + for (i = 0; s->elements[i] != NULL; i++) + { + char *item_base; + ffi_type *p = s->elements[i]; + /* Find the start of this item (0 for the first one). */ + if (i > 0) + struct_offset = FFI_ALIGN(struct_offset, p->alignment); + item_base = src + struct_offset; + + switch (p->type) + { + case FFI_TYPE_STRUCT: + darwin64_pass_struct_floats (p, item_base, nfpr, + &fpr_base); + break; + case FFI_TYPE_LONGDOUBLE: + if (*nfpr < NUM_FPR_ARG_REGISTERS) + *fpr_base++ = *(double *)item_base; + (*nfpr) += 1; + item_base += 8; + /* FALL THROUGH */ + case FFI_TYPE_DOUBLE: + if (*nfpr < NUM_FPR_ARG_REGISTERS) + *fpr_base++ = *(double *)item_base; + (*nfpr) += 1; + break; + case FFI_TYPE_FLOAT: + if (*nfpr < NUM_FPR_ARG_REGISTERS) + *fpr_base++ = (double) *(float *)item_base; + (*nfpr) += 1; + break; + default: + break; + } + /* now count the size of what we just used. */ + struct_offset += p->size; + } + /* Update the scores. */ + *fprs = fpr_base; +} + +/* Darwin64 special rules. + Break out a struct into params and float registers. */ +static void +darwin64_pass_struct_by_value (ffi_type *s, char *src, unsigned size, + unsigned *nfpr, double **fprs, unsigned long **arg) +{ + unsigned long *next_arg = *arg; + char *dest_cpy = (char *)next_arg; + + FFI_ASSERT (s->type == FFI_TYPE_STRUCT) + + if (!size) + return; + + /* First... special cases. */ + if (size < 3 + || (size == 4 + && s->elements[0] + && s->elements[0]->type != FFI_TYPE_FLOAT)) + { + /* Must be at least one GPR, padding is unspecified in value, + let's make it zero. */ + *next_arg = 0UL; + dest_cpy += 8 - size; + memcpy ((char *) dest_cpy, src, size); + next_arg++; + } + else if (size == 16) + { + memcpy ((char *) dest_cpy, src, size); + next_arg += 2; + } + else + { + /* now the general case, we consider embedded floats. */ + memcpy ((char *) dest_cpy, src, size); + darwin64_pass_struct_floats (s, src, nfpr, fprs); + next_arg += (size+7)/8; + } + + *arg = next_arg; +} + +double * +darwin64_struct_floats_to_mem (ffi_type *s, char *dest, double *fprs, unsigned *nf) +{ + int i; + unsigned struct_offset = 0; + + /* We don't assume anything about the alignment of the source. */ + for (i = 0; s->elements[i] != NULL; i++) + { + char *item_base; + ffi_type *p = s->elements[i]; + /* Find the start of this item (0 for the first one). */ + if (i > 0) + struct_offset = FFI_ALIGN(struct_offset, p->alignment); + item_base = dest + struct_offset; + + switch (p->type) + { + case FFI_TYPE_STRUCT: + fprs = darwin64_struct_floats_to_mem (p, item_base, fprs, nf); + break; + case FFI_TYPE_LONGDOUBLE: + if (*nf < NUM_FPR_ARG_REGISTERS) + { + *(double *)item_base = *fprs++ ; + (*nf) += 1; + } + item_base += 8; + /* FALL THROUGH */ + case FFI_TYPE_DOUBLE: + if (*nf < NUM_FPR_ARG_REGISTERS) + { + *(double *)item_base = *fprs++ ; + (*nf) += 1; + } + break; + case FFI_TYPE_FLOAT: + if (*nf < NUM_FPR_ARG_REGISTERS) + { + *(float *)item_base = (float) *fprs++ ; + (*nf) += 1; + } + break; + default: + break; + } + /* now count the size of what we just used. */ + struct_offset += p->size; + } + return fprs; +} + +#endif + +/* Adjust the size of S to be correct for Darwin. + On Darwin m32, the first field of a structure has natural alignment. + On Darwin m64, all fields have 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]; + if (p->type == FFI_TYPE_STRUCT) + darwin_adjust_aggregate_sizes (p); +#if defined(POWERPC_DARWIN64) + /* Natural alignment for all items. */ + align = p->alignment; +#else + /* Natural alignment for the first item... */ + if (i == 0) + align = p->alignment; + else if (p->alignment == 16 || p->alignment < 4) + /* .. subsequent items with vector or align < 4 have natural align. */ + align = p->alignment; + else + /* .. or align is 4. */ + align = 4; +#endif + /* Pad, if necessary, before adding the current item. */ + s->size = FFI_ALIGN(s->size, align) + p->size; + } + + s->size = FFI_ALIGN(s->size, s->alignment); + + /* This should not be necessary on m64, but harmless. */ + 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. */ +} + +/* Adjust the size of S to be correct for AIX. + Word-align double unless it is the first member of a structure. */ + +static void +aix_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]; + aix_adjust_aggregate_sizes (p); + align = p->alignment; + if (i != 0 && p->type == FFI_TYPE_DOUBLE) + align = 4; + s->size = FFI_ALIGN(s->size, align) + p->size; + } + + s->size = FFI_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. */ + unsigned i; + ffi_type **ptr; + unsigned bytes; + unsigned 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]); + } + + if (cif->abi == FFI_AIX) + { + aix_adjust_aggregate_sizes (cif->rtype); + for (i = 0; i < cif->nargs; i++) + aix_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 = (LINKAGE_AREA_GPRS + ASM_NEEDS_REGISTERS) * sizeof(unsigned long); + + /* Return value handling. + The rules m32 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; + m64: + - 64-bit or smaller integral values are returned in GPR3 + - Single/double FP values are returned in fpr1; + - Long double FP values are returned in fpr1 and fpr2; + m64 Structures: + - If the structure could be accommodated in registers were it to be the + first argument to a routine, then it is returned in those registers. + m32/m64 structures otherwise: + - 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: +#ifdef POWERPC64 + case FFI_TYPE_POINTER: +#endif + flags |= FLAG_RETURNS_64BITS; + break; + + case FFI_TYPE_STRUCT: +#if defined(POWERPC_DARWIN64) + { + /* Can we fit the struct into regs? */ + if (darwin64_struct_ret_by_value_p (cif->rtype)) + { + unsigned nfpr = 0; + flags |= FLAG_RETURNS_STRUCT; + if (cif->rtype->size != 16) + darwin64_scan_struct_for_floats (cif->rtype, &nfpr) ; + else + flags |= FLAG_RETURNS_128BITS; + /* Will be 0 for 16byte struct. */ + if (nfpr) + flags |= FLAG_RETURNS_FP; + } + else /* By ref. */ + { + flags |= FLAG_RETVAL_REFERENCE; + flags |= FLAG_RETURNS_NOTHING; + intarg_count++; + } + } +#elif defined(DARWIN_PPC) + if (cif->rtype->size <= 4) + flags |= FLAG_RETURNS_STRUCT; + else /* else by reference. */ + { + flags |= FLAG_RETVAL_REFERENCE; + flags |= FLAG_RETURNS_NOTHING; + intarg_count++; + } +#else /* assume we pass by ref. */ + flags |= FLAG_RETVAL_REFERENCE; + flags |= FLAG_RETURNS_NOTHING; + intarg_count++; +#endif + 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 m64 the count is effectively of half-GPRs. */ + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + unsigned align_words; + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + fparg_count++; #if !defined(POWERPC_DARWIN64) - char *dest_cpy; -#endif - 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 long) (char *) ecif->rvalue; - - /* Now for the arguments. */ - for (i = nargs; 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) - *fpr_base++ = double_tmp; -#if defined(POWERPC_DARWIN) - *(float *)next_arg = *(float *) *p_argv; -#else - *(double *)next_arg = double_tmp; -#endif - next_arg++; - gp_count++; - 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) - *fpr_base++ = double_tmp; - *(double *)next_arg = double_tmp; -#ifdef POWERPC64 - next_arg++; - gp_count++; -#else - next_arg += 2; - gp_count += 2; -#endif - fparg_count++; - FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); - break; - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - - case FFI_TYPE_LONGDOUBLE: -# if defined(POWERPC64) && !defined(POWERPC_DARWIN64) - /* ??? This will exceed the regs count when the value starts at fp13 - and it will not put the extra bit on the stack. */ - if (fparg_count < NUM_FPR_ARG_REGISTERS) - *(long double *) fpr_base++ = *(long double *) *p_argv; - else - *(long double *) next_arg = *(long double *) *p_argv; - next_arg += 2; - fparg_count += 2; -# else - double_tmp = ((double *) *p_argv)[0]; - if (fparg_count < NUM_FPR_ARG_REGISTERS) - *fpr_base++ = double_tmp; - *(double *) next_arg = double_tmp; -# if defined(POWERPC_DARWIN64) - next_arg++; - gp_count++; -# else - next_arg += 2; - gp_count += 2; -# endif - fparg_count++; - double_tmp = ((double *) *p_argv)[1]; - if (fparg_count < NUM_FPR_ARG_REGISTERS) - *fpr_base++ = double_tmp; - *(double *) next_arg = double_tmp; -# if defined(POWERPC_DARWIN64) - next_arg++; - gp_count++; -# else - next_arg += 2; - gp_count += 2; -# endif - fparg_count++; -# endif - FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); - break; -#endif - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: -#ifdef POWERPC64 - gprvalue = *(long long *) *p_argv; - goto putgpr; -#else - *(long long *) next_arg = *(long long *) *p_argv; - next_arg += 2; - gp_count += 2; -#endif - break; - case FFI_TYPE_POINTER: - gprvalue = *(unsigned long *) *p_argv; - goto putgpr; - case FFI_TYPE_UINT8: - gprvalue = *(unsigned char *) *p_argv; - goto putgpr; - case FFI_TYPE_SINT8: - gprvalue = *(signed char *) *p_argv; - goto putgpr; - case FFI_TYPE_UINT16: - gprvalue = *(unsigned short *) *p_argv; - goto putgpr; - case FFI_TYPE_SINT16: - gprvalue = *(signed short *) *p_argv; - goto putgpr; - - case FFI_TYPE_STRUCT: - size_al = (*ptr)->size; -#if defined(POWERPC_DARWIN64) - next_arg = (unsigned long *)FFI_ALIGN((char *)next_arg, (*ptr)->alignment); - darwin64_pass_struct_by_value (*ptr, (char *) *p_argv, - (unsigned) size_al, - (unsigned int *) &fparg_count, - &fpr_base, &next_arg); -#else - dest_cpy = (char *) next_arg; - - /* If the first member of the struct is a double, then include enough - padding in the struct size to align it to double-word. */ - if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE) - size_al = FFI_ALIGN((*ptr)->size, 8); - + /* If this FP arg is going on the stack, it must be + 8-byte-aligned. */ + if (fparg_count > NUM_FPR_ARG_REGISTERS + && (intarg_count & 0x01) != 0) + intarg_count++; +#endif + 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 + 16-byte-aligned. */ + if (fparg_count >= NUM_FPR_ARG_REGISTERS) +#if defined (POWERPC64) + intarg_count = FFI_ALIGN(intarg_count, 2); +#else + intarg_count = FFI_ALIGN(intarg_count, 4); +#endif + break; +#endif + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#if defined(POWERPC64) + intarg_count++; +#else + /* '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 & 0x01) != 0)) + intarg_count++; + intarg_count += 2; +#endif + break; + + case FFI_TYPE_STRUCT: + size_al = (*ptr)->size; +#if defined(POWERPC_DARWIN64) + align_words = (*ptr)->alignment >> 3; + if (align_words) + intarg_count = FFI_ALIGN(intarg_count, align_words); + /* Base size of the struct. */ + intarg_count += (size_al + 7) / 8; + /* If 16 bytes then don't worry about floats. */ + if (size_al != 16) + /* Scan through for floats to be placed in regs. */ + darwin64_scan_struct_for_floats (*ptr, &fparg_count) ; +#else + align_words = (*ptr)->alignment >> 2; + if (align_words) + intarg_count = FFI_ALIGN(intarg_count, align_words); + /* If the first member of the struct is a double, then align + the struct to double-word. + if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = FFI_ALIGN((*ptr)->size, 8); */ +# ifdef POWERPC64 + intarg_count += (size_al + 7) / 8; +# else + intarg_count += (size_al + 3) / 4; +# endif +#endif + 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; + +#if defined(POWERPC_DARWIN64) + /* Space to image the FPR registers, if needed - which includes when they might be + used in a struct return. */ + if (fparg_count != 0 + || ((flags & FLAG_RETURNS_STRUCT) + && (flags & FLAG_RETURNS_FP))) + bytes += NUM_FPR_ARG_REGISTERS * sizeof(double); +#else + /* Space for the FPR registers, if needed. */ + if (fparg_count != 0) + bytes += NUM_FPR_ARG_REGISTERS * sizeof(double); +#endif + + /* Stack space. */ +#ifdef POWERPC64 + if ((intarg_count + fparg_count) > NUM_GPR_ARG_REGISTERS) + bytes += (intarg_count + fparg_count) * sizeof(long); +#else + if ((intarg_count + 2 * fparg_count) > NUM_GPR_ARG_REGISTERS) + bytes += (intarg_count + 2 * fparg_count) * sizeof(long); +#endif + else + bytes += NUM_GPR_ARG_REGISTERS * sizeof(long); + + /* The stack space allocated needs to be a multiple of 16 bytes. */ + bytes = FFI_ALIGN(bytes, 16) ; + + cif->flags = flags; + cif->bytes = bytes; + + return FFI_OK; +} + +extern void ffi_call_AIX(extended_cif *, long, unsigned, unsigned *, + void (*fn)(void), void (*fn2)(void)); + +extern void ffi_call_go_AIX(extended_cif *, long, unsigned, unsigned *, + void (*fn)(void), void (*fn2)(void), void *closure); + +extern void ffi_call_DARWIN(extended_cif *, long, unsigned, unsigned *, + void (*fn)(void), void (*fn2)(void), ffi_type*); + +void +ffi_call (ffi_cif *cif, void (*fn)(void), 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, -(long)cif->bytes, cif->flags, ecif.rvalue, fn, + FFI_FN(ffi_prep_args)); + break; + case FFI_DARWIN: + ffi_call_DARWIN(&ecif, -(long)cif->bytes, cif->flags, ecif.rvalue, fn, + FFI_FN(ffi_prep_args), cif->rtype); + break; + default: + FFI_ASSERT(0); + break; + } +} + +void +ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, + void *closure) +{ + 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_go_AIX(&ecif, -(long)cif->bytes, cif->flags, ecif.rvalue, fn, + FFI_FN(ffi_prep_args), closure); + 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_closure.S + + m32/m64 + + The stack layout looks like this: + + | Additional params... | | Higher address + ~ ~ ~ + | Parameters (at least 8*4/8=32/64) | | NUM_GPR_ARG_REGISTERS + |--------------------------------------------| | + | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | + |--------------------------------------------| | + | Reserved 2*4/8 | | + |--------------------------------------------| | + | Space for callee's LR 4/8 | | + |--------------------------------------------| | + | Saved CR [low word for m64] 4/8 | | + |--------------------------------------------| | + | Current backchain pointer 4/8 |-/ Parent's frame. + |--------------------------------------------| <+ <<< on entry to ffi_closure_ASM + | Result Bytes 16 | | + |--------------------------------------------| | + ~ padding to 16-byte alignment ~ ~ + |--------------------------------------------| | + | NUM_FPR_ARG_REGISTERS slots | | + | here fp13 .. fp1 13*8 | | + |--------------------------------------------| | + | R3..R10 8*4/8=32/64 | | NUM_GPR_ARG_REGISTERS + |--------------------------------------------| | + | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | + |--------------------------------------------| | stack | + | Reserved [compiler,binder] 2*4/8 | | grows | + |--------------------------------------------| | down V + | Space for callee's LR 4/8 | | + |--------------------------------------------| | lower addresses + | Saved CR [low word for m64] 4/8 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 4/8 |-/ during + |--------------------------------------------| <<< ffi_closure_ASM. + +*/ + +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]; +#if defined(POWERPC_DARWIN64) + tramp[0] = 0x7c0802a6; /* mflr r0 */ + tramp[1] = 0x429f0015; /* bcl- 20,4*cr7+so, +0x18 (L1) */ + /* We put the addresses here. */ + tramp[6] = 0x7d6802a6; /*L1: mflr r11 */ + tramp[7] = 0xe98b0000; /* ld r12,0(r11) function address */ + tramp[8] = 0x7c0803a6; /* mtlr r0 */ + tramp[9] = 0x7d8903a6; /* mtctr r12 */ + tramp[10] = 0xe96b0008; /* lwz r11,8(r11) static chain */ + tramp[11] = 0x4e800420; /* bctr */ + + *((unsigned long *)&tramp[2]) = (unsigned long) ffi_closure_ASM; /* function */ + *((unsigned long *)&tramp[4]) = (unsigned long) codeloc; /* context */ +#else + 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 */ +#endif + 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; + break; + + default: + return FFI_BAD_ABI; + break; + } + return FFI_OK; +} + +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*)) +{ + switch (cif->abi) + { + case FFI_AIX: + + FFI_ASSERT (cif->abi == FFI_AIX); + + closure->tramp = (void *)ffi_go_closure_ASM; + closure->cif = cif; + closure->fun = fun; + return FFI_OK; + + // For now, ffi_prep_go_closure is only implemented for AIX, not for Darwin + default: + return FFI_BAD_ABI; + 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; + +ffi_type * +ffi_closure_helper_DARWIN (ffi_closure *, void *, + unsigned long *, ffi_dblfl *); + +ffi_type * +ffi_go_closure_helper_DARWIN (ffi_go_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. */ + +static ffi_type * +ffi_closure_helper_common (ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, 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; + ffi_dblfl * end_pfr = pfr + NUM_FPR_ARG_REGISTERS; + unsigned size_al; +#if defined(POWERPC_DARWIN64) + unsigned fpsused = 0; +#endif + + avalue = alloca (cif->nargs * sizeof(void *)); + + if (cif->rtype->type == FFI_TYPE_STRUCT) + { +#if defined(POWERPC_DARWIN64) + if (!darwin64_struct_ret_by_value_p (cif->rtype)) + { + /* Won't fit into the regs - return by ref. */ + rvalue = (void *) *pgr; + pgr++; + } +#elif defined(DARWIN_PPC) + if (cif->rtype->size > 4) + { + rvalue = (void *) *pgr; + pgr++; + } +#else /* assume we return by ref. */ + rvalue = (void *) *pgr; + pgr++; +#endif + } + + 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: +#if defined(POWERPC64) + avalue[i] = (char *) pgr + 7; +#else + avalue[i] = (char *) pgr + 3; +#endif + pgr++; + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: +#if defined(POWERPC64) + avalue[i] = (char *) pgr + 6; +#else + avalue[i] = (char *) pgr + 2; +#endif + pgr++; + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: +#if defined(POWERPC64) + avalue[i] = (char *) pgr + 4; +#else + case FFI_TYPE_POINTER: + avalue[i] = pgr; +#endif + pgr++; + break; + + case FFI_TYPE_STRUCT: + size_al = arg_types[i]->size; +#if defined(POWERPC_DARWIN64) + pgr = (unsigned long *)FFI_ALIGN((char *)pgr, arg_types[i]->alignment); + if (size_al < 3 || size_al == 4) + { + avalue[i] = ((char *)pgr)+8-size_al; + if (arg_types[i]->elements[0]->type == FFI_TYPE_FLOAT + && fpsused < NUM_FPR_ARG_REGISTERS) + { + *(float *)pgr = (float) *(double *)pfr; + pfr++; + fpsused++; + } + } + else + { + if (size_al != 16) + pfr = (ffi_dblfl *) + darwin64_struct_floats_to_mem (arg_types[i], (char *)pgr, + (double *)pfr, &fpsused); + avalue[i] = pgr; + } + pgr += (size_al + 7) / 8; +#else + /* If the first member of the struct is a double, then align + the struct to double-word. */ + if (arg_types[i]->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = FFI_ALIGN(arg_types[i]->size, 8); # if defined(POWERPC64) - FFI_ASSERT (abi != FFI_DARWIN); - memcpy ((char *) dest_cpy, (char *) *p_argv, size_al); - next_arg += (size_al + 7) / 8; -# else - /* 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. */ - if (size_al < 3 && abi == FFI_DARWIN) - dest_cpy += 4 - size_al; - - memcpy((char *) dest_cpy, (char *) *p_argv, size_al); - next_arg += (size_al + 3) / 4; -# endif -#endif - break; - - case FFI_TYPE_INT: - case FFI_TYPE_SINT32: - gprvalue = *(signed int *) *p_argv; - goto putgpr; - - case FFI_TYPE_UINT32: - gprvalue = *(unsigned int *) *p_argv; - putgpr: - *next_arg++ = gprvalue; - gp_count++; - 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); */ -} - -#if defined(POWERPC_DARWIN64) - -/* See if we can put some of the struct into fprs. - This should not be called for structures of size 16 bytes, since these are not - broken out this way. */ -static void -darwin64_scan_struct_for_floats (ffi_type *s, unsigned *nfpr) -{ - int i; - - FFI_ASSERT (s->type == FFI_TYPE_STRUCT) - - for (i = 0; s->elements[i] != NULL; i++) - { - ffi_type *p = s->elements[i]; - switch (p->type) - { - case FFI_TYPE_STRUCT: - darwin64_scan_struct_for_floats (p, nfpr); - break; - case FFI_TYPE_LONGDOUBLE: - (*nfpr) += 2; - break; - case FFI_TYPE_DOUBLE: - case FFI_TYPE_FLOAT: - (*nfpr) += 1; - break; - default: - break; - } - } -} - -static int -darwin64_struct_size_exceeds_gprs_p (ffi_type *s, char *src, unsigned *nfpr) -{ - unsigned struct_offset=0, i; - - for (i = 0; s->elements[i] != NULL; i++) - { - char *item_base; - ffi_type *p = s->elements[i]; - /* Find the start of this item (0 for the first one). */ - if (i > 0) - struct_offset = FFI_ALIGN(struct_offset, p->alignment); - - item_base = src + struct_offset; - - switch (p->type) - { - case FFI_TYPE_STRUCT: - if (darwin64_struct_size_exceeds_gprs_p (p, item_base, nfpr)) - return 1; - break; - case FFI_TYPE_LONGDOUBLE: - if (*nfpr >= NUM_FPR_ARG_REGISTERS) - return 1; - (*nfpr) += 1; - item_base += 8; - /* FALL THROUGH */ - case FFI_TYPE_DOUBLE: - if (*nfpr >= NUM_FPR_ARG_REGISTERS) - return 1; - (*nfpr) += 1; - break; - case FFI_TYPE_FLOAT: - if (*nfpr >= NUM_FPR_ARG_REGISTERS) - return 1; - (*nfpr) += 1; - break; - default: - /* If we try and place any item, that is non-float, once we've - exceeded the 8 GPR mark, then we can't fit the struct. */ - if ((unsigned long)item_base >= 8*8) - return 1; - break; - } - /* now count the size of what we just used. */ - struct_offset += p->size; - } - return 0; -} - -/* Can this struct be returned by value? */ -int -darwin64_struct_ret_by_value_p (ffi_type *s) -{ - unsigned nfp = 0; - - FFI_ASSERT (s && s->type == FFI_TYPE_STRUCT); - - /* The largest structure we can return is 8long + 13 doubles. */ - if (s->size > 168) - return 0; - - /* We can't pass more than 13 floats. */ - darwin64_scan_struct_for_floats (s, &nfp); - if (nfp > 13) - return 0; - - /* If there are not too many floats, and the struct is - small enough to accommodate in the GPRs, then it must be OK. */ - if (s->size <= 64) - return 1; - - /* Well, we have to look harder. */ - nfp = 0; - if (darwin64_struct_size_exceeds_gprs_p (s, NULL, &nfp)) - return 0; - - return 1; -} - -void -darwin64_pass_struct_floats (ffi_type *s, char *src, - unsigned *nfpr, double **fprs) -{ - int i; - double *fpr_base = *fprs; - unsigned struct_offset = 0; - - /* We don't assume anything about the alignment of the source. */ - for (i = 0; s->elements[i] != NULL; i++) - { - char *item_base; - ffi_type *p = s->elements[i]; - /* Find the start of this item (0 for the first one). */ - if (i > 0) - struct_offset = FFI_ALIGN(struct_offset, p->alignment); - item_base = src + struct_offset; - - switch (p->type) - { - case FFI_TYPE_STRUCT: - darwin64_pass_struct_floats (p, item_base, nfpr, - &fpr_base); - break; - case FFI_TYPE_LONGDOUBLE: - if (*nfpr < NUM_FPR_ARG_REGISTERS) - *fpr_base++ = *(double *)item_base; - (*nfpr) += 1; - item_base += 8; - /* FALL THROUGH */ - case FFI_TYPE_DOUBLE: - if (*nfpr < NUM_FPR_ARG_REGISTERS) - *fpr_base++ = *(double *)item_base; - (*nfpr) += 1; - break; - case FFI_TYPE_FLOAT: - if (*nfpr < NUM_FPR_ARG_REGISTERS) - *fpr_base++ = (double) *(float *)item_base; - (*nfpr) += 1; - break; - default: - break; - } - /* now count the size of what we just used. */ - struct_offset += p->size; - } - /* Update the scores. */ - *fprs = fpr_base; -} - -/* Darwin64 special rules. - Break out a struct into params and float registers. */ -static void -darwin64_pass_struct_by_value (ffi_type *s, char *src, unsigned size, - unsigned *nfpr, double **fprs, unsigned long **arg) -{ - unsigned long *next_arg = *arg; - char *dest_cpy = (char *)next_arg; - - FFI_ASSERT (s->type == FFI_TYPE_STRUCT) - - if (!size) - return; - - /* First... special cases. */ - if (size < 3 - || (size == 4 - && s->elements[0] - && s->elements[0]->type != FFI_TYPE_FLOAT)) - { - /* Must be at least one GPR, padding is unspecified in value, - let's make it zero. */ - *next_arg = 0UL; - dest_cpy += 8 - size; - memcpy ((char *) dest_cpy, src, size); - next_arg++; - } - else if (size == 16) - { - memcpy ((char *) dest_cpy, src, size); - next_arg += 2; - } - else - { - /* now the general case, we consider embedded floats. */ - memcpy ((char *) dest_cpy, src, size); - darwin64_pass_struct_floats (s, src, nfpr, fprs); - next_arg += (size+7)/8; - } - - *arg = next_arg; -} - -double * -darwin64_struct_floats_to_mem (ffi_type *s, char *dest, double *fprs, unsigned *nf) -{ - int i; - unsigned struct_offset = 0; - - /* We don't assume anything about the alignment of the source. */ - for (i = 0; s->elements[i] != NULL; i++) - { - char *item_base; - ffi_type *p = s->elements[i]; - /* Find the start of this item (0 for the first one). */ - if (i > 0) - struct_offset = FFI_ALIGN(struct_offset, p->alignment); - item_base = dest + struct_offset; - - switch (p->type) - { - case FFI_TYPE_STRUCT: - fprs = darwin64_struct_floats_to_mem (p, item_base, fprs, nf); - break; - case FFI_TYPE_LONGDOUBLE: - if (*nf < NUM_FPR_ARG_REGISTERS) - { - *(double *)item_base = *fprs++ ; - (*nf) += 1; - } - item_base += 8; - /* FALL THROUGH */ - case FFI_TYPE_DOUBLE: - if (*nf < NUM_FPR_ARG_REGISTERS) - { - *(double *)item_base = *fprs++ ; - (*nf) += 1; - } - break; - case FFI_TYPE_FLOAT: - if (*nf < NUM_FPR_ARG_REGISTERS) - { - *(float *)item_base = (float) *fprs++ ; - (*nf) += 1; - } - break; - default: - break; - } - /* now count the size of what we just used. */ - struct_offset += p->size; - } - return fprs; -} - -#endif - -/* Adjust the size of S to be correct for Darwin. - On Darwin m32, the first field of a structure has natural alignment. - On Darwin m64, all fields have 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]; - if (p->type == FFI_TYPE_STRUCT) - darwin_adjust_aggregate_sizes (p); -#if defined(POWERPC_DARWIN64) - /* Natural alignment for all items. */ - align = p->alignment; -#else - /* Natural alignment for the first item... */ - if (i == 0) - align = p->alignment; - else if (p->alignment == 16 || p->alignment < 4) - /* .. subsequent items with vector or align < 4 have natural align. */ - align = p->alignment; - else - /* .. or align is 4. */ - align = 4; -#endif - /* Pad, if necessary, before adding the current item. */ - s->size = FFI_ALIGN(s->size, align) + p->size; - } - - s->size = FFI_ALIGN(s->size, s->alignment); - - /* This should not be necessary on m64, but harmless. */ - 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. */ -} - -/* Adjust the size of S to be correct for AIX. - Word-align double unless it is the first member of a structure. */ - -static void -aix_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]; - aix_adjust_aggregate_sizes (p); - align = p->alignment; - if (i != 0 && p->type == FFI_TYPE_DOUBLE) - align = 4; - s->size = FFI_ALIGN(s->size, align) + p->size; - } - - s->size = FFI_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. */ - unsigned i; - ffi_type **ptr; - unsigned bytes; - unsigned 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]); - } - - if (cif->abi == FFI_AIX) - { - aix_adjust_aggregate_sizes (cif->rtype); - for (i = 0; i < cif->nargs; i++) - aix_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 = (LINKAGE_AREA_GPRS + ASM_NEEDS_REGISTERS) * sizeof(unsigned long); - - /* Return value handling. - The rules m32 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; - m64: - - 64-bit or smaller integral values are returned in GPR3 - - Single/double FP values are returned in fpr1; - - Long double FP values are returned in fpr1 and fpr2; - m64 Structures: - - If the structure could be accommodated in registers were it to be the - first argument to a routine, then it is returned in those registers. - m32/m64 structures otherwise: - - 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: -#ifdef POWERPC64 - case FFI_TYPE_POINTER: -#endif - flags |= FLAG_RETURNS_64BITS; - break; - - case FFI_TYPE_STRUCT: -#if defined(POWERPC_DARWIN64) - { - /* Can we fit the struct into regs? */ - if (darwin64_struct_ret_by_value_p (cif->rtype)) - { - unsigned nfpr = 0; - flags |= FLAG_RETURNS_STRUCT; - if (cif->rtype->size != 16) - darwin64_scan_struct_for_floats (cif->rtype, &nfpr) ; - else - flags |= FLAG_RETURNS_128BITS; - /* Will be 0 for 16byte struct. */ - if (nfpr) - flags |= FLAG_RETURNS_FP; - } - else /* By ref. */ - { - flags |= FLAG_RETVAL_REFERENCE; - flags |= FLAG_RETURNS_NOTHING; - intarg_count++; - } - } -#elif defined(DARWIN_PPC) - if (cif->rtype->size <= 4) - flags |= FLAG_RETURNS_STRUCT; - else /* else by reference. */ - { - flags |= FLAG_RETVAL_REFERENCE; - flags |= FLAG_RETURNS_NOTHING; - intarg_count++; - } -#else /* assume we pass by ref. */ - flags |= FLAG_RETVAL_REFERENCE; - flags |= FLAG_RETURNS_NOTHING; - intarg_count++; -#endif - 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 m64 the count is effectively of half-GPRs. */ - for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) - { - unsigned align_words; - switch ((*ptr)->type) - { - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - fparg_count++; -#if !defined(POWERPC_DARWIN64) - /* If this FP arg is going on the stack, it must be - 8-byte-aligned. */ - if (fparg_count > NUM_FPR_ARG_REGISTERS - && (intarg_count & 0x01) != 0) - intarg_count++; -#endif - 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 - 16-byte-aligned. */ - if (fparg_count >= NUM_FPR_ARG_REGISTERS) -#if defined (POWERPC64) - intarg_count = FFI_ALIGN(intarg_count, 2); -#else - intarg_count = FFI_ALIGN(intarg_count, 4); -#endif - break; -#endif - - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: -#if defined(POWERPC64) - intarg_count++; -#else - /* '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 & 0x01) != 0)) - intarg_count++; - intarg_count += 2; -#endif - break; - - case FFI_TYPE_STRUCT: - size_al = (*ptr)->size; -#if defined(POWERPC_DARWIN64) - align_words = (*ptr)->alignment >> 3; - if (align_words) - intarg_count = FFI_ALIGN(intarg_count, align_words); - /* Base size of the struct. */ - intarg_count += (size_al + 7) / 8; - /* If 16 bytes then don't worry about floats. */ - if (size_al != 16) - /* Scan through for floats to be placed in regs. */ - darwin64_scan_struct_for_floats (*ptr, &fparg_count) ; -#else - align_words = (*ptr)->alignment >> 2; - if (align_words) - intarg_count = FFI_ALIGN(intarg_count, align_words); - /* If the first member of the struct is a double, then align - the struct to double-word. - if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE) - size_al = FFI_ALIGN((*ptr)->size, 8); */ -# ifdef POWERPC64 - intarg_count += (size_al + 7) / 8; -# else - intarg_count += (size_al + 3) / 4; -# endif -#endif - 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; - -#if defined(POWERPC_DARWIN64) - /* Space to image the FPR registers, if needed - which includes when they might be - used in a struct return. */ - if (fparg_count != 0 - || ((flags & FLAG_RETURNS_STRUCT) - && (flags & FLAG_RETURNS_FP))) - bytes += NUM_FPR_ARG_REGISTERS * sizeof(double); -#else - /* Space for the FPR registers, if needed. */ - if (fparg_count != 0) - bytes += NUM_FPR_ARG_REGISTERS * sizeof(double); -#endif - - /* Stack space. */ -#ifdef POWERPC64 - if ((intarg_count + fparg_count) > NUM_GPR_ARG_REGISTERS) - bytes += (intarg_count + fparg_count) * sizeof(long); -#else - if ((intarg_count + 2 * fparg_count) > NUM_GPR_ARG_REGISTERS) - bytes += (intarg_count + 2 * fparg_count) * sizeof(long); -#endif - else - bytes += NUM_GPR_ARG_REGISTERS * sizeof(long); - - /* The stack space allocated needs to be a multiple of 16 bytes. */ - bytes = FFI_ALIGN(bytes, 16) ; - - cif->flags = flags; - cif->bytes = bytes; - - return FFI_OK; -} - -extern void ffi_call_AIX(extended_cif *, long, unsigned, unsigned *, - void (*fn)(void), void (*fn2)(void)); - -extern void ffi_call_go_AIX(extended_cif *, long, unsigned, unsigned *, - void (*fn)(void), void (*fn2)(void), void *closure); - -extern void ffi_call_DARWIN(extended_cif *, long, unsigned, unsigned *, - void (*fn)(void), void (*fn2)(void), ffi_type*); - -void -ffi_call (ffi_cif *cif, void (*fn)(void), 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, -(long)cif->bytes, cif->flags, ecif.rvalue, fn, - FFI_FN(ffi_prep_args)); - break; - case FFI_DARWIN: - ffi_call_DARWIN(&ecif, -(long)cif->bytes, cif->flags, ecif.rvalue, fn, - FFI_FN(ffi_prep_args), cif->rtype); - break; - default: - FFI_ASSERT(0); - break; - } -} - -void -ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, - void *closure) -{ - 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_go_AIX(&ecif, -(long)cif->bytes, cif->flags, ecif.rvalue, fn, - FFI_FN(ffi_prep_args), closure); - 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_closure.S - - m32/m64 - - The stack layout looks like this: - - | Additional params... | | Higher address - ~ ~ ~ - | Parameters (at least 8*4/8=32/64) | | NUM_GPR_ARG_REGISTERS - |--------------------------------------------| | - | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | - |--------------------------------------------| | - | Reserved 2*4/8 | | - |--------------------------------------------| | - | Space for callee's LR 4/8 | | - |--------------------------------------------| | - | Saved CR [low word for m64] 4/8 | | - |--------------------------------------------| | - | Current backchain pointer 4/8 |-/ Parent's frame. - |--------------------------------------------| <+ <<< on entry to ffi_closure_ASM - | Result Bytes 16 | | - |--------------------------------------------| | - ~ padding to 16-byte alignment ~ ~ - |--------------------------------------------| | - | NUM_FPR_ARG_REGISTERS slots | | - | here fp13 .. fp1 13*8 | | - |--------------------------------------------| | - | R3..R10 8*4/8=32/64 | | NUM_GPR_ARG_REGISTERS - |--------------------------------------------| | - | TOC=R2 (AIX) Reserved (Darwin) 4/8 | | - |--------------------------------------------| | stack | - | Reserved [compiler,binder] 2*4/8 | | grows | - |--------------------------------------------| | down V - | Space for callee's LR 4/8 | | - |--------------------------------------------| | lower addresses - | Saved CR [low word for m64] 4/8 | | - |--------------------------------------------| | stack pointer here - | Current backchain pointer 4/8 |-/ during - |--------------------------------------------| <<< ffi_closure_ASM. - -*/ - -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]; -#if defined(POWERPC_DARWIN64) - tramp[0] = 0x7c0802a6; /* mflr r0 */ - tramp[1] = 0x429f0015; /* bcl- 20,4*cr7+so, +0x18 (L1) */ - /* We put the addresses here. */ - tramp[6] = 0x7d6802a6; /*L1: mflr r11 */ - tramp[7] = 0xe98b0000; /* ld r12,0(r11) function address */ - tramp[8] = 0x7c0803a6; /* mtlr r0 */ - tramp[9] = 0x7d8903a6; /* mtctr r12 */ - tramp[10] = 0xe96b0008; /* lwz r11,8(r11) static chain */ - tramp[11] = 0x4e800420; /* bctr */ - - *((unsigned long *)&tramp[2]) = (unsigned long) ffi_closure_ASM; /* function */ - *((unsigned long *)&tramp[4]) = (unsigned long) codeloc; /* context */ -#else - 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 */ -#endif - 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; - break; - - default: - return FFI_BAD_ABI; - break; - } - return FFI_OK; -} - -ffi_status -ffi_prep_go_closure (ffi_go_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*, void*, void**, void*)) -{ - switch (cif->abi) - { - case FFI_AIX: - - FFI_ASSERT (cif->abi == FFI_AIX); - - closure->tramp = (void *)ffi_go_closure_ASM; - closure->cif = cif; - closure->fun = fun; - return FFI_OK; - - // For now, ffi_prep_go_closure is only implemented for AIX, not for Darwin - default: - return FFI_BAD_ABI; - 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; - -ffi_type * -ffi_closure_helper_DARWIN (ffi_closure *, void *, - unsigned long *, ffi_dblfl *); - -ffi_type * -ffi_go_closure_helper_DARWIN (ffi_go_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. */ - -static ffi_type * -ffi_closure_helper_common (ffi_cif* cif, - void (*fun)(ffi_cif*, void*, void**, void*), - void *user_data, 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; - ffi_dblfl * end_pfr = pfr + NUM_FPR_ARG_REGISTERS; - unsigned size_al; -#if defined(POWERPC_DARWIN64) - unsigned fpsused = 0; -#endif - - avalue = alloca (cif->nargs * sizeof(void *)); - - if (cif->rtype->type == FFI_TYPE_STRUCT) - { -#if defined(POWERPC_DARWIN64) - if (!darwin64_struct_ret_by_value_p (cif->rtype)) - { - /* Won't fit into the regs - return by ref. */ - rvalue = (void *) *pgr; - pgr++; - } -#elif defined(DARWIN_PPC) - if (cif->rtype->size > 4) - { - rvalue = (void *) *pgr; - pgr++; - } -#else /* assume we return by ref. */ - rvalue = (void *) *pgr; - pgr++; -#endif - } - - 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: -#if defined(POWERPC64) - avalue[i] = (char *) pgr + 7; -#else - avalue[i] = (char *) pgr + 3; -#endif - pgr++; - break; - - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT16: -#if defined(POWERPC64) - avalue[i] = (char *) pgr + 6; -#else - avalue[i] = (char *) pgr + 2; -#endif - pgr++; - break; - - case FFI_TYPE_SINT32: - case FFI_TYPE_UINT32: -#if defined(POWERPC64) - avalue[i] = (char *) pgr + 4; -#else - case FFI_TYPE_POINTER: - avalue[i] = pgr; -#endif - pgr++; - break; - - case FFI_TYPE_STRUCT: - size_al = arg_types[i]->size; -#if defined(POWERPC_DARWIN64) - pgr = (unsigned long *)FFI_ALIGN((char *)pgr, arg_types[i]->alignment); - if (size_al < 3 || size_al == 4) - { - avalue[i] = ((char *)pgr)+8-size_al; - if (arg_types[i]->elements[0]->type == FFI_TYPE_FLOAT - && fpsused < NUM_FPR_ARG_REGISTERS) - { - *(float *)pgr = (float) *(double *)pfr; - pfr++; - fpsused++; - } - } + FFI_ASSERT (cif->abi != FFI_DARWIN); + avalue[i] = pgr; + pgr += (size_al + 7) / 8; +# else + /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, + SI 4 bytes) are aligned as if they were those modes. */ + if (size_al < 3 && cif->abi == FFI_DARWIN) + avalue[i] = (char*) pgr + 4 - size_al; + else + avalue[i] = pgr; + pgr += (size_al + 3) / 4; +# endif +#endif + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: +#if defined(POWERPC64) + case FFI_TYPE_POINTER: + avalue[i] = pgr; + pgr++; + break; +#else + /* Long long ints are passed in two gpr's. */ + avalue[i] = pgr; + pgr += 2; + break; +#endif + + case FFI_TYPE_FLOAT: + /* A float value consumes a GPR. + 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] = pgr; + } + pgr++; + break; + + case FFI_TYPE_DOUBLE: + /* A double value consumes two GPRs. + There are 13 64bit floating point registers. */ + if (pfr < end_pfr) + { + avalue[i] = pfr; + pfr++; + } + else + { + avalue[i] = pgr; + } +#ifdef POWERPC64 + pgr++; +#else + pgr += 2; +#endif + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_LONGDOUBLE: +#ifdef POWERPC64 + if (pfr + 1 < end_pfr) + { + avalue[i] = pfr; + pfr += 2; + } + else + { + if (pfr < end_pfr) + { + *pgr = *(unsigned long *) pfr; + pfr++; + } + avalue[i] = pgr; + } + pgr += 2; +#else /* POWERPC64 */ + /* A long double value consumes four GPRs and two FPRs. + There are 13 64bit floating point registers. */ + if (pfr + 1 < end_pfr) + { + 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 (pfr + 1 == end_pfr) + { + union ldu temp_ld; + memcpy (&temp_ld.lb[0], pfr, sizeof(ldbits)); + memcpy (&temp_ld.lb[1], pgr + 2, sizeof(ldbits)); + avalue[i] = &temp_ld.ld; + pfr++; + } else - { - if (size_al != 16) - pfr = (ffi_dblfl *) - darwin64_struct_floats_to_mem (arg_types[i], (char *)pgr, - (double *)pfr, &fpsused); - avalue[i] = pgr; - } - pgr += (size_al + 7) / 8; -#else - /* If the first member of the struct is a double, then align - the struct to double-word. */ - if (arg_types[i]->elements[0]->type == FFI_TYPE_DOUBLE) - size_al = FFI_ALIGN(arg_types[i]->size, 8); -# if defined(POWERPC64) - FFI_ASSERT (cif->abi != FFI_DARWIN); - avalue[i] = pgr; - pgr += (size_al + 7) / 8; -# else - /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, - SI 4 bytes) are aligned as if they were those modes. */ - if (size_al < 3 && cif->abi == FFI_DARWIN) - avalue[i] = (char*) pgr + 4 - size_al; - else - avalue[i] = pgr; - pgr += (size_al + 3) / 4; -# endif -#endif - break; - - case FFI_TYPE_SINT64: - case FFI_TYPE_UINT64: -#if defined(POWERPC64) - case FFI_TYPE_POINTER: - avalue[i] = pgr; - pgr++; - break; -#else - /* Long long ints are passed in two gpr's. */ - avalue[i] = pgr; - pgr += 2; - break; -#endif - - case FFI_TYPE_FLOAT: - /* A float value consumes a GPR. - 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] = pgr; - } - pgr++; - break; - - case FFI_TYPE_DOUBLE: - /* A double value consumes two GPRs. - There are 13 64bit floating point registers. */ - if (pfr < end_pfr) - { - avalue[i] = pfr; - pfr++; - } - else - { - avalue[i] = pgr; - } -#ifdef POWERPC64 - pgr++; -#else - pgr += 2; -#endif - break; - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - - case FFI_TYPE_LONGDOUBLE: -#ifdef POWERPC64 - if (pfr + 1 < end_pfr) - { - avalue[i] = pfr; - pfr += 2; - } - else - { - if (pfr < end_pfr) - { - *pgr = *(unsigned long *) pfr; - pfr++; - } - avalue[i] = pgr; - } - pgr += 2; -#else /* POWERPC64 */ - /* A long double value consumes four GPRs and two FPRs. - There are 13 64bit floating point registers. */ - if (pfr + 1 < end_pfr) - { - 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 (pfr + 1 == end_pfr) - { - union ldu temp_ld; - memcpy (&temp_ld.lb[0], pfr, sizeof(ldbits)); - memcpy (&temp_ld.lb[1], pgr + 2, sizeof(ldbits)); - avalue[i] = &temp_ld.ld; - pfr++; - } - else - { - avalue[i] = pgr; - } - pgr += 4; -#endif /* POWERPC64 */ - break; -#endif - default: - FFI_ASSERT(0); - } - i++; - } - - (fun) (cif, rvalue, avalue, user_data); - - /* Tell ffi_closure_ASM to perform return type promotions. */ - return cif->rtype; -} - -ffi_type * -ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue, - unsigned long *pgr, ffi_dblfl *pfr) -{ - return ffi_closure_helper_common (closure->cif, closure->fun, - closure->user_data, rvalue, pgr, pfr); -} - -ffi_type * -ffi_go_closure_helper_DARWIN (ffi_go_closure *closure, void *rvalue, - unsigned long *pgr, ffi_dblfl *pfr) -{ - return ffi_closure_helper_common (closure->cif, closure->fun, - closure, rvalue, pgr, pfr); -} - + { + avalue[i] = pgr; + } + pgr += 4; +#endif /* POWERPC64 */ + break; +#endif + default: + FFI_ASSERT(0); + } + i++; + } + + (fun) (cif, rvalue, avalue, user_data); + + /* Tell ffi_closure_ASM to perform return type promotions. */ + return cif->rtype; +} + +ffi_type * +ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue, + unsigned long *pgr, ffi_dblfl *pfr) +{ + return ffi_closure_helper_common (closure->cif, closure->fun, + closure->user_data, rvalue, pgr, pfr); +} + +ffi_type * +ffi_go_closure_helper_DARWIN (ffi_go_closure *closure, void *rvalue, + unsigned long *pgr, ffi_dblfl *pfr) +{ + return ffi_closure_helper_common (closure->cif, closure->fun, + closure, rvalue, pgr, pfr); +} + diff --git a/contrib/restricted/libffi/src/powerpc/ffi_linux64.c b/contrib/restricted/libffi/src/powerpc/ffi_linux64.c index de0d033769..f4c5014a86 100644 --- a/contrib/restricted/libffi/src/powerpc/ffi_linux64.c +++ b/contrib/restricted/libffi/src/powerpc/ffi_linux64.c @@ -1,1153 +1,1153 @@ -/* ----------------------------------------------------------------------- - ffi_linux64.c - Copyright (C) 2013 IBM - Copyright (C) 2011 Anthony Green - Copyright (C) 2011 Kyle Moffett - Copyright (C) 2008 Red Hat, Inc - Copyright (C) 2007, 2008 Free Software Foundation, Inc - Copyright (c) 1998 Geoffrey Keating - - 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" - -#ifdef POWERPC64 -#include "ffi_common.h" -#include "ffi_powerpc.h" - - -/* About the LINUX64 ABI. */ -enum { - NUM_GPR_ARG_REGISTERS64 = 8, - NUM_FPR_ARG_REGISTERS64 = 13, - NUM_VEC_ARG_REGISTERS64 = 12, -}; -enum { ASM_NEEDS_REGISTERS64 = 4 }; - - -#if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE -/* Adjust size of ffi_type_longdouble. */ -void FFI_HIDDEN -ffi_prep_types_linux64 (ffi_abi abi) -{ - if ((abi & (FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128)) == FFI_LINUX) - { - ffi_type_longdouble.size = 8; - ffi_type_longdouble.alignment = 8; - } - else - { - ffi_type_longdouble.size = 16; - ffi_type_longdouble.alignment = 16; - } -} -#endif - - -static unsigned int -discover_homogeneous_aggregate (ffi_abi abi, - const ffi_type *t, - unsigned int *elnum) -{ - switch (t->type) - { -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: - /* 64-bit long doubles are equivalent to doubles. */ - if ((abi & FFI_LINUX_LONG_DOUBLE_128) == 0) - { - *elnum = 1; - return FFI_TYPE_DOUBLE; - } - /* IBM extended precision values use unaligned pairs - of FPRs, but according to the ABI must be considered - distinct from doubles. They are also limited to a - maximum of four members in a homogeneous aggregate. */ - else if ((abi & FFI_LINUX_LONG_DOUBLE_IEEE128) == 0) - { - *elnum = 2; - return FFI_TYPE_LONGDOUBLE; - } - /* Fall through. */ -#endif - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - *elnum = 1; - return (int) t->type; - - case FFI_TYPE_STRUCT:; - { - unsigned int base_elt = 0, total_elnum = 0; - ffi_type **el = t->elements; - while (*el) - { - unsigned int el_elt, el_elnum = 0; - el_elt = discover_homogeneous_aggregate (abi, *el, &el_elnum); - if (el_elt == 0 - || (base_elt && base_elt != el_elt)) - return 0; - base_elt = el_elt; - total_elnum += el_elnum; -#if _CALL_ELF == 2 - if (total_elnum > 8) - return 0; -#else - if (total_elnum > 1) - return 0; -#endif - el++; - } - *elnum = total_elnum; - return base_elt; - } - - default: - return 0; - } -} - - -/* Perform machine dependent cif processing */ -static ffi_status -ffi_prep_cif_linux64_core (ffi_cif *cif) -{ - ffi_type **ptr; - unsigned bytes; - unsigned i, fparg_count = 0, intarg_count = 0, vecarg_count = 0; - unsigned flags = cif->flags; - unsigned elt, elnum, rtype; - -#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE - /* If compiled without long double support... */ - if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0 || - (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - return FFI_BAD_ABI; -#elif !defined(__VEC__) - /* If compiled without vector register support (used by assembly)... */ - if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - return FFI_BAD_ABI; -#else - /* If the IEEE128 flag is set, but long double is only 64 bits wide... */ - if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) == 0 && - (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - return FFI_BAD_ABI; -#endif - - /* The machine-independent calculation of cif->bytes doesn't work - for us. Redo the calculation. */ -#if _CALL_ELF == 2 - /* Space for backchain, CR, LR, TOC and the asm's temp regs. */ - bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long); - - /* Space for the general registers. */ - bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long); -#else - /* 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); -#endif - - /* Return value handling. */ - rtype = cif->rtype->type; -#if _CALL_ELF == 2 -homogeneous: -#endif - switch (rtype) - { -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: - if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - { - flags |= FLAG_RETURNS_VEC; - break; - } - if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) - flags |= FLAG_RETURNS_128BITS; - /* Fall through. */ -#endif - case FFI_TYPE_DOUBLE: - flags |= FLAG_RETURNS_64BITS; - /* Fall through. */ - case FFI_TYPE_FLOAT: - flags |= FLAG_RETURNS_FP; - break; - - case FFI_TYPE_UINT128: - flags |= FLAG_RETURNS_128BITS; - /* Fall through. */ - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: - case FFI_TYPE_POINTER: - flags |= FLAG_RETURNS_64BITS; - break; - - case FFI_TYPE_STRUCT: -#if _CALL_ELF == 2 - elt = discover_homogeneous_aggregate (cif->abi, cif->rtype, &elnum); - if (elt) - { - flags |= FLAG_RETURNS_SMST; - rtype = elt; - goto homogeneous; - } - if (cif->rtype->size <= 16) - { - flags |= FLAG_RETURNS_SMST; - break; - } -#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; - } - - for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) - { - unsigned int align; - - switch ((*ptr)->type) - { -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: - if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - { - vecarg_count++; - /* Align to 16 bytes, plus the 16-byte argument. */ - intarg_count = (intarg_count + 3) & ~0x1; - if (vecarg_count > NUM_VEC_ARG_REGISTERS64) - flags |= FLAG_ARG_NEEDS_PSAVE; - break; - } - if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) - { - fparg_count++; - intarg_count++; - } - /* Fall through. */ -#endif - case FFI_TYPE_DOUBLE: - case FFI_TYPE_FLOAT: - fparg_count++; - intarg_count++; - if (fparg_count > NUM_FPR_ARG_REGISTERS64) - flags |= FLAG_ARG_NEEDS_PSAVE; - break; - - case FFI_TYPE_STRUCT: - if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0) - { - align = (*ptr)->alignment; - if (align > 16) - align = 16; - align = align / 8; - if (align > 1) - intarg_count = FFI_ALIGN (intarg_count, align); - } - intarg_count += ((*ptr)->size + 7) / 8; - elt = discover_homogeneous_aggregate (cif->abi, *ptr, &elnum); -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - if (elt == FFI_TYPE_LONGDOUBLE && - (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - { - vecarg_count += elnum; - if (vecarg_count > NUM_VEC_ARG_REGISTERS64) - flags |= FLAG_ARG_NEEDS_PSAVE; - break; - } - else -#endif - if (elt) - { - fparg_count += elnum; - if (fparg_count > NUM_FPR_ARG_REGISTERS64) - flags |= FLAG_ARG_NEEDS_PSAVE; - } - else - { - if (intarg_count > NUM_GPR_ARG_REGISTERS64) - flags |= FLAG_ARG_NEEDS_PSAVE; - } - break; - - case FFI_TYPE_POINTER: - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: - case FFI_TYPE_INT: - case FFI_TYPE_UINT32: - case FFI_TYPE_SINT32: - case FFI_TYPE_UINT16: - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT8: - case FFI_TYPE_SINT8: - /* Everything else is passed as a 8-byte word in a GPR, either - the object itself or a pointer to it. */ - intarg_count++; - if (intarg_count > NUM_GPR_ARG_REGISTERS64) - flags |= FLAG_ARG_NEEDS_PSAVE; - break; - default: - FFI_ASSERT (0); - } - } - - if (fparg_count != 0) - flags |= FLAG_FP_ARGUMENTS; - if (intarg_count > 4) - flags |= FLAG_4_GPR_ARGUMENTS; - if (vecarg_count != 0) - flags |= FLAG_VEC_ARGUMENTS; - - /* Space for the FPR registers, if needed. */ - if (fparg_count != 0) - bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double); - /* Space for the vector registers, if needed, aligned to 16 bytes. */ - if (vecarg_count != 0) { - bytes = (bytes + 15) & ~0xF; - bytes += NUM_VEC_ARG_REGISTERS64 * sizeof (float128); - } - - /* Stack space. */ -#if _CALL_ELF == 2 - if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0) - bytes += intarg_count * sizeof (long); -#else - if (intarg_count > NUM_GPR_ARG_REGISTERS64) - bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long); -#endif - - /* 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; -} - -ffi_status FFI_HIDDEN -ffi_prep_cif_linux64 (ffi_cif *cif) -{ - if ((cif->abi & FFI_LINUX) != 0) - cif->nfixedargs = cif->nargs; -#if _CALL_ELF != 2 - else if (cif->abi == FFI_COMPAT_LINUX64) - { - /* This call is from old code. Don't touch cif->nfixedargs - since old code will be using a smaller cif. */ - cif->flags |= FLAG_COMPAT; - /* Translate to new abi value. */ - cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128; - } -#endif - else - return FFI_BAD_ABI; - return ffi_prep_cif_linux64_core (cif); -} - -ffi_status FFI_HIDDEN -ffi_prep_cif_linux64_var (ffi_cif *cif, - unsigned int nfixedargs, - unsigned int ntotalargs MAYBE_UNUSED) -{ - if ((cif->abi & FFI_LINUX) != 0) - cif->nfixedargs = nfixedargs; -#if _CALL_ELF != 2 - else if (cif->abi == FFI_COMPAT_LINUX64) - { - /* This call is from old code. Don't touch cif->nfixedargs - since old code will be using a smaller cif. */ - cif->flags |= FLAG_COMPAT; - /* Translate to new abi value. */ - cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128; - } -#endif - else - return FFI_BAD_ABI; -#if _CALL_ELF == 2 - cif->flags |= FLAG_ARG_NEEDS_PSAVE; -#endif - return ffi_prep_cif_linux64_core (cif); -} - - -/* 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 | | - |--------------------------------------------| | - | VEC registers v2-v13 (optional) 12*16 | | - |--------------------------------------------| | - | 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; - float128 *f128; - size_t p; - } 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 f1, and grows upwards as - we use FPR registers. */ - valp fpr_base; - unsigned int fparg_count; - - /* 'vec_base' points at the space for v2, and grows upwards as - we use vector registers. */ - valp vec_base; - unsigned int vecarg_count; - - unsigned int i, words, nargs, nfixedargs; - 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; - float128 **f128; - } p_argv; - unsigned long gprvalue; - unsigned long align; - - 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; -#if _CALL_ELF == 2 - rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64; -#else - rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64; -#endif - fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64; - fparg_count = 0; - /* Place the vector args below the FPRs, if used, else the GPRs. */ - if (ecif->cif->flags & FLAG_FP_ARGUMENTS) - vec_base.p = fpr_base.p & ~0xF; - else - vec_base.p = gpr_base.p; - vec_base.f128 -= NUM_VEC_ARG_REGISTERS64; - vecarg_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 (((unsigned long) gpr_base.c & 0xF) == 0); - FFI_ASSERT (((unsigned long) gpr_end.c & 0xF) == 0); - FFI_ASSERT (((unsigned long) vec_base.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; - nargs = ecif->cif->nargs; -#if _CALL_ELF != 2 - nfixedargs = (unsigned) -1; - if ((flags & FLAG_COMPAT) == 0) -#endif - nfixedargs = ecif->cif->nfixedargs; - for (ptr = ecif->cif->arg_types, i = 0; - i < nargs; - i++, ptr++, p_argv.v++) - { - unsigned int elt, elnum; - - switch ((*ptr)->type) - { -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: - if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - { - next_arg.p = FFI_ALIGN (next_arg.p, 16); - if (next_arg.ul == gpr_end.ul) - next_arg.ul = rest.ul; - if (vecarg_count < NUM_VEC_ARG_REGISTERS64 && i < nfixedargs) - *vec_base.f128++ = **p_argv.f128; - else - *next_arg.f128 = **p_argv.f128; - if (++next_arg.f128 == gpr_end.f128) - next_arg.f128 = rest.f128; - vecarg_count++; - FFI_ASSERT (__LDBL_MANT_DIG__ == 113); - FFI_ASSERT (flags & FLAG_VEC_ARGUMENTS); - break; - } - if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) - { - double_tmp = (*p_argv.d)[0]; - if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) - { - *fpr_base.d++ = double_tmp; -# if _CALL_ELF != 2 - if ((flags & FLAG_COMPAT) != 0) - *next_arg.d = double_tmp; -# endif - } - else - *next_arg.d = double_tmp; - if (++next_arg.ul == gpr_end.ul) - next_arg.ul = rest.ul; - fparg_count++; - double_tmp = (*p_argv.d)[1]; - if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) - { - *fpr_base.d++ = double_tmp; -# if _CALL_ELF != 2 - if ((flags & FLAG_COMPAT) != 0) - *next_arg.d = double_tmp; -# endif - } - else - *next_arg.d = double_tmp; - if (++next_arg.ul == gpr_end.ul) - next_arg.ul = rest.ul; - fparg_count++; - FFI_ASSERT (__LDBL_MANT_DIG__ == 106); - FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); - break; - } - /* Fall through. */ -#endif - case FFI_TYPE_DOUBLE: -#if _CALL_ELF != 2 - do_double: -#endif - double_tmp = **p_argv.d; - if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) - { - *fpr_base.d++ = double_tmp; -#if _CALL_ELF != 2 - if ((flags & FLAG_COMPAT) != 0) - *next_arg.d = double_tmp; -#endif - } - else - *next_arg.d = double_tmp; - if (++next_arg.ul == gpr_end.ul) - next_arg.ul = rest.ul; - fparg_count++; - FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); - break; - - case FFI_TYPE_FLOAT: -#if _CALL_ELF != 2 - do_float: -#endif - double_tmp = **p_argv.f; - if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) - { - *fpr_base.d++ = double_tmp; -#if _CALL_ELF != 2 - if ((flags & FLAG_COMPAT) != 0) - { -# ifndef __LITTLE_ENDIAN__ - next_arg.f[1] = (float) double_tmp; -# else - next_arg.f[0] = (float) double_tmp; -# endif - } -#endif - } - else - { -# ifndef __LITTLE_ENDIAN__ - next_arg.f[1] = (float) double_tmp; -# else - next_arg.f[0] = (float) double_tmp; -# endif - } - if (++next_arg.ul == gpr_end.ul) - next_arg.ul = rest.ul; - fparg_count++; - FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); - break; - - case FFI_TYPE_STRUCT: - if ((ecif->cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0) - { - align = (*ptr)->alignment; - if (align > 16) - align = 16; - if (align > 1) - { - next_arg.p = FFI_ALIGN (next_arg.p, align); - if (next_arg.ul == gpr_end.ul) - next_arg.ul = rest.ul; - } - } - elt = discover_homogeneous_aggregate (ecif->cif->abi, *ptr, &elnum); - if (elt) - { -#if _CALL_ELF == 2 - union { - void *v; - float *f; - double *d; - float128 *f128; - } arg; - - arg.v = *p_argv.v; -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - if (elt == FFI_TYPE_LONGDOUBLE && - (ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - { - do - { - if (vecarg_count < NUM_VEC_ARG_REGISTERS64 - && i < nfixedargs) - *vec_base.f128++ = *arg.f128++; - else - *next_arg.f128 = *arg.f128++; - if (++next_arg.f128 == gpr_end.f128) - next_arg.f128 = rest.f128; - vecarg_count++; - } - while (--elnum != 0); - } - else -#endif - if (elt == FFI_TYPE_FLOAT) - { - do - { - double_tmp = *arg.f++; - if (fparg_count < NUM_FPR_ARG_REGISTERS64 - && i < nfixedargs) - *fpr_base.d++ = double_tmp; - else - *next_arg.f = (float) double_tmp; - if (++next_arg.f == gpr_end.f) - next_arg.f = rest.f; - fparg_count++; - } - while (--elnum != 0); - if ((next_arg.p & 7) != 0) - if (++next_arg.f == gpr_end.f) - next_arg.f = rest.f; - } - else - do - { - double_tmp = *arg.d++; - if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) - *fpr_base.d++ = double_tmp; - else - *next_arg.d = double_tmp; - if (++next_arg.d == gpr_end.d) - next_arg.d = rest.d; - fparg_count++; - } - while (--elnum != 0); -#else - if (elt == FFI_TYPE_FLOAT) - goto do_float; - else - goto do_double; -#endif - } - else - { - 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; - -#ifndef __LITTLE_ENDIAN__ - /* Structures with size less than eight bytes are passed - left-padded. */ - if ((*ptr)->size < 8) - where += 8 - (*ptr)->size; -#endif - 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)); -} - - -#if _CALL_ELF == 2 -#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_HIDDEN -ffi_prep_closure_loc_linux64 (ffi_closure *closure, - ffi_cif *cif, - void (*fun) (ffi_cif *, void *, void **, void *), - void *user_data, - void *codeloc) -{ -#if _CALL_ELF == 2 - unsigned int *tramp = (unsigned int *) &closure->tramp[0]; - - if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI) - return FFI_BAD_ABI; - - tramp[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */ - tramp[1] = 0xe98c0010; /* ld 12,1f-0b(12) */ - tramp[2] = 0x7d8903a6; /* mtctr 12 */ - tramp[3] = 0x4e800420; /* bctr */ - /* 1: .quad function_addr */ - /* 2: .quad context */ - *(void **) &tramp[4] = (void *) ffi_closure_LINUX64; - *(void **) &tramp[6] = codeloc; - flush_icache ((char *) tramp, (char *) codeloc, 4 * 4); -#else - void **tramp = (void **) &closure->tramp[0]; - - if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI) - return FFI_BAD_ABI; - - /* Copy function address and TOC from ffi_closure_LINUX64 OPD. */ - memcpy (&tramp[0], (void **) ffi_closure_LINUX64, sizeof (void *)); - tramp[1] = codeloc; - memcpy (&tramp[2], (void **) ffi_closure_LINUX64 + 1, sizeof (void *)); -#endif - - closure->cif = cif; - closure->fun = fun; - closure->user_data = user_data; - - return FFI_OK; -} - - -int FFI_HIDDEN -ffi_closure_helper_LINUX64 (ffi_cif *cif, - void (*fun) (ffi_cif *, void *, void **, void *), - void *user_data, - void *rvalue, - unsigned long *pst, - ffi_dblfl *pfr, - float128 *pvec) -{ - /* 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 */ - /* pvec is the pointer to where v2-v13 are stored in ffi_closure_LINUX64 */ - - void **avalue; - ffi_type **arg_types; - unsigned long i, avn, nfixedargs; - ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; - float128 *end_pvec = pvec + NUM_VEC_ARG_REGISTERS64; - unsigned long align; - - 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 - && (cif->flags & FLAG_RETURNS_SMST) == 0) - { - rvalue = (void *) *pst; - pst++; - } - - i = 0; - avn = cif->nargs; -#if _CALL_ELF != 2 - nfixedargs = (unsigned) -1; - if ((cif->flags & FLAG_COMPAT) == 0) -#endif - nfixedargs = cif->nfixedargs; - arg_types = cif->arg_types; - - /* Grab the addresses of the arguments from the stack frame. */ - while (i < avn) - { - unsigned int elt, elnum; - - switch (arg_types[i]->type) - { - case FFI_TYPE_SINT8: - case FFI_TYPE_UINT8: -#ifndef __LITTLE_ENDIAN__ - avalue[i] = (char *) pst + 7; - pst++; - break; -#endif - - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT16: -#ifndef __LITTLE_ENDIAN__ - avalue[i] = (char *) pst + 6; - pst++; - break; -#endif - - case FFI_TYPE_SINT32: - case FFI_TYPE_UINT32: -#ifndef __LITTLE_ENDIAN__ - avalue[i] = (char *) pst + 4; - pst++; - break; -#endif - - case FFI_TYPE_SINT64: - case FFI_TYPE_UINT64: - case FFI_TYPE_POINTER: - avalue[i] = pst; - pst++; - break; - - case FFI_TYPE_STRUCT: - if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0) - { - align = arg_types[i]->alignment; - if (align > 16) - align = 16; - if (align > 1) - pst = (unsigned long *) FFI_ALIGN ((size_t) pst, align); - } - elt = discover_homogeneous_aggregate (cif->abi, arg_types[i], &elnum); - if (elt) - { -#if _CALL_ELF == 2 - union { - void *v; - unsigned long *ul; - float *f; - double *d; - float128 *f128; - size_t p; - } to, from; - - /* Repackage the aggregate from its parts. The - aggregate size is not greater than the space taken by - the registers so store back to the register/parameter - save arrays. */ -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - if (elt == FFI_TYPE_LONGDOUBLE && - (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - { - if (pvec + elnum <= end_pvec) - to.v = pvec; - else - to.v = pst; - } - else -#endif - if (pfr + elnum <= end_pfr) - to.v = pfr; - else - to.v = pst; - - avalue[i] = to.v; - from.ul = pst; -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - if (elt == FFI_TYPE_LONGDOUBLE && - (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - { - do - { - if (pvec < end_pvec && i < nfixedargs) - *to.f128 = *pvec++; - else - *to.f128 = *from.f128; - to.f128++; - from.f128++; - } - while (--elnum != 0); - } - else -#endif - if (elt == FFI_TYPE_FLOAT) - { - do - { - if (pfr < end_pfr && i < nfixedargs) - { - *to.f = (float) pfr->d; - pfr++; - } - else - *to.f = *from.f; - to.f++; - from.f++; - } - while (--elnum != 0); - } - else - { - do - { - if (pfr < end_pfr && i < nfixedargs) - { - *to.d = pfr->d; - pfr++; - } - else - *to.d = *from.d; - to.d++; - from.d++; - } - while (--elnum != 0); - } -#else - if (elt == FFI_TYPE_FLOAT) - goto do_float; - else - goto do_double; -#endif - } - else - { -#ifndef __LITTLE_ENDIAN__ - /* 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 -#endif - avalue[i] = pst; - } - pst += (arg_types[i]->size + 7) / 8; - break; - -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: - if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) - { - if (((unsigned long) pst & 0xF) != 0) - ++pst; - if (pvec < end_pvec && i < nfixedargs) - avalue[i] = pvec++; - else - avalue[i] = pst; - pst += 2; - break; - } - else if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) - { - if (pfr + 1 < end_pfr && i + 1 < nfixedargs) - { - avalue[i] = pfr; - pfr += 2; - } - else - { - if (pfr < end_pfr && i < nfixedargs) - { - /* 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; - } - /* Fall through. */ -#endif - case FFI_TYPE_DOUBLE: -#if _CALL_ELF != 2 - do_double: -#endif - /* On the outgoing stack all values are aligned to 8 */ - /* there are 13 64bit floating point registers */ - - if (pfr < end_pfr && i < nfixedargs) - { - avalue[i] = pfr; - pfr++; - } - else - avalue[i] = pst; - pst++; - break; - - case FFI_TYPE_FLOAT: -#if _CALL_ELF != 2 - do_float: -#endif - if (pfr < end_pfr && i < nfixedargs) - { - /* Float values are stored as doubles in the - ffi_closure_LINUX64 code. Fix them here. */ - pfr->f = (float) pfr->d; - avalue[i] = pfr; - pfr++; - } - else - { -#ifndef __LITTLE_ENDIAN__ - avalue[i] = (char *) pst + 4; -#else - avalue[i] = pst; -#endif - } - pst++; - break; - - default: - FFI_ASSERT (0); - } - - i++; - } - - (*fun) (cif, rvalue, avalue, user_data); - - /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ - if ((cif->flags & FLAG_RETURNS_SMST) != 0) - { - if ((cif->flags & (FLAG_RETURNS_FP | FLAG_RETURNS_VEC)) == 0) - return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1; - else if ((cif->flags & FLAG_RETURNS_VEC) != 0) - return FFI_V2_TYPE_VECTOR_HOMOG; - else if ((cif->flags & FLAG_RETURNS_64BITS) != 0) - return FFI_V2_TYPE_DOUBLE_HOMOG; - else - return FFI_V2_TYPE_FLOAT_HOMOG; - } - if ((cif->flags & FLAG_RETURNS_VEC) != 0) - return FFI_V2_TYPE_VECTOR; - return cif->rtype->type; -} -#endif +/* ----------------------------------------------------------------------- + ffi_linux64.c - Copyright (C) 2013 IBM + Copyright (C) 2011 Anthony Green + Copyright (C) 2011 Kyle Moffett + Copyright (C) 2008 Red Hat, Inc + Copyright (C) 2007, 2008 Free Software Foundation, Inc + Copyright (c) 1998 Geoffrey Keating + + 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" + +#ifdef POWERPC64 +#include "ffi_common.h" +#include "ffi_powerpc.h" + + +/* About the LINUX64 ABI. */ +enum { + NUM_GPR_ARG_REGISTERS64 = 8, + NUM_FPR_ARG_REGISTERS64 = 13, + NUM_VEC_ARG_REGISTERS64 = 12, +}; +enum { ASM_NEEDS_REGISTERS64 = 4 }; + + +#if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +/* Adjust size of ffi_type_longdouble. */ +void FFI_HIDDEN +ffi_prep_types_linux64 (ffi_abi abi) +{ + if ((abi & (FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128)) == FFI_LINUX) + { + ffi_type_longdouble.size = 8; + ffi_type_longdouble.alignment = 8; + } + else + { + ffi_type_longdouble.size = 16; + ffi_type_longdouble.alignment = 16; + } +} +#endif + + +static unsigned int +discover_homogeneous_aggregate (ffi_abi abi, + const ffi_type *t, + unsigned int *elnum) +{ + switch (t->type) + { +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + /* 64-bit long doubles are equivalent to doubles. */ + if ((abi & FFI_LINUX_LONG_DOUBLE_128) == 0) + { + *elnum = 1; + return FFI_TYPE_DOUBLE; + } + /* IBM extended precision values use unaligned pairs + of FPRs, but according to the ABI must be considered + distinct from doubles. They are also limited to a + maximum of four members in a homogeneous aggregate. */ + else if ((abi & FFI_LINUX_LONG_DOUBLE_IEEE128) == 0) + { + *elnum = 2; + return FFI_TYPE_LONGDOUBLE; + } + /* Fall through. */ +#endif + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + *elnum = 1; + return (int) t->type; + + case FFI_TYPE_STRUCT:; + { + unsigned int base_elt = 0, total_elnum = 0; + ffi_type **el = t->elements; + while (*el) + { + unsigned int el_elt, el_elnum = 0; + el_elt = discover_homogeneous_aggregate (abi, *el, &el_elnum); + if (el_elt == 0 + || (base_elt && base_elt != el_elt)) + return 0; + base_elt = el_elt; + total_elnum += el_elnum; +#if _CALL_ELF == 2 + if (total_elnum > 8) + return 0; +#else + if (total_elnum > 1) + return 0; +#endif + el++; + } + *elnum = total_elnum; + return base_elt; + } + + default: + return 0; + } +} + + +/* Perform machine dependent cif processing */ +static ffi_status +ffi_prep_cif_linux64_core (ffi_cif *cif) +{ + ffi_type **ptr; + unsigned bytes; + unsigned i, fparg_count = 0, intarg_count = 0, vecarg_count = 0; + unsigned flags = cif->flags; + unsigned elt, elnum, rtype; + +#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE + /* If compiled without long double support... */ + if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0 || + (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + return FFI_BAD_ABI; +#elif !defined(__VEC__) + /* If compiled without vector register support (used by assembly)... */ + if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + return FFI_BAD_ABI; +#else + /* If the IEEE128 flag is set, but long double is only 64 bits wide... */ + if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) == 0 && + (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + return FFI_BAD_ABI; +#endif + + /* The machine-independent calculation of cif->bytes doesn't work + for us. Redo the calculation. */ +#if _CALL_ELF == 2 + /* Space for backchain, CR, LR, TOC and the asm's temp regs. */ + bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long); + + /* Space for the general registers. */ + bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long); +#else + /* 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); +#endif + + /* Return value handling. */ + rtype = cif->rtype->type; +#if _CALL_ELF == 2 +homogeneous: +#endif + switch (rtype) + { +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + { + flags |= FLAG_RETURNS_VEC; + break; + } + if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) + flags |= FLAG_RETURNS_128BITS; + /* Fall through. */ +#endif + case FFI_TYPE_DOUBLE: + flags |= FLAG_RETURNS_64BITS; + /* Fall through. */ + case FFI_TYPE_FLOAT: + flags |= FLAG_RETURNS_FP; + break; + + case FFI_TYPE_UINT128: + flags |= FLAG_RETURNS_128BITS; + /* Fall through. */ + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + flags |= FLAG_RETURNS_64BITS; + break; + + case FFI_TYPE_STRUCT: +#if _CALL_ELF == 2 + elt = discover_homogeneous_aggregate (cif->abi, cif->rtype, &elnum); + if (elt) + { + flags |= FLAG_RETURNS_SMST; + rtype = elt; + goto homogeneous; + } + if (cif->rtype->size <= 16) + { + flags |= FLAG_RETURNS_SMST; + break; + } +#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; + } + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + unsigned int align; + + switch ((*ptr)->type) + { +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + { + vecarg_count++; + /* Align to 16 bytes, plus the 16-byte argument. */ + intarg_count = (intarg_count + 3) & ~0x1; + if (vecarg_count > NUM_VEC_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + break; + } + if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) + { + fparg_count++; + intarg_count++; + } + /* Fall through. */ +#endif + case FFI_TYPE_DOUBLE: + case FFI_TYPE_FLOAT: + fparg_count++; + intarg_count++; + if (fparg_count > NUM_FPR_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + break; + + case FFI_TYPE_STRUCT: + if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0) + { + align = (*ptr)->alignment; + if (align > 16) + align = 16; + align = align / 8; + if (align > 1) + intarg_count = FFI_ALIGN (intarg_count, align); + } + intarg_count += ((*ptr)->size + 7) / 8; + elt = discover_homogeneous_aggregate (cif->abi, *ptr, &elnum); +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + if (elt == FFI_TYPE_LONGDOUBLE && + (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + { + vecarg_count += elnum; + if (vecarg_count > NUM_VEC_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + break; + } + else +#endif + if (elt) + { + fparg_count += elnum; + if (fparg_count > NUM_FPR_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + } + else + { + if (intarg_count > NUM_GPR_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + } + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + /* Everything else is passed as a 8-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; + if (intarg_count > NUM_GPR_ARG_REGISTERS64) + flags |= FLAG_ARG_NEEDS_PSAVE; + break; + default: + FFI_ASSERT (0); + } + } + + if (fparg_count != 0) + flags |= FLAG_FP_ARGUMENTS; + if (intarg_count > 4) + flags |= FLAG_4_GPR_ARGUMENTS; + if (vecarg_count != 0) + flags |= FLAG_VEC_ARGUMENTS; + + /* Space for the FPR registers, if needed. */ + if (fparg_count != 0) + bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double); + /* Space for the vector registers, if needed, aligned to 16 bytes. */ + if (vecarg_count != 0) { + bytes = (bytes + 15) & ~0xF; + bytes += NUM_VEC_ARG_REGISTERS64 * sizeof (float128); + } + + /* Stack space. */ +#if _CALL_ELF == 2 + if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0) + bytes += intarg_count * sizeof (long); +#else + if (intarg_count > NUM_GPR_ARG_REGISTERS64) + bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long); +#endif + + /* 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; +} + +ffi_status FFI_HIDDEN +ffi_prep_cif_linux64 (ffi_cif *cif) +{ + if ((cif->abi & FFI_LINUX) != 0) + cif->nfixedargs = cif->nargs; +#if _CALL_ELF != 2 + else if (cif->abi == FFI_COMPAT_LINUX64) + { + /* This call is from old code. Don't touch cif->nfixedargs + since old code will be using a smaller cif. */ + cif->flags |= FLAG_COMPAT; + /* Translate to new abi value. */ + cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128; + } +#endif + else + return FFI_BAD_ABI; + return ffi_prep_cif_linux64_core (cif); +} + +ffi_status FFI_HIDDEN +ffi_prep_cif_linux64_var (ffi_cif *cif, + unsigned int nfixedargs, + unsigned int ntotalargs MAYBE_UNUSED) +{ + if ((cif->abi & FFI_LINUX) != 0) + cif->nfixedargs = nfixedargs; +#if _CALL_ELF != 2 + else if (cif->abi == FFI_COMPAT_LINUX64) + { + /* This call is from old code. Don't touch cif->nfixedargs + since old code will be using a smaller cif. */ + cif->flags |= FLAG_COMPAT; + /* Translate to new abi value. */ + cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128; + } +#endif + else + return FFI_BAD_ABI; +#if _CALL_ELF == 2 + cif->flags |= FLAG_ARG_NEEDS_PSAVE; +#endif + return ffi_prep_cif_linux64_core (cif); +} + + +/* 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 | | + |--------------------------------------------| | + | VEC registers v2-v13 (optional) 12*16 | | + |--------------------------------------------| | + | 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; + float128 *f128; + size_t p; + } 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 f1, and grows upwards as + we use FPR registers. */ + valp fpr_base; + unsigned int fparg_count; + + /* 'vec_base' points at the space for v2, and grows upwards as + we use vector registers. */ + valp vec_base; + unsigned int vecarg_count; + + unsigned int i, words, nargs, nfixedargs; + 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; + float128 **f128; + } p_argv; + unsigned long gprvalue; + unsigned long align; + + 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; +#if _CALL_ELF == 2 + rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64; +#else + rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64; +#endif + fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64; + fparg_count = 0; + /* Place the vector args below the FPRs, if used, else the GPRs. */ + if (ecif->cif->flags & FLAG_FP_ARGUMENTS) + vec_base.p = fpr_base.p & ~0xF; + else + vec_base.p = gpr_base.p; + vec_base.f128 -= NUM_VEC_ARG_REGISTERS64; + vecarg_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 (((unsigned long) gpr_base.c & 0xF) == 0); + FFI_ASSERT (((unsigned long) gpr_end.c & 0xF) == 0); + FFI_ASSERT (((unsigned long) vec_base.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; + nargs = ecif->cif->nargs; +#if _CALL_ELF != 2 + nfixedargs = (unsigned) -1; + if ((flags & FLAG_COMPAT) == 0) +#endif + nfixedargs = ecif->cif->nfixedargs; + for (ptr = ecif->cif->arg_types, i = 0; + i < nargs; + i++, ptr++, p_argv.v++) + { + unsigned int elt, elnum; + + switch ((*ptr)->type) + { +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + { + next_arg.p = FFI_ALIGN (next_arg.p, 16); + if (next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + if (vecarg_count < NUM_VEC_ARG_REGISTERS64 && i < nfixedargs) + *vec_base.f128++ = **p_argv.f128; + else + *next_arg.f128 = **p_argv.f128; + if (++next_arg.f128 == gpr_end.f128) + next_arg.f128 = rest.f128; + vecarg_count++; + FFI_ASSERT (__LDBL_MANT_DIG__ == 113); + FFI_ASSERT (flags & FLAG_VEC_ARGUMENTS); + break; + } + if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) + { + double_tmp = (*p_argv.d)[0]; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) + { + *fpr_base.d++ = double_tmp; +# if _CALL_ELF != 2 + if ((flags & FLAG_COMPAT) != 0) + *next_arg.d = double_tmp; +# endif + } + else + *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + fparg_count++; + double_tmp = (*p_argv.d)[1]; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) + { + *fpr_base.d++ = double_tmp; +# if _CALL_ELF != 2 + if ((flags & FLAG_COMPAT) != 0) + *next_arg.d = double_tmp; +# endif + } + else + *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + fparg_count++; + FFI_ASSERT (__LDBL_MANT_DIG__ == 106); + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + } + /* Fall through. */ +#endif + case FFI_TYPE_DOUBLE: +#if _CALL_ELF != 2 + do_double: +#endif + double_tmp = **p_argv.d; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) + { + *fpr_base.d++ = double_tmp; +#if _CALL_ELF != 2 + if ((flags & FLAG_COMPAT) != 0) + *next_arg.d = double_tmp; +#endif + } + else + *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_FLOAT: +#if _CALL_ELF != 2 + do_float: +#endif + double_tmp = **p_argv.f; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) + { + *fpr_base.d++ = double_tmp; +#if _CALL_ELF != 2 + if ((flags & FLAG_COMPAT) != 0) + { +# ifndef __LITTLE_ENDIAN__ + next_arg.f[1] = (float) double_tmp; +# else + next_arg.f[0] = (float) double_tmp; +# endif + } +#endif + } + else + { +# ifndef __LITTLE_ENDIAN__ + next_arg.f[1] = (float) double_tmp; +# else + next_arg.f[0] = (float) double_tmp; +# endif + } + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_STRUCT: + if ((ecif->cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0) + { + align = (*ptr)->alignment; + if (align > 16) + align = 16; + if (align > 1) + { + next_arg.p = FFI_ALIGN (next_arg.p, align); + if (next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + } + } + elt = discover_homogeneous_aggregate (ecif->cif->abi, *ptr, &elnum); + if (elt) + { +#if _CALL_ELF == 2 + union { + void *v; + float *f; + double *d; + float128 *f128; + } arg; + + arg.v = *p_argv.v; +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + if (elt == FFI_TYPE_LONGDOUBLE && + (ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + { + do + { + if (vecarg_count < NUM_VEC_ARG_REGISTERS64 + && i < nfixedargs) + *vec_base.f128++ = *arg.f128++; + else + *next_arg.f128 = *arg.f128++; + if (++next_arg.f128 == gpr_end.f128) + next_arg.f128 = rest.f128; + vecarg_count++; + } + while (--elnum != 0); + } + else +#endif + if (elt == FFI_TYPE_FLOAT) + { + do + { + double_tmp = *arg.f++; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 + && i < nfixedargs) + *fpr_base.d++ = double_tmp; + else + *next_arg.f = (float) double_tmp; + if (++next_arg.f == gpr_end.f) + next_arg.f = rest.f; + fparg_count++; + } + while (--elnum != 0); + if ((next_arg.p & 7) != 0) + if (++next_arg.f == gpr_end.f) + next_arg.f = rest.f; + } + else + do + { + double_tmp = *arg.d++; + if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs) + *fpr_base.d++ = double_tmp; + else + *next_arg.d = double_tmp; + if (++next_arg.d == gpr_end.d) + next_arg.d = rest.d; + fparg_count++; + } + while (--elnum != 0); +#else + if (elt == FFI_TYPE_FLOAT) + goto do_float; + else + goto do_double; +#endif + } + else + { + 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; + +#ifndef __LITTLE_ENDIAN__ + /* Structures with size less than eight bytes are passed + left-padded. */ + if ((*ptr)->size < 8) + where += 8 - (*ptr)->size; +#endif + 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)); +} + + +#if _CALL_ELF == 2 +#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_HIDDEN +ffi_prep_closure_loc_linux64 (ffi_closure *closure, + ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + void *codeloc) +{ +#if _CALL_ELF == 2 + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + + if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI) + return FFI_BAD_ABI; + + tramp[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */ + tramp[1] = 0xe98c0010; /* ld 12,1f-0b(12) */ + tramp[2] = 0x7d8903a6; /* mtctr 12 */ + tramp[3] = 0x4e800420; /* bctr */ + /* 1: .quad function_addr */ + /* 2: .quad context */ + *(void **) &tramp[4] = (void *) ffi_closure_LINUX64; + *(void **) &tramp[6] = codeloc; + flush_icache ((char *) tramp, (char *) codeloc, 4 * 4); +#else + void **tramp = (void **) &closure->tramp[0]; + + if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI) + return FFI_BAD_ABI; + + /* Copy function address and TOC from ffi_closure_LINUX64 OPD. */ + memcpy (&tramp[0], (void **) ffi_closure_LINUX64, sizeof (void *)); + tramp[1] = codeloc; + memcpy (&tramp[2], (void **) ffi_closure_LINUX64 + 1, sizeof (void *)); +#endif + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + + +int FFI_HIDDEN +ffi_closure_helper_LINUX64 (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + void *rvalue, + unsigned long *pst, + ffi_dblfl *pfr, + float128 *pvec) +{ + /* 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 */ + /* pvec is the pointer to where v2-v13 are stored in ffi_closure_LINUX64 */ + + void **avalue; + ffi_type **arg_types; + unsigned long i, avn, nfixedargs; + ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; + float128 *end_pvec = pvec + NUM_VEC_ARG_REGISTERS64; + unsigned long align; + + 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 + && (cif->flags & FLAG_RETURNS_SMST) == 0) + { + rvalue = (void *) *pst; + pst++; + } + + i = 0; + avn = cif->nargs; +#if _CALL_ELF != 2 + nfixedargs = (unsigned) -1; + if ((cif->flags & FLAG_COMPAT) == 0) +#endif + nfixedargs = cif->nfixedargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + unsigned int elt, elnum; + + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: +#ifndef __LITTLE_ENDIAN__ + avalue[i] = (char *) pst + 7; + pst++; + break; +#endif + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: +#ifndef __LITTLE_ENDIAN__ + avalue[i] = (char *) pst + 6; + pst++; + break; +#endif + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: +#ifndef __LITTLE_ENDIAN__ + avalue[i] = (char *) pst + 4; + pst++; + break; +#endif + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + avalue[i] = pst; + pst++; + break; + + case FFI_TYPE_STRUCT: + if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0) + { + align = arg_types[i]->alignment; + if (align > 16) + align = 16; + if (align > 1) + pst = (unsigned long *) FFI_ALIGN ((size_t) pst, align); + } + elt = discover_homogeneous_aggregate (cif->abi, arg_types[i], &elnum); + if (elt) + { +#if _CALL_ELF == 2 + union { + void *v; + unsigned long *ul; + float *f; + double *d; + float128 *f128; + size_t p; + } to, from; + + /* Repackage the aggregate from its parts. The + aggregate size is not greater than the space taken by + the registers so store back to the register/parameter + save arrays. */ +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + if (elt == FFI_TYPE_LONGDOUBLE && + (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + { + if (pvec + elnum <= end_pvec) + to.v = pvec; + else + to.v = pst; + } + else +#endif + if (pfr + elnum <= end_pfr) + to.v = pfr; + else + to.v = pst; + + avalue[i] = to.v; + from.ul = pst; +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + if (elt == FFI_TYPE_LONGDOUBLE && + (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + { + do + { + if (pvec < end_pvec && i < nfixedargs) + *to.f128 = *pvec++; + else + *to.f128 = *from.f128; + to.f128++; + from.f128++; + } + while (--elnum != 0); + } + else +#endif + if (elt == FFI_TYPE_FLOAT) + { + do + { + if (pfr < end_pfr && i < nfixedargs) + { + *to.f = (float) pfr->d; + pfr++; + } + else + *to.f = *from.f; + to.f++; + from.f++; + } + while (--elnum != 0); + } + else + { + do + { + if (pfr < end_pfr && i < nfixedargs) + { + *to.d = pfr->d; + pfr++; + } + else + *to.d = *from.d; + to.d++; + from.d++; + } + while (--elnum != 0); + } +#else + if (elt == FFI_TYPE_FLOAT) + goto do_float; + else + goto do_double; +#endif + } + else + { +#ifndef __LITTLE_ENDIAN__ + /* 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 +#endif + avalue[i] = pst; + } + pst += (arg_types[i]->size + 7) / 8; + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0) + { + if (((unsigned long) pst & 0xF) != 0) + ++pst; + if (pvec < end_pvec && i < nfixedargs) + avalue[i] = pvec++; + else + avalue[i] = pst; + pst += 2; + break; + } + else if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) + { + if (pfr + 1 < end_pfr && i + 1 < nfixedargs) + { + avalue[i] = pfr; + pfr += 2; + } + else + { + if (pfr < end_pfr && i < nfixedargs) + { + /* 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; + } + /* Fall through. */ +#endif + case FFI_TYPE_DOUBLE: +#if _CALL_ELF != 2 + do_double: +#endif + /* On the outgoing stack all values are aligned to 8 */ + /* there are 13 64bit floating point registers */ + + if (pfr < end_pfr && i < nfixedargs) + { + avalue[i] = pfr; + pfr++; + } + else + avalue[i] = pst; + pst++; + break; + + case FFI_TYPE_FLOAT: +#if _CALL_ELF != 2 + do_float: +#endif + if (pfr < end_pfr && i < nfixedargs) + { + /* Float values are stored as doubles in the + ffi_closure_LINUX64 code. Fix them here. */ + pfr->f = (float) pfr->d; + avalue[i] = pfr; + pfr++; + } + else + { +#ifndef __LITTLE_ENDIAN__ + avalue[i] = (char *) pst + 4; +#else + avalue[i] = pst; +#endif + } + pst++; + break; + + default: + FFI_ASSERT (0); + } + + i++; + } + + (*fun) (cif, rvalue, avalue, user_data); + + /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ + if ((cif->flags & FLAG_RETURNS_SMST) != 0) + { + if ((cif->flags & (FLAG_RETURNS_FP | FLAG_RETURNS_VEC)) == 0) + return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1; + else if ((cif->flags & FLAG_RETURNS_VEC) != 0) + return FFI_V2_TYPE_VECTOR_HOMOG; + else if ((cif->flags & FLAG_RETURNS_64BITS) != 0) + return FFI_V2_TYPE_DOUBLE_HOMOG; + else + return FFI_V2_TYPE_FLOAT_HOMOG; + } + if ((cif->flags & FLAG_RETURNS_VEC) != 0) + return FFI_V2_TYPE_VECTOR; + return cif->rtype->type; +} +#endif diff --git a/contrib/restricted/libffi/src/powerpc/ffi_powerpc.h b/contrib/restricted/libffi/src/powerpc/ffi_powerpc.h index 5ee2a7095a..7956cf81d0 100644 --- a/contrib/restricted/libffi/src/powerpc/ffi_powerpc.h +++ b/contrib/restricted/libffi/src/powerpc/ffi_powerpc.h @@ -1,105 +1,105 @@ -/* ----------------------------------------------------------------------- - ffi_powerpc.h - Copyright (C) 2013 IBM - Copyright (C) 2011 Anthony Green - Copyright (C) 2011 Kyle Moffett - Copyright (C) 2008 Red Hat, Inc - Copyright (C) 2007, 2008 Free Software Foundation, Inc - Copyright (c) 1998 Geoffrey Keating - - 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. - ----------------------------------------------------------------------- */ - -enum { - /* The assembly depends on these exact flags. */ - /* These go in cr7 */ - FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */ - FLAG_RETURNS_NOTHING = 1 << (31-30), - FLAG_RETURNS_FP = 1 << (31-29), - FLAG_RETURNS_VEC = 1 << (31-28), - - /* These go in cr6 */ - FLAG_RETURNS_64BITS = 1 << (31-27), - FLAG_RETURNS_128BITS = 1 << (31-26), - - FLAG_COMPAT = 1 << (31- 8), /* Not used by assembly */ - - /* These go in cr1 */ - FLAG_ARG_NEEDS_COPY = 1 << (31- 7), /* Used by sysv code */ - FLAG_ARG_NEEDS_PSAVE = FLAG_ARG_NEEDS_COPY, /* Used by linux64 code */ - FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ - FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), - FLAG_RETVAL_REFERENCE = 1 << (31- 4), - FLAG_VEC_ARGUMENTS = 1 << (31- 3), -}; - -typedef union -{ - float f; - double d; -} ffi_dblfl; - -#if defined(__FLOAT128_TYPE__) -typedef _Float128 float128; -#elif defined(__FLOAT128__) -typedef __float128 float128; -#else -typedef __int128 float128; -#endif - -void FFI_HIDDEN ffi_closure_SYSV (void); -void FFI_HIDDEN ffi_go_closure_sysv (void); -void FFI_HIDDEN ffi_call_SYSV(extended_cif *, void (*)(void), void *, - unsigned, void *, int); - -void FFI_HIDDEN ffi_prep_types_sysv (ffi_abi); -ffi_status FFI_HIDDEN ffi_prep_cif_sysv (ffi_cif *); -ffi_status FFI_HIDDEN ffi_prep_closure_loc_sysv (ffi_closure *, - ffi_cif *, - void (*) (ffi_cif *, void *, - void **, void *), - void *, void *); -int FFI_HIDDEN ffi_closure_helper_SYSV (ffi_cif *, - void (*) (ffi_cif *, void *, - void **, void *), - void *, void *, unsigned long *, - ffi_dblfl *, unsigned long *); - -void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, void (*) (void), void *, - unsigned long, void *, long); -void FFI_HIDDEN ffi_closure_LINUX64 (void); -void FFI_HIDDEN ffi_go_closure_linux64 (void); - -void FFI_HIDDEN ffi_prep_types_linux64 (ffi_abi); -ffi_status FFI_HIDDEN ffi_prep_cif_linux64 (ffi_cif *); -ffi_status FFI_HIDDEN ffi_prep_cif_linux64_var (ffi_cif *, unsigned int, - unsigned int); -void FFI_HIDDEN ffi_prep_args64 (extended_cif *, unsigned long *const); -ffi_status FFI_HIDDEN ffi_prep_closure_loc_linux64 (ffi_closure *, ffi_cif *, - void (*) (ffi_cif *, void *, - void **, void *), - void *, void *); -int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_cif *, - void (*) (ffi_cif *, void *, - void **, void *), - void *, void *, - unsigned long *, ffi_dblfl *, - float128 *); +/* ----------------------------------------------------------------------- + ffi_powerpc.h - Copyright (C) 2013 IBM + Copyright (C) 2011 Anthony Green + Copyright (C) 2011 Kyle Moffett + Copyright (C) 2008 Red Hat, Inc + Copyright (C) 2007, 2008 Free Software Foundation, Inc + Copyright (c) 1998 Geoffrey Keating + + 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. + ----------------------------------------------------------------------- */ + +enum { + /* The assembly depends on these exact flags. */ + /* These go in cr7 */ + FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */ + FLAG_RETURNS_NOTHING = 1 << (31-30), + FLAG_RETURNS_FP = 1 << (31-29), + FLAG_RETURNS_VEC = 1 << (31-28), + + /* These go in cr6 */ + FLAG_RETURNS_64BITS = 1 << (31-27), + FLAG_RETURNS_128BITS = 1 << (31-26), + + FLAG_COMPAT = 1 << (31- 8), /* Not used by assembly */ + + /* These go in cr1 */ + FLAG_ARG_NEEDS_COPY = 1 << (31- 7), /* Used by sysv code */ + FLAG_ARG_NEEDS_PSAVE = FLAG_ARG_NEEDS_COPY, /* Used by linux64 code */ + FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ + FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), + FLAG_RETVAL_REFERENCE = 1 << (31- 4), + FLAG_VEC_ARGUMENTS = 1 << (31- 3), +}; + +typedef union +{ + float f; + double d; +} ffi_dblfl; + +#if defined(__FLOAT128_TYPE__) +typedef _Float128 float128; +#elif defined(__FLOAT128__) +typedef __float128 float128; +#else +typedef __int128 float128; +#endif + +void FFI_HIDDEN ffi_closure_SYSV (void); +void FFI_HIDDEN ffi_go_closure_sysv (void); +void FFI_HIDDEN ffi_call_SYSV(extended_cif *, void (*)(void), void *, + unsigned, void *, int); + +void FFI_HIDDEN ffi_prep_types_sysv (ffi_abi); +ffi_status FFI_HIDDEN ffi_prep_cif_sysv (ffi_cif *); +ffi_status FFI_HIDDEN ffi_prep_closure_loc_sysv (ffi_closure *, + ffi_cif *, + void (*) (ffi_cif *, void *, + void **, void *), + void *, void *); +int FFI_HIDDEN ffi_closure_helper_SYSV (ffi_cif *, + void (*) (ffi_cif *, void *, + void **, void *), + void *, void *, unsigned long *, + ffi_dblfl *, unsigned long *); + +void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, void (*) (void), void *, + unsigned long, void *, long); +void FFI_HIDDEN ffi_closure_LINUX64 (void); +void FFI_HIDDEN ffi_go_closure_linux64 (void); + +void FFI_HIDDEN ffi_prep_types_linux64 (ffi_abi); +ffi_status FFI_HIDDEN ffi_prep_cif_linux64 (ffi_cif *); +ffi_status FFI_HIDDEN ffi_prep_cif_linux64_var (ffi_cif *, unsigned int, + unsigned int); +void FFI_HIDDEN ffi_prep_args64 (extended_cif *, unsigned long *const); +ffi_status FFI_HIDDEN ffi_prep_closure_loc_linux64 (ffi_closure *, ffi_cif *, + void (*) (ffi_cif *, void *, + void **, void *), + void *, void *); +int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_cif *, + void (*) (ffi_cif *, void *, + void **, void *), + void *, void *, + unsigned long *, ffi_dblfl *, + float128 *); diff --git a/contrib/restricted/libffi/src/powerpc/ffi_sysv.c b/contrib/restricted/libffi/src/powerpc/ffi_sysv.c index 4078e75116..d641d929e3 100644 --- a/contrib/restricted/libffi/src/powerpc/ffi_sysv.c +++ b/contrib/restricted/libffi/src/powerpc/ffi_sysv.c @@ -1,923 +1,923 @@ -/* ----------------------------------------------------------------------- - ffi_sysv.c - Copyright (C) 2013 IBM - Copyright (C) 2011 Anthony Green - Copyright (C) 2011 Kyle Moffett - Copyright (C) 2008 Red Hat, Inc - Copyright (C) 2007, 2008 Free Software Foundation, Inc - Copyright (c) 1998 Geoffrey Keating - - 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" - -#ifndef POWERPC64 -#include "ffi_common.h" -#include "ffi_powerpc.h" - - -/* About the SYSV ABI. */ -#define ASM_NEEDS_REGISTERS 6 -#define NUM_GPR_ARG_REGISTERS 8 -#define NUM_FPR_ARG_REGISTERS 8 - - -#if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE -/* Adjust size of ffi_type_longdouble. */ -void FFI_HIDDEN -ffi_prep_types_sysv (ffi_abi abi) -{ - if ((abi & (FFI_SYSV | FFI_SYSV_LONG_DOUBLE_128)) == FFI_SYSV) - { - ffi_type_longdouble.size = 8; - ffi_type_longdouble.alignment = 8; - } - else - { - ffi_type_longdouble.size = 16; - ffi_type_longdouble.alignment = 16; - } -} -#endif - -/* Transform long double, double and float to other types as per abi. */ -static int -translate_float (int abi, int type) -{ -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - if (type == FFI_TYPE_LONGDOUBLE - && (abi & FFI_SYSV_LONG_DOUBLE_128) == 0) - type = FFI_TYPE_DOUBLE; -#endif - if ((abi & FFI_SYSV_SOFT_FLOAT) != 0) - { - if (type == FFI_TYPE_FLOAT) - type = FFI_TYPE_UINT32; - else if (type == FFI_TYPE_DOUBLE) - type = FFI_TYPE_UINT64; -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - else if (type == FFI_TYPE_LONGDOUBLE) - type = FFI_TYPE_UINT128; - } - else if ((abi & FFI_SYSV_IBM_LONG_DOUBLE) == 0) - { - if (type == FFI_TYPE_LONGDOUBLE) - type = FFI_TYPE_STRUCT; -#endif - } - return type; -} - -/* Perform machine dependent cif processing */ -static ffi_status -ffi_prep_cif_sysv_core (ffi_cif *cif) -{ - ffi_type **ptr; - unsigned bytes; - unsigned i, fpr_count = 0, gpr_count = 0, stack_count = 0; - unsigned flags = cif->flags; - unsigned struct_copy_size = 0; - unsigned type = cif->rtype->type; - unsigned size = cif->rtype->size; - - /* The machine-independent calculation of cif->bytes doesn't work - for us. Redo the calculation. */ - - /* 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); - - /* 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; - - Larger structures are allocated space and a pointer is passed as - the first argument. - - Single/double FP values are returned in fpr1; - - long doubles (if not equivalent to double) are returned in - fpr1,fpr2 for Linux and as for large structs for SysV. */ - - type = translate_float (cif->abi, type); - - switch (type) - { -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: - flags |= FLAG_RETURNS_128BITS; - /* Fall through. */ -#endif - case FFI_TYPE_DOUBLE: - flags |= FLAG_RETURNS_64BITS; - /* Fall through. */ - case FFI_TYPE_FLOAT: - flags |= FLAG_RETURNS_FP; -#ifdef __NO_FPRS__ - return FFI_BAD_ABI; -#endif - break; - - case FFI_TYPE_UINT128: - flags |= FLAG_RETURNS_128BITS; - /* Fall through. */ - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: - flags |= FLAG_RETURNS_64BITS; - break; - - case FFI_TYPE_STRUCT: - /* The final SYSV ABI says that structures smaller or equal 8 bytes - are returned in r3/r4. A draft ABI used by linux instead - returns them in memory. */ - if ((cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8) - { - flags |= FLAG_RETURNS_SMST; - break; - } - gpr_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; - } - - /* 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++) - { - unsigned short typenum = (*ptr)->type; - - typenum = translate_float (cif->abi, typenum); - - switch (typenum) - { -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: - if (fpr_count >= NUM_FPR_ARG_REGISTERS - 1) - { - fpr_count = NUM_FPR_ARG_REGISTERS; - /* 8-byte align long doubles. */ - stack_count += stack_count & 1; - stack_count += 4; - } - else - fpr_count += 2; -#ifdef __NO_FPRS__ - return FFI_BAD_ABI; -#endif - break; -#endif - - case FFI_TYPE_DOUBLE: - if (fpr_count >= NUM_FPR_ARG_REGISTERS) - { - /* 8-byte align doubles. */ - stack_count += stack_count & 1; - stack_count += 2; - } - else - fpr_count += 1; -#ifdef __NO_FPRS__ - return FFI_BAD_ABI; -#endif - break; - - case FFI_TYPE_FLOAT: - if (fpr_count >= NUM_FPR_ARG_REGISTERS) - /* Yes, we don't follow the ABI, but neither does gcc. */ - stack_count += 1; - else - fpr_count += 1; -#ifdef __NO_FPRS__ - return FFI_BAD_ABI; -#endif - break; - - case FFI_TYPE_UINT128: - /* A long double in FFI_LINUX_SOFT_FLOAT can use only a set - of four consecutive gprs. If we do not have enough, we - have to adjust the gpr_count value. */ - if (gpr_count >= NUM_GPR_ARG_REGISTERS - 3) - gpr_count = NUM_GPR_ARG_REGISTERS; - if (gpr_count >= NUM_GPR_ARG_REGISTERS) - stack_count += 4; - else - gpr_count += 4; - break; - - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: - /* 'long long' arguments are passed as two words, but - either both words must fit in registers or both go - on the stack. If they go on the stack, they must - be 8-byte-aligned. - - Also, only certain register pairs can be used for - passing long long int -- specifically (r3,r4), (r5,r6), - (r7,r8), (r9,r10). */ - gpr_count += gpr_count & 1; - if (gpr_count >= NUM_GPR_ARG_REGISTERS) - { - stack_count += stack_count & 1; - stack_count += 2; - } - else - gpr_count += 2; - break; - - case FFI_TYPE_STRUCT: - /* 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). */ - - case FFI_TYPE_POINTER: - case FFI_TYPE_INT: - case FFI_TYPE_UINT32: - case FFI_TYPE_SINT32: - case FFI_TYPE_UINT16: - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT8: - case FFI_TYPE_SINT8: - /* Everything else is passed as a 4-byte word in a GPR, either - the object itself or a pointer to it. */ - if (gpr_count >= NUM_GPR_ARG_REGISTERS) - stack_count += 1; - else - gpr_count += 1; - break; - - default: - FFI_ASSERT (0); - } - } - - if (fpr_count != 0) - flags |= FLAG_FP_ARGUMENTS; - if (gpr_count > 4) - flags |= FLAG_4_GPR_ARGUMENTS; - if (struct_copy_size != 0) - flags |= FLAG_ARG_NEEDS_COPY; - - /* Space for the FPR registers, if needed. */ - if (fpr_count != 0) - bytes += NUM_FPR_ARG_REGISTERS * sizeof (double); - - /* Stack space. */ - bytes += stack_count * sizeof (int); - - /* 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; -} - -ffi_status FFI_HIDDEN -ffi_prep_cif_sysv (ffi_cif *cif) -{ - if ((cif->abi & FFI_SYSV) == 0) - { - /* This call is from old code. Translate to new ABI values. */ - cif->flags |= FLAG_COMPAT; - switch (cif->abi) - { - default: - return FFI_BAD_ABI; - - case FFI_COMPAT_SYSV: - cif->abi = FFI_SYSV | FFI_SYSV_STRUCT_RET | FFI_SYSV_LONG_DOUBLE_128; - break; - - case FFI_COMPAT_GCC_SYSV: - cif->abi = FFI_SYSV | FFI_SYSV_LONG_DOUBLE_128; - break; - - case FFI_COMPAT_LINUX: - cif->abi = (FFI_SYSV | FFI_SYSV_IBM_LONG_DOUBLE - | FFI_SYSV_LONG_DOUBLE_128); - break; - - case FFI_COMPAT_LINUX_SOFT_FLOAT: - cif->abi = (FFI_SYSV | FFI_SYSV_SOFT_FLOAT | FFI_SYSV_IBM_LONG_DOUBLE - | FFI_SYSV_LONG_DOUBLE_128); - break; - } - } - return ffi_prep_cif_sysv_core (cif); -} - -/* 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_HIDDEN -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; - valp gpr_end; - -#ifndef __NO_FPRS__ - /* 'fpr_base' points at the space for fpr1, and grows upwards as - we use FPR registers. */ - valp fpr_base; - valp fpr_end; -#endif - - /* '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; - ffi_type **ptr; -#ifndef __NO_FPRS__ - double double_tmp; -#endif - 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; - - stacktop.c = (char *) stack + bytes; - gpr_end.u = stacktop.u - ASM_NEEDS_REGISTERS; - gpr_base.u = gpr_end.u - NUM_GPR_ARG_REGISTERS; -#ifndef __NO_FPRS__ - fpr_end.d = gpr_base.d; - fpr_base.d = fpr_end.d - NUM_FPR_ARG_REGISTERS; - copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c); -#else - copy_space.c = gpr_base.c; -#endif - next_arg.u = stack + 2; - - /* Check that everything starts aligned properly. */ - FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); - FFI_ASSERT (((unsigned long) copy_space.c & 0xF) == 0); - FFI_ASSERT (((unsigned long) 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) (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++) - { - unsigned int typenum = (*ptr)->type; - - typenum = translate_float (ecif->cif->abi, typenum); - - /* Now test the translated value */ - switch (typenum) - { -#ifndef __NO_FPRS__ -# if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - case FFI_TYPE_LONGDOUBLE: - double_tmp = (*p_argv.d)[0]; - - if (fpr_base.d >= fpr_end.d - 1) - { - fpr_base.d = fpr_end.d; - if (((next_arg.u - stack) & 1) != 0) - next_arg.u += 1; - *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; - } - FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); - break; -# endif - case FFI_TYPE_DOUBLE: - double_tmp = **p_argv.d; - - if (fpr_base.d >= fpr_end.d) - { - if (((next_arg.u - stack) & 1) != 0) - next_arg.u += 1; - *next_arg.d = double_tmp; - next_arg.u += 2; - } - else - *fpr_base.d++ = double_tmp; - FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); - break; - - case FFI_TYPE_FLOAT: - double_tmp = **p_argv.f; - if (fpr_base.d >= fpr_end.d) - { - *next_arg.f = (float) double_tmp; - next_arg.u += 1; - } - else - *fpr_base.d++ = double_tmp; - FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); - break; -#endif /* have FPRs */ - - case FFI_TYPE_UINT128: - /* 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 (gpr_base.u >= gpr_end.u - 3) - { - unsigned int ii; - gpr_base.u = gpr_end.u; - for (ii = 0; ii < 4; ii++) - { - unsigned int int_tmp = (*p_argv.ui)[ii]; - *next_arg.u++ = int_tmp; - } - } - else - { - unsigned int ii; - for (ii = 0; ii < 4; ii++) - { - unsigned int int_tmp = (*p_argv.ui)[ii]; - *gpr_base.u++ = int_tmp; - } - } - break; - - case FFI_TYPE_UINT64: - case FFI_TYPE_SINT64: - if (gpr_base.u >= gpr_end.u - 1) - { - gpr_base.u = gpr_end.u; - if (((next_arg.u - stack) & 1) != 0) - next_arg.u++; - *next_arg.ll = **p_argv.ll; - next_arg.u += 2; - } - else - { - /* The abi states only certain register pairs can be - used for passing long long int specifically (r3,r4), - (r5,r6), (r7,r8), (r9,r10). If next arg is long long - but not correct starting register of pair then skip - until the proper starting register. */ - if (((gpr_end.u - gpr_base.u) & 1) != 0) - gpr_base.u++; - *gpr_base.ll++ = **p_argv.ll; - } - break; - - case FFI_TYPE_STRUCT: - 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: - - gprvalue = **p_argv.ui; - - putgpr: - if (gpr_base.u >= gpr_end.u) - *next_arg.u++ = gprvalue; - else - *gpr_base.u++ = gprvalue; - break; - } - } - - /* Check that we didn't overrun the stack... */ - FFI_ASSERT (copy_space.c >= next_arg.c); - FFI_ASSERT (gpr_base.u <= gpr_end.u); -#ifndef __NO_FPRS__ - FFI_ASSERT (fpr_base.u <= fpr_end.u); -#endif - FFI_ASSERT (((flags & FLAG_4_GPR_ARGUMENTS) != 0) - == (gpr_end.u - gpr_base.u < 4)); -} - -#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"); -} - -ffi_status FFI_HIDDEN -ffi_prep_closure_loc_sysv (ffi_closure *closure, - ffi_cif *cif, - void (*fun) (ffi_cif *, void *, void **, void *), - void *user_data, - void *codeloc) -{ - unsigned int *tramp; - - if (cif->abi < FFI_SYSV || cif->abi >= FFI_LAST_ABI) - return FFI_BAD_ABI; - - tramp = (unsigned int *) &closure->tramp[0]; - tramp[0] = 0x7c0802a6; /* mflr r0 */ - tramp[1] = 0x429f0005; /* bcl 20,31,.+4 */ - tramp[2] = 0x7d6802a6; /* mflr r11 */ - tramp[3] = 0x7c0803a6; /* mtlr r0 */ - tramp[4] = 0x800b0018; /* lwz r0,24(r11) */ - tramp[5] = 0x816b001c; /* lwz r11,28(r11) */ - tramp[6] = 0x7c0903a6; /* mtctr r0 */ - tramp[7] = 0x4e800420; /* bctr */ - *(void **) &tramp[8] = (void *) ffi_closure_SYSV; /* function */ - *(void **) &tramp[9] = codeloc; /* context */ - - /* Flush the icache. */ - flush_icache ((char *)tramp, (char *)codeloc, 8 * 4); - - closure->cif = cif; - closure->fun = fun; - closure->user_data = user_data; - - return FFI_OK; -} - -/* 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_cif *cif, - void (*fun) (ffi_cif *, void *, void **, void *), - void *user_data, - 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; -#ifndef __NO_FPRS__ - long nf = 0; /* number of floating registers already used */ -#endif - long ng = 0; /* number of general registers already used */ - - unsigned size = cif->rtype->size; - unsigned short rtypenum = cif->rtype->type; - - avalue = alloca (cif->nargs * sizeof (void *)); - - /* First translate for softfloat/nonlinux */ - rtypenum = translate_float (cif->abi, rtypenum); - - /* 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 (rtypenum == FFI_TYPE_STRUCT - && !((cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8)) - { - 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) { - unsigned short typenum = arg_types[i]->type; - - /* We may need to handle some values depending on ABI. */ - typenum = translate_float (cif->abi, typenum); - - switch (typenum) - { -#ifndef __NO_FPRS__ - case FFI_TYPE_FLOAT: - /* Unfortunately float values are stored as doubles - in the ffi_closure_SYSV code (since we don't check - the type in that routine). */ - if (nf < NUM_FPR_ARG_REGISTERS) - { - /* 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... */ - double temp = pfr->d; - pfr->f = (float) temp; - avalue[i] = pfr; - nf++; - pfr++; - } - else - { - avalue[i] = pst; - pst += 1; - } - break; - - case FFI_TYPE_DOUBLE: - if (nf < NUM_FPR_ARG_REGISTERS) - { - 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 (nf < NUM_FPR_ARG_REGISTERS - 1) - { - avalue[i] = pfr; - pfr += 2; - nf += 2; - } - else - { - if (((long) pst) & 4) - pst++; - avalue[i] = pst; - pst += 4; - nf = 8; - } - break; -# endif -#endif - - case FFI_TYPE_UINT128: - /* Test if for the whole long double, 4 gprs are available. - otherwise the stuff ends up on the stack. */ - if (ng < NUM_GPR_ARG_REGISTERS - 3) - { - avalue[i] = pgr; - pgr += 4; - ng += 4; - } - else - { - avalue[i] = pst; - pst += 4; - ng = 8+4; - } - break; - - case FFI_TYPE_SINT8: - case FFI_TYPE_UINT8: -#ifndef __LITTLE_ENDIAN__ - if (ng < NUM_GPR_ARG_REGISTERS) - { - avalue[i] = (char *) pgr + 3; - ng++; - pgr++; - } - else - { - avalue[i] = (char *) pst + 3; - pst++; - } - break; -#endif - - case FFI_TYPE_SINT16: - case FFI_TYPE_UINT16: -#ifndef __LITTLE_ENDIAN__ - if (ng < NUM_GPR_ARG_REGISTERS) - { - avalue[i] = (char *) pgr + 2; - ng++; - pgr++; - } - else - { - avalue[i] = (char *) pst + 2; - pst++; - } - break; -#endif - - case FFI_TYPE_SINT32: - case FFI_TYPE_UINT32: - case FFI_TYPE_POINTER: - if (ng < NUM_GPR_ARG_REGISTERS) - { - avalue[i] = pgr; - ng++; - pgr++; - } - else - { - avalue[i] = pst; - pst++; - } - break; - - case FFI_TYPE_STRUCT: - /* Structs are passed by reference. The address will appear in a - gpr if it is one of the first 8 arguments. */ - if (ng < NUM_GPR_ARG_REGISTERS) - { - avalue[i] = (void *) *pgr; - ng++; - pgr++; - } - else - { - avalue[i] = (void *) *pst; - pst++; - } - break; - - case FFI_TYPE_SINT64: - case FFI_TYPE_UINT64: - /* Passing long long ints are complex, they must - be passed in suitable register pairs such as - (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) - and if the entire pair aren't available then the outgoing - parameter stack is used for both but an alignment of 8 - must will be kept. So we must either look in pgr - or pst to find the correct address for this type - of parameter. */ - if (ng < NUM_GPR_ARG_REGISTERS - 1) - { - if (ng & 1) - { - /* 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; - ng = NUM_GPR_ARG_REGISTERS; - } - break; - - default: - FFI_ASSERT (0); - } - - i++; - } - - (*fun) (cif, rvalue, avalue, 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. We - combine the base type FFI_SYSV_TYPE_SMALL_STRUCT with the size of - the struct less one. We never have a struct with size zero. - See the comment in ffitarget.h about ordering. */ - if (rtypenum == FFI_TYPE_STRUCT - && (cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8) - return FFI_SYSV_TYPE_SMALL_STRUCT - 1 + size; - return rtypenum; -} -#endif +/* ----------------------------------------------------------------------- + ffi_sysv.c - Copyright (C) 2013 IBM + Copyright (C) 2011 Anthony Green + Copyright (C) 2011 Kyle Moffett + Copyright (C) 2008 Red Hat, Inc + Copyright (C) 2007, 2008 Free Software Foundation, Inc + Copyright (c) 1998 Geoffrey Keating + + 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" + +#ifndef POWERPC64 +#include "ffi_common.h" +#include "ffi_powerpc.h" + + +/* About the SYSV ABI. */ +#define ASM_NEEDS_REGISTERS 6 +#define NUM_GPR_ARG_REGISTERS 8 +#define NUM_FPR_ARG_REGISTERS 8 + + +#if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +/* Adjust size of ffi_type_longdouble. */ +void FFI_HIDDEN +ffi_prep_types_sysv (ffi_abi abi) +{ + if ((abi & (FFI_SYSV | FFI_SYSV_LONG_DOUBLE_128)) == FFI_SYSV) + { + ffi_type_longdouble.size = 8; + ffi_type_longdouble.alignment = 8; + } + else + { + ffi_type_longdouble.size = 16; + ffi_type_longdouble.alignment = 16; + } +} +#endif + +/* Transform long double, double and float to other types as per abi. */ +static int +translate_float (int abi, int type) +{ +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + if (type == FFI_TYPE_LONGDOUBLE + && (abi & FFI_SYSV_LONG_DOUBLE_128) == 0) + type = FFI_TYPE_DOUBLE; +#endif + if ((abi & FFI_SYSV_SOFT_FLOAT) != 0) + { + if (type == FFI_TYPE_FLOAT) + type = FFI_TYPE_UINT32; + else if (type == FFI_TYPE_DOUBLE) + type = FFI_TYPE_UINT64; +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + else if (type == FFI_TYPE_LONGDOUBLE) + type = FFI_TYPE_UINT128; + } + else if ((abi & FFI_SYSV_IBM_LONG_DOUBLE) == 0) + { + if (type == FFI_TYPE_LONGDOUBLE) + type = FFI_TYPE_STRUCT; +#endif + } + return type; +} + +/* Perform machine dependent cif processing */ +static ffi_status +ffi_prep_cif_sysv_core (ffi_cif *cif) +{ + ffi_type **ptr; + unsigned bytes; + unsigned i, fpr_count = 0, gpr_count = 0, stack_count = 0; + unsigned flags = cif->flags; + unsigned struct_copy_size = 0; + unsigned type = cif->rtype->type; + unsigned size = cif->rtype->size; + + /* The machine-independent calculation of cif->bytes doesn't work + for us. Redo the calculation. */ + + /* 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); + + /* 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; + - Larger structures are allocated space and a pointer is passed as + the first argument. + - Single/double FP values are returned in fpr1; + - long doubles (if not equivalent to double) are returned in + fpr1,fpr2 for Linux and as for large structs for SysV. */ + + type = translate_float (cif->abi, type); + + switch (type) + { +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + flags |= FLAG_RETURNS_128BITS; + /* Fall through. */ +#endif + case FFI_TYPE_DOUBLE: + flags |= FLAG_RETURNS_64BITS; + /* Fall through. */ + case FFI_TYPE_FLOAT: + flags |= FLAG_RETURNS_FP; +#ifdef __NO_FPRS__ + return FFI_BAD_ABI; +#endif + break; + + case FFI_TYPE_UINT128: + flags |= FLAG_RETURNS_128BITS; + /* Fall through. */ + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + flags |= FLAG_RETURNS_64BITS; + break; + + case FFI_TYPE_STRUCT: + /* The final SYSV ABI says that structures smaller or equal 8 bytes + are returned in r3/r4. A draft ABI used by linux instead + returns them in memory. */ + if ((cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8) + { + flags |= FLAG_RETURNS_SMST; + break; + } + gpr_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; + } + + /* 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++) + { + unsigned short typenum = (*ptr)->type; + + typenum = translate_float (cif->abi, typenum); + + switch (typenum) + { +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if (fpr_count >= NUM_FPR_ARG_REGISTERS - 1) + { + fpr_count = NUM_FPR_ARG_REGISTERS; + /* 8-byte align long doubles. */ + stack_count += stack_count & 1; + stack_count += 4; + } + else + fpr_count += 2; +#ifdef __NO_FPRS__ + return FFI_BAD_ABI; +#endif + break; +#endif + + case FFI_TYPE_DOUBLE: + if (fpr_count >= NUM_FPR_ARG_REGISTERS) + { + /* 8-byte align doubles. */ + stack_count += stack_count & 1; + stack_count += 2; + } + else + fpr_count += 1; +#ifdef __NO_FPRS__ + return FFI_BAD_ABI; +#endif + break; + + case FFI_TYPE_FLOAT: + if (fpr_count >= NUM_FPR_ARG_REGISTERS) + /* Yes, we don't follow the ABI, but neither does gcc. */ + stack_count += 1; + else + fpr_count += 1; +#ifdef __NO_FPRS__ + return FFI_BAD_ABI; +#endif + break; + + case FFI_TYPE_UINT128: + /* A long double in FFI_LINUX_SOFT_FLOAT can use only a set + of four consecutive gprs. If we do not have enough, we + have to adjust the gpr_count value. */ + if (gpr_count >= NUM_GPR_ARG_REGISTERS - 3) + gpr_count = NUM_GPR_ARG_REGISTERS; + if (gpr_count >= NUM_GPR_ARG_REGISTERS) + stack_count += 4; + else + gpr_count += 4; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + /* 'long long' arguments are passed as two words, but + either both words must fit in registers or both go + on the stack. If they go on the stack, they must + be 8-byte-aligned. + + Also, only certain register pairs can be used for + passing long long int -- specifically (r3,r4), (r5,r6), + (r7,r8), (r9,r10). */ + gpr_count += gpr_count & 1; + if (gpr_count >= NUM_GPR_ARG_REGISTERS) + { + stack_count += stack_count & 1; + stack_count += 2; + } + else + gpr_count += 2; + break; + + case FFI_TYPE_STRUCT: + /* 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). */ + + case FFI_TYPE_POINTER: + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + /* Everything else is passed as a 4-byte word in a GPR, either + the object itself or a pointer to it. */ + if (gpr_count >= NUM_GPR_ARG_REGISTERS) + stack_count += 1; + else + gpr_count += 1; + break; + + default: + FFI_ASSERT (0); + } + } + + if (fpr_count != 0) + flags |= FLAG_FP_ARGUMENTS; + if (gpr_count > 4) + flags |= FLAG_4_GPR_ARGUMENTS; + if (struct_copy_size != 0) + flags |= FLAG_ARG_NEEDS_COPY; + + /* Space for the FPR registers, if needed. */ + if (fpr_count != 0) + bytes += NUM_FPR_ARG_REGISTERS * sizeof (double); + + /* Stack space. */ + bytes += stack_count * sizeof (int); + + /* 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; +} + +ffi_status FFI_HIDDEN +ffi_prep_cif_sysv (ffi_cif *cif) +{ + if ((cif->abi & FFI_SYSV) == 0) + { + /* This call is from old code. Translate to new ABI values. */ + cif->flags |= FLAG_COMPAT; + switch (cif->abi) + { + default: + return FFI_BAD_ABI; + + case FFI_COMPAT_SYSV: + cif->abi = FFI_SYSV | FFI_SYSV_STRUCT_RET | FFI_SYSV_LONG_DOUBLE_128; + break; + + case FFI_COMPAT_GCC_SYSV: + cif->abi = FFI_SYSV | FFI_SYSV_LONG_DOUBLE_128; + break; + + case FFI_COMPAT_LINUX: + cif->abi = (FFI_SYSV | FFI_SYSV_IBM_LONG_DOUBLE + | FFI_SYSV_LONG_DOUBLE_128); + break; + + case FFI_COMPAT_LINUX_SOFT_FLOAT: + cif->abi = (FFI_SYSV | FFI_SYSV_SOFT_FLOAT | FFI_SYSV_IBM_LONG_DOUBLE + | FFI_SYSV_LONG_DOUBLE_128); + break; + } + } + return ffi_prep_cif_sysv_core (cif); +} + +/* 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_HIDDEN +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; + valp gpr_end; + +#ifndef __NO_FPRS__ + /* 'fpr_base' points at the space for fpr1, and grows upwards as + we use FPR registers. */ + valp fpr_base; + valp fpr_end; +#endif + + /* '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; + ffi_type **ptr; +#ifndef __NO_FPRS__ + double double_tmp; +#endif + 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; + + stacktop.c = (char *) stack + bytes; + gpr_end.u = stacktop.u - ASM_NEEDS_REGISTERS; + gpr_base.u = gpr_end.u - NUM_GPR_ARG_REGISTERS; +#ifndef __NO_FPRS__ + fpr_end.d = gpr_base.d; + fpr_base.d = fpr_end.d - NUM_FPR_ARG_REGISTERS; + copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c); +#else + copy_space.c = gpr_base.c; +#endif + next_arg.u = stack + 2; + + /* Check that everything starts aligned properly. */ + FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); + FFI_ASSERT (((unsigned long) copy_space.c & 0xF) == 0); + FFI_ASSERT (((unsigned long) 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) (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++) + { + unsigned int typenum = (*ptr)->type; + + typenum = translate_float (ecif->cif->abi, typenum); + + /* Now test the translated value */ + switch (typenum) + { +#ifndef __NO_FPRS__ +# if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + double_tmp = (*p_argv.d)[0]; + + if (fpr_base.d >= fpr_end.d - 1) + { + fpr_base.d = fpr_end.d; + if (((next_arg.u - stack) & 1) != 0) + next_arg.u += 1; + *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; + } + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; +# endif + case FFI_TYPE_DOUBLE: + double_tmp = **p_argv.d; + + if (fpr_base.d >= fpr_end.d) + { + if (((next_arg.u - stack) & 1) != 0) + next_arg.u += 1; + *next_arg.d = double_tmp; + next_arg.u += 2; + } + else + *fpr_base.d++ = double_tmp; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_FLOAT: + double_tmp = **p_argv.f; + if (fpr_base.d >= fpr_end.d) + { + *next_arg.f = (float) double_tmp; + next_arg.u += 1; + } + else + *fpr_base.d++ = double_tmp; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; +#endif /* have FPRs */ + + case FFI_TYPE_UINT128: + /* 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 (gpr_base.u >= gpr_end.u - 3) + { + unsigned int ii; + gpr_base.u = gpr_end.u; + for (ii = 0; ii < 4; ii++) + { + unsigned int int_tmp = (*p_argv.ui)[ii]; + *next_arg.u++ = int_tmp; + } + } + else + { + unsigned int ii; + for (ii = 0; ii < 4; ii++) + { + unsigned int int_tmp = (*p_argv.ui)[ii]; + *gpr_base.u++ = int_tmp; + } + } + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + if (gpr_base.u >= gpr_end.u - 1) + { + gpr_base.u = gpr_end.u; + if (((next_arg.u - stack) & 1) != 0) + next_arg.u++; + *next_arg.ll = **p_argv.ll; + next_arg.u += 2; + } + else + { + /* The abi states only certain register pairs can be + used for passing long long int specifically (r3,r4), + (r5,r6), (r7,r8), (r9,r10). If next arg is long long + but not correct starting register of pair then skip + until the proper starting register. */ + if (((gpr_end.u - gpr_base.u) & 1) != 0) + gpr_base.u++; + *gpr_base.ll++ = **p_argv.ll; + } + break; + + case FFI_TYPE_STRUCT: + 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: + + gprvalue = **p_argv.ui; + + putgpr: + if (gpr_base.u >= gpr_end.u) + *next_arg.u++ = gprvalue; + else + *gpr_base.u++ = gprvalue; + break; + } + } + + /* Check that we didn't overrun the stack... */ + FFI_ASSERT (copy_space.c >= next_arg.c); + FFI_ASSERT (gpr_base.u <= gpr_end.u); +#ifndef __NO_FPRS__ + FFI_ASSERT (fpr_base.u <= fpr_end.u); +#endif + FFI_ASSERT (((flags & FLAG_4_GPR_ARGUMENTS) != 0) + == (gpr_end.u - gpr_base.u < 4)); +} + +#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"); +} + +ffi_status FFI_HIDDEN +ffi_prep_closure_loc_sysv (ffi_closure *closure, + ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + void *codeloc) +{ + unsigned int *tramp; + + if (cif->abi < FFI_SYSV || cif->abi >= FFI_LAST_ABI) + return FFI_BAD_ABI; + + tramp = (unsigned int *) &closure->tramp[0]; + tramp[0] = 0x7c0802a6; /* mflr r0 */ + tramp[1] = 0x429f0005; /* bcl 20,31,.+4 */ + tramp[2] = 0x7d6802a6; /* mflr r11 */ + tramp[3] = 0x7c0803a6; /* mtlr r0 */ + tramp[4] = 0x800b0018; /* lwz r0,24(r11) */ + tramp[5] = 0x816b001c; /* lwz r11,28(r11) */ + tramp[6] = 0x7c0903a6; /* mtctr r0 */ + tramp[7] = 0x4e800420; /* bctr */ + *(void **) &tramp[8] = (void *) ffi_closure_SYSV; /* function */ + *(void **) &tramp[9] = codeloc; /* context */ + + /* Flush the icache. */ + flush_icache ((char *)tramp, (char *)codeloc, 8 * 4); + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +/* 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_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + 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; +#ifndef __NO_FPRS__ + long nf = 0; /* number of floating registers already used */ +#endif + long ng = 0; /* number of general registers already used */ + + unsigned size = cif->rtype->size; + unsigned short rtypenum = cif->rtype->type; + + avalue = alloca (cif->nargs * sizeof (void *)); + + /* First translate for softfloat/nonlinux */ + rtypenum = translate_float (cif->abi, rtypenum); + + /* 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 (rtypenum == FFI_TYPE_STRUCT + && !((cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8)) + { + 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) { + unsigned short typenum = arg_types[i]->type; + + /* We may need to handle some values depending on ABI. */ + typenum = translate_float (cif->abi, typenum); + + switch (typenum) + { +#ifndef __NO_FPRS__ + case FFI_TYPE_FLOAT: + /* Unfortunately float values are stored as doubles + in the ffi_closure_SYSV code (since we don't check + the type in that routine). */ + if (nf < NUM_FPR_ARG_REGISTERS) + { + /* 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... */ + double temp = pfr->d; + pfr->f = (float) temp; + avalue[i] = pfr; + nf++; + pfr++; + } + else + { + avalue[i] = pst; + pst += 1; + } + break; + + case FFI_TYPE_DOUBLE: + if (nf < NUM_FPR_ARG_REGISTERS) + { + 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 (nf < NUM_FPR_ARG_REGISTERS - 1) + { + avalue[i] = pfr; + pfr += 2; + nf += 2; + } + else + { + if (((long) pst) & 4) + pst++; + avalue[i] = pst; + pst += 4; + nf = 8; + } + break; +# endif +#endif + + case FFI_TYPE_UINT128: + /* Test if for the whole long double, 4 gprs are available. + otherwise the stuff ends up on the stack. */ + if (ng < NUM_GPR_ARG_REGISTERS - 3) + { + avalue[i] = pgr; + pgr += 4; + ng += 4; + } + else + { + avalue[i] = pst; + pst += 4; + ng = 8+4; + } + break; + + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: +#ifndef __LITTLE_ENDIAN__ + if (ng < NUM_GPR_ARG_REGISTERS) + { + avalue[i] = (char *) pgr + 3; + ng++; + pgr++; + } + else + { + avalue[i] = (char *) pst + 3; + pst++; + } + break; +#endif + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: +#ifndef __LITTLE_ENDIAN__ + if (ng < NUM_GPR_ARG_REGISTERS) + { + avalue[i] = (char *) pgr + 2; + ng++; + pgr++; + } + else + { + avalue[i] = (char *) pst + 2; + pst++; + } + break; +#endif + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + if (ng < NUM_GPR_ARG_REGISTERS) + { + avalue[i] = pgr; + ng++; + pgr++; + } + else + { + avalue[i] = pst; + pst++; + } + break; + + case FFI_TYPE_STRUCT: + /* Structs are passed by reference. The address will appear in a + gpr if it is one of the first 8 arguments. */ + if (ng < NUM_GPR_ARG_REGISTERS) + { + avalue[i] = (void *) *pgr; + ng++; + pgr++; + } + else + { + avalue[i] = (void *) *pst; + pst++; + } + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + /* Passing long long ints are complex, they must + be passed in suitable register pairs such as + (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) + and if the entire pair aren't available then the outgoing + parameter stack is used for both but an alignment of 8 + must will be kept. So we must either look in pgr + or pst to find the correct address for this type + of parameter. */ + if (ng < NUM_GPR_ARG_REGISTERS - 1) + { + if (ng & 1) + { + /* 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; + ng = NUM_GPR_ARG_REGISTERS; + } + break; + + default: + FFI_ASSERT (0); + } + + i++; + } + + (*fun) (cif, rvalue, avalue, 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. We + combine the base type FFI_SYSV_TYPE_SMALL_STRUCT with the size of + the struct less one. We never have a struct with size zero. + See the comment in ffitarget.h about ordering. */ + if (rtypenum == FFI_TYPE_STRUCT + && (cif->abi & FFI_SYSV_STRUCT_RET) != 0 && size <= 8) + return FFI_SYSV_TYPE_SMALL_STRUCT - 1 + size; + return rtypenum; +} +#endif diff --git a/contrib/restricted/libffi/src/powerpc/ffitarget.h b/contrib/restricted/libffi/src/powerpc/ffitarget.h index 7fb9a93908..1a25a43141 100644 --- a/contrib/restricted/libffi/src/powerpc/ffitarget.h +++ b/contrib/restricted/libffi/src/powerpc/ffitarget.h @@ -1,204 +1,204 @@ -/* -----------------------------------------------------------------*-C-*- - ffitarget.h - Copyright (c) 2012 Anthony Green - Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc - Copyright (c) 1996-2003 Red Hat, Inc. - - Target configuration macros for PowerPC. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL 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 - -#ifndef LIBFFI_H -#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." -#endif - -/* ---- System specific configurations ----------------------------------- */ - -#if defined (POWERPC) && defined (__powerpc64__) /* linux64 */ -#ifndef POWERPC64 -#define POWERPC64 -#endif -#elif defined (POWERPC_DARWIN) && defined (__ppc64__) /* Darwin64 */ -#ifndef POWERPC64 -#define POWERPC64 -#endif -#ifndef POWERPC_DARWIN64 -#define POWERPC_DARWIN64 -#endif -#elif defined (POWERPC_AIX) && defined (__64BIT__) /* AIX64 */ -#ifndef POWERPC64 -#define POWERPC64 -#endif -#endif - -#ifndef LIBFFI_ASM -typedef unsigned long ffi_arg; -typedef signed long ffi_sarg; - -typedef enum ffi_abi { - FFI_FIRST_ABI = 0, - -#if defined (POWERPC_AIX) - FFI_AIX, - FFI_DARWIN, - FFI_DEFAULT_ABI = FFI_AIX, - FFI_LAST_ABI - -#elif defined (POWERPC_DARWIN) - FFI_AIX, - FFI_DARWIN, - FFI_DEFAULT_ABI = FFI_DARWIN, - FFI_LAST_ABI - -#else - /* The FFI_COMPAT values are used by old code. Since libffi may be - a shared library we have to support old values for backwards - compatibility. */ - FFI_COMPAT_SYSV, - FFI_COMPAT_GCC_SYSV, - FFI_COMPAT_LINUX64, - FFI_COMPAT_LINUX, - FFI_COMPAT_LINUX_SOFT_FLOAT, - -# if defined (POWERPC64) - /* This bit, always set in new code, must not be set in any of the - old FFI_COMPAT values that might be used for 64-bit linux. We - only need worry about FFI_COMPAT_LINUX64, but to be safe avoid - all old values. */ - FFI_LINUX = 8, - /* This and following bits can reuse FFI_COMPAT values. */ - FFI_LINUX_STRUCT_ALIGN = 1, - FFI_LINUX_LONG_DOUBLE_128 = 2, - FFI_LINUX_LONG_DOUBLE_IEEE128 = 4, - FFI_DEFAULT_ABI = (FFI_LINUX -# ifdef __STRUCT_PARM_ALIGN__ - | FFI_LINUX_STRUCT_ALIGN -# endif -# ifdef __LONG_DOUBLE_128__ - | FFI_LINUX_LONG_DOUBLE_128 -# ifdef __LONG_DOUBLE_IEEE128__ - | FFI_LINUX_LONG_DOUBLE_IEEE128 -# endif -# endif - ), - FFI_LAST_ABI = 16 - -# else - /* This bit, always set in new code, must not be set in any of the - old FFI_COMPAT values that might be used for 32-bit linux/sysv/bsd. */ - FFI_SYSV = 8, - /* This and following bits can reuse FFI_COMPAT values. */ - FFI_SYSV_SOFT_FLOAT = 1, - FFI_SYSV_STRUCT_RET = 2, - FFI_SYSV_IBM_LONG_DOUBLE = 4, - FFI_SYSV_LONG_DOUBLE_128 = 16, - - FFI_DEFAULT_ABI = (FFI_SYSV -# ifdef __NO_FPRS__ - | FFI_SYSV_SOFT_FLOAT -# endif -# if (defined (__SVR4_STRUCT_RETURN) \ - || defined (POWERPC_FREEBSD) && !defined (__AIX_STRUCT_RETURN)) - | FFI_SYSV_STRUCT_RET -# endif -# if __LDBL_MANT_DIG__ == 106 - | FFI_SYSV_IBM_LONG_DOUBLE -# endif -# ifdef __LONG_DOUBLE_128__ - | FFI_SYSV_LONG_DOUBLE_128 -# endif - ), - FFI_LAST_ABI = 32 -# endif -#endif - -} ffi_abi; -#endif - -/* ---- Definitions for closures ----------------------------------------- */ - -#define FFI_CLOSURES 1 -#define FFI_NATIVE_RAW_API 0 -#if defined (POWERPC) || defined (POWERPC_FREEBSD) -# define FFI_GO_CLOSURES 1 -# define FFI_TARGET_SPECIFIC_VARIADIC 1 -# define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs -#endif -#if defined (POWERPC_AIX) -# define FFI_GO_CLOSURES 1 -#endif - -/* ppc_closure.S and linux64_closure.S expect this. */ -#define FFI_PPC_TYPE_LAST FFI_TYPE_POINTER - -/* We define additional types below. If generic types are added that - must be supported by powerpc libffi then it is likely that - FFI_PPC_TYPE_LAST needs increasing *and* the jump tables in - ppc_closure.S and linux64_closure.S be extended. */ - -#if !(FFI_TYPE_LAST == FFI_PPC_TYPE_LAST \ - || (FFI_TYPE_LAST == FFI_TYPE_COMPLEX \ - && !defined FFI_TARGET_HAS_COMPLEX_TYPE)) -# error "You likely have a broken powerpc libffi" -#endif - -/* Needed for soft-float long-double-128 support. */ -#define FFI_TYPE_UINT128 (FFI_PPC_TYPE_LAST + 1) - -/* Needed for FFI_SYSV small structure returns. */ -#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2) - -/* Used by ELFv2 for homogenous structure returns. */ -#define FFI_V2_TYPE_VECTOR (FFI_PPC_TYPE_LAST + 1) -#define FFI_V2_TYPE_VECTOR_HOMOG (FFI_PPC_TYPE_LAST + 2) -#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 3) -#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 4) -#define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 5) - -#if _CALL_ELF == 2 -# define FFI_TRAMPOLINE_SIZE 32 -#else -# if defined(POWERPC64) || defined(POWERPC_AIX) -# if defined(POWERPC_DARWIN64) -# define FFI_TRAMPOLINE_SIZE 48 -# else -# define FFI_TRAMPOLINE_SIZE 24 -# endif -# else /* POWERPC || POWERPC_AIX */ -# define FFI_TRAMPOLINE_SIZE 40 -# endif -#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 +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2012 Anthony Green + Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc + Copyright (c) 1996-2003 Red Hat, Inc. + + Target configuration macros for PowerPC. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL 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 + +#ifndef LIBFFI_H +#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." +#endif + +/* ---- System specific configurations ----------------------------------- */ + +#if defined (POWERPC) && defined (__powerpc64__) /* linux64 */ +#ifndef POWERPC64 +#define POWERPC64 +#endif +#elif defined (POWERPC_DARWIN) && defined (__ppc64__) /* Darwin64 */ +#ifndef POWERPC64 +#define POWERPC64 +#endif +#ifndef POWERPC_DARWIN64 +#define POWERPC_DARWIN64 +#endif +#elif defined (POWERPC_AIX) && defined (__64BIT__) /* AIX64 */ +#ifndef POWERPC64 +#define POWERPC64 +#endif +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + +#if defined (POWERPC_AIX) + FFI_AIX, + FFI_DARWIN, + FFI_DEFAULT_ABI = FFI_AIX, + FFI_LAST_ABI + +#elif defined (POWERPC_DARWIN) + FFI_AIX, + FFI_DARWIN, + FFI_DEFAULT_ABI = FFI_DARWIN, + FFI_LAST_ABI + +#else + /* The FFI_COMPAT values are used by old code. Since libffi may be + a shared library we have to support old values for backwards + compatibility. */ + FFI_COMPAT_SYSV, + FFI_COMPAT_GCC_SYSV, + FFI_COMPAT_LINUX64, + FFI_COMPAT_LINUX, + FFI_COMPAT_LINUX_SOFT_FLOAT, + +# if defined (POWERPC64) + /* This bit, always set in new code, must not be set in any of the + old FFI_COMPAT values that might be used for 64-bit linux. We + only need worry about FFI_COMPAT_LINUX64, but to be safe avoid + all old values. */ + FFI_LINUX = 8, + /* This and following bits can reuse FFI_COMPAT values. */ + FFI_LINUX_STRUCT_ALIGN = 1, + FFI_LINUX_LONG_DOUBLE_128 = 2, + FFI_LINUX_LONG_DOUBLE_IEEE128 = 4, + FFI_DEFAULT_ABI = (FFI_LINUX +# ifdef __STRUCT_PARM_ALIGN__ + | FFI_LINUX_STRUCT_ALIGN +# endif +# ifdef __LONG_DOUBLE_128__ + | FFI_LINUX_LONG_DOUBLE_128 +# ifdef __LONG_DOUBLE_IEEE128__ + | FFI_LINUX_LONG_DOUBLE_IEEE128 +# endif +# endif + ), + FFI_LAST_ABI = 16 + +# else + /* This bit, always set in new code, must not be set in any of the + old FFI_COMPAT values that might be used for 32-bit linux/sysv/bsd. */ + FFI_SYSV = 8, + /* This and following bits can reuse FFI_COMPAT values. */ + FFI_SYSV_SOFT_FLOAT = 1, + FFI_SYSV_STRUCT_RET = 2, + FFI_SYSV_IBM_LONG_DOUBLE = 4, + FFI_SYSV_LONG_DOUBLE_128 = 16, + + FFI_DEFAULT_ABI = (FFI_SYSV +# ifdef __NO_FPRS__ + | FFI_SYSV_SOFT_FLOAT +# endif +# if (defined (__SVR4_STRUCT_RETURN) \ + || defined (POWERPC_FREEBSD) && !defined (__AIX_STRUCT_RETURN)) + | FFI_SYSV_STRUCT_RET +# endif +# if __LDBL_MANT_DIG__ == 106 + | FFI_SYSV_IBM_LONG_DOUBLE +# endif +# ifdef __LONG_DOUBLE_128__ + | FFI_SYSV_LONG_DOUBLE_128 +# endif + ), + FFI_LAST_ABI = 32 +# endif +#endif + +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 +#if defined (POWERPC) || defined (POWERPC_FREEBSD) +# define FFI_GO_CLOSURES 1 +# define FFI_TARGET_SPECIFIC_VARIADIC 1 +# define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs +#endif +#if defined (POWERPC_AIX) +# define FFI_GO_CLOSURES 1 +#endif + +/* ppc_closure.S and linux64_closure.S expect this. */ +#define FFI_PPC_TYPE_LAST FFI_TYPE_POINTER + +/* We define additional types below. If generic types are added that + must be supported by powerpc libffi then it is likely that + FFI_PPC_TYPE_LAST needs increasing *and* the jump tables in + ppc_closure.S and linux64_closure.S be extended. */ + +#if !(FFI_TYPE_LAST == FFI_PPC_TYPE_LAST \ + || (FFI_TYPE_LAST == FFI_TYPE_COMPLEX \ + && !defined FFI_TARGET_HAS_COMPLEX_TYPE)) +# error "You likely have a broken powerpc libffi" +#endif + +/* Needed for soft-float long-double-128 support. */ +#define FFI_TYPE_UINT128 (FFI_PPC_TYPE_LAST + 1) + +/* Needed for FFI_SYSV small structure returns. */ +#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2) + +/* Used by ELFv2 for homogenous structure returns. */ +#define FFI_V2_TYPE_VECTOR (FFI_PPC_TYPE_LAST + 1) +#define FFI_V2_TYPE_VECTOR_HOMOG (FFI_PPC_TYPE_LAST + 2) +#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 3) +#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 4) +#define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 5) + +#if _CALL_ELF == 2 +# define FFI_TRAMPOLINE_SIZE 32 +#else +# if defined(POWERPC64) || defined(POWERPC_AIX) +# if defined(POWERPC_DARWIN64) +# define FFI_TRAMPOLINE_SIZE 48 +# else +# define FFI_TRAMPOLINE_SIZE 24 +# endif +# else /* POWERPC || POWERPC_AIX */ +# define FFI_TRAMPOLINE_SIZE 40 +# endif +#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/contrib/restricted/libffi/src/powerpc/linux64.S b/contrib/restricted/libffi/src/powerpc/linux64.S index c99889c1c6..ec1a9c160c 100644 --- a/contrib/restricted/libffi/src/powerpc/linux64.S +++ b/contrib/restricted/libffi/src/powerpc/linux64.S @@ -1,283 +1,283 @@ -/* ----------------------------------------------------------------------- - sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com> - Copyright (c) 2008 Red Hat, Inc. - - 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 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. - ----------------------------------------------------------------------- */ - -#define LIBFFI_ASM -#include <fficonfig.h> -#include <ffi.h> - -#ifdef POWERPC64 - .hidden ffi_call_LINUX64 - .globl ffi_call_LINUX64 - .text - .cfi_startproc -# if _CALL_ELF == 2 -ffi_call_LINUX64: - addis %r2, %r12, .TOC.-ffi_call_LINUX64@ha - addi %r2, %r2, .TOC.-ffi_call_LINUX64@l - .localentry ffi_call_LINUX64, . - ffi_call_LINUX64 -# else - .section ".opd","aw" - .align 3 -ffi_call_LINUX64: -# ifdef _CALL_LINUX - .quad .L.ffi_call_LINUX64,.TOC.@tocbase,0 - .type ffi_call_LINUX64,@function - .text -.L.ffi_call_LINUX64: -# else - .hidden .ffi_call_LINUX64 - .globl .ffi_call_LINUX64 - .quad .ffi_call_LINUX64,.TOC.@tocbase,0 - .size ffi_call_LINUX64,24 - .type .ffi_call_LINUX64,@function - .text -.ffi_call_LINUX64: -# endif -# endif - mflr %r0 - std %r28, -32(%r1) - std %r29, -24(%r1) - std %r30, -16(%r1) - std %r31, -8(%r1) - std %r7, 8(%r1) /* closure, saved in cr field. */ - std %r0, 16(%r1) - - mr %r28, %r1 /* our AP. */ - .cfi_def_cfa_register 28 - .cfi_offset 65, 16 - .cfi_offset 31, -8 - .cfi_offset 30, -16 - .cfi_offset 29, -24 - .cfi_offset 28, -32 - - stdux %r1, %r1, %r8 - mr %r31, %r6 /* flags, */ - mr %r30, %r5 /* rvalue, */ - mr %r29, %r4 /* function address. */ -/* Save toc pointer, not for the ffi_prep_args64 call, but for the later - bctrl function call. */ -# if _CALL_ELF == 2 - std %r2, 24(%r1) -# else - std %r2, 40(%r1) -# endif - - /* Call ffi_prep_args64. */ - mr %r4, %r1 -# if defined _CALL_LINUX || _CALL_ELF == 2 - bl ffi_prep_args64 -# else - bl .ffi_prep_args64 -# endif - -# if _CALL_ELF == 2 - mr %r12, %r29 -# else - ld %r12, 0(%r29) - ld %r2, 8(%r29) -# endif - /* Now do the call. */ - /* Set up cr1 with bits 3-7 of the flags. */ - mtcrf 0xc0, %r31 - - /* Get the address to call into CTR. */ - mtctr %r12 - /* Load all those argument registers. */ - addi %r29, %r28, -32-(8*8) - ld %r3, (0*8)(%r29) - ld %r4, (1*8)(%r29) - ld %r5, (2*8)(%r29) - ld %r6, (3*8)(%r29) - bf- 5, 1f - ld %r7, (4*8)(%r29) - ld %r8, (5*8)(%r29) - ld %r9, (6*8)(%r29) - ld %r10, (7*8)(%r29) -1: - - /* Load all the FP registers. */ - bf- 6, 2f - addi %r29, %r29, -(14*8) - lfd %f1, ( 1*8)(%r29) - lfd %f2, ( 2*8)(%r29) - lfd %f3, ( 3*8)(%r29) - lfd %f4, ( 4*8)(%r29) - lfd %f5, ( 5*8)(%r29) - lfd %f6, ( 6*8)(%r29) - lfd %f7, ( 7*8)(%r29) - lfd %f8, ( 8*8)(%r29) - lfd %f9, ( 9*8)(%r29) - lfd %f10, (10*8)(%r29) - lfd %f11, (11*8)(%r29) - lfd %f12, (12*8)(%r29) - lfd %f13, (13*8)(%r29) -2: - - /* Load all the vector registers. */ - bf- 3, 3f - addi %r29, %r29, -16 - lvx %v13, 0, %r29 - addi %r29, %r29, -16 - lvx %v12, 0, %r29 - addi %r29, %r29, -16 - lvx %v11, 0, %r29 - addi %r29, %r29, -16 - lvx %v10, 0, %r29 - addi %r29, %r29, -16 - lvx %v9, 0, %r29 - addi %r29, %r29, -16 - lvx %v8, 0, %r29 - addi %r29, %r29, -16 - lvx %v7, 0, %r29 - addi %r29, %r29, -16 - lvx %v6, 0, %r29 - addi %r29, %r29, -16 - lvx %v5, 0, %r29 - addi %r29, %r29, -16 - lvx %v4, 0, %r29 - addi %r29, %r29, -16 - lvx %v3, 0, %r29 - addi %r29, %r29, -16 - lvx %v2, 0, %r29 -3: - - /* Make the call. */ - ld %r11, 8(%r28) - bctrl - - /* This must follow the call immediately, the unwinder - uses this to find out if r2 has been saved or not. */ -# if _CALL_ELF == 2 - ld %r2, 24(%r1) -# else - ld %r2, 40(%r1) -# endif - - /* Now, deal with the return value. */ - mtcrf 0x01, %r31 - bt 31, .Lstruct_return_value - bt 30, .Ldone_return_value - bt 29, .Lfp_return_value - bt 28, .Lvec_return_value - std %r3, 0(%r30) - /* Fall through... */ - -.Ldone_return_value: - /* Restore the registers we used and return. */ - mr %r1, %r28 - .cfi_def_cfa_register 1 - ld %r0, 16(%r28) - ld %r28, -32(%r28) - mtlr %r0 - ld %r29, -24(%r1) - ld %r30, -16(%r1) - ld %r31, -8(%r1) - blr - -.Lvec_return_value: - stvx %v2, 0, %r30 - b .Ldone_return_value - -.Lfp_return_value: - .cfi_def_cfa_register 28 - mtcrf 0x02, %r31 /* cr6 */ - bf 27, .Lfloat_return_value - stfd %f1, 0(%r30) - bf 26, .Ldone_return_value - stfd %f2, 8(%r30) - b .Ldone_return_value -.Lfloat_return_value: - stfs %f1, 0(%r30) - b .Ldone_return_value - -.Lstruct_return_value: - bf 29, .Lvec_homog_or_small_struct - mtcrf 0x02, %r31 /* cr6 */ - bf 27, .Lfloat_homog_return_value - stfd %f1, 0(%r30) - stfd %f2, 8(%r30) - stfd %f3, 16(%r30) - stfd %f4, 24(%r30) - stfd %f5, 32(%r30) - stfd %f6, 40(%r30) - stfd %f7, 48(%r30) - stfd %f8, 56(%r30) - b .Ldone_return_value - -.Lfloat_homog_return_value: - stfs %f1, 0(%r30) - stfs %f2, 4(%r30) - stfs %f3, 8(%r30) - stfs %f4, 12(%r30) - stfs %f5, 16(%r30) - stfs %f6, 20(%r30) - stfs %f7, 24(%r30) - stfs %f8, 28(%r30) - b .Ldone_return_value - -.Lvec_homog_or_small_struct: - bf 28, .Lsmall_struct - stvx %v2, 0, %r30 - addi %r30, %r30, 16 - stvx %v3, 0, %r30 - addi %r30, %r30, 16 - stvx %v4, 0, %r30 - addi %r30, %r30, 16 - stvx %v5, 0, %r30 - addi %r30, %r30, 16 - stvx %v6, 0, %r30 - addi %r30, %r30, 16 - stvx %v7, 0, %r30 - addi %r30, %r30, 16 - stvx %v8, 0, %r30 - addi %r30, %r30, 16 - stvx %v9, 0, %r30 - b .Ldone_return_value - -.Lsmall_struct: - std %r3, 0(%r30) - std %r4, 8(%r30) - b .Ldone_return_value - - .cfi_endproc -# if _CALL_ELF == 2 - .size ffi_call_LINUX64,.-ffi_call_LINUX64 -# else -# ifdef _CALL_LINUX - .size ffi_call_LINUX64,.-.L.ffi_call_LINUX64 -# else - .long 0 - .byte 0,12,0,1,128,4,0,0 - .size .ffi_call_LINUX64,.-.ffi_call_LINUX64 -# endif -# endif - -#endif - -#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 - .section .note.GNU-stack,"",@progbits -#endif +/* ----------------------------------------------------------------------- + sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com> + Copyright (c) 2008 Red Hat, Inc. + + 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 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. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +#ifdef POWERPC64 + .hidden ffi_call_LINUX64 + .globl ffi_call_LINUX64 + .text + .cfi_startproc +# if _CALL_ELF == 2 +ffi_call_LINUX64: + addis %r2, %r12, .TOC.-ffi_call_LINUX64@ha + addi %r2, %r2, .TOC.-ffi_call_LINUX64@l + .localentry ffi_call_LINUX64, . - ffi_call_LINUX64 +# else + .section ".opd","aw" + .align 3 +ffi_call_LINUX64: +# ifdef _CALL_LINUX + .quad .L.ffi_call_LINUX64,.TOC.@tocbase,0 + .type ffi_call_LINUX64,@function + .text +.L.ffi_call_LINUX64: +# else + .hidden .ffi_call_LINUX64 + .globl .ffi_call_LINUX64 + .quad .ffi_call_LINUX64,.TOC.@tocbase,0 + .size ffi_call_LINUX64,24 + .type .ffi_call_LINUX64,@function + .text +.ffi_call_LINUX64: +# endif +# endif + mflr %r0 + std %r28, -32(%r1) + std %r29, -24(%r1) + std %r30, -16(%r1) + std %r31, -8(%r1) + std %r7, 8(%r1) /* closure, saved in cr field. */ + std %r0, 16(%r1) + + mr %r28, %r1 /* our AP. */ + .cfi_def_cfa_register 28 + .cfi_offset 65, 16 + .cfi_offset 31, -8 + .cfi_offset 30, -16 + .cfi_offset 29, -24 + .cfi_offset 28, -32 + + stdux %r1, %r1, %r8 + mr %r31, %r6 /* flags, */ + mr %r30, %r5 /* rvalue, */ + mr %r29, %r4 /* function address. */ +/* Save toc pointer, not for the ffi_prep_args64 call, but for the later + bctrl function call. */ +# if _CALL_ELF == 2 + std %r2, 24(%r1) +# else + std %r2, 40(%r1) +# endif + + /* Call ffi_prep_args64. */ + mr %r4, %r1 +# if defined _CALL_LINUX || _CALL_ELF == 2 + bl ffi_prep_args64 +# else + bl .ffi_prep_args64 +# endif + +# if _CALL_ELF == 2 + mr %r12, %r29 +# else + ld %r12, 0(%r29) + ld %r2, 8(%r29) +# endif + /* Now do the call. */ + /* Set up cr1 with bits 3-7 of the flags. */ + mtcrf 0xc0, %r31 + + /* Get the address to call into CTR. */ + mtctr %r12 + /* Load all those argument registers. */ + addi %r29, %r28, -32-(8*8) + ld %r3, (0*8)(%r29) + ld %r4, (1*8)(%r29) + ld %r5, (2*8)(%r29) + ld %r6, (3*8)(%r29) + bf- 5, 1f + ld %r7, (4*8)(%r29) + ld %r8, (5*8)(%r29) + ld %r9, (6*8)(%r29) + ld %r10, (7*8)(%r29) +1: + + /* Load all the FP registers. */ + bf- 6, 2f + addi %r29, %r29, -(14*8) + lfd %f1, ( 1*8)(%r29) + lfd %f2, ( 2*8)(%r29) + lfd %f3, ( 3*8)(%r29) + lfd %f4, ( 4*8)(%r29) + lfd %f5, ( 5*8)(%r29) + lfd %f6, ( 6*8)(%r29) + lfd %f7, ( 7*8)(%r29) + lfd %f8, ( 8*8)(%r29) + lfd %f9, ( 9*8)(%r29) + lfd %f10, (10*8)(%r29) + lfd %f11, (11*8)(%r29) + lfd %f12, (12*8)(%r29) + lfd %f13, (13*8)(%r29) +2: + + /* Load all the vector registers. */ + bf- 3, 3f + addi %r29, %r29, -16 + lvx %v13, 0, %r29 + addi %r29, %r29, -16 + lvx %v12, 0, %r29 + addi %r29, %r29, -16 + lvx %v11, 0, %r29 + addi %r29, %r29, -16 + lvx %v10, 0, %r29 + addi %r29, %r29, -16 + lvx %v9, 0, %r29 + addi %r29, %r29, -16 + lvx %v8, 0, %r29 + addi %r29, %r29, -16 + lvx %v7, 0, %r29 + addi %r29, %r29, -16 + lvx %v6, 0, %r29 + addi %r29, %r29, -16 + lvx %v5, 0, %r29 + addi %r29, %r29, -16 + lvx %v4, 0, %r29 + addi %r29, %r29, -16 + lvx %v3, 0, %r29 + addi %r29, %r29, -16 + lvx %v2, 0, %r29 +3: + + /* Make the call. */ + ld %r11, 8(%r28) + bctrl + + /* This must follow the call immediately, the unwinder + uses this to find out if r2 has been saved or not. */ +# if _CALL_ELF == 2 + ld %r2, 24(%r1) +# else + ld %r2, 40(%r1) +# endif + + /* Now, deal with the return value. */ + mtcrf 0x01, %r31 + bt 31, .Lstruct_return_value + bt 30, .Ldone_return_value + bt 29, .Lfp_return_value + bt 28, .Lvec_return_value + std %r3, 0(%r30) + /* Fall through... */ + +.Ldone_return_value: + /* Restore the registers we used and return. */ + mr %r1, %r28 + .cfi_def_cfa_register 1 + ld %r0, 16(%r28) + ld %r28, -32(%r28) + mtlr %r0 + ld %r29, -24(%r1) + ld %r30, -16(%r1) + ld %r31, -8(%r1) + blr + +.Lvec_return_value: + stvx %v2, 0, %r30 + b .Ldone_return_value + +.Lfp_return_value: + .cfi_def_cfa_register 28 + mtcrf 0x02, %r31 /* cr6 */ + bf 27, .Lfloat_return_value + stfd %f1, 0(%r30) + bf 26, .Ldone_return_value + stfd %f2, 8(%r30) + b .Ldone_return_value +.Lfloat_return_value: + stfs %f1, 0(%r30) + b .Ldone_return_value + +.Lstruct_return_value: + bf 29, .Lvec_homog_or_small_struct + mtcrf 0x02, %r31 /* cr6 */ + bf 27, .Lfloat_homog_return_value + stfd %f1, 0(%r30) + stfd %f2, 8(%r30) + stfd %f3, 16(%r30) + stfd %f4, 24(%r30) + stfd %f5, 32(%r30) + stfd %f6, 40(%r30) + stfd %f7, 48(%r30) + stfd %f8, 56(%r30) + b .Ldone_return_value + +.Lfloat_homog_return_value: + stfs %f1, 0(%r30) + stfs %f2, 4(%r30) + stfs %f3, 8(%r30) + stfs %f4, 12(%r30) + stfs %f5, 16(%r30) + stfs %f6, 20(%r30) + stfs %f7, 24(%r30) + stfs %f8, 28(%r30) + b .Ldone_return_value + +.Lvec_homog_or_small_struct: + bf 28, .Lsmall_struct + stvx %v2, 0, %r30 + addi %r30, %r30, 16 + stvx %v3, 0, %r30 + addi %r30, %r30, 16 + stvx %v4, 0, %r30 + addi %r30, %r30, 16 + stvx %v5, 0, %r30 + addi %r30, %r30, 16 + stvx %v6, 0, %r30 + addi %r30, %r30, 16 + stvx %v7, 0, %r30 + addi %r30, %r30, 16 + stvx %v8, 0, %r30 + addi %r30, %r30, 16 + stvx %v9, 0, %r30 + b .Ldone_return_value + +.Lsmall_struct: + std %r3, 0(%r30) + std %r4, 8(%r30) + b .Ldone_return_value + + .cfi_endproc +# if _CALL_ELF == 2 + .size ffi_call_LINUX64,.-ffi_call_LINUX64 +# else +# ifdef _CALL_LINUX + .size ffi_call_LINUX64,.-.L.ffi_call_LINUX64 +# else + .long 0 + .byte 0,12,0,1,128,4,0,0 + .size .ffi_call_LINUX64,.-.ffi_call_LINUX64 +# endif +# endif + +#endif + +#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/restricted/libffi/src/powerpc/linux64_closure.S b/contrib/restricted/libffi/src/powerpc/linux64_closure.S index d67e4bbbd1..051d5410b8 100644 --- a/contrib/restricted/libffi/src/powerpc/linux64_closure.S +++ b/contrib/restricted/libffi/src/powerpc/linux64_closure.S @@ -1,552 +1,552 @@ -/* ----------------------------------------------------------------------- - sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com> - Copyright (c) 2008 Red Hat, Inc. - - 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 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. - ----------------------------------------------------------------------- */ -#define LIBFFI_ASM -#include <fficonfig.h> -#include <ffi.h> - - .file "linux64_closure.S" - -#ifdef POWERPC64 - FFI_HIDDEN (ffi_closure_LINUX64) - .globl ffi_closure_LINUX64 - .text - .cfi_startproc -# if _CALL_ELF == 2 -ffi_closure_LINUX64: - addis %r2, %r12, .TOC.-ffi_closure_LINUX64@ha - addi %r2, %r2, .TOC.-ffi_closure_LINUX64@l - .localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64 -# else - .section ".opd","aw" - .align 3 -ffi_closure_LINUX64: -# ifdef _CALL_LINUX - .quad .L.ffi_closure_LINUX64,.TOC.@tocbase,0 - .type ffi_closure_LINUX64,@function - .text -.L.ffi_closure_LINUX64: -# else - FFI_HIDDEN (.ffi_closure_LINUX64) - .globl .ffi_closure_LINUX64 - .quad .ffi_closure_LINUX64,.TOC.@tocbase,0 - .size ffi_closure_LINUX64,24 - .type .ffi_closure_LINUX64,@function - .text -.ffi_closure_LINUX64: -# endif -# endif - -# if _CALL_ELF == 2 -# ifdef __VEC__ -# 32 byte special reg save area + 64 byte parm save area -# + 128 byte retval area + 13*8 fpr save area + 12*16 vec save area + round to 16 -# define STACKFRAME 528 -# else -# 32 byte special reg save area + 64 byte parm save area -# + 64 byte retval area + 13*8 fpr save area + round to 16 -# define STACKFRAME 272 -# endif -# define PARMSAVE 32 -# define RETVAL PARMSAVE+64 -# else -# 48 bytes special reg save area + 64 bytes parm save area -# + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 -# define STACKFRAME 240 -# define PARMSAVE 48 -# define RETVAL PARMSAVE+64 -# endif - -# if _CALL_ELF == 2 - ld %r12, FFI_TRAMPOLINE_SIZE(%r11) # closure->cif - mflr %r0 - lwz %r12, 28(%r12) # cif->flags - mtcrf 0x40, %r12 - addi %r12, %r1, PARMSAVE - bt 7, 0f - # Our caller has not allocated a parameter save area. - # We need to allocate one here and use it to pass gprs to - # ffi_closure_helper_LINUX64. - addi %r12, %r1, -STACKFRAME+PARMSAVE -0: - # Save general regs into parm save area - std %r3, 0(%r12) - std %r4, 8(%r12) - std %r5, 16(%r12) - std %r6, 24(%r12) - std %r7, 32(%r12) - std %r8, 40(%r12) - std %r9, 48(%r12) - std %r10, 56(%r12) - - # load up the pointer to the parm save area - mr %r7, %r12 -# else - # copy r2 to r11 and load TOC into r2 - mr %r11, %r2 - ld %r2, 16(%r2) - - mflr %r0 - # Save general regs into parm save area - # This is the parameter save area set up by our caller. - std %r3, PARMSAVE+0(%r1) - std %r4, PARMSAVE+8(%r1) - std %r5, PARMSAVE+16(%r1) - std %r6, PARMSAVE+24(%r1) - std %r7, PARMSAVE+32(%r1) - std %r8, PARMSAVE+40(%r1) - std %r9, PARMSAVE+48(%r1) - std %r10, PARMSAVE+56(%r1) - - # load up the pointer to the parm save area - addi %r7, %r1, PARMSAVE -# endif - std %r0, 16(%r1) - - # closure->cif - ld %r3, FFI_TRAMPOLINE_SIZE(%r11) - # closure->fun - ld %r4, FFI_TRAMPOLINE_SIZE+8(%r11) - # closure->user_data - ld %r5, FFI_TRAMPOLINE_SIZE+16(%r11) - -.Ldoclosure: - # next save fpr 1 to fpr 13 - stfd %f1, -104+(0*8)(%r1) - stfd %f2, -104+(1*8)(%r1) - stfd %f3, -104+(2*8)(%r1) - stfd %f4, -104+(3*8)(%r1) - stfd %f5, -104+(4*8)(%r1) - stfd %f6, -104+(5*8)(%r1) - stfd %f7, -104+(6*8)(%r1) - stfd %f8, -104+(7*8)(%r1) - stfd %f9, -104+(8*8)(%r1) - stfd %f10, -104+(9*8)(%r1) - stfd %f11, -104+(10*8)(%r1) - stfd %f12, -104+(11*8)(%r1) - stfd %f13, -104+(12*8)(%r1) - - # load up the pointer to the saved fpr registers - addi %r8, %r1, -104 - -# ifdef __VEC__ - # load up the pointer to the saved vector registers - # 8 bytes padding for 16-byte alignment at -112(%r1) - addi %r9, %r8, -24 - stvx %v13, 0, %r9 - addi %r9, %r9, -16 - stvx %v12, 0, %r9 - addi %r9, %r9, -16 - stvx %v11, 0, %r9 - addi %r9, %r9, -16 - stvx %v10, 0, %r9 - addi %r9, %r9, -16 - stvx %v9, 0, %r9 - addi %r9, %r9, -16 - stvx %v8, 0, %r9 - addi %r9, %r9, -16 - stvx %v7, 0, %r9 - addi %r9, %r9, -16 - stvx %v6, 0, %r9 - addi %r9, %r9, -16 - stvx %v5, 0, %r9 - addi %r9, %r9, -16 - stvx %v4, 0, %r9 - addi %r9, %r9, -16 - stvx %v3, 0, %r9 - addi %r9, %r9, -16 - stvx %v2, 0, %r9 -# endif - - # load up the pointer to the result storage - addi %r6, %r1, -STACKFRAME+RETVAL - - stdu %r1, -STACKFRAME(%r1) - .cfi_def_cfa_offset STACKFRAME - .cfi_offset 65, 16 - - # make the call -# if defined _CALL_LINUX || _CALL_ELF == 2 - bl ffi_closure_helper_LINUX64 -# else - bl .ffi_closure_helper_LINUX64 -# endif -.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 - ld %r0, STACKFRAME+16(%r1) - cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT - bge .Lsmall - mflr %r4 # move address of .Lret to r4 - sldi %r3, %r3, 4 # now multiply return type by 16 - addi %r4, %r4, .Lret_type0 - .Lret - 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, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME - nop -# case FFI_TYPE_INT -# ifdef __LITTLE_ENDIAN__ - lwa %r3, RETVAL+0(%r1) -# else - lwa %r3, RETVAL+4(%r1) -# endif - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_FLOAT - lfs %f1, RETVAL+0(%r1) - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_DOUBLE - lfd %f1, RETVAL+0(%r1) - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_LONGDOUBLE - lfd %f1, RETVAL+0(%r1) - mtlr %r0 - lfd %f2, RETVAL+8(%r1) - b .Lfinish -# case FFI_TYPE_UINT8 -# ifdef __LITTLE_ENDIAN__ - lbz %r3, RETVAL+0(%r1) -# else - lbz %r3, RETVAL+7(%r1) -# endif - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_SINT8 -# ifdef __LITTLE_ENDIAN__ - lbz %r3, RETVAL+0(%r1) -# else - lbz %r3, RETVAL+7(%r1) -# endif - extsb %r3,%r3 - mtlr %r0 - b .Lfinish -# case FFI_TYPE_UINT16 -# ifdef __LITTLE_ENDIAN__ - lhz %r3, RETVAL+0(%r1) -# else - lhz %r3, RETVAL+6(%r1) -# endif - mtlr %r0 -.Lfinish: - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_SINT16 -# ifdef __LITTLE_ENDIAN__ - lha %r3, RETVAL+0(%r1) -# else - lha %r3, RETVAL+6(%r1) -# endif - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_UINT32 -# ifdef __LITTLE_ENDIAN__ - lwz %r3, RETVAL+0(%r1) -# else - lwz %r3, RETVAL+4(%r1) -# endif - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_SINT32 -# ifdef __LITTLE_ENDIAN__ - lwa %r3, RETVAL+0(%r1) -# else - lwa %r3, RETVAL+4(%r1) -# endif - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_UINT64 - ld %r3, RETVAL+0(%r1) - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_SINT64 - ld %r3, RETVAL+0(%r1) - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_TYPE_STRUCT - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME - nop -# case FFI_TYPE_POINTER - ld %r3, RETVAL+0(%r1) - mtlr %r0 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -# case FFI_V2_TYPE_VECTOR - addi %r3, %r1, RETVAL - lvx %v2, 0, %r3 - mtlr %r0 - b .Lfinish -# case FFI_V2_TYPE_VECTOR_HOMOG - addi %r3, %r1, RETVAL - lvx %v2, 0, %r3 - addi %r3, %r3, 16 - b .Lmorevector -# case FFI_V2_TYPE_FLOAT_HOMOG - lfs %f1, RETVAL+0(%r1) - lfs %f2, RETVAL+4(%r1) - lfs %f3, RETVAL+8(%r1) - b .Lmorefloat -# case FFI_V2_TYPE_DOUBLE_HOMOG - lfd %f1, RETVAL+0(%r1) - lfd %f2, RETVAL+8(%r1) - lfd %f3, RETVAL+16(%r1) - lfd %f4, RETVAL+24(%r1) - mtlr %r0 - lfd %f5, RETVAL+32(%r1) - lfd %f6, RETVAL+40(%r1) - lfd %f7, RETVAL+48(%r1) - lfd %f8, RETVAL+56(%r1) - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -.Lmorevector: - lvx %v3, 0, %r3 - addi %r3, %r3, 16 - lvx %v4, 0, %r3 - addi %r3, %r3, 16 - lvx %v5, 0, %r3 - mtlr %r0 - addi %r3, %r3, 16 - lvx %v6, 0, %r3 - addi %r3, %r3, 16 - lvx %v7, 0, %r3 - addi %r3, %r3, 16 - lvx %v8, 0, %r3 - addi %r3, %r3, 16 - lvx %v9, 0, %r3 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -.Lmorefloat: - lfs %f4, RETVAL+12(%r1) - mtlr %r0 - lfs %f5, RETVAL+16(%r1) - lfs %f6, RETVAL+20(%r1) - lfs %f7, RETVAL+24(%r1) - lfs %f8, RETVAL+28(%r1) - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -.Lsmall: -# ifdef __LITTLE_ENDIAN__ - ld %r3,RETVAL+0(%r1) - mtlr %r0 - ld %r4,RETVAL+8(%r1) - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr -# else - # A struct smaller than a dword is returned in the low bits of r3 - # ie. right justified. Larger structs are passed left justified - # in r3 and r4. The return value area on the stack will have - # the structs as they are usually stored in memory. - cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes? - neg %r5, %r3 - ld %r3,RETVAL+0(%r1) - blt .Lsmalldown - mtlr %r0 - ld %r4,RETVAL+8(%r1) - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset STACKFRAME -.Lsmalldown: - addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7 - mtlr %r0 - sldi %r5, %r5, 3 - addi %r1, %r1, STACKFRAME - .cfi_def_cfa_offset 0 - srd %r3, %r3, %r5 - blr -# endif - - .cfi_endproc -# if _CALL_ELF == 2 - .size ffi_closure_LINUX64,.-ffi_closure_LINUX64 -# else -# ifdef _CALL_LINUX - .size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64 -# else - .long 0 - .byte 0,12,0,1,128,0,0,0 - .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 -# endif -# endif - - - FFI_HIDDEN (ffi_go_closure_linux64) - .globl ffi_go_closure_linux64 - .text - .cfi_startproc -# if _CALL_ELF == 2 -ffi_go_closure_linux64: - addis %r2, %r12, .TOC.-ffi_go_closure_linux64@ha - addi %r2, %r2, .TOC.-ffi_go_closure_linux64@l - .localentry ffi_go_closure_linux64, . - ffi_go_closure_linux64 -# else - .section ".opd","aw" - .align 3 -ffi_go_closure_linux64: -# ifdef _CALL_LINUX - .quad .L.ffi_go_closure_linux64,.TOC.@tocbase,0 - .type ffi_go_closure_linux64,@function - .text -.L.ffi_go_closure_linux64: -# else - FFI_HIDDEN (.ffi_go_closure_linux64) - .globl .ffi_go_closure_linux64 - .quad .ffi_go_closure_linux64,.TOC.@tocbase,0 - .size ffi_go_closure_linux64,24 - .type .ffi_go_closure_linux64,@function - .text -.ffi_go_closure_linux64: -# endif -# endif - -# if _CALL_ELF == 2 - ld %r12, 8(%r11) # closure->cif - mflr %r0 - lwz %r12, 28(%r12) # cif->flags - mtcrf 0x40, %r12 - addi %r12, %r1, PARMSAVE - bt 7, 0f - # Our caller has not allocated a parameter save area. - # We need to allocate one here and use it to pass gprs to - # ffi_closure_helper_LINUX64. - addi %r12, %r1, -STACKFRAME+PARMSAVE -0: - # Save general regs into parm save area - std %r3, 0(%r12) - std %r4, 8(%r12) - std %r5, 16(%r12) - std %r6, 24(%r12) - std %r7, 32(%r12) - std %r8, 40(%r12) - std %r9, 48(%r12) - std %r10, 56(%r12) - - # load up the pointer to the parm save area - mr %r7, %r12 -# else - mflr %r0 - # Save general regs into parm save area - # This is the parameter save area set up by our caller. - std %r3, PARMSAVE+0(%r1) - std %r4, PARMSAVE+8(%r1) - std %r5, PARMSAVE+16(%r1) - std %r6, PARMSAVE+24(%r1) - std %r7, PARMSAVE+32(%r1) - std %r8, PARMSAVE+40(%r1) - std %r9, PARMSAVE+48(%r1) - std %r10, PARMSAVE+56(%r1) - - # load up the pointer to the parm save area - addi %r7, %r1, PARMSAVE -# endif - std %r0, 16(%r1) - - # closure->cif - ld %r3, 8(%r11) - # closure->fun - ld %r4, 16(%r11) - # user_data - mr %r5, %r11 - b .Ldoclosure - - .cfi_endproc -# if _CALL_ELF == 2 - .size ffi_go_closure_linux64,.-ffi_go_closure_linux64 -# else -# ifdef _CALL_LINUX - .size ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64 -# else - .long 0 - .byte 0,12,0,1,128,0,0,0 - .size .ffi_go_closure_linux64,.-.ffi_go_closure_linux64 -# endif -# endif -#endif - -#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 - .section .note.GNU-stack,"",@progbits -#endif +/* ----------------------------------------------------------------------- + sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com> + Copyright (c) 2008 Red Hat, Inc. + + 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 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. + ----------------------------------------------------------------------- */ +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .file "linux64_closure.S" + +#ifdef POWERPC64 + FFI_HIDDEN (ffi_closure_LINUX64) + .globl ffi_closure_LINUX64 + .text + .cfi_startproc +# if _CALL_ELF == 2 +ffi_closure_LINUX64: + addis %r2, %r12, .TOC.-ffi_closure_LINUX64@ha + addi %r2, %r2, .TOC.-ffi_closure_LINUX64@l + .localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64 +# else + .section ".opd","aw" + .align 3 +ffi_closure_LINUX64: +# ifdef _CALL_LINUX + .quad .L.ffi_closure_LINUX64,.TOC.@tocbase,0 + .type ffi_closure_LINUX64,@function + .text +.L.ffi_closure_LINUX64: +# else + FFI_HIDDEN (.ffi_closure_LINUX64) + .globl .ffi_closure_LINUX64 + .quad .ffi_closure_LINUX64,.TOC.@tocbase,0 + .size ffi_closure_LINUX64,24 + .type .ffi_closure_LINUX64,@function + .text +.ffi_closure_LINUX64: +# endif +# endif + +# if _CALL_ELF == 2 +# ifdef __VEC__ +# 32 byte special reg save area + 64 byte parm save area +# + 128 byte retval area + 13*8 fpr save area + 12*16 vec save area + round to 16 +# define STACKFRAME 528 +# else +# 32 byte special reg save area + 64 byte parm save area +# + 64 byte retval area + 13*8 fpr save area + round to 16 +# define STACKFRAME 272 +# endif +# define PARMSAVE 32 +# define RETVAL PARMSAVE+64 +# else +# 48 bytes special reg save area + 64 bytes parm save area +# + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 +# define STACKFRAME 240 +# define PARMSAVE 48 +# define RETVAL PARMSAVE+64 +# endif + +# if _CALL_ELF == 2 + ld %r12, FFI_TRAMPOLINE_SIZE(%r11) # closure->cif + mflr %r0 + lwz %r12, 28(%r12) # cif->flags + mtcrf 0x40, %r12 + addi %r12, %r1, PARMSAVE + bt 7, 0f + # Our caller has not allocated a parameter save area. + # We need to allocate one here and use it to pass gprs to + # ffi_closure_helper_LINUX64. + addi %r12, %r1, -STACKFRAME+PARMSAVE +0: + # Save general regs into parm save area + std %r3, 0(%r12) + std %r4, 8(%r12) + std %r5, 16(%r12) + std %r6, 24(%r12) + std %r7, 32(%r12) + std %r8, 40(%r12) + std %r9, 48(%r12) + std %r10, 56(%r12) + + # load up the pointer to the parm save area + mr %r7, %r12 +# else + # copy r2 to r11 and load TOC into r2 + mr %r11, %r2 + ld %r2, 16(%r2) + + mflr %r0 + # Save general regs into parm save area + # This is the parameter save area set up by our caller. + std %r3, PARMSAVE+0(%r1) + std %r4, PARMSAVE+8(%r1) + std %r5, PARMSAVE+16(%r1) + std %r6, PARMSAVE+24(%r1) + std %r7, PARMSAVE+32(%r1) + std %r8, PARMSAVE+40(%r1) + std %r9, PARMSAVE+48(%r1) + std %r10, PARMSAVE+56(%r1) + + # load up the pointer to the parm save area + addi %r7, %r1, PARMSAVE +# endif + std %r0, 16(%r1) + + # closure->cif + ld %r3, FFI_TRAMPOLINE_SIZE(%r11) + # closure->fun + ld %r4, FFI_TRAMPOLINE_SIZE+8(%r11) + # closure->user_data + ld %r5, FFI_TRAMPOLINE_SIZE+16(%r11) + +.Ldoclosure: + # next save fpr 1 to fpr 13 + stfd %f1, -104+(0*8)(%r1) + stfd %f2, -104+(1*8)(%r1) + stfd %f3, -104+(2*8)(%r1) + stfd %f4, -104+(3*8)(%r1) + stfd %f5, -104+(4*8)(%r1) + stfd %f6, -104+(5*8)(%r1) + stfd %f7, -104+(6*8)(%r1) + stfd %f8, -104+(7*8)(%r1) + stfd %f9, -104+(8*8)(%r1) + stfd %f10, -104+(9*8)(%r1) + stfd %f11, -104+(10*8)(%r1) + stfd %f12, -104+(11*8)(%r1) + stfd %f13, -104+(12*8)(%r1) + + # load up the pointer to the saved fpr registers + addi %r8, %r1, -104 + +# ifdef __VEC__ + # load up the pointer to the saved vector registers + # 8 bytes padding for 16-byte alignment at -112(%r1) + addi %r9, %r8, -24 + stvx %v13, 0, %r9 + addi %r9, %r9, -16 + stvx %v12, 0, %r9 + addi %r9, %r9, -16 + stvx %v11, 0, %r9 + addi %r9, %r9, -16 + stvx %v10, 0, %r9 + addi %r9, %r9, -16 + stvx %v9, 0, %r9 + addi %r9, %r9, -16 + stvx %v8, 0, %r9 + addi %r9, %r9, -16 + stvx %v7, 0, %r9 + addi %r9, %r9, -16 + stvx %v6, 0, %r9 + addi %r9, %r9, -16 + stvx %v5, 0, %r9 + addi %r9, %r9, -16 + stvx %v4, 0, %r9 + addi %r9, %r9, -16 + stvx %v3, 0, %r9 + addi %r9, %r9, -16 + stvx %v2, 0, %r9 +# endif + + # load up the pointer to the result storage + addi %r6, %r1, -STACKFRAME+RETVAL + + stdu %r1, -STACKFRAME(%r1) + .cfi_def_cfa_offset STACKFRAME + .cfi_offset 65, 16 + + # make the call +# if defined _CALL_LINUX || _CALL_ELF == 2 + bl ffi_closure_helper_LINUX64 +# else + bl .ffi_closure_helper_LINUX64 +# endif +.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 + ld %r0, STACKFRAME+16(%r1) + cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + bge .Lsmall + mflr %r4 # move address of .Lret to r4 + sldi %r3, %r3, 4 # now multiply return type by 16 + addi %r4, %r4, .Lret_type0 - .Lret + 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, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME + nop +# case FFI_TYPE_INT +# ifdef __LITTLE_ENDIAN__ + lwa %r3, RETVAL+0(%r1) +# else + lwa %r3, RETVAL+4(%r1) +# endif + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_FLOAT + lfs %f1, RETVAL+0(%r1) + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_DOUBLE + lfd %f1, RETVAL+0(%r1) + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_LONGDOUBLE + lfd %f1, RETVAL+0(%r1) + mtlr %r0 + lfd %f2, RETVAL+8(%r1) + b .Lfinish +# case FFI_TYPE_UINT8 +# ifdef __LITTLE_ENDIAN__ + lbz %r3, RETVAL+0(%r1) +# else + lbz %r3, RETVAL+7(%r1) +# endif + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_SINT8 +# ifdef __LITTLE_ENDIAN__ + lbz %r3, RETVAL+0(%r1) +# else + lbz %r3, RETVAL+7(%r1) +# endif + extsb %r3,%r3 + mtlr %r0 + b .Lfinish +# case FFI_TYPE_UINT16 +# ifdef __LITTLE_ENDIAN__ + lhz %r3, RETVAL+0(%r1) +# else + lhz %r3, RETVAL+6(%r1) +# endif + mtlr %r0 +.Lfinish: + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_SINT16 +# ifdef __LITTLE_ENDIAN__ + lha %r3, RETVAL+0(%r1) +# else + lha %r3, RETVAL+6(%r1) +# endif + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_UINT32 +# ifdef __LITTLE_ENDIAN__ + lwz %r3, RETVAL+0(%r1) +# else + lwz %r3, RETVAL+4(%r1) +# endif + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_SINT32 +# ifdef __LITTLE_ENDIAN__ + lwa %r3, RETVAL+0(%r1) +# else + lwa %r3, RETVAL+4(%r1) +# endif + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_UINT64 + ld %r3, RETVAL+0(%r1) + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_SINT64 + ld %r3, RETVAL+0(%r1) + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_TYPE_STRUCT + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME + nop +# case FFI_TYPE_POINTER + ld %r3, RETVAL+0(%r1) + mtlr %r0 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +# case FFI_V2_TYPE_VECTOR + addi %r3, %r1, RETVAL + lvx %v2, 0, %r3 + mtlr %r0 + b .Lfinish +# case FFI_V2_TYPE_VECTOR_HOMOG + addi %r3, %r1, RETVAL + lvx %v2, 0, %r3 + addi %r3, %r3, 16 + b .Lmorevector +# case FFI_V2_TYPE_FLOAT_HOMOG + lfs %f1, RETVAL+0(%r1) + lfs %f2, RETVAL+4(%r1) + lfs %f3, RETVAL+8(%r1) + b .Lmorefloat +# case FFI_V2_TYPE_DOUBLE_HOMOG + lfd %f1, RETVAL+0(%r1) + lfd %f2, RETVAL+8(%r1) + lfd %f3, RETVAL+16(%r1) + lfd %f4, RETVAL+24(%r1) + mtlr %r0 + lfd %f5, RETVAL+32(%r1) + lfd %f6, RETVAL+40(%r1) + lfd %f7, RETVAL+48(%r1) + lfd %f8, RETVAL+56(%r1) + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +.Lmorevector: + lvx %v3, 0, %r3 + addi %r3, %r3, 16 + lvx %v4, 0, %r3 + addi %r3, %r3, 16 + lvx %v5, 0, %r3 + mtlr %r0 + addi %r3, %r3, 16 + lvx %v6, 0, %r3 + addi %r3, %r3, 16 + lvx %v7, 0, %r3 + addi %r3, %r3, 16 + lvx %v8, 0, %r3 + addi %r3, %r3, 16 + lvx %v9, 0, %r3 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +.Lmorefloat: + lfs %f4, RETVAL+12(%r1) + mtlr %r0 + lfs %f5, RETVAL+16(%r1) + lfs %f6, RETVAL+20(%r1) + lfs %f7, RETVAL+24(%r1) + lfs %f8, RETVAL+28(%r1) + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +.Lsmall: +# ifdef __LITTLE_ENDIAN__ + ld %r3,RETVAL+0(%r1) + mtlr %r0 + ld %r4,RETVAL+8(%r1) + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr +# else + # A struct smaller than a dword is returned in the low bits of r3 + # ie. right justified. Larger structs are passed left justified + # in r3 and r4. The return value area on the stack will have + # the structs as they are usually stored in memory. + cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes? + neg %r5, %r3 + ld %r3,RETVAL+0(%r1) + blt .Lsmalldown + mtlr %r0 + ld %r4,RETVAL+8(%r1) + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset STACKFRAME +.Lsmalldown: + addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7 + mtlr %r0 + sldi %r5, %r5, 3 + addi %r1, %r1, STACKFRAME + .cfi_def_cfa_offset 0 + srd %r3, %r3, %r5 + blr +# endif + + .cfi_endproc +# if _CALL_ELF == 2 + .size ffi_closure_LINUX64,.-ffi_closure_LINUX64 +# else +# ifdef _CALL_LINUX + .size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64 +# else + .long 0 + .byte 0,12,0,1,128,0,0,0 + .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 +# endif +# endif + + + FFI_HIDDEN (ffi_go_closure_linux64) + .globl ffi_go_closure_linux64 + .text + .cfi_startproc +# if _CALL_ELF == 2 +ffi_go_closure_linux64: + addis %r2, %r12, .TOC.-ffi_go_closure_linux64@ha + addi %r2, %r2, .TOC.-ffi_go_closure_linux64@l + .localentry ffi_go_closure_linux64, . - ffi_go_closure_linux64 +# else + .section ".opd","aw" + .align 3 +ffi_go_closure_linux64: +# ifdef _CALL_LINUX + .quad .L.ffi_go_closure_linux64,.TOC.@tocbase,0 + .type ffi_go_closure_linux64,@function + .text +.L.ffi_go_closure_linux64: +# else + FFI_HIDDEN (.ffi_go_closure_linux64) + .globl .ffi_go_closure_linux64 + .quad .ffi_go_closure_linux64,.TOC.@tocbase,0 + .size ffi_go_closure_linux64,24 + .type .ffi_go_closure_linux64,@function + .text +.ffi_go_closure_linux64: +# endif +# endif + +# if _CALL_ELF == 2 + ld %r12, 8(%r11) # closure->cif + mflr %r0 + lwz %r12, 28(%r12) # cif->flags + mtcrf 0x40, %r12 + addi %r12, %r1, PARMSAVE + bt 7, 0f + # Our caller has not allocated a parameter save area. + # We need to allocate one here and use it to pass gprs to + # ffi_closure_helper_LINUX64. + addi %r12, %r1, -STACKFRAME+PARMSAVE +0: + # Save general regs into parm save area + std %r3, 0(%r12) + std %r4, 8(%r12) + std %r5, 16(%r12) + std %r6, 24(%r12) + std %r7, 32(%r12) + std %r8, 40(%r12) + std %r9, 48(%r12) + std %r10, 56(%r12) + + # load up the pointer to the parm save area + mr %r7, %r12 +# else + mflr %r0 + # Save general regs into parm save area + # This is the parameter save area set up by our caller. + std %r3, PARMSAVE+0(%r1) + std %r4, PARMSAVE+8(%r1) + std %r5, PARMSAVE+16(%r1) + std %r6, PARMSAVE+24(%r1) + std %r7, PARMSAVE+32(%r1) + std %r8, PARMSAVE+40(%r1) + std %r9, PARMSAVE+48(%r1) + std %r10, PARMSAVE+56(%r1) + + # load up the pointer to the parm save area + addi %r7, %r1, PARMSAVE +# endif + std %r0, 16(%r1) + + # closure->cif + ld %r3, 8(%r11) + # closure->fun + ld %r4, 16(%r11) + # user_data + mr %r5, %r11 + b .Ldoclosure + + .cfi_endproc +# if _CALL_ELF == 2 + .size ffi_go_closure_linux64,.-ffi_go_closure_linux64 +# else +# ifdef _CALL_LINUX + .size ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64 +# else + .long 0 + .byte 0,12,0,1,128,0,0,0 + .size .ffi_go_closure_linux64,.-.ffi_go_closure_linux64 +# endif +# endif +#endif + +#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/restricted/libffi/src/powerpc/ppc_closure.S b/contrib/restricted/libffi/src/powerpc/ppc_closure.S index b6d209de86..a88b732281 100644 --- a/contrib/restricted/libffi/src/powerpc/ppc_closure.S +++ b/contrib/restricted/libffi/src/powerpc/ppc_closure.S @@ -1,397 +1,397 @@ -/* ----------------------------------------------------------------------- - sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com> - Copyright (c) 2008 Red Hat, 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 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. - ----------------------------------------------------------------------- */ -#define LIBFFI_ASM -#include <fficonfig.h> -#include <ffi.h> -#include <powerpc/asm.h> - - .file "ppc_closure.S" - -#ifndef POWERPC64 - -FFI_HIDDEN(ffi_closure_SYSV) -ENTRY(ffi_closure_SYSV) - .cfi_startproc - stwu %r1,-144(%r1) - .cfi_def_cfa_offset 144 - mflr %r0 - stw %r0,148(%r1) - .cfi_offset 65, 4 - -# 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) - - # set up registers for the routine that does the work - - # closure->cif - lwz %r3,FFI_TRAMPOLINE_SIZE(%r11) - # closure->fun - lwz %r4,FFI_TRAMPOLINE_SIZE+4(%r11) - # closure->user_data - lwz %r5,FFI_TRAMPOLINE_SIZE+8(%r11) - -.Ldoclosure: - 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 - - # pointer to the result storage - addi %r6,%r1,112 - - # pointer to the saved gpr registers - addi %r7,%r1,16 - - # pointer to the saved fpr registers - addi %r8,%r1,48 - - # pointer to the outgoing parameter save area in the previous frame - # i.e. the previous frame pointer + 8 - addi %r9,%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 - -# 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 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - nop - -# case FFI_TYPE_INT - lwz %r3,112+0(%r1) - mtlr %r0 -.Lfinish: - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_TYPE_FLOAT -#ifndef __NO_FPRS__ - lfs %f1,112+0(%r1) -#else - nop -#endif - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_TYPE_DOUBLE -#ifndef __NO_FPRS__ - lfd %f1,112+0(%r1) -#else - nop -#endif - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_TYPE_LONGDOUBLE -#ifndef __NO_FPRS__ - lfd %f1,112+0(%r1) - lfd %f2,112+8(%r1) - mtlr %r0 - b .Lfinish -#else - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - nop -#endif - -# case FFI_TYPE_UINT8 -#ifdef __LITTLE_ENDIAN__ - lbz %r3,112+0(%r1) -#else - lbz %r3,112+3(%r1) -#endif - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_TYPE_SINT8 -#ifdef __LITTLE_ENDIAN__ - lbz %r3,112+0(%r1) -#else - lbz %r3,112+3(%r1) -#endif - extsb %r3,%r3 - mtlr %r0 - b .Lfinish - -# case FFI_TYPE_UINT16 -#ifdef __LITTLE_ENDIAN__ - lhz %r3,112+0(%r1) -#else - lhz %r3,112+2(%r1) -#endif - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_TYPE_SINT16 -#ifdef __LITTLE_ENDIAN__ - lha %r3,112+0(%r1) -#else - lha %r3,112+2(%r1) -#endif - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_TYPE_UINT32 - lwz %r3,112+0(%r1) - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_TYPE_SINT32 - lwz %r3,112+0(%r1) - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# 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 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - nop - -# case FFI_TYPE_POINTER - lwz %r3,112+0(%r1) - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_TYPE_UINT128 - lwz %r3,112+0(%r1) - lwz %r4,112+4(%r1) - lwz %r5,112+8(%r1) - b .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 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct. - lhz %r3,112+0(%r1) - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct. - lwz %r3,112+0(%r1) -#ifdef __LITTLE_ENDIAN__ - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 -#else - srwi %r3,%r3,8 - mtlr %r0 - b .Lfinish -#endif - -# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct. - lwz %r3,112+0(%r1) - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 - -# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct. - lwz %r3,112+0(%r1) - lwz %r4,112+4(%r1) -#ifdef __LITTLE_ENDIAN__ - mtlr %r0 - b .Lfinish -#else - li %r5,24 - b .Lstruct567 -#endif - -# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct. - lwz %r3,112+0(%r1) - lwz %r4,112+4(%r1) -#ifdef __LITTLE_ENDIAN__ - mtlr %r0 - b .Lfinish -#else - li %r5,16 - b .Lstruct567 -#endif - -# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct. - lwz %r3,112+0(%r1) - lwz %r4,112+4(%r1) -#ifdef __LITTLE_ENDIAN__ - mtlr %r0 - b .Lfinish -#else - li %r5,8 - b .Lstruct567 -#endif - -# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct. - lwz %r3,112+0(%r1) - lwz %r4,112+4(%r1) - mtlr %r0 - b .Lfinish - -#ifndef __LITTLE_ENDIAN__ -.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 - .cfi_def_cfa_offset 0 - blr - .cfi_def_cfa_offset 144 -#endif - -.Luint128: - lwz %r6,112+12(%r1) - mtlr %r0 - addi %r1,%r1,144 - .cfi_def_cfa_offset 0 - blr - .cfi_endproc -END(ffi_closure_SYSV) - - -FFI_HIDDEN(ffi_go_closure_sysv) -ENTRY(ffi_go_closure_sysv) - .cfi_startproc - stwu %r1,-144(%r1) - .cfi_def_cfa_offset 144 - mflr %r0 - stw %r0,148(%r1) - .cfi_offset 65, 4 - - stw %r3, 16(%r1) - stw %r4, 20(%r1) - stw %r5, 24(%r1) - - # closure->cif - lwz %r3,4(%r11) - # closure->fun - lwz %r4,8(%r11) - # user_data - mr %r5,%r11 - b .Ldoclosure - .cfi_endproc -END(ffi_go_closure_sysv) - -#if defined __ELF__ && defined __linux__ - .section .note.GNU-stack,"",@progbits -#endif -#endif +/* ----------------------------------------------------------------------- + sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com> + Copyright (c) 2008 Red Hat, 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 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. + ----------------------------------------------------------------------- */ +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#include <powerpc/asm.h> + + .file "ppc_closure.S" + +#ifndef POWERPC64 + +FFI_HIDDEN(ffi_closure_SYSV) +ENTRY(ffi_closure_SYSV) + .cfi_startproc + stwu %r1,-144(%r1) + .cfi_def_cfa_offset 144 + mflr %r0 + stw %r0,148(%r1) + .cfi_offset 65, 4 + +# 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) + + # set up registers for the routine that does the work + + # closure->cif + lwz %r3,FFI_TRAMPOLINE_SIZE(%r11) + # closure->fun + lwz %r4,FFI_TRAMPOLINE_SIZE+4(%r11) + # closure->user_data + lwz %r5,FFI_TRAMPOLINE_SIZE+8(%r11) + +.Ldoclosure: + 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 + + # pointer to the result storage + addi %r6,%r1,112 + + # pointer to the saved gpr registers + addi %r7,%r1,16 + + # pointer to the saved fpr registers + addi %r8,%r1,48 + + # pointer to the outgoing parameter save area in the previous frame + # i.e. the previous frame pointer + 8 + addi %r9,%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 + +# 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 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + nop + +# case FFI_TYPE_INT + lwz %r3,112+0(%r1) + mtlr %r0 +.Lfinish: + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_TYPE_FLOAT +#ifndef __NO_FPRS__ + lfs %f1,112+0(%r1) +#else + nop +#endif + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_TYPE_DOUBLE +#ifndef __NO_FPRS__ + lfd %f1,112+0(%r1) +#else + nop +#endif + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_TYPE_LONGDOUBLE +#ifndef __NO_FPRS__ + lfd %f1,112+0(%r1) + lfd %f2,112+8(%r1) + mtlr %r0 + b .Lfinish +#else + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + nop +#endif + +# case FFI_TYPE_UINT8 +#ifdef __LITTLE_ENDIAN__ + lbz %r3,112+0(%r1) +#else + lbz %r3,112+3(%r1) +#endif + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_TYPE_SINT8 +#ifdef __LITTLE_ENDIAN__ + lbz %r3,112+0(%r1) +#else + lbz %r3,112+3(%r1) +#endif + extsb %r3,%r3 + mtlr %r0 + b .Lfinish + +# case FFI_TYPE_UINT16 +#ifdef __LITTLE_ENDIAN__ + lhz %r3,112+0(%r1) +#else + lhz %r3,112+2(%r1) +#endif + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_TYPE_SINT16 +#ifdef __LITTLE_ENDIAN__ + lha %r3,112+0(%r1) +#else + lha %r3,112+2(%r1) +#endif + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_TYPE_UINT32 + lwz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_TYPE_SINT32 + lwz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# 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 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + nop + +# case FFI_TYPE_POINTER + lwz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_TYPE_UINT128 + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + lwz %r5,112+8(%r1) + b .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 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct. + lhz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct. + lwz %r3,112+0(%r1) +#ifdef __LITTLE_ENDIAN__ + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 +#else + srwi %r3,%r3,8 + mtlr %r0 + b .Lfinish +#endif + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct. + lwz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) +#ifdef __LITTLE_ENDIAN__ + mtlr %r0 + b .Lfinish +#else + li %r5,24 + b .Lstruct567 +#endif + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) +#ifdef __LITTLE_ENDIAN__ + mtlr %r0 + b .Lfinish +#else + li %r5,16 + b .Lstruct567 +#endif + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) +#ifdef __LITTLE_ENDIAN__ + mtlr %r0 + b .Lfinish +#else + li %r5,8 + b .Lstruct567 +#endif + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + mtlr %r0 + b .Lfinish + +#ifndef __LITTLE_ENDIAN__ +.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 + .cfi_def_cfa_offset 0 + blr + .cfi_def_cfa_offset 144 +#endif + +.Luint128: + lwz %r6,112+12(%r1) + mtlr %r0 + addi %r1,%r1,144 + .cfi_def_cfa_offset 0 + blr + .cfi_endproc +END(ffi_closure_SYSV) + + +FFI_HIDDEN(ffi_go_closure_sysv) +ENTRY(ffi_go_closure_sysv) + .cfi_startproc + stwu %r1,-144(%r1) + .cfi_def_cfa_offset 144 + mflr %r0 + stw %r0,148(%r1) + .cfi_offset 65, 4 + + stw %r3, 16(%r1) + stw %r4, 20(%r1) + stw %r5, 24(%r1) + + # closure->cif + lwz %r3,4(%r11) + # closure->fun + lwz %r4,8(%r11) + # user_data + mr %r5,%r11 + b .Ldoclosure + .cfi_endproc +END(ffi_go_closure_sysv) + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif +#endif diff --git a/contrib/restricted/libffi/src/powerpc/sysv.S b/contrib/restricted/libffi/src/powerpc/sysv.S index 1474ce702b..47e0d509fa 100644 --- a/contrib/restricted/libffi/src/powerpc/sysv.S +++ b/contrib/restricted/libffi/src/powerpc/sysv.S @@ -1,175 +1,175 @@ -/* ----------------------------------------------------------------------- - 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 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. - ----------------------------------------------------------------------- */ - -#define LIBFFI_ASM -#include <fficonfig.h> -#include <ffi.h> -#include <powerpc/asm.h> - -#ifndef POWERPC64 -FFI_HIDDEN(ffi_call_SYSV) -ENTRY(ffi_call_SYSV) - .cfi_startproc - /* Save the old stack pointer as AP. */ - mr %r10,%r1 - .cfi_def_cfa_register 10 - - /* Allocate the stack space we need. */ - stwux %r1,%r1,%r8 - /* Save registers we use. */ - mflr %r9 - stw %r28,-16(%r10) - stw %r29,-12(%r10) - stw %r30, -8(%r10) - stw %r31, -4(%r10) - stw %r9, 4(%r10) - .cfi_offset 65, 4 - .cfi_offset 31, -4 - .cfi_offset 30, -8 - .cfi_offset 29, -12 - .cfi_offset 28, -16 - - /* Save arguments over call... */ - stw %r7, -20(%r10) /* closure, */ - mr %r31,%r6 /* flags, */ - mr %r30,%r5 /* rvalue, */ - mr %r29,%r4 /* function address, */ - mr %r28,%r10 /* our AP. */ - .cfi_def_cfa_register 28 - - /* 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,-24-(8*4)(%r28) - lwz %r4,-24-(7*4)(%r28) - lwz %r5,-24-(6*4)(%r28) - lwz %r6,-24-(5*4)(%r28) - bf- 5,1f - nop - lwz %r7,-24-(4*4)(%r28) - lwz %r8,-24-(3*4)(%r28) - lwz %r9,-24-(2*4)(%r28) - lwz %r10,-24-(1*4)(%r28) - nop -1: - -#ifndef __NO_FPRS__ - /* Load all the FP registers. */ - bf- 6,2f - lfd %f1,-24-(8*4)-(8*8)(%r28) - lfd %f2,-24-(8*4)-(7*8)(%r28) - lfd %f3,-24-(8*4)-(6*8)(%r28) - lfd %f4,-24-(8*4)-(5*8)(%r28) - nop - lfd %f5,-24-(8*4)-(4*8)(%r28) - lfd %f6,-24-(8*4)-(3*8)(%r28) - lfd %f7,-24-(8*4)-(2*8)(%r28) - lfd %f8,-24-(8*4)-(1*8)(%r28) -#endif -2: - - /* Make the call. */ - lwz %r11, -20(%r28) - bctrl - - /* Now, deal with the return value. */ - mtcrf 0x01,%r31 /* cr7 */ - bt- 31,L(small_struct_return_value) - bt- 30,L(done_return_value) -#ifndef __NO_FPRS__ - bt- 29,L(fp_return_value) -#endif - 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) - .cfi_remember_state - /* At this point we don't have a cfa register. Say all our - saved regs have been restored. */ - .cfi_same_value 65 - .cfi_same_value 31 - .cfi_same_value 30 - .cfi_same_value 29 - .cfi_same_value 28 - /* Hopefully this works.. */ - .cfi_def_cfa_register 1 - .cfi_offset 1, 0 - lwz %r1,0(%r1) - .cfi_same_value 1 - blr - -#ifndef __NO_FPRS__ -L(fp_return_value): - .cfi_restore_state - 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) -#endif - -L(small_struct_return_value): - /* - * The C code always allocates a properly-aligned 8-byte bounce - * buffer to make this assembly code very simple. Just write out - * r3 and r4 to the buffer to allow the C code to handle the rest. - */ - stw %r3, 0(%r30) - stw %r4, 4(%r30) - b L(done_return_value) - .cfi_endproc - -END(ffi_call_SYSV) - -#if defined __ELF__ && defined __linux__ - .section .note.GNU-stack,"",@progbits -#endif -#endif +/* ----------------------------------------------------------------------- + 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 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. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#include <powerpc/asm.h> + +#ifndef POWERPC64 +FFI_HIDDEN(ffi_call_SYSV) +ENTRY(ffi_call_SYSV) + .cfi_startproc + /* Save the old stack pointer as AP. */ + mr %r10,%r1 + .cfi_def_cfa_register 10 + + /* Allocate the stack space we need. */ + stwux %r1,%r1,%r8 + /* Save registers we use. */ + mflr %r9 + stw %r28,-16(%r10) + stw %r29,-12(%r10) + stw %r30, -8(%r10) + stw %r31, -4(%r10) + stw %r9, 4(%r10) + .cfi_offset 65, 4 + .cfi_offset 31, -4 + .cfi_offset 30, -8 + .cfi_offset 29, -12 + .cfi_offset 28, -16 + + /* Save arguments over call... */ + stw %r7, -20(%r10) /* closure, */ + mr %r31,%r6 /* flags, */ + mr %r30,%r5 /* rvalue, */ + mr %r29,%r4 /* function address, */ + mr %r28,%r10 /* our AP. */ + .cfi_def_cfa_register 28 + + /* 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,-24-(8*4)(%r28) + lwz %r4,-24-(7*4)(%r28) + lwz %r5,-24-(6*4)(%r28) + lwz %r6,-24-(5*4)(%r28) + bf- 5,1f + nop + lwz %r7,-24-(4*4)(%r28) + lwz %r8,-24-(3*4)(%r28) + lwz %r9,-24-(2*4)(%r28) + lwz %r10,-24-(1*4)(%r28) + nop +1: + +#ifndef __NO_FPRS__ + /* Load all the FP registers. */ + bf- 6,2f + lfd %f1,-24-(8*4)-(8*8)(%r28) + lfd %f2,-24-(8*4)-(7*8)(%r28) + lfd %f3,-24-(8*4)-(6*8)(%r28) + lfd %f4,-24-(8*4)-(5*8)(%r28) + nop + lfd %f5,-24-(8*4)-(4*8)(%r28) + lfd %f6,-24-(8*4)-(3*8)(%r28) + lfd %f7,-24-(8*4)-(2*8)(%r28) + lfd %f8,-24-(8*4)-(1*8)(%r28) +#endif +2: + + /* Make the call. */ + lwz %r11, -20(%r28) + bctrl + + /* Now, deal with the return value. */ + mtcrf 0x01,%r31 /* cr7 */ + bt- 31,L(small_struct_return_value) + bt- 30,L(done_return_value) +#ifndef __NO_FPRS__ + bt- 29,L(fp_return_value) +#endif + 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) + .cfi_remember_state + /* At this point we don't have a cfa register. Say all our + saved regs have been restored. */ + .cfi_same_value 65 + .cfi_same_value 31 + .cfi_same_value 30 + .cfi_same_value 29 + .cfi_same_value 28 + /* Hopefully this works.. */ + .cfi_def_cfa_register 1 + .cfi_offset 1, 0 + lwz %r1,0(%r1) + .cfi_same_value 1 + blr + +#ifndef __NO_FPRS__ +L(fp_return_value): + .cfi_restore_state + 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) +#endif + +L(small_struct_return_value): + /* + * The C code always allocates a properly-aligned 8-byte bounce + * buffer to make this assembly code very simple. Just write out + * r3 and r4 to the buffer to allow the C code to handle the rest. + */ + stw %r3, 0(%r30) + stw %r4, 4(%r30) + b L(done_return_value) + .cfi_endproc + +END(ffi_call_SYSV) + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif +#endif |