| /* ----------------------------------------------------------------------- | |
| 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> | |
| .machine altivec | |
| #ifdef POWERPC64 | |
| .hidden ffi_call_LINUX64 | |
| .globl ffi_call_LINUX64 | |
| .text | |
| .cfi_startproc | |
| # if _CALL_ELF == 2 | |
| ffi_call_LINUX64: | |
| # ifndef __PCREL__ | |
| addis %r2, %r12, .TOC.-ffi_call_LINUX64@ha | |
| addi %r2, %r2, .TOC.-ffi_call_LINUX64@l | |
| # endif | |
| .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 | |
| # ifdef __PCREL__ | |
| bl ffi_prep_args64@notoc | |
| # else | |
| bl ffi_prep_args64 | |
| nop | |
| # endif | |
| # else | |
| bl .ffi_prep_args64 | |
| nop | |
| # 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 |